深度学习之卷积网络attention机制SENET、CBAM模块原理总结

SENET

SENET是2017年的世界冠军,SE全称Squeeze-and-Excitation是一个模块,将现有的网络嵌入SE模块的话,那么该网络就是SENet,它几乎可以嵌入当前流行的任何网络,那么为什么会引出这个东西呢,来看下图:

在这里插入图片描述

一个feature map经过一系列卷积池化得到的feature map,通常我们认为这个得到的feature map的每个通道都是同样重要的,我们并没有分那个通道重要,那个通道不怎么重要,那么实际上会不会有这种情况呢,就是得到的featurmap 的每个通道的重要性都不一样,比如确实有的图片三个通道,我只有一个通道有用,其它通道没什么用,比如一张包含动物的图片,那么背景肯定不怎么重要,它转化为灰度图后,只有一个通道比较重要,其它的不怎么重要,那么其实实际上我们得到的feature map每个通道的重要程度还是不一样的,也就是说每个通道其实还应该有一个重要性权值才行,然后每个通道的重要性权值乘以每个通道原来的值,就是我们求的真正feature map,这个feature map不同的通道重要性不一样(可能权值大的乘以原来的数要大些)如上面得到最终图,每个通道颜色不一样,也就代表着不同的重要性

那么每个通道的权值或者重要性怎么来呢,就是上面这块,做法如下:
在这里插入图片描述
其实很简单,假入原来feature map 是 h * w * c的,给它做一个global池化(池化窗口就是h * w 得到的就是1 * 1窗口,通道数不变)得到 1 * 1 * c的feature map,然后它再接两个全连接层(第一个全连接层神经元个数是c/16,相当于对c进行了降维,输入是c个特征,第二个全连接层神经元个数为c,相当于又增维回到了c个特征,这样做比直接用一个 Fully Connected 层的好处在于具有更多的非线性,可以更好地拟合通道间复杂的相关性,极大地减少了参数量和计算量),然后再接一个sigmod层(这里采用sigmod应该是通道之间是具有相关性的,所以不能用softmax,softmax的话,最终加起来必须为1),输出1 * 1 * c,
原来的feature map维度h * w * c,得到的是通道的权值维度1 * 1 * c,然后它们进行相乘,这里是全乘,不是矩阵相乘,然后得到的feature map对应的每个通道重要性就不一样了(可能更重要的它的值要大些)
那么h * w * c 和1 * 1 * c 是怎么相乘的呢?看一个例子
在这里插入图片描述
在这里插入图片描述
像这样相乘

这个是一个通道的,看到没它乘的倍率是1,

这个通道的倍率是乘2

它就是这么实现不同通道乘以不同的倍率,从而得到不同的重要性的
相当于是每次乘以一列通道

注意:对于图片数组,我们来熟悉下:
在这里插入图片描述
一行

一行里面一个像素点对应的一列通道

一个像素
注意:
每个通道的权值都是网路学习出来的,那么怎么学习呢,记住学习,只要有参数和loss就可以,如下
在这里插入图片描述
所以它主要学习的是SE模块这两个全连接层的参数,它们学到了,自然最终结果就有了,所用用最终的分类损失去更新这两个全连接层的参数就可以了
#注意上面采用两层全连接,第一层全连接单元个数为c/16,主要是为了压缩参数的如下,
c. * c/r + c/r * c = 2c2/r = 2/r * c2
只用一层全连接参数的话参数个数:
c * c = c * 2

实际中可能会用一个比例reduction_ratio
reduction_ratio = 0.5的话
那么就是c * 0.5c + 0.5c * c = c2
reduction_ratio如果 = 0.3的话那么就是c * 0.3c + 0.3c * c = 0.6
c2
如果只用一层全连接层的话那么就是
c * c = c * 2个,显然参数减少了0.4c
2个

CBAM

