
做语义分割的朋友应该都有一种体会同一张图里不同区域对模型能力的需求完全不一样。墙角的白墙、密集的栏杆、半透明的塑料布、远处的小人有的地方只需要局部纹理就能分辨有的地方却必须把整张图的上下文都揽进来看才行。可传统卷积网络在设计上有一个天然的“公平病”不管特征图上的哪个位置都用同一套卷积核、同一组权重去推理。这种一刀切的做法在分类任务里问题不大但到了语义分割这种逐像素决策的任务里就等于让一个全能选手干所有精度活既浪费算力又容易在空间细节上栽跟头。《Learning Dynamic Routing for Semantic Segmentation》这篇论文解决的就是这个矛盾。直白说它让网络学会“看菜下饭”对每个像素位置动态地决定用哪些计算路径、什么样的卷积核去处理而不是所有人穿同一条裤子。论文的核心贡献是一个叫动态路由网络的框架可以在不显著增加参数量和训练难度的前提下把语义分割的精度和效率一起往上推。这篇文章我会从问题动机、方法拆解、架构设计、实验结论到复现细节逐层展开适合已经做过分割相关项目、想深入理解动态条件计算的读者也适合刚入门、想弄明白这类论文到底在解决什么问题的朋友。1. 论文要解决的核心问题1.1 固定权重与空间变化需求之间的冲突所有基于卷积的模型本质上都在干同一件事用一组可学习的权重在输入上做加权求和。这组权重一旦训练完就是全局绑定的——图片左上角的小船和右下角的草地用的是同一套滤波器。这在图像分类里说得过去因为分类只需要一个全局结论不关心每个局部到底有多大尺度、什么形状。可语义分割要求的是对每个点给出语义标签模型必须理解“哪里是船”、“哪里是草”而不同的物体在尺度和外观上差异巨大。更麻烦的是感受野问题。一个标准残差网络里高层特征的感受野是固定的顶多通过空洞卷积去扩大。但分割目标的尺度跨度极大栅栏可能只有几个像素宽需要细小的卷积核去抓而天空、地面这种大面积区域又需要大感受野来避免歧义。你用一个大空洞卷积去做细枝末节很容易把边界糊过去你用一个小核去做大面积上下文又会觉得信息不足。传统方案要么同时堆多尺度分支要么用ASPP这类模块去枚举空洞率但这些都是“静态”的——它们在所有位置都做同样强度的计算不会根据局部内容去调节。1.2 语义分割对空间差异化计算的天然需求如果你做过真实场景语义分割项目应该见过这样的案例一张路测图里人行道纹理和远处的车辆在浅层特征上非常相似但高层上下文完全不同。这时候如果模型把所有计算资源都均匀分配就会出现典型的“远处车辆被吃掉”现象。反过来如果模型把所有位置都做强上下文建模又会造成边缘细节过度平滑物体边界轻飘飘的。这篇论文的作者正是从这种观察出发语义分割的最优计算方式应该是空间的函数。什么含义对于每个像素位置网络应该有一个“决策器”判断当前区域适合走什么计算路径然后才调用对应参数去完成特征提取。这种做法在思路上把“静态网络”转化成了“动态路由”把原来单一的卷积参数化方式变成了由输入特征驱动选择的空间变体卷积。1.3 从条件计算到动态路由的演进脉络动态路由并不是凭空冒出来的。早年的条件计算研究就提出过不是所有输入都需要走完整网络可以让一部分简单样本跳过某些层。后来的动态滤波网络、可变形卷积,也在尝试让卷积核或采样位置随输入变化。再往近了说SE模块用的全局注意力本质上也是给不同通道分配不同权重但它的粒度是全局的做不到逐像素路由。这篇论文的聪明之处在于把条件计算的思想放到了语义分割的场景里并且做成了端到端可训练的完整框架。它不是在特征图上做轻量级门控而是真正把卷积核的参数都变成了空间可变的——不同位置使用不同路径卷积结果的组合网络权重本身就在动态变化。这种改变比简单的注意力要彻底也比单纯的动态滤波更容易训练稳定因为在整体结构上仍然保留了非常强的骨干网络约束。2. 方法拆解动态路由网络2.1 路由模块的组成与预测方式动态路由网络的基础是特征图上的一个轻量级子网络论文里叫路由模块。这个路由模块接收骨干网络某个阶段的特征图输出每个空间位置关于各候选路径的概率分布。举个例子假设某个残差块内安排了4条候选计算路径路由模块就会输出一个形状为H×W×4的得分图经过归一化后在每个位置得到一个4分类的软选择。路由模块本身不复杂基本就是几层卷积加归一化操作计算量非常小。关键设计在于路由预测的粒度。论文选择了逐像素级别的路由也就是每个位置都独立选择路径。这个选择和特征图上的局部内容强相关如果一个位置是背景区域可能轻轻松松选一个低成本的简单路径如果是物体边界或者小目标区域就会倾向于激活多个复杂路径。这种细粒度的路由决策让空间变体卷积有了真正的物理意义。这里有个很多人容易忽略的点路由模块的输出不是一个标量门控而是一个路径选择分布。位置 u 处的输出可以写成 π(u) softmax(r(x; u))其中 r 是路由网络的logits输出。这个分布不仅决定最终输出怎么组合各条路径的卷积结果还直接参与梯度的回传所以路由网络和主干网络是同时优化的。2.2 空间变体卷积的实现方式为了让不同位置真正用上不同参数论文把原来单一的卷积权重拆成了多条路径。每条路径有自己的卷积核参数但没有任何一个位置会直接使用单独的某条路径的所有权重而是把多条路径的卷积结果做加权求和。这个权重就是路由模块给出的概率分布。用一个式子来表达就是y(u) Σ_{i1..K} π_i(u) * (W_i * x(u))简单说先把输入特征图分别通过K个不同的卷积层得到K组中间结果然后每个位置用路由分布 π 去加权融合这些结果。因为 π 是空间变化的所以最终等效的卷积核在每个位置上都不同这就是“空间变体卷积”的由来。这样做有一个天然的好处多条路径可以设计成不同感受野、不同通道比例的形态。论文中常用的设计是几条路径分别采用普通卷积、不同空洞率的卷积、甚至不同卷积核尺寸的组合。这样路由模块的决策就变成了一个“该看多近/多远”的选择问题。边界清晰的小目标会选择小感受野路径权重更高而大片同类区域则会让大空洞卷积分支发挥主要作用。实际工程实现时通常不需要真正的逐像素张量乘法去动态生成K个独立卷积核而是把K个卷积的结果保存下来再按权重加权求和这样实现成本低得多也方便GPU并行。2.3 离散路由选择的训练技巧细心的读者可能已经发现问题路由模块的目标是让每个位置尽量只走一条最优路径可训练时要做到“尽量只走一条”就需要引入离散选择。但离散选择是不可导的梯度无法回传到路由网络。这个问题不解决整个框架就训不动。论文采用的做法是Gumbel-Softmax重参数化。Gumbel-Softmax是处理离散采样可微化的标准工具它给每个logits加上Gumbel噪声再通过一个带温度系数的Softmax做松弛。温度越低输出的分布越接近one-hot温度越高分布越平滑梯度越稳定。训练初期用较高温度让路由模块探索各类路径随着训练推进逐步降温让路由决策趋向确定。这里有一个实操层面的心得温度退火的节奏很重要。如果降温太快路由分布会早早锁死在某条路径上后续主网络还没充分训练精度会很差如果降温太慢路由始终在多个路径之间左右摇摆卷积参数的收敛也会受限。合理的做法是先训练一小段让主干网络初步稳定再把温度降下去。论文的实验也证明了温度策略对最终mIoU的影响可以达到一到两个百分点。3. 整体架构设计与训练方案3.1 在ResNet骨干上植入动态路径为了验证框架的通用性论文把动态路由放到了经典的残差网络上。具体改动方式很直接在ResNet的若干关键阶段中残差块内部不再是单一卷积路径而是被替换成一组候选路径并在路径前接入路由模块。为什么要挑多个阶段而不是只在最后一层做因为语义分割的问题既关乎高层语义也关乎底层空间细节。只在高分辨率特征图上做动态选择虽然能帮助边缘细化但缺少语义区分度只在高语义层做动态选择又无法照顾细粒度场景。论文在多个阶段同时引入路由机制相当于让低层路径侧重空间细节、高层路径侧重语义类别整体配合起来效果才会好。这种替换并非无脑全部替换。论文在设置里保留了骨干网络的前几层不动在更深的Stage 2、Stage 3、Stage 4中加入动态路由。保留浅层不动有两个原因一是浅层卷积计算量占比高盲目替换会增大训练开销二是浅层提取的是普适特征没有太多任务特异性均匀计算即可。3.2 路径设计要掌握好组合维度具体到每条路径论文实验过几种分支组合。最常见的设计是路径1为1×1卷积负责快速线性变换路径2为3×3普通卷积负责局部纹理路径3为3×3空洞卷积空洞率2负责中等上下文路径4为5×5或3×3空洞率更高的卷积负责大范围语义建模。这样组合的价值在于不同路径覆盖了从像素级局部到全局范围的特征尺度路由选择本质上是在做“多尺度感知”的暴力搜索替代方案。这里有一个调参建议路径数量控制在3到5条比较好。路径太少了动态路由的好处体现不出来跟普通多分支差不多路径太多了路由分布很难训稳定而且四条以上路径之间的计算冗余开始超过收益。作者在消融里也发现从2条增加到4条时精度提升最大继续增加到6条后提升就非常有限。每条路径保持不同的结构还有一个额外好处路由可视化时会变得非常可解释。比如你在某个数据集的验证集上统计每个物体类别被路由到哪条路径的比例会发现人、车这类对象倾向于激活大感受野路径而背景、墙体则经常走低成本路径。这种规律说明网络学到的不只是像素纹理而是真正的语义判别差异。3.3 训练配置与损失设计训练整体上还是语义分割的标准套路。骨干部分使用ImageNet预训练权重新增的路径分支和路由模块使用随机初始化。优化器一般选SGD初始学习率0.01量级配合poly学习率衰减策略。数据增强包括随机缩放、随机裁剪和左右翻转。损失函数方面主损失仍然是逐像素交叉熵。因为动态路由在空间上改变了特征聚合方式作者还发现配合一个边界感知辅助损失有正向收益。边界感知可以简单理解成在物体边缘区域对损失函数加权放大让路由模块和主网络都更重视边界处的决策精度。这个辅助损失不额外增加模型参数量只在训练时使用。另外一个容易被忽略的配置是路由正则化。直接训练路由分布很容易出现退化——所有位置都选同一条路径动态性完全失效。作者在损失里加上了一项熵正则化鼓励路由分布保持一定的随机性避免路由模块陷入局部最优。实际加权值不用太大0.01量级就能起到抑制作用。4. 实验验证精度与效率的权衡4.1 在公开基准上的表现论文在标准语义分割数据集上做了充分对比实验设置基本是主流的半监督训练加评估。和当时的FCN、PSPNet、DeepLab系列放在一起看动态路由网络在mIoU上明显领先。这里可以给一个大概的量化参考以ResNet-101为骨干时动态路由网络在中心裁剪单尺度测试下比同骨干的DeepLab风格多尺度模型能高出1到3个百分点的mIoU同时计算量减少大约百分之十几。不要小看这几个点的提升在语义分割里1个mIoU的差距往往意味着大量工程优化才能补回来。而且更有意思的是速度优势。动态路由通过稀疏激活路径使得理论计算量大幅下降。虽然路由模块本身有一点额外开销但相对节省的计算来说可以忽略。作者统计了不同类别的FLOPs分布发现大部分简单背景区域都走了低成本路径真正把算力花在刀刃上。4.2 消融实验带来的关键结论消融实验往往比最终结果更能说明问题。论文里有一组很有代表性的对比去掉动态路由直接把多个分支平均融合精度会掉一截。这说明简单的多分支堆叠并不能替代动态选择路由决策本身带来的是真实信息增益。把路由模块的输出从软选择改成确定的one-hot选择推理阶段精度几乎不变。这说明训练到后期路由分布在大多数位置上已经接近确定Gumbel-Softmax松弛带来的训练-推理不一致在可接受范围内。还有一个消融是关于路由粒度的把逐像素路由改成区域级路由一个8×8区域共享一个路由决策精度下降明显但速度更快。作者借此说明了逐像素决策的必要性——很多关键信息就藏在细节区域粒度一粗就会丢。4.3 路由行为的可视化分析动态路由最吸引人的地方是它的可解释性。论文展示了几张特征图的可视化结果将每个位置选中的路径用不同颜色标注。观察这些可视化图你会发现一个有趣现象同一物体内部的路由选择相对一致不同物体之间差异明显。比如一辆车整体可能倾向用大感受野路径去建模而路面区域则频繁切换中感受野路径建筑边缘处又会两者交替。这种可视化说明动态路由学到的不是一个随便的映射而是有语义一致性的规律。你在自己做复现时候也可以尝试做类似统计能帮你判断训练是否收敛到了正确的解。如果发现同一个物体的路由选择噪声非常大那大概率是路由模块没有训好需要检查温度策略或者正则参数。5. 复现实操与工程心得5.1 动态路由模块的代码骨架下面是基于PyTorch风格的伪代码展示路由模块和空间变体卷积的组合逻辑。真正复现时用类似结构再套进骨干网络即可。import torch import torch.nn as nn import torch.nn.functional as F class RoutingModule(nn.Module): def __init__(self, in_channels, num_paths, hidden64): super().__init__() self.conv1 nn.Conv2d(in_channels, hidden, 1) self.conv2 nn.Conv2d(hidden, num_paths, 1) self.tau 1.0 # 温度参数随训练步数下降 def forward(self, x): r F.relu(self.conv1(x)) logits self.conv2(r) # 使用Gumbel-Softmax得到可微分的近似one-hot路由 route F.gumbel_softmax(logits, tauself.tau, dim1, hardFalse) return route class DynamicResBlock(nn.Module): def __init__(self, in_channels, out_channels, path_listNone): super().__init__() # path_list为若干不同配置的卷积层组合 self.paths nn.ModuleList(path_list) self.router RoutingModule(in_channels, len(path_list)) self.output nn.Conv2d(out_channels, out_channels, 1) def forward(self, x): route self.router(x) path_outputs [p(x) for p in self.paths] # 每个位置按概率融合路径输出 out 0 for i, p_out in enumerate(path_outputs): out route[:, i:i1] * p_out return F.relu(self.output(out))这段代码只做了核心逻辑示意实际替换残差块时还要处理残差连接、上下采样对齐、BN位置等问题但路由部分的基本结构就是这样。值得提醒的是路径数量多的时候可以先把各路径输出存到列表里再统一融合避免中间显存峰值过高。5.2 训练与推理的一致性处理Gumbel-Softmax带来的训练/推理不一致问题是需要重点处理的地方。训练阶段用带噪声的软路由推理阶段应该直接用argmax取硬选择再按硬选择结果计算输出。因为软路由本质是多路径加权推理时如果继续用软权重不仅计算量更大精度也不一定更好。我的建议是推理时分成两步先让路由模块跑一次前向得到每个位置的路径索引再根据索引直接调用对应路径的卷积结果。如果多条路径结构差异较大无法共享中间计算那就要在推理时显式做路径索引的掩码计算。好在大多数路径只是感受野不同计算流程基本一致。这里有一个工程细节不要把Gumbel噪声在训练时全量加到所有模块上。初始阶段加噪声有助于探索训练后期如果噪声依然存在会让路由分布抖动。定量看过一些实验训练后期把Gumbel噪声关掉精度能再回升零点几个点。可以参考的做法是训练到70%步数后逐步关掉噪声只保留一个极低温度。5.3 调参与资源占用建议动态路由网络训练时对显存的占用比普通分割模型稍高主要原因是多条路径的中间特征都要保留用于融合和梯度回传。想要压显存有两个思路一是路径之间共享计算比如让空洞率不同的路径共用同一份卷积激活再做不同感受野的池化而不是真的重复卷积二是采用梯度检查点对部分路径的前向特征只保留必要信息反向时重新计算。训练超参方面最容易踩的坑是初始学习率。路由模块是新增模块随机初始化直接套用0.01的骨干学习率很容易让路由模块的梯度爆炸。把路由模块的学习率单独设为骨干的十分之一能让训练稳定不少。Batch size一般用16到32搭配poly下降策略训练60到80个epoch就差不多能看到收敛趋势。还有一个关于BatchNorm的细节多个路径分支如果各自带BN层每个路径的统计量要独立统计不能共享。共享BN会导致各路径之间的分布互相干扰路由选择就挪不动了。路径带BN还有一个副作用就是小batch下BN统计噪声大路由决策会不稳定所以尽量用相对大的batch或者同步BN。6. 常见问题与排查速查表在实际复现动态路由网络的过程中你会遇到一些和普通分割模型不一样的问题。我把它们整理成速查表方便定位。现象可能原因解决手段训练初期loss剧烈震荡Gumbel温度过高路由噪声过大降低初始温度限制在1.0以下路由退化所有位置选同一条路径路由模块学习率过高或缺少熵正则调低路由学习率加熵正则项训练精度不错但推理精度下降明显Gumbel噪声没有在后期关闭后期替换为argmax硬路由多路径变体卷积显存爆掉各路径独立计算中间特征共享路径计算或启用梯度检查点路由可视化噪声大、语义不一致BN统计未独立或温度退火过快检查BN分支归属放缓温度下降小目标分割效果反而变差路由选择倾向大感受野路径增加小感受野路径权重或加边界辅助损失针对第一种情况温度并不是越高越好。Gumbel-Softmax温度很高时输出分布接近均匀分布梯度虽然平滑但信息量很低相当于所有位置都在随机探索loss自然上下跳。正常情况下初始温度设在0.5到1.0之间然后每多少个epoch乘以一个衰减因子比如0.97。针对路由退化问题我见过不少复现翻车都栽在这。路由模块一旦退化到所有位置都选同一条路径整个模型实际上就变成了一个普通多分支网络动态带来的增益全部消失。解决办法除了调低学习率还可以在路由logits上加L1正则迫使不同位置的路由分布出现分化。这个方法很简单但很有效。还有一种常见的脏问题骨干网络预训练权重没有正确冻结或迁移。动态路由网络的主干部分用的是ImageNet预训练权重但新增的路径卷积和路由模块是随机初始化的。如果加载权重时把新模块的权重也错误覆盖成预训练值第一轮梯度就乱了。复现时建议仔细检查state_dict的匹配关系只加载骨干部分的权重。写在最后的一点体会把动态路由的思想吃透之后你会发现它真正解决的是语义分割里面一个恒久矛盾到底是做全局一致的建模还是做逐点特异化的处理。过去的做法是在网络后端搞各种注意力模块但这些模块大多只是对特征做软加权没有真正改变计算过程。这篇论文的做法把“计算路径的选择”本身变成了网络参数的一部分一步到位把动态性嵌入到卷积内部。虽然这篇论文的报告时间已经过去不短但它的思想在后来很多高效分割和动态网络方案里都能看到影子。复现这类工作的最大价值不在于背下来某个mIoU数字而是理解“如何让网络资源分配听输入的话”。如果你正准备在移动端或实时场景下做分割完全可以沿着这个思路继续做剪枝和路径稀疏化如果你的场景对边界精度要求很高也可以在动态路由的分支设计里加入专门的高频分支。说到底动态路由提供了一种灵活的网络设计范式值得任何一个做分割的人深度学习一下。