【论文阅读】RepVGG: Making VGG-style ConvNets Great Again翻译

RepVGG是一种基于VGG架构的卷积神经网络,通过结构重参数化技术在训练时使用多分支结构,而在推理时转换为单一路径,实现了性能和速度的良好平衡。论文指出,RepVGG模型在ImageNet上达到了超过80%的top-1精度,同时在GPU上的运行速度比ResNet-50快83%。这种技术通过解耦训练和推理时间的架构,简化推理阶段的模型,提高了推理效率。此外,RepVGG模型的构建不需要自动或手动的架构搜索,而是通过简单的结构实例化,展现出易用性和灵活性。

RepVGG: Making VGG-style ConvNets Great Again论文翻译-CVPR2021

论文地址:https://arxiv.org/abs/2101.03697
代码地址:https://github.com/DingXiaoH/RepVGG
图片作者信息

摘要

我们提出了一个简单但功能强大的卷积神经网络体系结构,它有一个推理阶段的VGG-like型主体,只有一个由3*3卷积和ReLU组成的堆栈,而训练时间模型具有多分支拓扑。这种训练时间和推理时间体系结构的解耦是通过一种结构重参数化技术实现的,因此该模型被命名为RepVGG。在ImageNet上,据我们所知,RepVGG作为普通模型第一次达到了80%以上的top-1精度。在NVIDIA 1080Ti GPU上,RepVGG模型的运行速度比ResNet-50快83%,比ResNet-101快101%,且具有更高的精度,与最先进的模型如EfficientNet和RegNet相比,显示出良好的精度-速度平衡。代码和训练模型在https://github.com/megvii-model/RepVGG。

Introduction

卷积神经网络(ConvNets)已经成为许多任务的主流解决方案。VGG[30]通过由conv、ReLU、pooling组成的简单架构,在图像识别方面取得了巨大的成功。随着Inception [32,33,31,17], ResNet[10]和DenseNet[15]的出现,大量的研究兴趣转向了良好设计的架构,使得模型越来越复杂。最近一些强大的架构是通过自动[43,28,22]或手动[27]架构搜索,或在基本架构[34]上搜索复合缩放策略获得的。
尽管许多复杂的卷积神经网络比简单的卷积神经网络具有更高的精度,但缺点也很明显。1)复杂的多分支设计(如ResNet中的剩余添加和Inception中的分支连接)使模型难以实现和自定义,降低了推理速度,降低了内存利用率。2)一些组件(例如,Xception[2]和MobileNets[14, 29]中的深度卷积和ShuffleNets中的信道搅乱[23, 40])增加内存访问成本,缺乏各种设备的支持。由于影响推断速度的因素有很多,浮点操作(FLOPs)的数量并不能准确地反映实际速度。虽然一些新的模型比之前的诸如VGG和resnet -18/34/ 50[10]有更低的FLOPs,但它们运行起来可能不会更快(表4)。因此,VGG和ResNets的原始版本仍然在学术界和工业界的现实应用中大量使用。

figure1
图1:ImageNet上的最高精度与实际速度。左图:轻量级和中量级RepVGG和120个时代训练的基线。右图:重量级模型训练了200个时代。该速度在相同的1080Ti上进行测试,批量尺寸为128,全精度(fp32),单批,以示例/秒进行测量。effentnet - b3[34]的输入分辨率为300,其余[34]的输入分辨率为224。

figure2
图2:RepVGG基础框架。RepVGG有5个阶段,在阶段开始时通过stride-2卷积进行下行采样。这里我们只展示第一个特定阶段的4个层次。受ResNet[10]的启发,我们也使用identity和1*1分支,但只用于训练。

在本文中,我们提出了RepVGG,一个vgg风格的架构,它优于许多复杂的模型(图1).。RepVGG具有以下优势:

  • 该模型具有VGG-like的平面(也称为前馈)拓扑结构没有任何分支。也就是说,每一层都将其上一层的输出作为输入,并将输出输入到下一层。
  • 模型的主体只使用3*3 卷积和ReLU激励函数。
  • 具体的架构(包括特定的深度和层宽)实例化时不需要自动搜索[43]、手动细化[27]、复合缩放[34],或者其他繁重的设计。