它是2018年的分类冠军,它和SE一样也是一个模型,现在任何流行网络都可以嵌入这个模块,那么它的由来是什么呢?
SE的由来是因为不同通道的像素的重要性可能不一样,那么既然这样,同一个通道的不同位置像素重要性也可能不一样,所以就有了CBAM,既考虑不同通道像素的重要性,又考虑了同一通道不同位置像素的重要性

Convolutional Block Attention Module (CBAM) 表示卷积模块的注意力机制模块。是一种结合了空间(spatial)和通道(channel)的注意力机制模块。相比于senet只关注通道(channel)的注意力机制可以取得更好的效果。
它相对于SE多了一个空间attension,这个空间其实就是宽高对应的方形或者说是一个通道对应的feature map,SE只关注通道,它既关注通道,也关注宽高,
它的大概流程如下:
在这里插入图片描述

先来看通道上的attension:
在这里插入图片描述
它这里和SE模块有点区别就是,SE只用了一个池化globalpool(一般是maxpool),而它这里用了两个池化maxpool,avgpool(池化本身是提取高层次特征,不同的池化意味着提取的高层次特征更加丰富),既然是两个那么输出肯定也是两个都是11c,然后将输出两个相加,再进行sigmod,结果也是11c,然后再和原来的feature map相乘
然后再来看空间上的attension
在这里插入图片描述
它的过程也很简单:
它是原来的feature map先做完通道attension ,然后它在这个基础之上进一步做空间attension的,它先将feature map 进行基于通道的池化,一般的池化都是在长宽的维度,它这个其实就是在列通道的维度池化(取一列通道的最大值,平均值),这就意味着一次池化一列通道变成了一个值就是一个通道了,长宽不变,假如输入feature map是 h * w * c,它这个一次池化后就变成了h * w * 1的feature map了,它进行了两次池化,那就是两个h * w * 1的feature map,然后将它们进行基于通道的拼接,那就变成了 h * w * 2的feature map了,然后对这个feature map用一个7*7的卷积核进行卷积,将通道数压缩成了1(因为只用了一个卷积核),得到一个新的feature map,然后对这个feature map进行sigmod的,得到一个attension feature map,然后将它和最开始的feature map进行相乘,比如下面:
原先的经过channel attension后的feature map是 h * w * c,那么经过空间attension后,它得到的attension feature map就是 h * w * 1了,那么它们怎么相乘呢,如下:
b.shape = (2,2,3)
在这里插入图片描述
这一列就是一个通道上的像素,显然,他每次乘都是乘以一个通道上的像素,对一个通道上的像素进行增大或者缩小,下一次再乘以另外一个通道的

最终它这个空间attension feature map肯定也是学习出来的,那么具体是学习什么呢?肯定是参数,它这个过程有哪些参数,其实就是再到数第二步,用一个77的卷积核对输入的2层feature map卷积,那么它学习的就是这个77的卷积核参数

代码实现

