不定期读一篇Paper之SENet
前言
首先,引用原文中的一段文字,如下图:
所以,SENet的提出了更加关注不同通道的之间的重要程度,下面是VGG16网络第一层的特征图可视化图片来源,共有64个通道,从图中我们可以看出不同特征图所关注的图像的特征不同(当然,随着网络的加深,网络能够表达的信息更加的抽象,这里引用了浅层网络),有些通道关注是一些纹理信息,有些是一些轮廓信息等,所以,一个直观的理解在我们对图像的处理过程中我们希望关注的层次能够有”侧重点“,这样能够使我们的网络总会关注那些有用的信息。
框架
SENet提出关注网络卷积层中不同通道的重要程度,而这个重要程度是可以学习的,相当于我们可以学习到每一个通道相应的权重分数,然后,把它与我们的相应的通道的结合,就可以使得不同的通道表示的结果整体上有了侧重点。
下图是SENet模块:
实现原理结合以下pytorch代码理解,个人觉得这是一个原理上很直观,但是思路新奇的架构
class SELayer(nn.Module):
def __init__(self, channel, reduction=16):
"""
:param channel:输入通道
:param reduction:缩减倍数
"""
super(SELayer, self).__init__()
# 1. Squeeze(average pooling)
self.avg_pool = nn.AdaptiveAvgPool2d(1)
# 2.Excitation
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
)
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y.expand_as(x)
这里列举几个重要的点:
-
缩减倍数的选择,作者说这是一个超参数,在不同的深度的layer中,你可以选择调整不同的缩减比例来提高你的网络性能。
-
全局平均池化的选择,原则上你也可以选择最大池化,作者证明两者效果相差不大,但全局平均池化在整体效果会好一点。
-
网络模块的插入应该在卷积操作后,非线性激活函数的前面(relu),因为SENet最后选择sigmoid来凸显不同通道的重要程度(实验上sigmoid的效果也更好一些,相比于relu、tanh),相当于一个门控单元。而我们知道simmoid激活函数在网络很深的时候会出现梯度消失和爆炸,尤其是在嵌入残差网络,所以选择在原激活函数前添加模块。下图是在inception Net和Residual Net中插入SE module
实验
本次实验是在renet18上加入了SE模块实现图线分类任务,模型迭代100个epoch,数据集选择了cifar10分类,实验效果如下,当然本身残差网络在图像分类任务就有较好的任务。
train_acc | train_loss |
实验中也对网络中关注的点进行的了可视化,如下图中所示,我们通过热力图可以看出在分类为飞机时,网络正真关注的是飞机本身,而对于汽车的关注,也更加关注汽车区域。