普通模型要达到与多分支架构相当的性能水平是很有挑战性的。一种解释是多分支拓扑结构,例如ResNet,使模型成为众多浅模型[35]的隐式集合,因此训练一个多分支模型可以避免梯度消失的问题。
由于多分支体系结构的优点都是用于训练,而缺点则不是用于推理,因此我们提出通过结构重参数化将训练时间的多分支体系结构和推理时间的普通体系结构解耦,这意味着通过转换其参数将体系结构从一个转换为另一个。具体来说,一个网络结构是与一组参数耦合的,例如,一个卷积层用一个四阶核张量来表示。如果将某一结构的参数转换成另一结构耦合的另一组参数,我们就可以将前者等效为后者,从而改变整个网络结构。
具体来说,我们使用identity和1*1的分支构建训练时的RepVGG,这是受到ResNet的启发,但以不同的方式,可以通过结构重参数化删除分支(图2、4)。训练后,我们用简单代数来执行转换,一个identity分支可以被视为一个退化的1*1 卷积,而后者可以进一步被视为退化的3*3卷积,这样我们可以构造一个简单的3*3内核与原有的训练参数3*3内核、identity、1*1分支和批处理规范化(BN)[17]层。因此,转换后的模型有一堆3*3的卷积层,这些层被保存起来用于测试和部署。
值得注意的是,推理时间的RepVGG只涉及一种类型的操作:33的卷积和ReLU,这使得RepVGG在gpu等通用计算设备上运行速度很快。更好的是,RepVGG允许专用硬件实现更高的速度,因为考虑到芯片大小和功耗,我们需要的操作类型越少,我们可以集成到芯片上的计算单元就越多。也就是说,专门用于RepVGG的推理芯片可以拥有大量的33-ReLU单元和更少的内存单元(因为简单拓扑是内存经济的,如图3所示)。我们的贡献总结如下。

  • 我们提出了RepVGG,一种简单的架构,与最先进的技术相比,具有良好的速度-精度平衡。
  • 我们提出使用结构重参数化来解耦训练时间多分支拓扑和推理时间简单结构。
  • 我们已经证明了RepVGG在图像分类和语义分割方面的有效性,以及实现的效率和易用性。
2. Related Work
2.1. From Single-path to Multi-branch(从单路径到多分支)

在VGG[30]将ImageNet分类的top-1准确率提高到70%以上之后,在使ConvNets变得复杂以达到高性能方面有很多创新,如当代的google[32]及以后的版本Inception模型[33,31,17]采用了精心设计的多分支架构,ResNet[10]提出了简化的双分支架构,DenseNet[15]通过将低层和大量的高层连接起来,使得拓扑结构更加复杂。神经结构搜索(Neural architecture search, NAS)[43,28,22,34]和人工设计空间设计[27]可以生成性能更高的卷积网络,但代价是大量的计算资源或人

