计算机视觉注意力网络(五)——SKNet [CVPR 2019]

论文地址:https://arxiv.org/abs/1903.06586
代码地址:https://github.com/implus/SKNet

SENet是对特征图的通道注意力机制的研究,之前的CBAM提到了对特征图空间注意力机制的研究。这里SKNet针对卷积核的注意力机制研究。
不同大小的感受视野(卷积核)对于不同尺度(远近、大小)的目标会有不同的效果。 尽管比如Inception这样的增加了多个卷积核来适应不同尺度图像,但是一旦训练完成后,参数就固定了,这样多尺度信息就会被全部使用了(每个卷积核的权重相同)。
SKNet提出了一种机制,即卷积核的重要性,即 不同的图像能够得到具有不同重要性的卷积核

SKNet对不同图像使用的卷积核权重不同,即一种针对不同尺度的图像动态生成卷积核。 整体结构如下图所示:
计算机视觉注意力网络(五)——SKNet [CVPR 2019]_第1张图片

此图为GiantPandaCV公众号作者根据代码重画的网络图
计算机视觉注意力网络(五)——SKNet [CVPR 2019]_第2张图片

网络主要由Split、Fuse、Select三部分组成。

Split 部分是对原特征图经过不同大小的卷积核部分进行卷积的过程,这里可以有多个分支。对输入X使用不同大小卷积核分别进行卷积操作(图中的卷积核size分别为3x3和5x5两个分支,但是可以有多个分支)。操作包括卷积、efficient grouped/depthwise convolutions、BN。

Fuse部分是计算每个卷积核权重的部分。将两部分的特征图按元素求和
在这里插入图片描述
U通过全局平均池化(GAP)生成通道统计信息。得到的Sc维度为C * 1
在这里插入图片描述
经过全连接生成紧凑的特征z(维度为d * 1), δ是RELU激活函数,B表示批标准化(BN),z的维度为卷积核的个数,W维度为d×C, d代表全连接后的特征维度,L在文中的值为32,r为压缩因子。

在这里插入图片描述
在这里插入图片描述
Select 部分是根据不同权重卷积核计算后得到的新的特征图的过程。
进行softmax计算每个卷积核的权重,计算方式如下图所示。如果是两个卷积核,则 ac + bc = 1。z的维度为(d * 1)A的维度为(C * d),B的维度为(C * d),则a = A x z的维度为1 * C。

Ac、Bc为A、B的第c行数据(1 * d)。ac为a的第c个元素,这样分别得到了每个卷积核的权重。

将权重应用到特征图上。其中V = [V1,V2,…,VC], Vc 维度为(H x W),如果

select中softmax部分可参考下图(3个卷积核)
计算机视觉注意力网络(五)——SKNet [CVPR 2019]_第3张图片

基于pytorch的代码实现:

class SKConv(nn.Module):
    def __init__(self, features, WH, M, G, r, stride=1, L=32):
      """ Constructor
        Args:
            features: input channel dimensionality.
            WH: input spatial dimensionality, used for GAP kernel size.
            M: the number of branchs.
            G: num of convolution groups.
            r: the radio for compute d, the length of z.
            stride: stride, default 1.
            L: the minimum dim of the vector z in paper, default 32.
        """
        super(SKConv, self).__init__()
        d = max(int(features / r), L)
        self.M = M
        self.features = features
        self.convs = nn.ModuleList([])
        for i in range(M):
            # 使用不同kernel size的卷积
            self.convs.append(
                nn.Sequential(
                    nn.Conv2d(features,
                              features,
                              kernel_size=3 + i * 2,
                              stride=stride,
                              padding=1 + i,
                              groups=G), nn.BatchNorm2d(features),
                    nn.ReLU(inplace=False)))
            
        self.fc = nn.Linear(features, d)
        self.fcs = nn.ModuleList([])
        for i in range(M):
            self.fcs.append(nn.Linear(d, features))
        self.softmax = nn.Softmax(dim=1)

    def forward(self, x):
        for i, conv in enumerate(self.convs):
            fea = conv(x).unsqueeze_(dim=1)
            if i == 0:
                feas = fea
            else:
                feas = torch.cat([feas, fea], dim=1)
        fea_U = torch.sum(feas, dim=1)
        fea_s = fea_U.mean(-1).mean(-1)
        fea_z = self.fc(fea_s)
        for i, fc in enumerate(self.fcs):
            print(i, fea_z.shape)
            vector = fc(fea_z).unsqueeze_(dim=1)
            print(i, vector.shape)
            if i == 0:
                attention_vectors = vector
            else:
                attention_vectors = torch.cat([attention_vectors, vector],
                                              dim=1)
        attention_vectors = self.softmax(attention_vectors)
        attention_vectors = attention_vectors.unsqueeze(-1).unsqueeze(-1)
        fea_v = (feas * attention_vectors).sum(dim=1)
        return fea_v	

你可能感兴趣的:(注意力机制)