前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【CV中的Attention机制】基于SENet的改进-SKNet

【CV中的Attention机制】基于SENet的改进-SKNet

作者头像
深度学习技术前沿公众号博主
发布2020-05-25 15:37:09
2.6K0
发布2020-05-25 15:37:09
举报
文章被收录于专栏:深度学习技术前沿

上一篇文章,我们详细介绍了Attention机制和视觉注意力机制在图像分类结构中的应用--SENet。本文我们将来聊一聊基于SENet的改进版--SKNet。

Selective Kernel Networks (SKNet)

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

Selective Kernel Networks(SKNet)发表在CVPR 2019,SKNet是SENet的加强版,结合了SE opetator、Merge-and-Run Mappings以及attention on inception block的产物。名为SK模块, 可以自适应调节自身的感受野。

之前的SENet是对特征图的通道注意力机制的研究,而SKNet则是针对卷积核的注意力机制研究。

SK模块核心思想就是:用multiple scale feature汇总的information来channel-wise地指导如何分配侧重使用哪个kernel的表征

不同大小的感受视野(卷积核)对于不同尺度(远近、大小)的目标会有不同的效果。尽管比如Inception这样的增加了多个卷积核来适应不同尺度图像,但是一旦训练完成后,参数就固定了,这样多尺度信息就会被全部使用了(每个卷积核的权重相同)。

因此,SKNet提出了一种机制,即卷积核的重要性。SKNet对不同图像使用的卷积核权重不同,即一种针对不同尺度的图像动态生成卷积核

据作者说,该模块在超分辨率任务上有很大提升,并且论文中的实验也证实了在分类任务上有很好的表现。

SKNet的核心结构图如下:

为了使神经元能够自适应地调整其感受野尺寸,我们在具有不同卷积核大小的多个卷积核中提出了自动选择操作SK卷积。具体来说,我们通过三个操作实现SK卷积 - Split,Fuse和Select,如上图所示,其中显示了一个双分支的情况。因此,在此示例中,只有两个卷积核具有不同的卷积核大小,但很容易扩展到多个分支的情况。

Split-Fuse-Select核心模块

Split:对于任何给定的特征映射

,默认情况下,我们首先分别进行卷积大小为3和5的两个转换

。请注意,

均由高效的分组/深度卷积,批量标准化和ReLU函数组成。为了进一步提高效率,5×5卷积核的常规卷积被替换为3×3卷积核和扩张尺寸为2的扩散卷积。

Fuse:基本思想是使用门来控制来自多个分支的信息流,这些分支携带不同尺度的信息到下一层的神经元中。为实现这一目标,门需要整合来自所有分支的信息。主要目的是计算得到每个卷积核权重的部分。首先通过element-wise summation融合来自多个(上图是两个分支)分支的结果:

U中融合了多个感受野的信息。然后得到的U是形状是[C,H,W](C代表channel,H代表height, W代表width)的特征图,然后沿着H和W维度求平均值,最终得到了关于channel的信息是一个C×1×1的一维向量,代表的是各个通道的信息的重要程度。

Fgp为全局平均池化操作,Ffc为先降维再升维的两层全连接层。需要注意的是输出的两个矩阵a和b,其中矩阵b为冗余矩阵,在图1两个分支的情况下b=1-a。

通过简单地使用全局平均池化以生成channel-wise统计信息

来生成全局信息。具体来说,s的第c个元素是通过空间尺寸H×W收缩U来计算的:

此外,还创建了一个紧凑的特征z∈Rd×1,以便为精确和自适应选择提供指导。这是通过一个简单的完全连接(fc)层实现的,降低了维度以提高效率:

。其中δ是ReLU函数,B表示批量标准化,

。为了研究d对模型效率的影响,我们使用reduction ratio r来控制其值:

其中L表示d的最小值(L=32是我们实验中的典型设置)

Select: Select操作对应于SE模块中的Scale。区别是Select使用a和b两个权重矩阵对

进行加权操作,然后求和得到最终的输出向量V。

跨通道的软关注用于自适应地选择信息的不同空间尺度,空间尺度由紧凑特征描述符z引导。具体而言,softmax运算符应用于channel-wise数字:

其中

,a、b表示

的soft attention,

是A的第c行,

是a的第c个元素。在两个分支的情况下,矩阵B是冗余的,因为

最终的特征映射V是通过各种卷积核的注意力权重获得的:

其中V=[V1,V2,...,VC],Vc∈RH×W,注意,这里我们提供了一个双分支情况的公式,并且可以通过扩展轻松推断出具有更多分支的情况。

以下是SKNet思维导图:

基于PyTorch的代码:

代码语言:javascript
复制
import torch.nn as nn
import torch

class SKConv(nn.Module):
    def __init__(self, features, WH, M, G, r, stride=1, L=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

if __name__ == "__main__":
    t = torch.ones((32, 256, 24,24))
    sk = SKConv(256,WH=1,M=2,G=1,r=2)
    out = sk(t)
    print(out.shape)

参考链接:

1. https://blog.csdn.net/qq_34784753/article/details/89381947

2. https://zhuanlan.zhihu.com/p/80513438

3. https://zhuanlan.zhihu.com/p/102034839

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深度学习技术前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参考链接:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档