tensorflow官方推荐用tfmot.sparsity.keras.polynomialdecay实现渐进式剪枝:从begin_step开始、end_step结束,以initial_sparsity(0.1–0.3)为起点逐步增加稀疏度;仅对prune_low_magnitude包装的dense/conv层生效,bn/activation/embedding等层不可剪;剪枝后需strip_pruning再导出h5或tflite以减体积;微调时应降学习率、禁早停、调低正则系数,并监控各层梯度与loss异常。

怎么用 tfmot.sparsity.keras 做渐进式剪枝
TensorFlow 官方推荐的剪枝方式不是“训练完再砍一刀”,而是边训边稀疏——靠 tfmot.sparsity.keras.PolynomialDecay 控制掩码(mask)逐步关闭不重要的权重。它不改模型结构,只给每层权重加个动态开关,训练中自动调节“关掉多少”。
- 必须指定
begin_step和end_step:前者建议设为 0 或 warmup 结束步数;后者要算准——比如 50 epoch × 每 epoch 步数,设小了会提前锁死稀疏度,设大了后期没变化 -
initial_sparsity别设太高(如 0.5),否则早期就大量归零,网络来不及适应,精度崩得快;0.1–0.3 更稳妥 - 剪枝只作用于你显式包装的层,
model.layers里没被prune_low_magnitude包裹的层完全不受影响
prune_low_magnitude 包装时哪些层该包、哪些不该包
不是所有层都适合剪枝。全连接层和卷积层是主力,但 BatchNorm 层、激活层、Dropout 层不能包——它们没权重,包了会报 ValueError: Layer has no weights to prune;而 Embedding 层虽然有权重,但剪它容易破坏语义对齐,一般跳过。
- 推荐只包
tf.keras.layers.Dense和tf.keras.layers.Conv2D(含Conv1D/Conv3D) - 如果用了自定义层(比如带 weight-sharing 的层),得确认它暴露了
kernel或weight属性,否则prune_low_magnitude找不到可剪对象 - BN 层后的卷积(如 ResNet 的 conv-bn-relu)可以剪 conv,但别剪 BN 本身;剪完后 BN 的
moving_mean/moving_variance仍需参与推理,不能丢
剪完模型变稀疏了,但导出 SavedModel 后体积没变小
剪枝只是把权重设为 0 并加掩码,原始张量尺寸没变,所以 model.save() 出来的 SavedModel 还是稠密格式,磁盘体积几乎不变。真要减体积,必须走稀疏化导出流程。
- 先调用
tfmot.sparsity.keras.strip_pruning(model):它会移除所有 pruning 相关 ops 和 mask 变量,只保留最终的 0/非0 权重 - 再用
tf.keras.models.save_model(..., save_format='h5')或转 TFLite;注意 h5 格式会自动压缩连续零值,体积明显下降 - 若要部署到边缘设备,强烈建议接量化:
tf.lite.TFLiteConverter.from_keras_model(stripped_model)+converter.optimizations = [tf.lite.Optimize.DEFAULT],稀疏+量化双压效果更实
剪枝后精度掉太多,微调时要注意什么
剪枝本质是约束优化,精度回落是常态。关键不是“能不能回得去”,而是“怎么让恢复过程不翻车”。微调不是简单 resume train,得换策略。
- 学习率要比原训练低一个数量级(比如从 1e-3 改成 1e-4),否则残存权重被剧烈扰动,稀疏结构瞬间失效
- 别用早停(early stopping):前几轮精度可能震荡甚至略低于剪枝前,得给够 10–15 epoch 让网络重校准重要连接
- 如果用了正则化(如 L2),微调阶段建议降低其系数——剪枝本身已有结构约束,双重压制反而抑制恢复
真正难的不是调参,是判断哪一层剪过头了:比如某层剪到 80% 稀疏度后梯度几乎消失,或者验证 loss 突然飙升,就得回头调该层的 pruning_schedule 或单独降低其 final_sparsity。这种细粒度干预,文档很少提,但线上调优时天天碰见。










