【论文阅读】——RepVGG: Making VGG-style ConvNets Great Again(二)代码+原理

紧接上篇:RepVGG: Making VGG-style ConvNets Great Again

这里我们解读其核心部分。

核心思想
其核心思想就是做一个算子融合,比如常见的conv + bn算子融合。只是这里做了更彻底,更好,将三个分支,融合成一个分支

【论文阅读】——RepVGG: Making VGG-style ConvNets Great Again(二)代码+原理_第1张图片

1. 重定义模型

训练的时候,模型主要由如下的模块组成。一个stage中有3个分支。

推理的时候,主要流程是:

  • stride != 1 的时候
    • conv3*3 + bn 融合 得到w1,b1
kernel = branch.conv.weight
running_mean = branch.bn.running_mean
running_var = branch.bn.running_var
gamma = branch.bn.weight
beta = branch.bn.bias
eps = branch.bn.eps
std = (running_var + eps).sqrt()
t = (gamma / std).reshape(-1, 1, 1, 1)
return kernel * t, beta - running_mean * gamma / std
  • conv1*1 + bn 融合 得到w2, b2。同上
  • 然后将上面两个 layer 转换成一个 conv layer ,这里的conv layer是有偏置的
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)

注意: conv3,conv1需要保持同样的stride

kernel3x3, bias3x3 = self._fuse_bn_tensor(self.rbr_dense)
kernel1x1, bias1x1 = self._fuse_bn_tensor(self.rbr_1x1)
kernelid, biasid = self._fuse_bn_tensor(self.rbr_identity)
  • stride == 1
    • conv3*3 + bn 融合 得到w1,b1
    • conv1*1 + bn 融合 得到w2, b2
    • bn 可以转换成一个中心点=1的conv3卷积,得到 w3,b3
    • 最后就是3个卷积核,偏置相加得到一个卷积核和偏置
kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid, bias3x3 + bias1x1 + biasid

2. 总结

这篇文章是算子融合 + 效果好。值得推荐

你可能感兴趣的:(深度学习,repvgg,算子融合)