卷积涨点论文 | Asymmetric Convolution ACNet | ICCV | 2019
文章原创来自作者的微信公众号:【机器学习炼丹术】。交流群氛围超好,我希望可以建议一个:当一个人遇到问题的时候,有这样一个平台可以快速讨论并解答,目前已经1群已经满员啦,2群欢迎你的到来哦。加入群唯一的要求就是,你对AI有兴趣。加我的微信我邀请进群cyx645016617。
- 论文名称:“ACNet: Strengthening the Kernel Skeletons for Powerful CNN via Asymmetric Convolution Blocks”
- 论文链接:https://arxiv.org/abs/1908.03930
- 模型缩写:ACNet
0 我的理解
这个ACNet是一个不错的对于卷积核结构的一个创新。总的来说是一个值得在CNN模型中尝试的trick,至于有没有效果还得看缘分。不过这个trick的听同行来说,算是一个好的trick,所以值得尝试。
这个trick的代价是增加了训练阶段的时间和参数,但是并不会增加推理阶段的时长,也不会增加最终模型的参数。
1 论文讲解
这个方法挺简单了,可以用这一张图来展示:
炼丹兄带你理解这图:
- 图片分为左右两个部分,左边是训练阶段的ACNet,右边是部署的模型,可以理解为测试推理阶段;
- 一般3x3的卷积,其实就是左图中第一行的那个卷积,ACNet的创新在于3x3的卷积的侧面并行了1x3和3x1两个矩形卷积核的卷积。可以理解为,任何一个卷积网络中,本来的一个3x3的卷积层,假如使用ACNet的方法,就会变成3哥卷积层并行的一个结构。
- 三个卷积层的输出结构相加,就是这个这个AC卷积层的输出特征图了
- 为什么说,测试阶段模型的参数没有增加呢?这不是多了两个卷积层,那参数怎么会不增加呢?从右边的图可以看到,这三个卷积核其实可以合并成一个卷积核,所以其实acnet是完全等价于一般的卷积模型的。
个人的理解,一般的模型也是有可能训练出ACNet的效果的,因为两者的参数完全等价。但是ACNet可能是因为强化了横向和纵向的特征,所以会取得更好的效果。并且这个相当于,给卷积核增加了一层限制,卷积核的每一个参数不再是同等中重要的,中心更为重要。因为增加了限制,可能也会避免过拟合。这是个人从实验中得到的一些猜想和思考。
下面看一下另外一篇文章的解释,看得懂的朋友可以验证自己理解的是否正确:
2 训练代码
我先写一个用一般卷积的非常简单的分类网络:
class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.features = nn.Sequential( nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(32), n 56c n.ReLU(inplace=True), nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(32), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(32, 64, kernel_size=3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.Conv2d(64, 64, kernel_size=3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2) ) self.classifier = nn.Sequential( nn.Dropout(p = 0.5), nn.Linear(64 * 7 * 7, 512), nn.BatchNorm1d(512), nn.ReLU(inplace=True), nn.Dropout(p = 0.5), nn.Linear(512, 512), nn.BatchNorm1d(512), nn.ReLU(inplace=True), nn.Dropout(p = 0.5), nn.Linear(512, 10), ) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x
下面我来把这个网络转成使用ACNet的结构,先构建一个acblock来代替卷积:
class ACConv2d(nn.Module): def __init__(self,in_channels,out_channels,kernel_size=3,stride=1,padding=1,bias=True): super(ACConv2d,self).__init_ ad8 _() self.conv = nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size, stride=stride,padding=padding,bias=True) self.ac1 = nn.Conv2d(in_channels,out_channels,kernel_size=(1,kernel_size), stride=stride,padding=(0,padding),bias=True) self.ac2 = nn.Conv2d(in_channels,out_channels,kernel_size=(kernel_size,1), stride=stride,padding=(padding,0),bias=True) def forward(self,x): ac1 = self.ac1(x) ac2 = self.ac2(x) x = self.conv(x) return (ac1+ac2+x)/3
然后把网路中的
nn.Conv2d替换成
ACConv2d即可:
class ACNet(nn.Module): def __init__(self): super(ACNet, self).__init__() self.features = nn.Sequential( ACConv2d(1, 32, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(32), nn.ReLU(inplace=True), ACConv2d(32, 32, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(32), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ACConv2d(32, 64, kernel_size=3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), ACConv2d(64, 64, kernel_size=3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2) ) self.classifier = nn.Sequential( nn.Dropout(p = 0.5), nn.Linear(64 * 7 * 7, 512), nn.BatchNorm1d(512), nn.ReLU(inplace=True), nn.Dropout(p = 0.5), nn.Linear(512, 512), nn.BatchNorm1d(512), nn.ReLU(inplace=True), nn.Dropout(p = 0.5), nn.Linear(512, 10), ) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x
3 效果及原因
效果上看,模型在ImageNet上是有一定的效果的。为什么会有这样的提升呢?论文中给出了一种解释,因为1x3和3x1的卷积核对于竖直翻转和水平翻转是有鲁棒性的。看下图:
特征图竖直翻转之后,对于1x3的卷积核的特征并没有影响,但是3x3的卷积核中的特征已经发生改变。同理,3x1的卷积核对于水平翻转也有鲁棒性。 103c
这个翻转鲁棒性是一种解释,下面还有另外一种解释:
这部分的原因个人理解是来自梯度差异化,原来只有一个[公式]卷积层,梯度可以看出一份,而添加了1x3和3x1卷积层后,部分位置的梯度变为2份和3份,也是更加细化了。而且理论上可以融合无数个卷积层不断逼近现有网络的效果极限,融合方式不限于相加(训练和推理阶段一致即可),融合的卷积层也不限于1x3或3x1尺寸。
我把这个方法用在我MNIST数据集的识别上,不过没有什么效果哈哈。希望将来可以我的项目有提升效果,是一个值得尝试的trick,欢迎大家收藏点赞。
4 改进
最后,如果你耐心看到这里,并且对之前的内容加以思考,就会发现,我写的ac卷积,并没有实现在推理过程的卷积核融合。我后来完善了一下代码,当调用
model.eval()后,acconv卷积就会融合成一个卷积层,而不是3个并行的卷积层:
class ACConv2d(nn.Module): def __init__(self,in_channels,out_channels,kernel_size=3,stride=1,padding=1,bias=False): super(ACConv2d,self).__init__() self.bias = bias self.conv = nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size, stride=stride,padding=padding,bias=bias) self.ac1 = nn.Conv2d(in_channels,out_channels,kernel_size=(1,kernel_size), stride=stride,padding=(0,padding),bias=bias) self.ac2 = nn.Conv2d(in_channels,out_channels,kernel_size=(kernel_size,1), stride=stride,padding=(padding,0),bias=bias) self.fusedconv = nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size, stride=stride,padding=padding,bias=bias) def forward(self,x): if self.training: ac1 = self.ac1(x) ac2 = self.ac2(x) x = self.conv(x) return (ac1+ac2+x)/3 else: x = self.fusedconv(x) return x def train(self,mode=True): super().train(mode=mode) if mode is False: weight = self.conv.weight.cpu().detach().numpy() weight[:,:,1:2,:] = weight[:,:,1:2,:] + self.ac1.weight.cpu().detach().numpy() weight[:,:,:,1:2] = weight[:,:,:,1:2] + self.ac2.weight.cpu().detach().numpy() self.fusedconv.weight = torch.nn.Parameter(torch.FloatTensor(weight/3)) if self.bias: bias = self.conv.bias.cpu().detach().numpy()+self.conv.ac1.cpu().detach().numpy()+self.conv.ac2.cpu().detach().numpy() self.fusedconv.bias = torch.nn.Parameter(torch.FloatTensor(bias/3)) if torch.cuda.is_available(): self.fusedconv = self.fusedconv.cuda()
感谢各位的阅读,喜欢的可以点个“赞”和“在看”!
参考文章:
- 人脸真伪验证与识别:ICCV2019论文解析
- ICCV2019论文点评:3D Object Detect疏密度点云三维目标检测
- 2019-ICCV最佳论文解读-SinGAN: Learning a Generative Model from a Single Natural Image
- ICCV 2019 最佳论文和最佳学生论文下载
- ICCV 2019 Oral 论文 FiNet: Compatible and Diverse Fashion Image Inpainting
- ICCV 2019 最佳论文《SinGAN:从单张自然图像学习生成式模型》
- 2019 CVPR和ICCV会议论文
- ICCV2019论文解读: 北大、华为联合提出无需数据集的Student Networks
- 我如何用飞桨复现了ICCV 2019 ACNet模型?
- ICCV2019入选论文分析 谷歌实力霸榜!国内中科院第一,产业界商汤领跑!
- 2019 Action Recognition 顶会论文(CVPR、ICCV)
- Few-Shot Unsupervised Image-to-Image Translation——ICCV2019论文解读
- 语义分割论文:Group-wise Deep Object Co-Segmentation with Co-AttentionRecurrent Neural Network(ICCV2019)
- 1人15篇入选?华人论文知多少?深度分析ICCV2019论文录取背后的那些事儿!
- 视频动作定位的分层自关注网络:ICCV2019论文解析
- 三维点云去噪无监督学习:ICCV2019论文分析
- ICCV 2019| Auto GAN 论文解读,神经网络结构搜索 + 生成对抗网络
- 摄像头定位:ICCV2019论文解析
- 论文解读:ICCV2019 Best paper SinGAN
- 细粒度语义分割:ICCV2019论文解析