语义分割注意力网络全解析:六种上下文建模机制对比与选型指南
做语义分割这几年给我冲击最大的不是某条网络把指标刷到多高而是一张图里的像素开始学会“隔空社交”。PSANet、DANet、OCNet、CCNet、EMANet、SANet这批基于注意力的语义分割工作殊途同归地做了一件传统卷积很难做到的事情让一个像素在计算特征时能直接参考全图范围内与它语义相关的其他区域。这不再是单纯把网络加深或加宽的问题而是重新设计了信息流动的方式。这篇文章想把这六个网络放在同一条演进线里讲清楚它们共同面对什么难题各自给出了什么解法复现时有哪些坑以及最后到底该怎么选型。内容会涉及一些公式和训练细节但尽量说人话目标是让刚入门语义分割的读者也能跟着思路走一遍。1. 语义分割缺的不只是深度而是跨距离的上下文关系1.1 全卷积网络在复杂图像上的上下文短板语义分割的任务很直接给输入图像上的每一个像素都打上类别标签。全卷积网络FCN第一次把分类网络改成端到端的分割结构让网络可以接受任意尺寸输入并通过上采样恢复空间分辨率这在当时是非常大的进步。但全卷积网络有一个绕不开的毛病卷积核天然只看局部邻域。一个3×3的卷积输出特征上的每个点只能感知输入图上对应的3×3区域就算叠加几十层信息也要一层一层地“传递”才能到达远方而且每经过一次采样或池化中间位置的信息都会被压缩、混合、稀释。在图像分类任务里这个问题不致命因为分类只需要得到一个全局语义但分割任务要求对每个像素做精细判断。比如一个行人被树干挡住身体断成两截模型要认出“这两截属于同一个行人”就需要跨越树干这个障碍把远处像素的信息拉过来。再比如机翼下的地面像素需要参考整片跑道的结构才能正确分类但这些上下文区域在空间上离它很远。有人会说把网络加深感受野不就大了吗理论上是的但实践上很尴尬。深层网络的感受野确实在扩大可中间每一层都在做局部混合远处信息传到目标位置时已经经过了太多非线性变换位置细节和原始语义都被磨掉了。空洞卷积和金字塔池化能扩大采样范围但空洞卷积是固定间隔网格采样碰到形状复杂的物体容易漏;金字塔池化把全图压缩成几个尺度的统计特征空间关系丢失严重。真正的问题不是“看不看得远”而是“怎么从远处精准地找到与当前像素语义相关的那些区域”。1.2 “注意力”到底在语义分割里做了什么注意力机制在视觉里其实没有多玄乎。它做的事情可以概括成一句话给特征图中的每一个位置计算一组权重然后用这组权重去加权汇总其他位置的信息。更具体地看通常会把特征变成三份query查询、key索引、value内容。当前位置的query和全图每个位置的key做相似度计算经过softmax得到权重再拿这些权重对全图的value做加权求和。结果就是当前位置的输出不再只是卷积窗口内特征的叠加而是全图范围内“与它语义相似、对它分类有用”的区域特征的加权组合。用一个生活化的类比卷积像是你走在小区里只能听见旁边几户人家的声音注意力像是你直接接入全城广播但系统会按你当下的需求把相关内容的音量调大、无关内容的音量调小。这不是简单的“看得更远”而是“知道该听谁的”。在Non-local结构出现之后这种跨距离建模方式很快成为视觉领域的主流工具之一。但“该听谁的”这件事不同论文的理解完全不同于是才有了标题里这一串基于注意力的语义分割网络。1.3 六篇论文的定位速览同一目标不同路线如果把“上下文建模”当成目标这六个网络在三条路线上展开全图矩阵路线PSANet和DANet。它们坚持算全图任意两个位置之间的相关性力求不遗漏任何一处上下文。代价是计算量很大O(N²)级别的复杂度N是像素数。目标区域路线OCNet和CCNet。OCNet认为上下文里只有“和当前像素属于同一物体的区域”才值得参考CCNet则把计算范围先限制在十字线上再用循环补全全局。低秩/分解路线EMANet和SANet。EMANet用EM迭代把特征压缩到一组基向量上SANet把二维空间注意力拆成水平、垂直两个一维方向都是为了大幅降低复杂度让注意力机制能落地到高分辨率场景。理解它们之间的差异比单独背任何一个网络的细节都更重要。下面逐个拆开讲。2. PSANet与DANet先把全图相似度矩阵做到极致2.1 PSANet的逐点空间注意力每个像素有自己的信息路由PSANetPoint-wise Spatial Attention Network看到的痛点是早期全局注意力方法虽然能让每个位置看到全图但全图所有位置用的几乎是同一套query-key映射。也就是说不管这个像素是天空、路面还是行人它获取上下文的方式都是同一套模板。这显然不合理。天空中的像素应该更关注远处同属天空的区域路面像素应该更关注延伸出去的车道结构。不同语义角色需要的“社交对象”不同就应该拥有不同的信息路由。PSANet的解法是为每一个空间位置单独生成一张attention map实现信息双向流动。如果用sigmoid表示收集权重当前位置从其他位置聚合信息时用σ那么把自身信息传播给其他位置时就用1-σ。两者互补正好构成一个双向广播机制既能从全图“吸取”对自己有用的上下文又能把自己携带的信息“派发”到全图需要它的地方。这个设计在概念上非常优雅但代价也很直接每个像素都要有一张覆盖全图的权重图复杂度是O(N²)。以一张512×512的特征图为例像素数N等于26万attention map的规模约有688亿个数值直接算会非常夸张。实际实现通常会把特征下采样到原图的1/8甚至1/16在低分辨率上计算attention weight再上采样回原分辨率和原始特征融合。这也是复现PSANet时最需要注意的工程细节。2.2 DANet的空间注意力通道注意力双通道设计DANetDual Attention Network的出发点更工程化既然分割任务对空间位置敏感也对通道语义敏感那就把空间和通道两个维度各自做一个注意力模块最后融合在一起。位置注意力模块的原理是把特征图记为X先做矩阵变换计算任意两个空间位置之间的特征相似度得到一个N×N的关联矩阵然后softmax归一化。这个矩阵里第(i, j)个值就是位置i对位置j的依赖权重。用这个矩阵去乘原特征就完成了“每个位置的信息被全图所有位置按相关度加权汇总”的步骤。通道注意力模块的逻辑稍微绕一点它把特征从N×C reshape成C×N然后计算C×C的通道相关性矩阵。这里的含义是某个通道的响应可以由其他所有通道按相关性加权后共同决定。和SENet那种“全局平均池化全连接”的方式不同DANet的通道注意力是在空间分布上两两计算相关性的能保留更多空间结构信息而不是把整张图压成一个统计值。两个模块分别计算完各自经过一层1×1卷积做通道对齐之后直接相加再和原始输入做一次残差连接。这样网络既拿到了“空间上哪些位置和当前像素相关”的信息也拿到了“语义上哪些通道和当前类别相关”的信息。两个维度互补实验里也比单独使用任何一个模块要稳。2.3 全局注意力矩阵的算力代价与应对PSANet和DANet在精度上的上限很高但它们的算力代价不能忽视。全图相似度矩阵有两个短板显存占用大。N×N的权重矩阵要保存在显存里batch稍微大一点就容易爆内存。以特征图64×64为例N4096矩阵规模是1600万左右个浮点数特征图再大一点显存直接告急。计算量增长快。输入分辨率翻倍N变四倍O(N²)的矩阵运算量变成十六倍。这对训练和推理都是巨大的压力。工程上常用的应对方法有几个。第一把特征图下采样到小尺度再计算attention算完上采样回原尺寸第二用可分离的策略把N×N矩阵拆成若干小块分批计算第三如果框架支持用梯度检查点gradient checkpointing换显存。这些手段实战中都验证过能做到精度几乎不掉显存下降一大截。但务必记住这类全图矩阵方法的高精度是在中低分辨率输入、足够显存的条件下成立的。一旦输入尺寸变得很大延迟增长会非常明显这也是后来很多落地项目转投CCNet和EMANet的直接原因。3. 从全图到目标区域OCNet与CCNet的上下文改造3.1 OCNet的object context和同类像素对话而不是和所有像素对话OCNetObject Context Network提出了一个非常关键的问题上下文上下文到底什么才算“相关上下文”一个位于马路中央的车辆像素它真正需要参考的信息是同一物体区域的其他车辆像素而不是远处一栋楼的窗户。但全图相似度矩阵把所有像素都当成候选权重再低也会产生计算浪费而且可能引入噪声。OCNet的做法可以理解为不要预定义固定的候选范围而是让网络自己学会“哪些区域和当前像素属于同一物体”。具体实现依然走相似度计算的路线对当前像素计算它与全图所有位置的相似度但这次把相似度解释成一个软性的物体掩码——也就是object context mapOCC。这张掩码里值高的位置大概率属于同一物体的区域值低的位置则不是。有了掩码之后对全图特征做加权求和得到的就是“同一个物体范围内的上下文特征”而不是“全图范围内所有东西的混杂特征”。这里最好和空洞卷积系列做个对比。ASPP这类方法用不同膨胀率的卷积核均匀采样相当于固定网格采样。无论当前像素处在什么语义环境里采样位置都是一套几何模式。OCNet是动态的每个位置的采样权重由语义相关性决定。一个简单的例子在“车”和“路”紧挨着的场景里ASPP可能同时采到车和路OCNet则能更集中地聚焦在同类区域。换句话说OCNet把上下文建模从“几何邻居”扩展到了“语义邻居”。3.2 CCNet的十字交叉注意力用两次传播换取全局视野CCNetCriss-Cross Attention Network选择了另一条路不追求第一次就拿到全局上下文而是先算局部的十字线再用循环把信息扩散到全图。交叉注意力的计算方式很巧妙。对特征图上的每个位置它只计算这一行和这一列上的注意力权重。也就是说每个位置的候选范围从“全图所有像素”缩减为“同一行的所有像素同一列的所有像素”。在这个十字范围内做相似度计算和softmax一次性覆盖的位置数量从N变成大约2√N计算量立刻降了一个数量级。但一次性十字显然不是全局。这里的关键是循环结构第一次做完十字注意力之后每个位置已经吸收了同行同列的信息。把输出再送入第二个交叉注意力模块时当前像素所在的行列邻居已经携带了从更远位置传来的信息。第二次十字交互本质上把第一次扩散出去的信息又接了回来。两步循环之后每个位置理论上都能汇聚到全图信息。可以这么理解第一个人先问左右邻居“你们知道什么”邻居只回答了自己附近的消息第二次再问时邻居已经把更远处打听到的消息告诉了第一个人。两步就能让消息传遍全村不需要每个人直接认识全村所有人。复杂度从O(N²)降到大约O(N^1.5)在常规分辨率下省掉一个量级以上的运算。3.3 上下文的“候选范围”到底该怎么选把OCNet和CCNet放在一起你会发现它们优化的不是同一个环节OCNet优化的是“候选集合的语义有效性”回答的是“参考哪些像素更好”CCNet优化的是“候选集合的计算代价”回答的是“如何用更少的计算拿到全局视野”。两种思路各有适用场景。物体大、边界复杂、类别之间视觉差异小的数据集OCNet类方法更容易发挥优势因为“同类物体区域”这个约束本身就是很强的先验。实时性要求高、输入分辨率又大的项目CCNet类方法则明显更友好计算量可控调参难度也低。实践里的折中方案也有把OCNet的object context思想和CCNet的十字稀疏化结合甚至把两者的模块并联分别提取语义相关上下文与空间扩散上下文再融合。很多后续工作都在这条路上做过尝试效果往往比单独使用一种更好。4. EMANet与SANet为了落地而生的低复杂度注意力4.1 EMANet用期望最大化思想把特征压缩进基向量空间EMANetExpectation-Maximization Attention Network是我个人觉得这批方法里数学味道最浓的一个但它的核心思想并不难。前面讲的方法不管全图还是十字本质上都在“像素和像素”之间做交互。EMANet换了一个思路先选出几个“基向量”作为场景中主要的语义模式然后每个像素不再直接和其他像素对话而是先和基向量对话再用几个基向量的加权组合来表示自己。整个过程用EM算法迭代完成E步固定当前基向量计算每个像素与每个基向量的相似度得到权重系数M步固定权重系数用全图特征按权重加权平均重新估计基向量。迭代若干次后基向量会逐渐稳定到一组能代表场景语义模式的向量。输出阶段用最终得到的系数与基向量线性组合生成每个像素的新特征。类比一下基向量就像一幅画里用到的几种主色调每个像素按“它更像天空还是更像地面”的比例把这几种主色调混合得到自己的最终颜色。R个基向量相当于最多能表示的语义原型数量通常R32就够用。K是迭代次数一般取3次再多边际收益很小。复杂度从O(N²)降到了O(N·R·K)。举个例子特征图256×256时N65536R32K3一次EM注意力的运算量约630万级别而全图相似度矩阵是43亿级别差距接近上千倍。这让EMANet在高分辨率语义分割里的落地价值非常明显。4.2 SANet将二维空间注意力拆解为横向纵向两个子空间说到SANet这里要先提醒一句视觉论文里“SANet”这个缩写其实被复用多次读文献时很容易搞混。在语义分割上下文里它通常指以空间非对称注意力Spatial Asymmetric Attention为核心模块的网络早期有一些用空间注意力做掩码的老版本不能混为一谈。空间非对称注意力的核心想法是既然完整二维注意力矩阵计算量太大那就把它在空间维度上拆开。对每个位置先做水平方向的一维注意力再做垂直方向的一维注意力两个方向的信息融合后再和原始特征组合。这样做有两个好处第一水平方向和垂直方向各自独立计算复杂度从O(N²)降到约两个O(N^1.5)高分辨率下提速明显第二相比全局平均池化把所有空间信息压扁非对称注意力保留了行、列方向上的精确位置信息空间定位不至于丢得太厉害。通俗点说完整二维注意力像是在全体像素里两两配对投票非对称注意力更像是先横向看一遍整行再纵向看一遍整列两次视野叠加起来基本能覆盖全局。SANet类网络通常还会做一些附加设计比如跨层的特征重建、多尺度特征融合让注意力模块在不同阶段都能发挥作用。代价是二维平面里“对角线方向”的联合表征能力会下降这也是它在一些边界精细场景里精度略逊于全图矩阵方法的原因。4.3 低复杂度注意力的收益与表达力损失没有免费的午餐。EMANet和SANet换来的速度和显存优势都是用一定表达力换来的收益很直观训练时batch size可以开更大推理速度更快移动端和实时视频流场景变得可行。很多工程团队拿它们做在线分割的前置网络效果比其他全局方法更稳。损失也很明确EMANet用聚类的方式近似全局相似度等价于把像素-像素关系降维到像素-原型关系SANet则靠横竖两个方向近似二维空间关系。在物体形状特别复杂、类别边界特别不规则的数据集上这两类方法通常比PSANet/DANet低0.5到1.5个点的mIoU但推理速度快3到5倍。选择的时候想清楚任务场景就行。离线榜单追求最高精度可以上全图矩阵在线实时系统要稳定PPS就别让一个O(N²)模块拖垮整个pipeline。在我实际测试过的项目里EMANet在无人机航拍分割这种大分辨率场景中表现非常出色SANet则在移动端道路分割上性价比极高。5. 复现这类注意力分割网络时最值得注意的四处细节5.1 从训练稳定性到分辨率下采样复现注意力分割网络第一步不是调模型结构而是把训练环境理顺。这类网络对batch size非常敏感因为注意力模块里的softmax需要统计全局分布信息batch太小BNBatch Normalization的均值和方差震荡会非常大导致训练不稳定。如果只有单张卡显存又有限最直接的办法是减小输入分辨率而不是强行调小batch。实测下来街景类分割任务常用768×768左右的裁块通用密集标注数据集常用512×512裁块再配合大一点的batch比如8以上效果会比“大分辨率小batch”稳定得多。多卡训练时必须用同步BNSyncBN否则每张卡各自统计模型看到的数据分布完全不一致。输入尺寸的选择也直接影响注意力模块的行为。分辨率先下采样到1/8再算注意力和下采样到1/16再算效果差异很大。1/16分辨率下注意力矩阵的计算量小但空间细节丢失多对小目标分割尤其不友好。我一般倾向在1/8特征图上算注意力如果显存不够可以再在该特征图上做一次最大池化计算完attention weight后上采样回1/8再和原特征融合。5.2 注意力的初始化与学习率控制注意力分支比普通卷积层更难训练这是复现这类网络最容易被忽视的一点。原因是attention weight经过softmax或sigmoid之后梯度传播路径更长对初始参数非常敏感。如果初始化值不合适训练第一步loss就可能飞到几万上或者出现某些通道权重全部为零的“死亡注意力”现象。实践中我有两个经验注意力模块里的卷积层不要用方差很大的初始化方式。用常规kaiming初始化通常没问题但要让BN层在开始时尽量接近恒等映射避免一开始就把注意力权重推到极端分布。学习率要单独控制。主干backbone、注意力模块、辅助分割头三个部分的初始学习率可以不一致。一般注意力模块比主干低一点会稳很多poly策略下初始学习率调到基准的0.1到0.5倍再配合2000步左右的warmup能有效避免attention矩阵在早期震荡。如果训练曲线出现“loss骤降但mIoU不涨”的诡异情况大概率是attention没有学到有用信息而是退化成了固定的空间先验。可以试着把softmax前的logits缩放因子调小或者去掉温度参数让权重分布更平滑让early training阶段有更多探索空间。5.3 辅助监督与深监督在注意力训练中的作用注意力模块参数量大训练初期主梯度很容易被噪声淹没。给backbone末端加一个辅助分割头做深监督是这类模型能稳定收敛的关键技巧之一。辅助loss的放置位置有讲究。通常放在backbone的最后一层之后、注意力模块之前让浅层信息也获得直接监督。权重一般在0.4左右训练到一半时可以考虑关闭或调低让主注意力模块在后期自由发挥。实测下来没有辅助监督的注意力分割网络在100个epoch里很难收敛到最好效果加了辅助监督后普遍能提升1到2个点而且训练曲线平滑很多。另一种有效的做法是“渐进式训练”先用较小分辨率训练几十个epoch等注意力模块学到稳定的上下文权重后再切到大分辨率微调。这种策略对PSANet这种高计算量模型特别有用能避免大分辨率下显存不足和训练不稳定同时爆发。5.4 显存受限时的工程处理先算小尺度再上采样很多读者在复现DANet、PSANet时会发现代码很简单但一跑训练显存就爆。这里推荐一个我反复使用的工程策略在进入注意力模块之前先把特征图做一个适配的通道压缩和空间下采样注意力计算放在小尺度特征上算完再上采样回原尺度并和残差分支融合。通道上一般把输入注意力模块的通道数压到128或256已经足够表达上下文关系空间上从1/8下采样到1/16对最终精度的影响很小。做过一次对比实验同样的模型和数据压缩通道和空间后显存占用下降了约50%mIoU只掉了0.3个点。对于显存捉襟见肘的复现环境这个交换非常划算。如果还有余力可以把注意力矩阵的计算改成半精度FP16或者用torch.utils.checkpoint把矩阵乘法包起来在forward时重新计算中间结果以时间换显存。这些都不是纸面技巧是真正能让你把代码跑起来的救命操作。6. 六种注意力机制横向对比与选型思路6.1 核心机制对比表先把六个网络的关键差异用一张表摆清楚网络核心机制上下文建模方式复杂度特征适用场景倾向PSANet逐点空间注意力每个位置专属attention map双向信息流O(N²)高学术实验、复杂场景高精度研究DANet位置注意力通道注意力空间相似度矩阵与通道相关性矩阵并联O(N²)高通用分割基准、物体较大场景OCNetobject context像素与同类物体区域动态关联较高大物体、边界复杂场景CCNet十字交叉注意力横向纵向十字线计算循环两次补全O(N^1.5)中高分辨率、实时性有一定要求EMANetEM迭代注意力基向量空间低维建模O(N·R·K)低大分辨率、服务器端高吞吐SANet空间非对称注意力水平垂直一维分解低移动端、实时视频流这六个网络没有一个在所有维度上都赢。它们的选择本质上是在“全局性”“语义有效性”“计算效率”三个指标之间权衡。6.2 不同资源条件下的选择建议如果你是刚入门想快速跑通一个注意力分割模型作为baseline首选CCNet。它计算量适中结构直观训练稳定对硬件要求不高能在多数分割数据集上取得不错的精度。从CCNet开始理解注意力机制在分割里的作用再回头看其他网络会容易很多。如果你在做学术实验或者竞赛想冲高精度DANet和OCNet是两条成熟路线。DANet的双路结构清晰扩展性强OCNet的object context思想影响深远后续很多工作都沿用了这个方向。这两类方法需要相对宽裕的显存和训练时间但收益也直接。如果你的场景是自动驾驶、无人机巡检这类高分辨率实时任务EMANet几乎是为这类场景量身定做的。计算量低显存友好方便后期加TTA和模型集成。SANet则更适合有移动端部署需求的项目参数和计算量都能压得比较低。至于PSANet理论价值大于工程价值。它的双向信息流设计很优雅但真正落地时往往要把分辨率下采样得很厉害精度损失不好控制。如果要做研究值得细读如果要上线我建议优先考虑其他方法。6.3 从这些注意力设计里延伸出的通用经验看多了这套工作会形成一个判断框架上下文建模本质上就是三个选择——候选范围怎么定、候选权重怎么算、权重结果怎么聚合。PSANet和DANet选的是全图候选相似度权重OCNet选的是语义聚类候选相似度权重CCNet选的是十字候选空间相似度权重EMANet选的是基向量候选EM系数SANet选的是横纵分解候选。这套框架对理解后续的mask类分割工作同样适用。后来那些基于可学习查询的分割思路其实也在回答这三个问题只是把候选从“像素”换成了“可学习的掩码空间”。学这六篇网络最大的收获不是记住某个模块结构而是养成“上下文问题去拆候选、权重、聚合”的思考习惯。我个人在实际操作中的体会是注意力分割模型的价格永远在“表达力”和“计算代价”之间平衡。第一次复现不要贪图惊艳的效果先跑通CCNet再往DANet、OCNet方向加码最后根据数据特性决定是否需要EMANet那种低秩方案。多跑几组对比你会明显感觉到这些网络在各自设计哲学上有多大的差异而选型最终还是要回到你的硬件条件和场景需求上。最后分享一个小技巧训练这类模型时把attention weight可视化出来看一次胜过调一整天参——你也会直观地发现它到底是在“看”远处的同类物体还是学到了奇怪的位置偏好。