论文链接:https://arxiv.org/abs/2101.03697
RepVGG提出 在训练时,训练一个多分支网络,以提高模型精度;在检测时,将训练的多分支网络等价装换为一个单分支网络,以提高运行速度。
模型结构方面,使用3×3卷积堆叠,构建模型。训练时,模型通过1×1卷积计算残差,并通过identity层短路连接进行恒等映射;在部署时,将模型中残差连接与短路连接进行等价转换,形成单分支模型。

进行等价转换时,主要思想为:conv(x, w1) + conv(x, w2) + conv(x, w3) = conv(x ,w1 + w2 + w3)。转换时,将identity视作核值固定为1的1×1卷积,将1×1卷积核padding0形为3×3卷积核,然后合并3×3与1×1卷积核。
# -*- coding: utf-8 -*-
# @Author : LG
import torch
from torch.nn import functional as f
import numpy as np
if __name__ == '__main__':
# 一个3x3的输入
input = torch.from_numpy(np.array([[[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]]]))
# 3x3卷积核
weight_3x3 = torch.tensor([[[[1,2,1], [2,1,2], [1,3,2]]]])
conv_3x3 = f.conv2d(input, weight=weight_3x3, stride=1,padding=1)
print(conv_3x3)
# 1x1卷积核
weight_1x1 = torch.tensor([[[[2]]]])
conv_1x1 = f.conv2d(input, weight=weight_1x1, stride=1)
print(conv_1x1)
# 这里identity 可以看作值为1的1x1卷积
weight_identity = torch.tensor([[[[1]]]])
identity = f.conv2d(input, weight=weight_identity, stride=1)
print(identity)
# 相加合并结果
result = conv_3x3 + conv_1x1 + identity
print(result)
# 先合并卷积核,然后计算。
# 1x1卷积需要padding0 作为一个3x3卷积核,然后相加
weight_merge = weight_3x3 + f.pad(weight_1x1, [1, 1, 1, 1]) + f.pad(weight_identity, [1, 1, 1, 1])
print(weight_merge)
# 单次卷积计算,结果相同
conv_merge = f.conv2d(input, weight_merge, stride=1, padding=1)
print(conv_merge)