DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解

今天为大家带来一篇CVPR2019的语义分割的一篇文章,我认为也是非常新颖的了。其中的对偶结构生成的attention map我认为很容易嵌入到其他网络中完成其他任务。
论文地址:here
官方源码:(基于pytorch)[https://github.com/junfu1115/DANet]

提出背景

当前的主流的语义分割网络应该就是空洞卷积和解码器这两个元素的组合。但这两个组件都是利用局部特征(因为卷积操作就是稀疏连接嘛,一次卷积能覆盖特征图全部的信息吗?当然不行啦,所以说是利用局部特征),作者提出两种模块,分别从分辨率维度(spatial)和通道维度来引入全局的信息,将局部特征和全局的依赖性自适应地整合到一起。

之前的一些方法,往往有两个问题。第一个是,如果某些目标受到光照,遮挡等因素不够显著,那么这些位置的预测结果很可能就被一些显著性的物体所影响了。第二个问题是,一张图像中很多物体的尺度是不一样的,占比不一样,那么不同尺度的特征应该被同等对待。作者通过自注意力机制从全局视野自适应地在整合任何尺度的相似的特征(没有明白的话,看下面的attention map的可视化应该就可以明白了)。作者认为局部特征对应的全局性的依赖是很重要的。

主要贡献

  • 提出了一种新颖的对偶注意力网络,利用自注意力机制提高特征表示的判别性。
  • 位置注意力模块用于学习特征的空间依赖性,通道注意力模块用来学习通道之间的内部关联性。
  • 在cityscapes,PASCAL context,COCO stuff上实现了更好的性能

方法

如果给结构分类,我会把它分到空洞卷积那类中,因为没有解码器嘛。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
backbone是ResNet,50或者101,都行,重点是融合空洞卷积核并删除了池化层的ResNet,其实就是现在流行的deeplab中使用的resnet结构了,注意resnet输出的特征图是原始尺寸的18\frac{1}{8}倍。
之后分两路(当然这里的resnet是只用卷积层部分,去除全连接层的!),这两路都先进过一个卷积层,然后分别送到位置注意力模块和通道注意力模块中去。这两个模块就有点意思了。理解起来比较费力气的。
先看下位置注意力模块的具体结构。

位置注意力模块 PAM

DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
A就是模块的输入,它被分别送到三个卷积层中获得了B,C,D。这四个特征图都是一样大小的,都是RC×H×WR^{C\times H\times W}的。现在把B和C都reshape为RC×NR^{C \times N},其中N=H×WN= H\times W 。 然后将C的转置和B相乘,得到了SRN×NS \in R^{N \times N},然后按列做softmax运算。见原文
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
sjis_{ji}就是第j行第i列的元素,它等于BB的第i行乘上CC的第J列的指数除以下面那串玩意,如果你耐心推到,就是把得到的S按列求softmax运算,再赋值给S。sjis_{ji}代表着第i个位置的特征对第J个位置的影响,如果这两个位置恰好都是属于同一类的像素点,那么sjis_{ji}就会产生很大的值,这样就会突出相似特征之间的联系,但其实为啥能这样我没看懂。再说一下,Bi,BjB_i,B_j其实都是R1×CR^{1\times C}的,i和j都是遍历1,2,...,H×W1,2,...,H\times W的,其实是空间维度上的运算,空间维度上的一个像素点的特征不就是R1×CR^{1\times C}的嘛!
那么sjis_{ji}确实能有表示第i个位置的特征对第J个位置的影响的意义,不过我也确实不明白为啥这样运算就是一个位置对另一个位置的影响。

然后把Dreshape为RC×NR^{C\times N},再做下面的运算
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
DiD_iDD的第ii列。a是训练参数,也是自注意力参数,等下说。按上面的公式,J遍历到1,2,...,C1,2,...,C就得到了ERC×NE \in R^{C\times N}RC×H×WR^{C\times H \times W}。之后这个特征图在经过一个卷积层,论文中没写(源码中写了),作为这个模块的输出。

通道注意力模块 CAM

DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
和PAM很类似,只不过这里的向量全部都是R1×CR^{1\times C}的了。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
而且整个模块是没有卷积层的。也是有个自注意力参数
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
过程我不重复了哈。很相似的。

自注意力参数

为啥叫自注意力呢,如果这两个参数为0,我们会发现两个模块其实没起到作用的。OK,我相信有人已经懂了,这两个参数确实用0初始化,随着参数更新,网络如果觉得模块有用,自然会增加这两个参数的值。即残差思想,最差我就不用这个模块了,最好就是将参数更新到合适的位置,自己去寻找最优的利用度。

实验

乱起八早的实验设置我跳过了,和大部分的语义分割网络是一致的,我也不想随意贴几张实验结果图看看指标敷衍了事。我们直接看看我认为最有意思的部分。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
因为SRN×NS\in R^{N\times N},那么SS可以被视为是R(H×W)×(H×W)R^{(H\times W)\times (H\times W)}的,每一个像素点位置都对应有一个H×WH\times W的子map,作者就抽取这个子map,看看attention map究竟是啥玩意。
第一列的红色点就是作者抽取的点,第二列对应标号为1的点的attention map,第三列对应标号为2的点的attention map。我们发现,attention map可以说将相同label的物体都不同程度显示出来了。越亮的地方表示该点对全局位置上具有相同label的点的依赖关系越强。所以回想起公式
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
也是显式的用注意力机制放大相似且关联的特征的值。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
作者同样抽取了第4和11通道,通过热图看看哪些区域被注意到了,越红的地方表示响应越大,即那些点都是一类的。
以上两方面的观察我们就明白了,两个模块PAM和CAM具有全局性的找寻相似特征的能力,并将他们建立起关系,无论像素点的空间距离是多少。

另外模型有很多矩阵运算,所以运行时间比较长;但该方法的理论我认为很强’

从源码看PAM和CAM

DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
首先定义了三个卷积层,而且softmax的定义是按最后一个维度做运算,其实就是按列嘛。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
在forward里面我们也可以看到步骤确实如上面所述。将一个卷积层的输出reshape之后转置,torch.bmm就是不在batch size那个位置做矩阵相乘(按第一个维度分开,分别在对应的batchsize维度做矩阵乘法。)。然后经过softmax,把D也reshape。
注意下面的公式可以换成矩阵相乘的写法。
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解

DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解

所以我们才看到

    out = torch.bmm(proj_value, attention.permute(0, 2, 1))  # permute 就是转置的意思
    out = out.view(m_batchsize, C, height, width)

    out = self.gamma*out + x

这三行,就对应上面的公式。 gamma就是自注意力参数,因为是常数,所以提出来最后才乘上去。

CAM 也是一样差不多的。就跳过了。那么既然官方开源了代码,我当然要试试看看啦

实现效果

源码不太好调试,未完待续-
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解
DANet:Dual Attention Network for Scene Segmentation论文解读和源代码详解上面的结果是我直接将2048x1024大小的原图resize成512x512的大小的结果,所以图像有不成比例的扭曲。因为内存占用太大了。如果我想获得好的结果,同样可以crop在将patch拼接,我懒就没弄了。但就从上面的结果来看,还是不错的,毕竟用的也是人家做实验的预训练模型。

;