《Dual Attention Network for Scene Segmentation》论文笔记

论文收录于CVPR2019,,本文通过基于Self Attention mechanism来捕获上下文依赖。提出了Dual Attention Networks (DANet)来自适应地整合局部特征和全局依赖。具体做法是,在一贯的dilated FCN中加入两种类型地attention module。其中position attention module选择性地通过所有位置的加权求和聚集每个位置的特征。channel attention module通过所有channle的feature map中的特征选择性地强调某个特征图。最后将两种attention module的output 求和得到最后的特征表达。所提出的DANet在三个数据集Cityscapes, PASCAL Context和COCO Stuff上实现了state-of-the-art的结果。

文章地址: https://arxiv.org/abs/1809.02983
源码地址:https://github.com/junfu1115/DANet

  • Contextual/Global/Long-range dependencies。18、19年的三大CV顶会文章中经常出现类似这几个词语,翻译成中文可以为上下文/全局/长依赖关系。具体来说,一张图像经过多个卷积层之后,感受野会逐渐变大,即CNN后面几层的feature map中的一个position往往包含了其周围的一些信息。然而,由于卷积操作是在局部进行的,即使经过了多层卷积,一个position也很难能够捕捉到所有position的信息,尤其是距离相对较远的。例如,一张图片左上角有一辆车,右下角有一辆相同型号和颜色的车,虽然它们在图片中的相对位置较远,但它们仍具有相似的特征。仅仅通过卷积的堆叠,左上角的汽车很难捕获到右下角的汽车,因此产生了long-range dependencies问题。该文提出的 Spatial attention module则是为了解决此问题。
  • Attention机制首先是在自然语言处理中提出,后来在CV任务中也被广泛使用,概括来讲它可以emphasize和suppress某些特征,这里对attention机制不做过多具体解释,网上资料一大堆。本文使用了self-attention机制,通过feature map与feature map之间的相互选择来构建similarity attention map,具体如何实现请看后面。

网络结构

在这里插入图片描述

基础网络为dilated ResNet(与DeepLab相同),最后得到的feature map大小为输入图像的1/8。之后是两个并行的attention module分别捕获spatial和channel的依赖性,最后整合两个attention module的输出得到更好的特征表达。

Position Attention Module

在这里插入图片描述
在Position Attention Module中,特征图A(C×H×W)首先分别通过3个卷积层得到3个特征图B,C,D,然后reshape为C×N,其中N=H×W,之后将reshape后的B的转置与reshape后的C相乘再通过softmax得到spatial attention map S(N×N),接着把S与D做乘积再乘以尺度系数α再reshape为原来形状,最后与A相加得到最后的输出E。其中α初始化为0,并逐渐的学习分配到更大的权重。可以看出E的每个位置的值是原始特征每个位置的加权求和得到的。
在这里插入图片描述

  • 作者给出的图例已经很详细地表达了设计的细节。首先,上面的两个分支用于生成attention map。将feature map A(CxHxW)分别经过两个带BN和ReLU的卷积层得到feature map B(CxHxW)和C(CxHxW),并将B和C reshape成CxN(N=HxW),将转置后的C(NxC)与B(CxN)做矩阵乘法,并将结果经过softmax layer得到spatial attention map S(NxN)。第三个分支同样将A经过一个卷积曾得到feature map D(CxHxW),并reshape成CxN,将D与spatial attention map S做矩阵相乘并reshape成CxHxW得到attention后的feature map。将其乘一个scale parameter α \alpha α并与原feature map A做一个element-wise sum操作得到最终输出。其中参数 α \alpha α初始值被设为0,并且由网络学到。
      以上皆出自论文原文中,下面是我个人的一些分析,详细分析一下这个module做了什么。首先来看最上面的两个分支,即得到attention map的过程。如下图,A1,A2(在原文中代表特征图B和C)为reshape后的feature map,S为attention map。红条为一个position vector,维度为C,A1和A2每个都有N(HxW)个position。A1,A2中的红色vector做element-wise multiply再求和就得到了S中左上角的绿色方格,代表position i对position i的依赖关系。A1与A2做矩阵相乘后得到的S则代表N个position对每个position的依赖关系。
    在这里插入图片描述

  • 下图中,A3为原图中第三个分支reshape后的feature map。注意作者用的是S’即attention map S的转置而不是S。在矩阵S中,每一行代表position i 对每个position的依赖关系,每一列代表每个position对position i的依赖关系。现在我们需要得到考虑了所有position后的position i的特征,作者将每个position的特征信息乘上position i 对每个positon的依赖关系并求和。即A3中的红色vector(代表第一个channel map中每个position的特征信息)乘S‘中的绿色vector(代表position i对每个position的依赖关系),再求和后得到紫色方格,即考虑了每个position依赖关系后的position i的第一个channel的特征信息。这部分读起来可能有些绕,但是还是希望读者能仔细了解下,如果觉得还有更好的解释或是我的解释不准确,也可以指出。

Channel Attention Module

