论文地址:Dual Attention Network for Scene Segmentation
代码地址:github
1. 简介
文章中介绍了一种注意力机制,分为两个模块PAM(position attention module)和CAM(channel attention module),结构和non-local之类的attention非常相似。作者使用这个结构的用意是通过不同通道和不同像素之间相互影响生成attention map来进行feature中的区域选取。实现方式基本就是attention的思想:通道加权,像素加权。
另外作者基于这两个模块设计了DANet。
2. 结构
下图是DANet的整体结构,基础网络是经过修改的ResNet,后面接两个分支PAM和CAM,最后将两个分支的feature进行相加经过一个卷积层得到最终的分割图。DANet的backbone是将Resnet最后的两个block的下采样层去掉之后使用dilation convolution(空洞卷积)实现保证网络的feture map尺寸只下降了
1
8
\frac{1}{8}
81。
2.1 Position Attention Module
途中PAM分为四个分支,其中生成Attention的上BC两个分支,D用来生成经过attention map处理的feature,最下面的是保留原有的feature保证信息不丢失。
基本的流程:
- 输入 A ∈ R C ∗ H ∗ W A\in R^{C*H*W} A∈RC∗H∗W,BCD三个分支分别经过conv+batch_norm+relu得到对应的输出 B ∈ R R ∗ H ∗ W B\in R^{R*H*W} B∈RR∗H∗W, C ∈ R C ∗ H ∗ W C\in R^{C*H*W} C∈RC∗H∗W, D ∈ R C ∗ H ∗ W D\in R^{C*H*W} D∈RC∗H∗W
-
B
,
C
B,C
B,C经过reshape维度编程
R
C
∗
N
,
N
=
H
∗
W
R^{C*N},N=H*W
RC∗N,N=H∗W,然后
B
T
∗
C
B^{T}*C
BT∗C得到
S
R
N
∗
N
S^{R^{N*N}}
SRN∗N,得到的输出经过softmax得到
S
∈
R
(
H
∗
W
)
∗
(
H
∗
W
)
S\in R^{(H*W)*(H*W)}
S∈R(H∗W)∗(H∗W)的相应图,其中
s
j
i
s_ji
sji表示feature上点
j
j
j对
i
i
i的影响。
s j i = e x p ( B i ⋅ C j ) ∑ i = 1 N e x p ( B i ⋅ C j ) s_{ji}=\frac{exp(B_i\cdot C_j)}{\sum^{N}_{i=1}exp(B_i\cdot C_j)} sji=∑i=1Nexp(Bi⋅Cj)exp(Bi⋅Cj) - 得到的attention map和输入进行相乘的操作;
- 最后和原有的输入进行加权的相加,如下公式,其中 α \alpha α初始化为0,是可学习的。
E
j
=
α
∑
i
=
1
N
(
s
j
i
D
i
)
+
A
j
E_j=\alpha \sum_{i=1}^{N}(s_{ji}D_i)+A_j
Ej=αi=1∑N(sjiDi)+Aj
下面为流程图,不会出现feature之类的标签,主要以维度为主如C*H*W表示feature或者attention map是
C
C
C通道高宽为
H
,
W
H,W
H,W。
2.2 Channel Attention Module
CAM模块的操作和PAM非常相似不同之处是操作室基于通道的生成的attention map
S
S
S大小为
C
∗
C
C*C
C∗C,最后的加权参数为
β
\beta
β也是可学习的,得到的attention map上的点
s
j
i
s_{ji}
sji表示
j
j
j通道对
i
i
i的影响。不做赘述。下面为流程图
2.3 代码实现
CAM:
def hw_flatten(x):
return K.reshape(x, shape=[K.shape(x)[0], K.shape(x)[1]*K.shape(x)[2], K.shape(x)[3]])
def cam(x):
f = hw_flatten(x) # [bs, h*w, c]
g = hw_flatten(x) # [bs, h*w, c]
h = hw_flatten(x) # [bs, h*w, c]
s = K.batch_dot(K.permute_dimensions(hw_flatten(g), (0, 2, 1)), hw_flatten(f))
beta = K.softmax(s, axis=-1) # attention map
o = K.batch_dot(hw_flatten(h),beta) # [bs, N, C]
o = K.reshape(o, shape=K.shape(x)) # [bs, h, w, C]
x = gamma * o + x
return x
PAM:
def hw_flatten(x):
return K.reshape(x, shape=[K.shape(x)[0], K.shape(x)[1]*K.shape(x)[2], K.shape(x)[3]])
def pam(x):
f = K.conv2d(x, kernel= kernel_f, strides=(1, 1), padding='same') # [bs, h, w, c']
g = K.conv2d(x, kernel= kernel_g, strides=(1, 1), padding='same') # [bs, h, w, c']
h = K.conv2d(x, kernel= kernel_h, strides=(1, 1), padding='same') # [bs, h, w, c]
s = K.batch_dot(hw_flatten(g), K.permute_dimensions(hw_flatten(f), (0, 2, 1))) #[bs, N, N]
beta = K.softmax(s, axis=-1) # attention map
o = K.batch_dot(beta, hw_flatten(h)) # [bs, N, C]
o = K.reshape(o, shape=K.shape(x)) # [bs, h, w, C]
x = gamma * o + x
return x
3. 实验结果
实验:分别在Citycapes,PASCAL Context, COCO Stuff上进行了实验。
3.1 实验设置
- 学习率初始化和更新为:
l r ∗ ( 1 − i t e r t o t a l i t e r ) 0.9 lr * (1-\frac{iter}{total_iter})^{0.9} lr∗(1−totaliteriter)0.9 - 基础学习率为0.01, Cityscapes为0.001, momentum=0.9, weight-decay=0.0001;
- 数据增强:随机左右翻转
3.2 结果
可视化: