论文链接:https://arxiv.org/pdf/1905.09646.pdf
代码链接https://github.com/implus/PytorchInsight
卷积神经网络(CNN)通过收集不同层次和不同部分的语义子特征来生成复杂对象的特征表示。这些子特征通常可以以分组形式分布在每一层的特征向量中,代表各种语义实体。然而,这些子特征的激活往往在空间上受到相似模式和噪声背景的影响,从而导致错误的定位和识别。本文提出了一个空间组增强(SGE)模块,该模块可以通过为每个语义组中的每个空间位置生成一个注意因子来调整每个子特征的重要性,从而每个单独的组可以自主地增强其学习的表达,并抑制可能的噪声。注意因素仅由各组内部的全局和局部特征描述符之间的相似性来引导,因此SGE模块的设计非常轻量级,几乎没有额外的参数和计算。
一、本文简介:
本文为了使每一组特征在空间上具有鲁棒性和均匀分布性,在每个特征组内建模了一个空间增强机制,通过使用注意力掩码在所有位置缩放特征向量。这种注意力掩码是为了抑制可能的噪声,突出正确的语义特征区域而设计的。与其他流行的注意方法不同,作者使用每个位置的全局统计特征和局部统计特征之间的相似性作为注意力掩码的生成源。上述简单而有效的机制是本文的空间分组增强(SGE)模块,本模块非常轻量,本质上几乎不需要额外的参数和计算。 在引入SGE模块后,我们检查了特征图分布的变化以及各组激活值方差的统计。结果表明,SGE显著改善了不同语义子特征在其组内的空间分布,并在统计上产生了较大的方差,从而加强了语义区域的特征学习,压缩了噪声和干扰。
作者考虑了通道C,H×W卷积特征图,并将其沿通道维数划分成G组。在不丧失一般性的情况下,首先单独检查某个组(参见图1中底部的黑框)。然后,该组在空间中的每个位置都具有向量表示,即x= {
x 1 … m x_1…m x1?…m }, x i ∈ r c / g x_i∈ r^{c/g} xi?∈rc/g,m=H×W。从概念上来说,作者进一步假设这一分组在网络学习过程中逐渐捕捉到特定的语义反应(如狗的眼睛)。在这个组空间中,理想情况下,可以获得在眼睛位置具有强烈响应的特征(在多个眼睛区域中具有更大向量长度和相似向量方向的特征),而其他位置几乎没有激活,成为零向量。然而,由于不可避免的噪声和相似模式的存在,CNN通常很难获得均匀分布的特征响应。为了解决这个问题,作者建议利用整个组空间的整体信息,进一步增强关键区域语义特征的学习,因为整个空间的特征不受噪声控制(否则模型从该组中什么也学不到)。因此,可以通过空间平均函数 F g p ( ? ) F_{gp}(·) Fgp?(?)使用全局统计特征来近似该组学习表示的语义向量:
其次,利用该全局特征,可以通过简单的点积来获得每个特征的对应重要系数,该点积在一定程度上度量了全局语义特征G与局部特征 x i x_i xi?之间的相似性。因此,对于每个位置,可以定义:
C i C_i Ci?也可以展开为 ∥ g ∥ ∥ x i ∥ c o s ( θ i ) \lVert g \lVert \lVert x_i \lVert cos(θ_i) ∥g∥∥xi?∥cos(θi?),其中 θ i θ_i θi?是 x i x_i xi?和g之间的夹角。这表明向量长度( ∥ x i ∥ \lVert x_i \lVert ∥xi?∥)和方向(即 θ i θ_i θi?)更接近g的特征,更有可能获得更大的初始系数。为了防止不同样本之间的系数大小有偏差,在空间上标准化c:
? \epsilon ?(通常为1e-5)是数值稳定性的常数。为了确保插入到网络中的归一化可以表示身份转换,为每个系数 x i ^ \hat{x_i} xi?^?引入了一对参数γ、β,用于缩放和移动归一化值:
γ、β是该模块中介绍的唯一参数。在单个SGE单元中,γ、β的数量与组(G)的数量相同,其数量级通常为32或64,与整个网络的数百万个参数相比,这基本上可以忽略不计。
对以上过程进行总结如下:
首先将特征分组,每组feature在空间上与其global pooling后的feature做点积(相似性)得到初始的attention mask,在对该attention mask进行减均值除标准差的normalize,并同时每个组学习两个缩放偏移参数使得normalize操作可被还原,然后再经过sigmoid得到最终的attention mask并对原始feature group中的每个位置的feature进行scale。
实验结果如下:
-
Group参数取适中,Top-1性能可到最高;
-
初始化建议将缩放的参数初始化为0,目的是在attention起到作用前先让网络脱离attention自己学一会,先学习到一个基本的semantic的表示,然后学着学着缩放参数经过梯度下降变成非0之后再渐渐使得attention起到作用;
-
Normalization非常必要,不可去除;
代码实现:
class SpatialGroupEnhance(nn.Module):def __init__(self, groups = 64):super(SpatialGroupEnhance, self).__init__()self.groups = groupsself.avg_pool = nn.AdaptiveAvgPool2d(1)self.weight = Parameter(torch.zeros(1, groups, 1, 1))self.bias = Parameter(torch.ones(1, groups, 1, 1))self.sig = nn.Sigmoid()def forward(self, x): # (b, c, h, w)b, c, h, w = x.size()# 将通道分组 (b*g , c/g, h, w)x = x.view(b * self.groups, -1, h, w) # 将分组后的特征图进行平均池化后进行点积xn = x * self.avg_pool(x)xn = xn.sum(dim=1, keepdim=True)t = xn.view(b * self.groups, -1)# 进行标准化t = t - t.mean(dim=1, keepdim=True)std = t.std(dim=1, keepdim=True) + 1e-5t = t / stdt = t.view(b, self.groups, h, w)# 进行权重加权t = t * self.weight + self.biast = t.view(b * self.groups, 1, h, w)x = x * self.sig(t)x = x.view(b, c, h, w)return