在这里插入图片描述
在Channel Attention Module中,分别对A做reshape和reshape与transpose,将得到的两个特征图相乘再通过softmax得到channel attention map X(C×C),接着把X与A做乘积再乘以尺度系数β再reshape为原来形状,最后与A相加得到最后的输出E。其中β初始化为0,并逐渐的学习分配到更大的权重。

  • 在Channel Attention Module中,与Position Attention Module不同的是,作者没有对输入特征A做卷积,而是直接reshape。先看最下面的两个分支,先把feature map A reshape成CxN(N=HxW),再对其中一个转置得到NxC,作矩阵相乘即(CxN)x(Nxc)=CxC,经softmax之后得到了channel维度的attention map。第二个分支将A reshape成CxN,并与attention map的转置作矩阵乘法,得到attention之后的feature map(CxN),将其reshape回CxHxW,将其乘一个scale parameter β \beta β并与原feature map A做一个element-wise sum操作得到最终输出。其中参数 β \beta β初始值也被设为0,并且由网络学到。
      同样地,我们深入矩阵乘法的内部来看看这个模块做了什么。如下图,A1,A2为reshape后的feature map,S为attention map。红条为一层channel map,维度为N,A1和A2每个都有C层channel map。A1,A2中的红色vector做element-wise multiply再求和就得到了S中左上角的绿色方格,代表channel map i对channel map i的依赖关系。A1与A2做矩阵相乘后得到的S则代表C个channel map对每个channel map的依赖关系。
    在这里插入图片描述
    下图中,A3为原图中第三个分支reshape后的feature map。同样作者用的是S’即attention map S的转置而不是S,但是这里我没有明白这个转置的必要性,在矩阵S中,每一行代表channel map i 对每层channel map的依赖关系,转置后S’的每一行代表每层channel map对channel map i 的依赖关系,但与position attention不同的是,为了得到对应的维度,S’在这里放在了矩阵乘法的左边,这样一来,相当于是作者将每层channel map对channel map i的依赖关系乘上每层channel map的特征信息并求和, 与position attention是相反的。也就是下图中S‘中的绿色vector(代表channel map i对每个channel map的依赖关系)乘上A3中的红色vector(代表第一个position的所有channel map的特征信息),再求和后得到紫色方格。
    在这里插入图片描述

Ablation Study

在Cityscapes上的测试结果
在这里插入图片描述
对比一些state-of-art的实验结果
在这里插入图片描述

Dual Attention模块源码

# https://github.com/junfu1115/DANet/blob/master/encoding/nn/attention.py

###########################################################################
# Created by: CASIA IVA
# Email: jliu@nlpr.ia.ac.cn
# Copyright (c) 2018
###########################################################################

import numpy as np
import torch
import math
from torch.nn import (Module, Sequential, Conv2d, ReLU, AdaptiveMaxPool2d,
                      AdaptiveAvgPool2d, NLLLoss, BCELoss, CrossEntropyLoss,
                      AvgPool2d, MaxPool2d, Parameter, Linear, Sigmoid, Softmax,
                      Dropout, Embedding)
from torch.nn import functional as F
from torch.autograd import Variable


class PAM_Module(Module):
    """ Position attention module"""

    # Ref from SAGAN
    def __init__(self, in_dim):
        super(PAM_Module, self).__init__()
        self.query_conv = Conv2d(in_channels=in_dim,
                                 out_channels=in_dim // 8,
                                 kernel_size=1)
        self.key_conv = Conv2d(in_channels=in_dim,
                               out_channels=in_dim // 8,
                               kernel_size=1)
        self.value_conv = Conv2d(in_channels=in_dim,
                                 out_channels=in_dim,
                                 kernel_size=1)
        self.gamma = Parameter(torch.zeros(1))

        self.softmax = Softmax(dim=-1)

    def forward(self, x):
        """
        inputs :
            x : input feature maps( N X C X H X W)
        returns :
            out : attention value + input feature
            attention: N X (HxW) X (HxW)
        """
        m_batchsize, C, height, width = x.size()

        # B => N, C, HW
        proj_query = self.query_conv(x).view(m_batchsize, -1, width * height)
        # B' => N, HW, C
        proj_query = proj_query.permute(0, 2, 1)

        # C => N, C, HW
        proj_key = self.key_conv(x).view(m_batchsize, -1, width * height)

        # B'xC => N, HW, HW
        energy = torch.bmm(proj_query, proj_key)
        # S = softmax(B'xC) => N, HW, HW
        attention = self.softmax(energy)

        # D => N, C, HW
        proj_value = self.value_conv(x).view(m_batchsize, -1, width * height)

        # DxS' => N, C, HW
        out = torch.bmm(proj_value, attention.permute(0, 2, 1))
        # N, C, H, W
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma * out + x
        return out


class CAM_Module(Module):
    """ Channel attention module"""

    def __init__(self):
        super(CAM_Module, self).__init__()

        self.gamma = Parameter(torch.zeros(1))
        self.softmax = Softmax(dim=-1)

    def forward(self, x):
        """
        inputs :
            x : input feature maps( N X C X H X W)
        returns :
            out : attention value + input feature
            attention: N X C X C
        """
        m_batchsize, C, height, width = x.size()
        proj_query = x.view(m_batchsize, C, -1)
        proj_key = x.view(m_batchsize, C, -1).permute(0, 2, 1)
        # N, C, C, bmm 批次矩阵乘法
        energy = torch.bmm(proj_query, proj_key)

        # 这里实现了softmax用最后一维的最大值减去了原始数据, 获得了一个不是太大的值
        # 沿着最后一维的C选择最大值, keepdim保证输出和输入形状一致, 除了指定的dim维度大小为1
        energy_new = torch.max(energy, -1, keepdim=True)
        energy_new = energy_new[0].expand_as(energy)  # 复制的形式扩展到energy的尺寸
        energy_new = energy_new - energy
        attention = self.softmax(energy_new)

        proj_value = x.view(m_batchsize, C, -1)

        out = torch.bmm(attention, proj_value)
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma * out + x
        return out


if __name__ == '__main__':
    module = CAM_Module()
    in_data = torch.randint(0, 255, (2, 3, 7, 7), dtype=torch.float32)
    print(module(in_data).size())

参考:
https://blog.csdn.net/pangyunsheng/article/details/89047178
https://blog.csdn.net/mieleizhi0522/article/details/83111183

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CV无名之辈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值