def cbam_module(inputs,reduction_ratio=0.5,name=""):
    with tf.variable_scope("cbam_"+name, reuse=tf.AUTO_REUSE):
        #假如输入是[batsize,h,w,channel],
        #channel attension 因为要得到batsize * 1 * 1 * channel,它的全连接层第一层
      #隐藏层单元个数是channel / r, 第二层是channel,所以这里把channel赋值给hidden_num
        batch_size,hidden_num=inputs.get_shape().as_list()[0],inputs.get_shape().as_list()[3]
 
       #通道attension
        #全局最大池化,窗口大小为h * w,所以对于这个数据[batsize,h,w,channel],他其实是求每个h * w面积的最大值
      #这里实现是先对h这个维度求最大值,然后对w这个维度求最大值,平均池化也一样
        maxpool_channel=tf.reduce_max(tf.reduce_max(inputs,axis=1,keepdims=True),axis=2,keepdims=True)
        avgpool_channel=tf.reduce_mean(tf.reduce_mean(inputs,axis=1,keepdims=True),axis=2,keepdims=True)
        
        #上面全局池化结果为batsize * 1 * 1 * channel,它这个拉平输入到全连接层
      #这个拉平,它会保留batsize,所以结果是[batsize,channel]
        maxpool_channel = tf.layers.Flatten()(maxpool_channel)
        avgpool_channel = tf.layers.Flatten()(avgpool_channel)
        
        #将上面拉平后结果输入到全连接层,第一个全连接层hiddensize = channel/r = channel * reduction_ratio,
      #第二哥全连接层hiddensize = channel
        mlp_1_max=tf.layers.dense(inputs=maxpool_channel,units=int(hidden_num*reduction_ratio),name="mlp_1",reuse=None,activation=tf.nn.relu)
        mlp_2_max=tf.layers.dense(inputs=mlp_1_max,units=hidden_num,name="mlp_2",reuse=None)
        #全连接层输出结果为[batsize,channel],这里又降它转回到原来维度batsize * 1 * 1 * channel,
       mlp_2_max=tf.reshape(mlp_2_max,[batch_size,1,1,hidden_num])
 
        mlp_1_avg=tf.layers.dense(inputs=avgpool_channel,units=int(hidden_num*reduction_ratio),name="mlp_1",reuse=True,activation=tf.nn.relu)
        mlp_2_avg=tf.layers.dense(inputs=mlp_1_avg,units=hidden_num,name="mlp_2",reuse=True)
        mlp_2_avg=tf.reshape(mlp_2_avg,[batch_size,1,1,hidden_num])
 
        #将平均和最大池化的结果维度都是[batch_size,1,1,channel]相加,然后进行sigmod,维度不变
        channel_attention=tf.nn.sigmoid(mlp_2_max+mlp_2_avg)
         #和最开始的inputs相乘,相当于[batch_size,1,1,channel] * [batch_size,h,w,channel]
       #只有维度一样才能相乘,这里相乘相当于给每个通道作用了不同的权重
        channel_refined_feature=inputs*channel_attention
 
       
        #空间attension
        #上面得到的结果维度依然是[batch_size,h,w,channel],
      #下面要进行全局通道池化,其实就是一条通道里面那个通道的值最大,其实就是对channel这个维度求最大值
      #每个通道池化相当于将通道压缩到了1维,有两个池化,结果为两个[batch_size,h,w,1]feature map
        maxpool_spatial=tf.reduce_max(inputs,axis=3,keepdims=True)
        avgpool_spatial=tf.reduce_mean(inputs,axis=3,keepdims=True)

        #将两个[batch_size,h,w,1]的feature map进行通道合并得到[batch_size,h,w,2]的feature map
        max_avg_pool_spatial=tf.concat([maxpool_spatial,avgpool_spatial],axis=3)

       #然后对上面的feature map用1个7*7的卷积核进行卷积得到[batch_size,h,w,1]的feature map,因为是用一个卷积核卷的
     #所以将2个输入通道压缩到了1个输出通道
        conv_layer=tf.layers.conv2d(inputs=max_avg_pool_spatial, filters=1, kernel_size=(7, 7), padding="same", activation=None)
      #然后再对上面得到的[batch_size,h,w,1]feature map进行sigmod,这里为什么要用一个卷积核压缩到1个通道,相当于只得到了一个面积的值
     #然后进行sigmod,因为我们要求的就是feature map面积上不同位置像素的中重要性,所以它压缩到了一个通道,然后求sigmod
        spatial_attention=tf.nn.sigmoid(conv_layer)
 
       #上面得到了空间attension feature map [batch_size,h,w,1],然后再用这个和经过空间attension作用的结果相乘得到最终的结果
     #这个结果就是经过通道和空间attension共同作用的结果
        refined_feature=channel_refined_feature*spatial_attention
 
    return refined_feature
  • 39
    点赞
  • 280
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值