论文的题目为《Dynamic Convolution: Attention over Convolution Kernels》
paper的地址https://arxiv.org/pdf/1912.03458.pdf
代码实现地址,其中包含一维,二维,三维的动态卷积;分别可以用于实现eeg的处理,正常图像的处理,医疗图像中三维脑部的处理等等(水漫金山)。https://github.com/kaijieshi7/Dynamic-convolution-Pytorch,大家觉得有帮助的话,我就求个star。
一句话描述下文的内容:将
文章简单的回顾
这篇文章主要是改进传统卷积,让每层的卷积参数在推理的时候也是随着输入可变的,而不是传统卷积中对任何输入都是固定不变的参数。(由于本文主要说明的是代码如何实现,所以推荐给大家一个讲解论文的连接:Happy:动态滤波器卷积|DynamicConv)

对于卷积过程中生成的一个特征图
下面是attention代码的简易版本,输出的是[
class attention2d(nn.Module):def __init__(self, in_planes, K,):super(attention2d, self).__init__()self.avgpool = nn.AdaptiveAvgPool2d(1)self.fc1 = nn.Conv2d(in_planes, K, 1,)self.fc2 = nn.Conv2d(K, K, 1,)def forward(self, x):x = self.avgpool(x)x = self.fc1(x)x = F.relu(x)x = self.fc2(x).view(x.size(0), -1)return F.softmax(x, 1)
下面是文章中

其中
但是,写代码的时候如果直接将
Pytorch卷积的实现
我会从维度的视角回顾一下Pytorch里面的卷积的实现(大家也可以手写一下,几个重点:输入维度、输出维度、正常卷积核参数维度、分组卷积维度、动态卷积维度、attention模块输出维度)。
输入:输入数据维度大小为[
输出:输出维度为[
卷积核:正常卷积核参数维度为[
这里我们可以注意到,正常卷积核参数的维度是不存在
可能会出现的问题
这里描述一下实现动态卷积代码的过程中可能因为
对于图中attention模块最后softmax输出的
问题所在:正常卷积,一次输入多个数据,他们的卷积核参数是一样的,所以只需要一份网络参数即可;但是对于动态卷积而言,每个输入数据用的都是不同的卷积核,所以需要
看下维度运算[
总之,
分组卷积以及如何通过分组卷积实现
一句话描述分组卷积:对于多通道的输入,将他们分成几部分各自进行卷积,结果concate。
组卷积过程用废话描述:对于输入的数据[
巧妙的转换:上面将
我们将
详细描述实现过程:将输入数据的维度看成[1,
具体代码如下:
class Dynamic_conv2d(nn.Module):def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,):super(Dynamic_conv2d, self).__init__()assert in_planes%groups==0self.in_planes = in_planesself.out_planes = out_planesself.kernel_size = kernel_sizeself.stride = strideself.padding = paddingself.dilation = dilationself.groups = groupsself.bias = biasself.K = Kself.attention = attention2d(in_planes, K, )self.weight = nn.Parameter(torch.Tensor(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True)if bias:self.bias = nn.Parameter(torch.Tensor(K, out_planes))else:self.bias = Nonedef forward(self, x):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的softmax_attention = self.attention(x)batch_size, in_planes, height, width = x.size()x = x.view(1, -1, height, width)# 变化成一个维度进行组卷积weight = self.weight.view(self.K, -1)# 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同)aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size)if self.bias is not None:aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1)output = F.conv2d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding,dilation=self.dilation, groups=self.groups*batch_size)else:output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,dilation=self.dilation, groups=self.groups * batch_size)output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))return output
完整的代码在https://github.com/kaijieshi7/Dynamic-convolution-Pytorch,大家觉得有帮助的话,我就求个star。
纸上得来终觉浅,绝知此事要躬行。试下代码,方能体会其中妙处。