《Context Encoding for Semantic Segmentation》论文笔记

参考代码:PyTorch-Encoding

1. 概述

导读:在这篇文章中研究了CNN特征图的全局上下文信息对于分割的影响,文章指出像之前工作中通过增加CNN网络层数感受野或者使用膨胀卷积,那么这样就能很好提取全局的上下文语义信息么?对此文章借鉴了channel-wise attention的思路对特征图进行优化,而对于目标分割任务(或者分类任务)提出了基于attention机制的Enc模块,使用attention的方式(编码器不同)增强特征的表达(Context Encoding Module)。此外对于传统上分割损失存在的偏心眼儿情况(对小目标不是很友好),在Enc模块基础上增加了基于GT像素类别先验监督的SE损失(与分类区域大小无关只与类别相关),进而引导更具表达能力特征的生成。在文章的方法也取得了不错的效果:PASCAL-Context和PASCAL-VOC上51.7% 和85.9%的mIoU。同样适用文章的方法在CIFAR-10数据集上只适用14层的卷积却获得了与更大体积(10倍)模型类似的结果,说明在依据GT类别来优化特征的生成还是挺有用的。

2. 方法设计

2.1 网络结构

文章的网络结构见下图所示:
在这里插入图片描述
这里是以ResNet的backbone基础在stage3和stage4上使用膨胀卷积和Enc模块(附带SE损失),之后再接一个分割头完成分割任务。

2.2 Enc模块

文章提出的Enc模块其详细结构见下图所示:

在这里插入图片描述
编码部分:
这部分可以看作是在原有channel-wise attention基础对编码器进行了改进而来,于输入的特征图 f ∈ R C ∗ H ∗ W f\in R^{C*H*W} fRCHW的,那么在channel维度进行切片可以得到数据 X = { x 1 , … , x n } ,   N = H ∗ W X=\{x_1,\dots,x_n\},\ N=H*W X={ x1,,xn}, N=HW,之后文章定义了 K K K个codewords D = { d 1 , … , d K } D=\{d_1,\dots,d_K\} D={ d1,,dK}以及smoothing factor S = { s 1 , … , s K } S=\{s_1,\dots,s_K\} S={ s1,,sK}。因而在输入特征图的某个channel维度上编码器的输出可以描述为 e k = ∑ i = 1 N e i k e_k=\sum_{i=1}^Ne_{ik} ek=i=1Neik,其中 e i k e_{ik} eik表示为:
e i k = e x p ( − s k ∣ ∣ r i k ∣ ∣ 2 ) ∑ j = 1 K e x p ( − s j ∣ ∣ r i j ∣ ∣ 2 ) r i k e_{ik}=\frac{exp(-s_k||r_{ik}||^2)}{\sum_{j=1}^Kexp(-s_j||r_{ij}||^2)}r_{ik} eik=j=1Kexp(sjrij2)exp(skrik2)rik
其中, r i k = x i − d k r_{ik}=x_i-d_k rik=xidk,之后进行操作 e = ∑ k = 1 K ϕ ( e k ) e=\sum_{k=1}^K\phi(e_k) e=k=1Kϕ(ek) ϕ \phi ϕ代表的是BN和ReLU的组合。

在得到编码之后的结果之后需要得到channel-wise上的权重因子(经过FC层),对此文章将其描述为:
γ = σ ( W ⋅ e ) \gamma=\sigma(W\cdot e) γ=σ(We)
之后再去做channel-wise的点乘 Y = X ⊗ γ Y=X\otimes \gamma Y=Xγ

这部分的实现参考代码:encnet.py

SE损失:
这部分损失使用GT的分类像素信息作为先验,从而去引导Enc模块产生更具有分辨能力的特征,其就是在上面编码器输出的基础上添加一个FC层,之后进行损失计算,具体见下面代码:

se_target = self._get_batch_label_vector(target, nclass=self.nclass).type_as(pred)
loss2 = self.bceloss(torch.sigmoid(se_pred), se_target)

对应的GT计算为:

def _get_batch_label_vector(target, nclass):
        # target is a 3D Variable BxHxW, output is 2D BxnClass
        batch = target.size(0)
        tvect = Variable(torch.zeros(batch, nclass))
        for i in range(batch):
            hist = torch.histc(target[i].cpu().data.float(), 
                               bins=nclass, min=0,
                               max=nclass-1)
            vect = hist>0
            tvect[i] = vect
        return tvect

3. 实验结果

PASCAL VOC数据集:
在这里插入图片描述
消融实验:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m_buddy/article/details/110144291