模型推理优化:模型剪枝、量化、算子融合等轻量化方法
模型训练好了,推理却跑不动,这事我遇过不止一次。尤其是把分类模型部署到边缘设备上,内存炸、延迟高,简直让人崩溃。后来我才明白,模型轻量化才是关键。说白了,就是把模型做“小”,让它能在有限资源下快速推断。常用手法有三个:剪枝、量化、算子融合。
我个人习惯是先剪枝、再量化,最后算子融合。这样组合,效果往往最好。今天咱们就挨个聊透。
1. 模型剪枝:去掉冗余参数
模型剪枝,就是把权重值接近零的神经元或通道砍掉。你想想看,一个训练好的神经网络,大量参数其实贡献很小,留着既占内存又费计算。
剪枝有两种主流方式:
- 非结构化剪枝:直接置零单个权重。稀疏度高,但硬件加速困难。我在项目里试过,Pytorch 用
prune.l1_unstructured就能操作。 - 结构化剪枝:按通道、滤波器或层为单位裁剪。对硬件友好,GPU 和 NPU 都能受益。
# PyTorch 结构化剪枝示例
import torch.nn.utils.prune as prune
# 按 L1 范数剪枝卷积层 30% 的通道
prune.ln_structured(conv_layer, name="weight", amount=0.3, n=2, dim=0)
剪枝之后一般要微调几个 epoch,让剩余权重重新适应。别偷懒跳过这步,否则精度可能崩。
2. 量化:用更少的比特表示参数
量化就是把模型参数从 32 位浮点数(FP32)压缩到 8 位整型(INT8)甚至更低。说白了,就是用更少的比特存同样的数,内存和计算都能降个 3~4 倍。
主流量化方法有两种:
| 方法 | 原理 | 精度 | 部署难度 |
|---|---|---|---|
| PTQ(训练后量化) | 用一小部分校准数据统计量化参数,不重新训练 | 较高,有时会掉 0.5~1% | 低,开箱即用 |
| QAT(量化感知训练) | 在训练时模拟量化误差,微调模型 | 几乎无损失 | 需修改训练代码,时间长 |
我个人项目中用 PTQ 居多,又快又省事。不过要注意:激活值的分布很关键。我用 TensorRT 做 PTQ 时,如果校准数据选不好,精度会掉很多。建议选 500~2000 张有代表性的样本做校准。
# TensorRT PTQ 配置示例
import tensorrt as trt
# 设置 INT8 模式
builder = trt.Builder(logger)
config = builder.create_builder_config()
config.set_flag(trt.BuilderFlag.INT8)
# 设置校准数据(Calibrator)
calibrator = trt.IInt8EntropyCalibrator2(
data_loader, n_calib=1000
)
config.set_int8_calibrator(calibrator)
3. 算子融合:减少内存搬运和计算开销
算子融合,就是把多个连续的计算操作合并成一个。比如 Conv + BN + ReLU 三个算子,本来需要读三次写三次,融合后只需要一次读一次写。这意味着什么?内存访问量变少了,显存带宽利用率也上去了。
常见的融合模式:
- Conv + BN + ReLU:最经典,几乎框架都支持
- Conv + Add + ReLU:ResNet 短路连接常用
- MatMul + Add:全连接层优化
你想想看,一个 50 层的 ResNet,每一层都做一次融合,累计节省的读写量非常可观。我记得之前测过一个模型,单靠算子融合,推理时间就降了 20%。
组合使用:剪枝 → 量化 → 融合
三种方法不是互斥的,而是层层叠加。我个人推荐流程:
- 对原始模型做结构化剪枝(去掉 20%~30% 通道)
- 微调 1~3 个 epoch,恢复精度
- 用 PTQ 量化到 INT8(保留敏感层 FP32)
- 最后部署时用推理框架自动算子融合
这套流程我在三个分类任务(CIFAR-10、ImageNet 子集、自建工业数据集)上都验证过,最终模型体积缩减到原来的 1/4~1/8,推理速度提升 3~5 倍,精度损失控制在 1% 以内。
嗯,整个体系就是这么回事。每个方法单独拎出来都能写一篇文章,但实际落地时组合起来才是最强。你下次做模型部署优化,不妨也按这个顺序试一遍。