剪枝本身不减模型体积,必须strip_pruning+h5导出才能看到磁盘大小下降:因PolynomialDecay仅加掩码,保存仍为稠密格式;strip_pruning移除mask后用h5保存,才利用零值压缩实现40–60%体积下降。

剪枝本身不减模型体积,必须 strip_pruning + h5 导出才能看到磁盘大小下降
为什么 model.save() 后剪枝模型体积没变小
因为 tfmot.sparsity.keras.PolynomialDecay 只是给权重加了掩码(mask),所有张量尺寸、dtype、存储格式都维持原样——model.save('pruned') 输出的 SavedModel 仍是稠密格式,0 值和非 0 值占同样空间。
常见错误现象:训练完稀疏度到 80%,但 os.path.getsize('pruned') 和原始模型几乎一样大。
- 真正压缩体积要两步走:先调用
tfmot.sparsity.keras.strip_pruning(model)移除所有 mask 变量和 pruning ops;再用save_format='h5'保存 -
h5格式会自动对连续零值做轻量级压缩,实测 70% 稀疏度可降体积 40–60% - 若导出 TFLite,strip 后再用
tf.lite.TFLiteConverter.from_keras_model(),能进一步利用稀疏性(需 target_spec.supported_ops 包含tf.lite.OpsSet.TFLITE_BUILTINS)
哪些层该用 prune_low_magnitude 包裹
只对有权重且适合稀疏化的层包装,否则报错或无效:
立即学习“Python免费学习笔记(深入)”;
- ✅ 推荐包:
tf.keras.layers.Dense、tf.keras.layers.Conv2D(含 Conv1D/Conv3D) - ❌ 绝对不包:
tf.keras.layers.BatchNormalization(报ValueError: Layer has no weights to prune)、tf.keras.layers.ReLU、tf.keras.layers.Dropout - ⚠️ 慎包:
tf.keras.layers.Embedding(剪后易破坏 token 对齐,精度抖动明显) - 自定义层必须暴露
kernel或weight属性,否则prune_low_magnitude找不到可剪对象
PolynomialDecay 的关键参数怎么设才不崩精度
initial_sparsity 和 end_step 设错是精度骤降主因:
-
initial_sparsity别超过 0.3:设 0.5 会导致前几轮大量权重归零,网络来不及重建梯度流,loss 爆涨、梯度消失频发 -
end_step必须算准:比如 50 epoch × 每 epoch 步数 = 10000,则设end_step=10000;设小了(如 5000)会提前锁死稀疏度,后期无法继续剪;设大了(如 50000)则后期稀疏度增长停滞,浪费剪枝潜力 -
begin_step建议设为 0 或 warmup 结束步数(如 1000),太晚(如 5000)会让模型先学满再砍,冗余参数已固化,剪不动
微调剪枝模型时容易被忽略的三件事
剪枝后直接 resume train 往往掉点,必须调整训练策略:
- 学习率要降:用原 lr 的 1/3~1/5,否则 mask 切换频繁导致权重震荡
- 禁用早停(
EarlyStopping):剪枝中期 loss 会短暂上扬(mask 重置导致),早停会误判收敛 - 正则系数调低:L2 权重衰减系数建议 ×0.5,否则和剪枝目标冲突(一个拉权重向 0,一个推权重远离 0)
监控重点不是总 loss,而是各 Dense/Conv 层的梯度 norm —— 若某层梯度持续 pruning_schedule 参数或考虑跳过该层剪枝。


