**RepVGG: Making VGG-Style ConvNets Great Again** 是一种通过结构重参数化(Structural Re-parameterization)技术,将训练时的多分支复杂结构转换为推理时的单路VGG风格结构(仅含3×3卷积和ReLU)的卷积神经网络设计方法。以下是其核心思想与实现的分步解析: --- ### **1. 核心动机** - **VGG风格的优势**: - 结构简单(仅堆叠3×3卷积和ReLU),硬件友好(适合并行计算)。 - 但纯VGG网络在深层时易梯度消失,性能落后于ResNet等复杂结构。 - **现有结构的矛盾**: - 训练时需多分支结构(如ResNet的残差连接、Inception的多路径)提升梯度流动。 - 推理时多分支增加内存访问开销(MACs),降低实际速度。 - **RepVGG的解决方案**: - **训练时**:采用多分支结构(如ResNet的恒等映射+1×1卷积分支)。 - **推理时**:通过重参数化将多分支合并为单路3×3卷积,实现“训练复杂、推理简单”。 --- ### **2. 结构重参数化技术** #### **(1) 训练阶段的多分支设计** RepVGG的训练块(Block)包含三个并行分支: 1. **3×3卷积分支**:主路径,提取局部特征。 2. **1×1卷积分支**:调整通道数,增加非线性。 3. **恒等映射(Identity)分支**:短连接,缓解梯度消失。 **数学形式**: 输入 \( x \),输出 \( y \) 为: \[ y = \text{ReLU}(\text{BN}_3(\text{Conv}_3(x)) + \text{BN}_1(\text{Conv}_1(x)) + \text{BN}_0(x)) \] 其中 \( \text{Conv}_3 \) 是3×3卷积,\( \text{Conv}_1 \) 是1×1卷积,\( \text{BN}_i \) 是批归一化层。 #### **(2) 推理阶段的单路转换** 通过以下步骤将多分支合并为单个3×3卷积: 1. **BN融合**: - 将每个分支的卷积(Conv)和批归一化(BN)合并为带偏置的卷积: \[ \text{Conv}_{\text{fused}} = \gamma \cdot \text{Conv} / \sqrt{\sigma^2 + \epsilon} + (\beta - \gamma \cdot \mu / \sqrt{\sigma^2 + \epsilon}) \] 其中 \( \gamma, \beta \) 是BN的缩放和平移参数,\( \mu, \sigma^2 \) 是均值和方差。 2. **1×1卷积→3×3卷积**: - 用零填充将1×1卷积的权重矩阵扩展为3×3(中心为原权重,四周为零)。 3. **恒等映射→3×3卷积**: - 将恒等映射视为一个特殊的3×3卷积,其权重矩阵中心为1,其余为零。 4. **分支合并**: - 将三个分支的3×3卷积权重和偏置相加,得到最终的3×3卷积: \[ W_{\text{final}} = W_3 + W_{1\to3} + W_{\text{id}\to3}, \quad b_{\text{final}} = b_3 + b_{1\to3} + b_{\text{id}\to3} \] **效果**: - 推理时模型变为纯VGG风格(仅3×3卷积+ReLU),速度更快(实测在GPU上比ResNet50快13%)。 - 参数和计算量与训练时相同(因重参数化无额外开销)。 --- ### **3. RepVGG的核心设计** #### **(1) 阶段式架构** - 类似ResNet,分多个阶段(Stage),每个阶段内堆叠相同结构的Block。 - **下采样**:通过步长为2的3×3卷积实现,同时通道数翻倍。 #### **(2) 通道数配置** - 浅层(如Stage1)通道数较少(如64),深层(如Stage4)通道数较多(如512)。 - **优势**:平衡计算量和表达能力,避免深层参数过多。 #### **(3) 训练技巧** - **数据增强**:采用AutoAugment或RandAugment提升泛化性。 - **标签平滑**:缓解过拟合(平滑系数0.1)。 - **混合精度训练**:加速训练并减少显存占用。 --- ### **4. 性能对比** | 模型 | 参数量(M) | Top-1准确率(ImageNet) | 推理速度(img/s, V100 GPU) | |---------------|-------------|--------------------------|-----------------------------| | ResNet50 | 25.6 | 76.5% | 1236 | | RepVGG-A0 | 8.3 | 72.4% | 3448(+179%) | | RepVGG-B1 | 51.8 | 78.4% | 1472(+19%) | | RepVGG-B3 | 103.9 | 80.5% | 831 | - **优势**:在相似参数量下,RepVGG的推理速度显著优于ResNet(尤其低参数量模型)。 - **代价**:训练时需多分支结构,可能增加内存占用(但可通过梯度检查点缓解)。 --- ### **5. 代码实现(PyTorch示例)** #### **(1) 训练块定义** ```python import torch import torch.nn as nn class RepVGGBlock(nn.Module): def __init__(self, in_channels, out_channels, stride=1): super().__init__() self.stride = stride self.conv1 = nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=False) self.conv3 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.bn3 = nn.BatchNorm2d(out_channels) self.bn_id = nn.BatchNorm2d(in_channels) if stride == 1 else None self.relu = nn.ReLU(inplace=True) def forward(self, x): id_out = 0 if self.stride == 1: id_out = self.bn_id(x) out3 = self.bn3(self.conv3(x)) out1 = self.bn1(self.conv1(x)) return self.relu(out3 + out1 + id_out) ``` #### **(2) 重参数化转换** ```python def repvgg_convert(block): # 融合BN到Conv def fuse_bn(conv, bn): w = conv.weight std = (bn.running_var + bn.eps).sqrt() t = (bn.running_mean - bn.bias) / std w_fused = w * (bn.weight / std).reshape([-1, 1, 1, 1]) b_fused = bn.bias + (bn.weight * t) - std * (w * t).sum([1, 2, 3]) return nn.Conv2d(conv.in_channels, conv.out_channels, 3, conv.stride, 1, bias=True) # 转换3×3分支 conv3_fused = fuse_bn(block.conv3, block.bn3) # 转换1×1分支为3×3 conv1_fused = nn.Conv2d(block.conv1.in_channels, block.conv1.out_channels, 3, 1, 1, bias=True) conv1_fused.weight.data.zero_() conv1_fused.weight.data[:, :, 1, 1] = block.conv1.weight.data conv1_fused.bias.data = block.bn1.bias - block.bn1.running_mean * block.bn1.weight / ( (block.bn1.running_var + block.bn1.eps).sqrt() ) # 合并分支 final_conv = nn.Conv2d( conv3_fused.in_channels, conv3_fused.out_channels, 3, conv3_fused.stride, 1, bias=True ) final_conv.weight.data = conv3_fused.weight.data + conv1_fused.weight.data if block.stride == 1: id_conv = nn.Conv2d(block.bn_id.num_features, block.bn_id.num_features, 3, 1, 1, bias=True) id_conv.weight.data.zero_() id_conv.weight.data[:, :, 1, 1] = 1.0 final_conv.weight.data += id_conv.weight.data final_conv.bias.data = conv3_fused.bias.data + conv1_fused.bias.data + block.bn_id.bias - block.bn_id.running_mean else: final_conv.bias.data = conv3_fused.bias.data + conv1_fused.bias.data return final_conv ``` --- ### **6. 挑战与改进方向** 1. **极深网络的训练稳定性**: - 超过50层的RepVGG可能需引入更多残差连接或梯度裁剪。 2. **移动端部署优化**: - 结合通道剪枝或量化(如INT8)进一步压缩模型。 3. **自适应结构**: - 根据任务动态调整分支数量(如浅层用1×1分支,深层用恒等映射)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值