动态网络推理:早停与动态 Channel 剪枝的设计思考

今天写完了约束参数量下的 sensitive 剪枝代码。VGG 的主要参数量都压在 FC 层,剪完卷积层收益有限,所以顺带看了几篇动态推理网络的相关工作,主要参考了 SkipNet 这类方案的测速方式——比较典型的做法是:在精度没有明显下降的前提下,测量 FLOPS 减少了多少。

FLOPS 为什么靠不住

调研过程中被一个数字搞懵了:EfficientNet-B3 的 FLOPS 小于 ResNet-18,但实测推理速度并不如 FLOPS 的差距那么悬殊。这让我开始觉得 FLOPS 这个指标”比较玄学”——它是一个衡量计算量的代理指标,但和实际延迟之间有一道沟。

原因大概在于:FLOPS 不考虑内存访问开销,也不考虑硬件并行度。EfficientNet 大量使用的 depthwise separable convolution,channel 间独立计算,运算密度低,GPU 上实际加速幅度远不及 FLOPS 的降幅。这个认识让我对以 FLOPS 为优化目标的剪枝方案产生了一些疑虑。

放弃多网络动态,转向单网络动态

之前我有一个”动态多网络”的设想:根据输入难易程度,在几个不同规模的网络之间做路由,容易的样本走小网络,难的走大网络。但现在基本可以放弃这个思路了,主要原因还是 FLOPS 的问题——多网络方案里 FLOPS 的计算更复杂,而且 EfficientNet-B3 vs ResNet-18 的例子说明,FLOPS 小不等于实测快,多网络带来的工程复杂度难以用不确定的加速收益来抵消。

更合理的方向是做成单网络的动态推理

早停策略:每个 block 后接分类器

具体的思路是:在主干网络每个 block 的输出后面各接一个分类器,单独训练这些 FC 层,训练时将前面特征提取的部分冻结掉。这样主干网络的表示能力不受影响,各出口的 FC 层独立训练。

推理时,以 entropy 作为判据:如果当前出口输出的 softmax 概率分布 entropy 足够低,说明模型对预测结果足够确定,就在此处提前输出,不再继续前向传播;entropy 高则说明模型还在犹豫,需要更深层的特征来帮助判断。

这个设计本质上和早停(early exit)策略类似,核心就是让简单样本在浅层就能给出答案,不必每次都跑完整个网络。

动态 Channel 选择:与剪枝结合

在早停的基础上,还可以引入动态 channel 选择——在每个 block 内部,根据输入特征动态决定哪些 channel 参与计算,而不是每次都激活全部 channel。两者结合起来,就形成了一个在深度和宽度两个维度上都动态的推理框架:

  • 深度维:通过 entropy 判断是否在当前 block 处早停;
  • 宽度维:在每个 block 内,动态选择实际参与计算的 channel 子集。

这样,简单样本既能在浅层早停,每层用到的 channel 数也可以更少;复杂样本才走完整的网络宽度和深度。

不过,动态 channel 选择的具体实现我还需要进一步调研,尤其是如何设计选择器模块、如何在保证可微的同时实现推理时的实际加速,这部分需要找宇超咨询一下。早停那边别人是怎么做的,也需要再看几篇文章梳理清楚。

今天其他进展

除了剪枝调研之外,今天还看完了编译原理第四章,以及 cache 课的收尾章节,晚上把 cache 作业也撸完了。