RepVGG
# RepVGG: Making VGG-style ConvNets Great Again
# 单位:THU, MegVII
# 作者:Xiaohan Ding, Xiangyu Zhang, Ningning Ma, Jungong Han, Guiguang Ding, Jian Sun
# 发表:CVPR 2021
# Motivation
- 多分支训练的优点:隐式集成,往往性能更高;
- 多分支训练的缺点:每个分支结果需要保存,直到最后一步融合才释放掉,比较消耗显存
- 单分支结构:速度快,省内存,但其性能较低
是否能融合多分支和单分支的优点呢:让单分支网络也有隐式的集成所带来的性能提升
RepVGG就做了这样的事情
# Method
先介绍一下做法:在训练的时候加入多分支结构进行训练,在推理的时候重参数化为单分支结构加速推理
Reparam(3x3) = 3x3-BN + 1x1-BN + BN。对每个3x3卷积,在训练时给它构造并行的恒等和1x1卷积分支,并各自过BN后相加。
# Problem
简单看完做法之后,提一些问题:
为什么去掉分支和多的 BN 不会对性能造成影响呢
- 去掉分支是否有等价性的证明?
- 作者将训练得到的三个卷积都看作是 3x3 卷积,其参数相加是等价于修改前的多分支的效果
- 去掉多的 BN 会不会对性能有所影响?
- BN 和 Conv 可以融合到一起形成 Fused BN,是加速的常用操作
- 但是积累的均值和方差会不一样?
- 在推理的时候 BN 的均值和方差都是采用训练阶段的
# Details
详细讲下设计到的两个核心部件
1、卷积等价性
参考资料
https://zhuanlan.zhihu.com/p/344324470
https://zhuanlan.zhihu.com/p/352239591
因为RepVGG Block中的1x1卷积是相当于一个特殊(卷积核中有很多0)的3x3卷积
而恒等映射是一个特殊(以单位矩阵为卷积核)的1x1卷积,因此也是一个特殊的3x3卷积!
操作方式
- 把identity转换为1x1卷积,只要构造出一个以单位矩阵为卷积核的1x1卷积即可;
- 把1x1卷积等价转换为3x3卷积,只要用0填充即可。
2、卷积和 BN 进行融合
参考资料:https://zhuanlan.zhihu.com/p/352239591
将其变形为
那么可以得到一个新卷积层,其参数为
最终融合的效果即为
代码参考,这份代码里没有处理原卷积的 bias,因为 RepVGG 的卷积层中没有使用 Bias
def _fuse_bn_tensor(self, branch):
if branch is None:
return 0, 0
if isinstance(branch, nn.Sequential):
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
else:
...
std = (running_var + eps).sqrt()
t = (gamma / std).reshape(-1, 1, 1, 1)
return kernel * t, beta - running_mean * gamma / std
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 参考资料
https://arxiv.org/abs/2101.03697
https://github.com/DingXiaoH/RepVGG
上次更新: 2023/03/25, 19:58:09
- 02
- README 美化05-20
- 03
- 常见 Tricks 代码片段05-12