模型优化概述

做深度学习这么久,我一直觉得模型优化是个“四两拨千斤”的活儿。你辛辛苦苦训出一个大模型,精度挺高,可一部署就傻眼——手机跑不动,延迟爆表,内存撑爆。这时候你才发现,优化不是锦上添花,是生存刚需。

这一章,我们先把底牌摊开:优化到底在追什么目标?会遇到哪些坑?用什么尺子量好坏?

优化目标

说白了,优化就是在资源受限的条件下,让模型表现得尽可能好。我总结为三个词:小、快、准。

  • 小 —— 模型体积小,参数量少,存储占用低。这样才好塞进手机、嵌入式设备。
  • 快 —— 推理延迟低,吞吐量高。用户可不想等两秒才看到识别结果。
  • 准 —— 精度尽量不掉。你不能为了省内存让分类准确率掉5个点,那还不如不用。

这三个目标经常打架。你想想看,剪枝掉一半参数,速度上去了,但精度可能跳水。量化到int8,体积小了,但推理时数值误差可能累积。我记得有个项目里,业务要求模型从500MB压到50MB以内,同时推理延迟<30ms,精度下降<1%。嗯,这就是典型的“既要又要”。

目标维度 典型目标值 常用手段
模型体积 从GB级降到MB级 剪枝、量化、知识蒸馏
推理速度 单帧<50ms(移动端) 算子融合、内存布局优化、量化
精度保持 Top-1下降<0.5% 感知量化训练、蒸馏损失设计
我的经验:别一上来就堆优化技术。先摸清业务上哪个目标最要紧,是体积还是速度?我曾经做过一个安防项目,客户只关心延迟,模型大点无所谓。那量化精度掉1个点也可以接受,但剪枝带来的速度提升不明显,最终我们只做了混合精度和算子融合。

常见挑战

优化路上没那么多坦途。我踩过的坑,大概能列一张清单。

  • 过拟合 —— 数据量不够,优化后的小模型更容易记住噪声。
  • 计算资源限制 —— GPU显存只有8GB,你想做更大batch的量化校准?没门。
  • 硬件兼容性 —— 有些NPU不支持某些算子,量化后的自定义算子没法跑。
  • 量化误差累积 —— 尤其是小模型,量化后某些层的激活值分布偏移严重,精度直接崩。
  • 回退成本 —— 你辛辛苦苦优化了一个月,结果精度不达标,得重训。我遇到过类似情况,教训就是优化之前先做精度基线复现。
避坑指南:千万不要假设优化后的模型和原模型完全等价。我曾有一次把ResNet-50量化到int8,在验证集上精度只掉0.3%,高兴坏了。但一上真实场景,图像噪声大,精度直接掉了2%。后来才明白,量化对数据分布敏感,离线校准的数据集要尽量覆盖真实分布。

评估指标

没有度量就没有优化。我习惯从四个维度去评估:大小、速度、精度、资源占用。

模型大小

  • 参数量(Params):单位通常是百万(M)或十亿(B)
  • 存储体积(Model Size):量化后.pt或.pth文件的实际大小

推理速度

  • 延迟(Latency):单次推理耗时,常用毫秒
  • 吞吐量(Throughput):每秒处理的样本数,常用FPS

精度

  • 分类:Top-1 / Top-5准确率
  • 检测:mAP
  • 分割:mIoU

资源占用

  • 峰值内存(Peak Memory):推理过程中显存或内存的最大占用
  • 功耗(Power):尤其在移动和边缘设备上

这些指标怎么测?我一般会用一段类似这样的脚本快速计算参数量和模型体积:

import torch
from torchvision import models

model = models.resnet18(pretrained=True)

total_params = sum(p.numel() for p in model.parameters())
print(f"参数量: {total_params / 1e6:.2f}M")

torch.save(model.state_dict(), "resnet18.pth")
import os
size_mb = os.path.getsize("resnet18.pth") / (1024 * 1024)
print(f"模型体积: {size_mb:.2f} MB")

输出结果:参数量大约11.7M,模型体积约44.7MB(float32)。如果你量化到int8,体积会直接降到~11MB左右。

至于延迟,我建议用实际推理框架测,而不是简单用PyTorch的`time`——Python的计时受调度影响很大。最好用`torch.cuda.Event`或者专门的profiling工具。

import torch
import time

dummy_input = torch.randn(1, 3, 224, 224)
model = models.resnet18().eval()

# 预热
with torch.no_grad():
    for _ in range(10):
        _ = model(dummy_input)

# 正式测100次
start = time.time()
with torch.no_grad():
    for _ in range(100):
        _ = model(dummy_input)
end = time.time()
avg_latency = (end - start) / 100 * 1000  # ms
print(f"平均延迟: {avg_latency:.2f} ms")
核心:评估指标必须和部署环境对齐。你在4090上测1ms,换到Jetson Nano可能变50ms。所以我建议在目标硬件上做最后的指标验收。

下面这张图概括了模型优化的全貌:目标、挑战、评估之间怎么关联。

模型优化知识结构图 模型优化 小(体积) 快(速度) 准(精度) 常见挑战 过拟合 资源限制 硬件兼容性 量化误差 评估指标 参数量/存储 延迟/吞吐量 准确率/mAP 峰值内存/功耗

我个人习惯在做优化之前,先拿这张图把项目当前所处的位置标出来:目标优先级是什么?最大的挑战在哪?评估指标怎么量化?这样才不会走偏。

好,模型优化的大框架就说到这里。后面的章节我们会逐个深入剪枝、量化、蒸馏、算子融合……到时候再一个个拆解。记住,优化不是一锤子买卖,而是持续迭代的过程。