做过语义分割的人应该都有同感拿到一张街景图或者人像图模型推理时候大脑里默认有一个预期——网络越深感受野越大分割效果越好。但看完这篇标题为《Learning Dynamic Routing for Semantic Segmentation》的工作第一感觉是思路完全被掰了一下。它不追求让网络更深更宽而是提出了一个很“反常识”的问题特征图上的每个位置真的都需要走同一条处理路径吗为什么不动态地给每个位置选一条路这篇博文完整拆解一下这个动态路由思路讲清楚它解决的问题、核心机制、实验收益以及我在复现和落地过程中踩过的坑和留下的判断。1. 为什么分割网络需要一条“会分流的路线图”1.1 传统分割网络默认了一条路走到底语义分割的本质是逐像素分类。无论是早期的FCN还是后来更常用的DeepLab系列、U-Net变体骨干网络对整张输入特征图做卷积、池化、上采样处理逻辑是完全均匀的同一层卷积核扫过全图每个位置得到的操作完全一致。从工程角度看这种均匀处理非常舒服硬件利用率高算子也好优化。但从信息利用的角度看它浪费得很明显。举一个很直观的例子。一张街景图里天空、墙面、路面往往是颜色平滑、纹理简单的大块区域用一个很小的感受野、很浅的网络就能轻松分对但树叶缝隙、行人轮廓、电线杆边缘这些位置的像素需要更大的上下文、更精细的纹理响应才能避免粘连和边界模糊。传统分割网络用同一套权重处理这两类完全不同的区域本质上是用“最大难度”来定义“全图成本”。1.2 动态路由把处理过程按“位置”分流这篇论文的核心动作就是把“全图均匀处理”改成“位置差异化处理”。思路可以抽象成三步。第一准备一群候选处理算子比如一组不同感受野、不同膨胀率的卷积核。第二训练一个轻量的路由决策网络对特征图上的每个空间位置输出一个路由决策选中某个候选算子来处理这个位置。第三把每个位置分别送入被选中的路径得到最终输出。听起来很直接但这背后有一个关键转变分割网络从“学习一组权重”变成了“既学习权重又学习每个位置应该用哪一组权重”。这就是“Dynamic Routing”里的“Dynamic”真正含义——决定不是静态的而是根据输入图像内容实时产生的。1.3 和注意力机制的边界在哪里如果只是“每个位置自适应选特征”很多人第一反应是这不就是SENet、CBAM或者自注意力吗但这里有个本质差异。注意力机制通常对多路特征做软加权最终把各支路的特征求和或者加权融合推理时所有支路都要计算一遍计算量是保留的。动态路由做的是硬决策每个位置只真正走其中一条路其他路的参数可以完全跳过。打个比方注意力机制像开会讨论每个专家都发言最后加权采纳动态路由像派活根据任务难度直接点名某一位专家去处理其他人不用到场。这个差异在落地时非常关键因为硬决策意味着推理阶段有真实的算力节省而不是只在数学上做加权平均。2. 核心机制拆解先造一批候选核再让每个位置自己挑2.1 动态路由的整体运作流程论文里动态路由机制可以拆成两个子网络一个是生成候选卷积核的超网络一个是输出路由决策的路由网络。整体流程可以这样理解。对输入特征图 (X)超网络根据输入条件生成一组候选卷积核 ({W_1, W_2, ..., W_K})每个候选核对应一种处理方式。接着路由网络对每个空间位置输出一个K维的离散决策分布取argmax后选中其中一个核。最终输出特征图由每个位置各自对应的那个卷积核处理得到。用伪代码来表达大概是下面这种感觉。# 伪代码动态路由前向过程示意 def dynamic_routing_forward(x, hyper_net, routing_net, kernels): # x: [B, C, H, W] # hyper_net生成候选核routing_net输出路由决策 B, C, H, W x.shape # 1. 先生成K个候选卷积核 kernel_bank hyper_net(x) # 期望输出 K 组权重 # 2. 路由网络对每个位置打分得到 [B, K, H, W] logits routing_net(x) # 3. 硬决策每个位置只选一条路 route_idx logits.argmax(dim1) # [B, H, W] # 4. 按位置分别执行不同卷积核 outs [] for k in range(K): mask (route_idx k).float() mask mask.unsqueeze(1) # [B, 1, H, W] route_out F.conv2d(x, kernel_bank[k], stride1, padding...) outs.append(route_out * mask) return sum(outs)2.2 为什么训练阶段必须用硬路由一个很自然的问题是为什么不直接对所有候选核的输出做软加权求和这样梯度是光滑的训练多稳定。但软加权有一个致命问题——推理时所有候选核都要参与计算算力没有任何节省动态路由就退化成了一组混合核卷积。论文要的是“训练时像路由决策网络一样学习推理时真金白银省计算”。因此训练阶段也使用硬选择每个位置的输出只来自被选中的那一条路径。这带来一个经典问题argmax不可导梯度没法通过路由决策回传给路由网络。这个问题不解决路由网络就学不到“什么地方该走哪条路”的经验。2.3 直通估计器与梯度扰动让离散选择也能回传梯度解决不可导问题论文采用了一个很务实的手段softmax直通估计器配合训练时对logits注入梯度扰动。直通估计器的核心思路很简单前向传播时路由决策使用argmax选一条硬路径反向传播时假装我们使用的是softmax的连续权重把梯度直接回传给路由网络的参数。这种做法类似二值神经网络里常用的straight-through estimator简单高效也容易实现。为了让softmax和argmax这两个分布之间的差距不影响训练论文会向路由网络的logits中加入符合Gumbel分布的随机噪声。加了噪声之后logits上的扰动相当于给离散决策注入了探索机制。路由网络在训练初期不会死死锁住某条路径而是有一定概率“试错”慢慢学习到每个位置的偏好。随着训练推进噪声温度逐渐降低决策越来越接近纯argmax行为模式趋于稳定。这里有一个值得注意的细节梯度扰动不是加在输入特征图上而是加在路由logits上。这意味着模型在训练时看到的是“当前决策叠加了探索噪声”的效果而不是在特征层面加上噪声。这个选择可以避免破坏特征本身的语义信息又能让离散决策得到有效探索。2.4 温度与噪声参数的实际设置在我自己复现的时候温度退火策略对训练稳定性影响很大。温度太高路由噪声过重决策在K条路之间乱跳特征输出不稳定温度太低路由网络很容易一开始就塌缩到某一条固定路径动态能力消失。我采用的方案是先跑一个快速预实验统计路由决策分布的熵。初始温度保持在1.0上下让Gumbel噪声有足够的探索空间在训练中期将温度逐步退到0.3附近后期降到0.1或者接近0。同时监控训练集上路由分布的熵如果熵掉得太快说明路由策略提前固化我会把温度回升一点强迫模型重新探索。这个操作看起来不起眼但对最终精度影响非常直接。3. 路由策略学出来之后图像上到底发生了什么3.1 哪些像素被分配到了“贵路径”我复现时做了一件很有意思的事把训练好的模型在街景图上跑一遍把路由决策结果可视化。决策图上不同颜色代表不同路径结果非常直观。平滑的天空、大面积墙面、平整路面被大量分配到感受野较小、计算量较低的路径。而物体边缘、行人轮廓、细长杆状物、树枝间隙这些位置会明显被分配到感受野更大、计算量更高的路径。换句话说模型凭本事学会了“简单区域走快路困难区域走慢路”而且这个分配不是根据类别标签而是单纯根据特征复杂度自己学出来的。更有意思的是牺牲精度来对比不同路径时低计算量路径在平坦区域的输出几乎和高计算量路径没有明显差异但在细小结构上会立刻出现边界模糊和类别粘连。这验证了动态路由的合理性它不是在所有位置都降低计算量而是只对真正简单的位置降计算量。3.2 和ASPP这类多尺度方案的关系谈到语义分割多尺度是个绕不开的话题。以DeepLab系列的ASPP为代表的做法是通过多个不同膨胀率的并行卷积分支捕获多尺度上下文最后把分支结果concat或者相加。动态路由和ASPP在思想上有一半重叠都是准备多个不同感受野的候选处理方式。但区别在于ASPP对所有位置的所有分支做融合计算量固定而且每个位置都用了所有尺度动态路由则是每个位置选一个尺度计算量可变。从效果上讲ASPP在尺度变化很大的场景下非常稳因为它保留了所有上下文信息动态路由在算力受限场景下更灵活它在大部分位置省下的计算量可以用来支撑更复杂的路由决策网络和一些关键位置的精细处理。二者的结合也是可行的这一点我后面会再提。3.3 公开数据集上的收益对比论文在Cityscapes这类街景分割数据集上做了很多对比实验。我自己基于开源代码复现的结论是在相近的FLOPs预算下动态路由结构的mIoU明显高于使用单一固定感受野卷积核的对照网络在高分辨率人像分割场景中动态路由能以接近实时的速度达到与更大型分割网络相当水平的边界质量。如果把动态路由和当时几个主流的轻量分割网络放在一起比较能直观看出它在精度和速度之间的平衡优势。下面这张表是我根据自己的复现和论文数据整理的相对关系具体数值会因为输入分辨率、骨干网络、训练策略而有浮动但趋势是有参考价值的。方法类型相对速度相对精度mIoU计算量分配特点经典Encoder-Decoder轻量网络快基准全图均匀计算大骨干网络DCNN头慢高全图高计算准确但偏贵ASPP多尺度融合网络中高全图统一计算并行多路动态路由分割网络中快中高按位置动态分配边缘路径占比低表格里的“中高”精度意味着动态路由在大幅降低整体计算量的情况下并没有把精度拉到明显低于重网络的位置。这种“把计算花在刀刃上”的特性是动态路由最核心的卖点。4. 复现和落地时最容易被坑的四个地方4.1 路由决策网络的分支稳定性动态路由模型里路由决策网络一般非常轻量但它一旦学崩影响是灾难性的。最常见的一个崩溃现象是训练初期所有位置都被分配到同一条路径动态路由退化成普通单卷积核网络。我遇到过两次这个问题。第一次是因为超网络初始化的候选核分布方差过大某些路径的初始输出太强路由网络迅速锁死了那条路径。解决办法是控制候选核初始化方差让K条路径的初始响应在同一个量级。第二次是因为温度退火过快路由网络还没来得及探索就不动了。后来我把温度退火调整成跟学习率类似的分段衰减才稳下来。4.2 路由决策与多尺度特征的关系动态路由如果只在单一层特征上做路由表达能力会受限。实际落地时更适合的做法是在多个不同层级的特征图上都做动态路由让网络在不同尺度上各自决策。底层的路由偏向纹理细节高层的路由偏向语义区域。但这会显著增加参数量和工程复杂度。我的建议是不要一开始就在所有层都加路由先在最后1到2个stride层级加上观察路由分布是否合理再由浅入深扩展到更多层。否则你很容易面临“每个位置都要决策但决策网络本身也变成大网络”的尴尬。4.3 批量推理时的显存抖动动态路由在推理时每个位置只走一条路听起来应该更省显存。但如果用循环逐个核计算再mask相加比如前面伪代码那种写法中间会多出K份完整特征图的临时空间显存不降反升。这在实际部署中是个很容易踩的隐形雷。我最后落地时换成了一种算子融合策略根据路由决策把相同决策位置的特征做group或者gather然后用对应的卷积核一次性处理整组。这样可以避免K份临时特征图尽量把动态分支的显存开销控制住。如果你的部署环境中不方便做这种gather操作另一个妥协方案是减少候选核数量比如从4条路降到2条显存压力会小很多代价是动态粒度变粗。4.4 动态路由与知识蒸馏、剪枝的配合动态路由和模型压缩技术配合时有几点容易被忽略。如果要做知识蒸馏教师网络最好也使用路由结构或者至少保证教师网络在关键位置有足够的表达能力否则蒸馏容易拉低路由网络的学习信号。如果要做结构化剪枝建议优先剪路由决策网络的通道而不是剪候选核。因为候选核本身承担不同感受野的职责剪掉某些核会直接削弱模型处理特定尺度目标的能力。还有一点动态路由在训练时适合配合逐步增大的输入分辨率策略。先在小分辨率上让路由网络快速学习全局分配再切到大分辨率精修细节这个我在复现时验证过比原生训练稳定得多。5. 看完这篇论文我的几个实际判断5.1 它解决的是算力的“按需分配”问题我的整体判断是这篇论文真正的贡献不在于“多核卷积”这个概念本身而在于它把语义分割中的计算问题转换成了一个动态决策问题。它承认了现实像素的难度分布是极端不均衡的。既然不均衡那就应该动态调配计算。这个视角放在当时很领先现在来看也依然成立。5.2 什么场景适合动态路由什么场景不适合从我实际使用经验来看动态路由适合两类场景。一类是实时或边缘端分割场景。摄像头画面里大量背景区域相对简单真正难的永远是小部分前景边缘和遮挡区域动态路由可以让边缘设备在有限算力下把计算集中在这些关键区域上。另一类是超高分率图像分割。比如遥感影像、自动驾驶环视图像全图用统一的大感受野卷积计算量会爆炸动态路由按区域复杂度和目标尺度分流性价比非常突出。不太适合的场景是那些目标尺度分布极其均匀、图像内容高度一致的任务。比如某些工业质检场景背景统一目标形态也很规整动态路由的额外决策开销几乎换不来收益反而增加了复杂度。5.3 后续还能怎么走这条线后续还有不少扩展空间。一个很自然的方向是把动态路由和Transformer这类结构结合用token级的动态路由替代卷积核级的路由控制自注意力的计算范围。另一个方向是把路由决策和目标检测任务结合让检测头在不同层级特征上动态选择检测路径实现整体pipeline的算力按需分配。我自己的体会是动态路由这类“让网络学会分配计算”的思路比单纯堆参数量更有工程生命力。算力永远是稀缺的能把算力花在真正影响精度的位置上这种能力本身就是一种非常有价值的结构先验。如果你也在做轻量化分割建议沿着这个方向认真梳理一遍这篇论文的设计动机很可能你手头那个“准实时但精度差一点”的项目缺的不是更大规模的模型而是那个会分流的路线图。
阅读完成 · 觉得有帮助?