RepVGG-重参数化Backbone | Making VGG-style ConvNets Great Again

ACNet的同理篇,很早就关注到了,同期待ACNetV2
论文地址:https://arxiv.org/pdf/2101.03697.pdf
github地址:https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py在这里插入图片描述

Abstract:

本文提出了一个简单但功能强大的卷积神经网络架构,该架构推理时候具有类似于VGG的骨干结构,该主体仅由3 x 3卷积和ReLU堆叠组成,而训练时候模型采用多分支拓扑结构。 训练和推理架构的这种解耦是通过结构重参数化技术实现的,因此该模型称为RepVGG。 在ImageNet上,据我们所知,RepVGG的top-1准确性达到80%以上,这是老模型首次实现该精度。 在NVIDIA 1080Ti GPU上,RepVGG模型的运行速度比ResNet-50快83%,比ResNet-101快101%,并且具有更高的精度,与诸如EfficientNet和RegNet的最新模型相比,RepVGG显示出良好的精度-速度权衡。 效果如下图:
在这里插入图片描述

Introduction:

现有最新的ConvNet通过复杂的结构设计都比简单的ConvNet提供更高的准确性,但缺点很明显

1)复杂的多分支设计(例如ResNet中的残差加法和Inception中的分支级联)使模型难以实现和定制,减慢了推理速度并降低了内存利用率。

2)一些组件(例如,Xception和MobileNets 中的深度卷积以及ShuffleNet中的通道shuffle播)增加了内存访问成本,并且缺乏对各种设备的支持。

此外,现有的很多模型虽然对外宣称其Flops低于VGG以及ResNet等基础模型,但是实际的推理速度远低于以上模型。因此,现有工业学术圈仍然将ResNet等基础模型大量用于现实应用中。在这里插入图片描述
因此,本文通过结构重新参数化将训练与推理结构进行解耦(之前的ACNet同理)。如上图所示,本文基于传统VGGNet+ResNet结构为基础,训练时候采用多分支结构来提升性能,推理时候则重参数化为单一的3x3卷积 + Relu结构来加速推理。本文主要贡献如下:

•本文提出了RepVGG,这是一种简单的体系结构,与最新技术相比,具有良好的速度精度权衡。

•本文提出使用结构重新参数化将训练时的多分支拓扑与推理时的简单体系结构分离。

•本文展示了RepVGG在图像分类和语义分割中的有效性,以及实现的效率和简便性。

Related Work:

重点介绍一下Winograd Convolution
在这里插入图片描述

RepVGG之所以仅使用3 x 3卷积,因为它已在GPU和CPU上通过某些现代计算库(如NVIDIA cuDNN 和Intel MKL)进行了高度优化。表。图1显示了在1080Ti GPU上使用cuDNN 7.5.0测试的理论FLOPs,实际运行时间和计算密度(以每秒Tera浮点运算,TFLOPS衡量)。

结果表明,3 x 3 conv的理论计算密度约为其他模型的4倍,这表明总的理论FLOP不能替代不同体系结构中的实际速度。加速3x3转换的经典算法是Winograd算法[仅当步幅为1时),而cuDNN和MKL等库已经很好地支持(默认情况下启用)。例如,使用标准F(2 x 2; 3 x 3)Winograd,3x3转换的乘法(MUL)数量将减少为原始的4/9。由于乘法比加法耗时得多,因此我们计算了MUL来衡量Winograd支持下的计算成本(在表4、5中由Wino MUL表示)。请注意,特定的计算库和硬件确定是否为每个运算符使用Winograd,因为小规模的卷积可能由于内存开销而无法加速。

RepVGG:

A.本文使用简单的ConvNet至少有三个原因:

1.Fast :

除了Winograd conv带来的加速之外,FLOPs和速度之间的差异可以归因于两个重要因素,它们对速度有很大影响,但FLOPs并未考虑这些因素:内存访问成本(MAC)和并行度。 另一方面,在相同的FLOPs下,具有高并行度的模型可能比具有低并行度的模型快得多。因此简单的推理结构可以避免多分支的零碎计算。

2.memory-economical:

在这里插入图片描述
如上图所示,多分支拓扑结构由于需要保留每个分支的结果,直到相加或串联为止,从而显着提高了内存占用的峰值。 假设该块保持特征图的大小,则内存占用的峰值为2倍。 相反,简单的拓扑允许在操作完成后立即释放特定层的输入所占用的内存。 在设计专用硬件时,普通的ConvNet可以进行深度内存优化并降低内存单元的成本,因此我们可以将更多计算单元集成到芯片上。

3.Flexible :

多分支拓扑结构限制了模型剪枝的应用。

B.Trainingtime Multibranch Architecture:

训练时采用的多分支结构采用3 x 3卷积 + 1 x 1卷积 + identity分支,比较简单,这里不再赘述。直接看代码:需要注意的是:1.通过deploy设置来进行重参数化推理;2.identity分支并不是直接相加,是有BN的

class RepVGGBlock(nn.Module):

    def __init__(self, in_channels, out_channels, kernel_size,
                 stride=1, padding=0, dilation=1, groups=1, padding_mode='zeros', deploy=False):
        super(RepVGGBlock, self).__init__()
        self.deploy = deploy
        self.groups = groups
        self.in_channels = in_channels

        assert kernel_size == 3
        assert padding == 1

        padding_11 = padding - kernel_size // 2

        self.nonlinearity = nn.ReLU()
		#用过deploy设置进行重参数化
        if deploy:
            self.rbr_reparam = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,
                                      padding=padding, dilation=dilation, groups=groups, bias=True, padding_mode=padding_mode)

        else:
            self.rbr_identity = nn.BatchNorm2d(num_features=in_channels) if out_channels == in_channels and stride == 1 else None
            self.rbr_dense = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride, padding=padding, groups=groups)
            self.rbr_1x1 = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=stride, padding=padding_11, groups=groups)
            print('RepVGG Block, identity = ', self.rbr_identity)


    def forward(self, inputs):
        if hasattr(self, 'rbr_reparam'):
            return self.nonlinearity(self.rbr_reparam(inputs))

        if self.rbr_identity is None:
            id_out = 0
        else:
            id_out = self.rbr_identity(inputs)

        return self.nonlinearity(self.rbr_dense(inputs) + self.rbr_1x1(inputs) + id_out)

C.Reparam for Plain Inference-timeModel:
在这里插入图片描述
如上图所示,针对输入M,则输出公式为,W代表卷积权重, μ , δ , γ , β \mu,\delta, \gamma, \beta μδγβ为BN的四个参数,重参数化就是对多分支的卷积BN进行层融合,原理比较简单,就是单纯的公式推导,我在参加中兴算法比赛的时候,有过记录
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210113162854622.png
具体来说,将3个分支卷积权重,identity映射可以看作是1x1卷积,以identity矩阵作为内核。将两个分支的1x1卷积权重进行padding至3x3大小,即可进行融合。BN层则可以直接融合。注意:这种变换的等效条件要求3 x 3和1 x 1层具有相同的步幅,并且后者的padding配置应比前者少一个像素。 例如,对于3x3的图层,将输入填充一个像素(这是最常见的情况),则1 x 1的图层应具有padding = 0。具体可以见源码。

Experiments:

1.Imagenet:
在这里插入图片描述
2.Semantic Segmentation:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42096202/article/details/112546234