参考
代码:https://github.com/kaijieshi7/Dynamic-convolution-Pytorch
博客:https://mp.weixin.qq.com/s/mZUSH7_7ysISoSMfxo4Vjw
就是原本的一个固定的卷积核,现在变为可以根据输入自适应改变注意力的卷积核
如上图所示,现在一个卷积核由K个卷积核决定,参数量大约上升了K倍(论文中说计算量并没有上升多少)
输入经过注意力提取,得到这k个卷积核的权重,线性加权起来就是新的一个卷积核
attention部分也就是普通的SENet那套,得到k个参数,不过要将原本的一个卷积核变为由k个卷积核加权的卷积核实现起来还是有坑,比如batchsize>1时,这个batch里的每个数据都需要不同的k个卷积核。
此时,attention和reshape后的kernel相乘,结果weight_size=[batch_size,out_plane*in_plane*kernel_size*kernel_size]
而x的shape为[batch_size,in_plane,height,width]
用分组卷积实现的话,weight_size的前两个维度融合,变成1个output_channel=batch_size*out_planes的卷积核,然后分batch_size组卷积,(输入x和kernel都会被分为batch_size组)即可实现每个sample对应不同的kernel
如果不用分组卷积,实际上就是不做前两个维度融合的操作,这样我们的卷积核weight_size=[batch_size, out_plane, in_plane, kernel_size, kernel_size],有5个维度,而用F.conv2d的话weigt参数要求是4个维度,而且是对所有x使用同样的一套卷积核,于是改用分组卷积来实现
以下为开头链接的代码,加了我自己的一些注释
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 import pdb
5 import os
6
7 os.environ['CUDA_VISIBLE_DEVICES'] = '7'
8 class attention2d(nn.Module):
9 def __init__(self,in_planes,ratio,K,temperature,init_weight=True):
10 super(attention2d, self).__init__()
11 assert temperature%3==1
12 self.avgpool = nn.AdaptiveAvgPool2d(1)
13 if in_planes != 3:
14 hidden_planes = int(in_planes*ratio)#这边是为了做一个bottleneck结构
15 else:
16 hidden_planes = K
17 self.fc1 = nn.Conv2d(in_planes, hidden_planes, 1, bias=False)
18