【注意力机制】Squeeze Excitation模块 (SE Net);Spatial Attention Module模型 (SAM YoloV4) 以及CAM,CBAM

之前的 文章 很详细的写了

bottleneck block的实现。
先回顾一下block的意义,网络的性能归根结底是对特征提取的优秀程度,
对特征提取越好,后面的分类,检测,分割等等,就会有更好的性能。

但是很深的网络会非常难训练,一方面是因为参数巨大,容易过拟合,
但是resnet实验中证明并不是因为过拟合导致的准确率下降,因为在训练阶段的准确率也下降了,
这并不是过拟合的结果。

另一方面,梯度的反向传播经过非常多次相乘会变得很小,这就导致了梯度消失现象,
因此性能饱和,无法进一步优化。

所以resnet不是一味的加深网络层数而提高性能的。
resnet的基本假设是,对于一个效果很好的网络,我在后面加上和前面层一模一样的层的时候,
模型的性能至少应该是和之前的浅层网络持平,

1

在下图中可以看到一个叫building block的基本结构,
block设计的初衷就是为了让x有两条路走,
第一条就是identify  mapping,让新的层即使不学任何信息也能和上一层持平, 

第二条就是resduial mapping,identify mapping确保了已经学到的信息被完整的保存下来,
如果需要有改进,那么就在resduial mapping中进行,也就是F(x)中进行,
F(x)学到的是block的输出相对于block输入的变化,如果F(x)什么都学不到,那么模型保持之前x状态的性能,即不会变差。

说了这么多,可以发现,F(x)对block之间的信息变化学的越好,那么模型的性能就越好。
因此如何设计F(x) 成了一个热门点。

在最初的resnet中,设计了两种F(x),也可以说是设计了两种block,左边叫build block,右边叫bottleneck block。一般有4个block和两个全连接层(早期用),可以构造为

resnet 18=2+(2+2+2+2)*2 ;
resnet 34=2+(3+4+6+3)*2; 
resnet 50=2+(3+4+6+3)*3; 
resnet 101=2+(3+4+23+3)*3;
resnet 152=2+(3+8+36+3)*3;
......

在这里插入图片描述

大多数简单任务,使用resnet 34或者50即可。
以上所说,统称为resent v1,发表在Deep Residual Learning for Image Recognition中,
在resnet v2,主要是引入了BN,如下图右边。
图中的resduial mapping都换到了右侧。

在这里插入图片描述
关于为什么使用full preactivation结构的解释,准备结合上一篇文章一起解释(两篇合一篇),以及不同channel的处理,在写完se block 和 gc block之后整理。

写了这么多前言,正题开始了,先讲Squeeze Excitation Net。

SE Net的核心思想是通过channel信息的attention机制(重新分布权重)来达到更好的学习效果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从上面的图和下面的代码可以看出,在右侧的se blocke模块,我们将整个channel通道的重要信息都提取了出来,然后乘以原有信息,这就是通过注意力机制进行信息加强。

def se_block(bottom, ratio=16):
    weight_initializer = tf.contrib.layers.variance_scaling_initializer()
    bias_initializer = tf.constant_initializer(value=0.0)

    # Bottom [N,H,W,C]
    # Global average pooling
    #with tf.variable_scope("se_block"):

    channel = bottom.get_shape()[-1]
    se = tf.reduce_mean(bottom, axis=[1,2], keep_dims=True)#[B,1,1,C]
    #squeeze过程 Global average pooling

    assert se.get_shape()[1:] == (1,1,channel)
    se = tf.layers.dense(se, channel//ratio, activation=tf.nn.relu,
                         kernel_initializer=weight_initializer,
                         bias_initializer=bias_initializer) 
    #[B,1,1,C/ratio]
    assert se.get_shape()[1:] == (1,1,channel//ratio)
    se = tf.layers.dense(se, channel, activation=tf.nn.sigmoid,
                         kernel_initializer=weight_initializer,
                         bias_initializer=bias_initializer)
    #[B,1,1,C]
    assert se.get_shape()[1:] == (1,1,channel)
    top = bottom * se 
    #[B,H,W,C] * [B,1,1,C]=[B,H,W,C]

    return top 
def res_block2(bottom, filters, training, use_bn, use_se_block, strides=1, downsample=False):
    path_2=bottom

    #conv 3x3
    path_1 = conv_layer(bottom, filters[0], kernel_size=3,strides=strides)
    path_1 = norm_layer(path_1, training, use_bn)
    path_1 = relu(path_1)
    # conv 3x3
    path_1 = conv_layer(path_1, filters[1], kernel_size=3)
    path_1 = norm_layer(path_1, training, use_bn)
    path_1 = relu(path_1)

    if use_se_block:
        path_1=se_block(path_1) #将两个3x3卷积的block变成了se block
    if downsample:
        path_2 = conv_layer(path_2, filters[1], kernel_size=1, strides=strides)
        path_2 = norm_layer(path_2, training, use_bn)
    top = path_1 + path_2
    top = relu(top)
    return top

参考
博客1
博客2

Spatial Attention Module

SAM是基于通道进行全局平均池化以及全局最大池化操作,产生两个代表不同信息的特征图,
合并后再通过一个感受野较大的7×7卷积进行特征融合,大的卷积核对获取全局特征有帮助。
最后再通过Sigmoid操作来生成权重图叠加回原始的输入特征图,从而使得目标区域得以增强。

在这里插入图片描述

import torch
from torch import nn
 
class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
 
        assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
        padding = 3 if kernel_size == 7 else 1
 
        self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)  # 7,3     3,1
        self.sigmoid = nn.Sigmoid()
 
    def forward(self, x):
        avg_out = torch.mean(x, dim=1, keepdim=True) # 8x1x300x300 avg pooling 
        max_out, _ = torch.max(x, dim=1, keepdim=True) # 8x1x300x300 max pooling 
        x = torch.cat([avg_out, max_out], dim=1) # 8x2x300x300
        x = self.conv1(x) # 8x1x300x300
        return self.sigmoid(x) #太大变成1 太小变成0
 
if __name__ == '__main__':
    SA = SpatialAttention(7)
    data_in = torch.randn(8,32,300,300)
    data_out = SA(data_in)
    print(data_in.shape)  # torch.Size([8, 32, 300, 300])
    print(data_out.shape)  # torch.Size([8, 1, 300, 300])

关于CAM和CBAM可以参考
博客地址

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值