
1. 从“模型优化器”这个热词说起它到底在解决什么问题“Model-Optimizer”这个词最近在技术社区里出现的频率明显变高了。很多人第一次看到它会下意识觉得这又是一个新的训练框架或者调参工具但实际接触之后会发现它解决的问题比“调参”要底层得多也现实得多。我先说一个我自己的真实场景。去年我接手了一个图像分类的项目训练集不大大概两万张图用的是迁移学习骨干网络选了一个中等规模的卷积网络。训练本身没什么难度半天就跑完了精度也还行。但问题出在部署环节模型文件接近一百兆推理一张图在普通CPU上要三百多毫秒业务方要求是单张一百毫秒以内而且内存占用不能超过两百兆。这时候你会发现训练阶段的那套东西——学习率调度、数据增强、损失函数设计——全都帮不上忙了。你需要的是一套专门针对“模型本身”做减法和重排的工具链这就是 Model-Optimizer 这类工具真正要干的事。所以先把这个概念说清楚。Model-Optimizer 不是训练优化器而是模型优化器。训练优化器比如 SGD、Adam优化的是参数更新的过程而模型优化器优化的是模型这个“成品”本身——它的体积、它的计算量、它在特定硬件上的执行效率。两者名字很像但完全在不同的阶段工作。很多人第一次接触会混淆我当初也绕了一圈才理清。它主要解决三类问题。第一类是体积问题模型太大存储、传输、加载都吃力尤其是在移动端或者嵌入式设备上。第二类是速度问题模型能跑但太慢达不到实时性要求。第三类是硬件适配问题模型在服务器上跑得好好的换到特定加速器或者边缘设备上就各种报错或者性能骤降。这三类问题往往同时出现而 Model-Optimizer 的价值就在于用一套相对统一的流程把这些问题一起处理掉。适合看这篇内容的人我大致分一下。如果你是把模型训练完就交给工程团队、自己不太管部署的算法工程师这篇能帮你理解下游到底在抱怨什么以及你在训练阶段可以提前做哪些配合。如果你是负责模型落地的工程同学那这篇基本就是你的日常工具箱说明书。如果你只是刚入门想搞清楚“模型压缩”“量化”“剪枝”这些词到底在说什么那这篇会给你一个从实际场景出发的完整图景而不是一堆名词解释。接下来我会按照一个真实的优化流程来展开先搞清楚优化目标怎么定再拆解核心技术手段然后讲工具链怎么选、怎么用最后重点讲那些文档里不会写、只有踩过才知道的坑。整个内容会围绕 Model-Optimizer 这个核心展开但不会只讲某一个具体工具因为这类工具的思路是相通的理解了思路换哪个工具都能上手。2. 优化之前先想清楚目标定错了后面全白干2.1 三个必须同时回答的问题我见过太多团队一上来就说“把这个模型压缩一下”然后就开始试各种工具结果折腾了两周发现压出来的模型精度掉得没法用或者速度根本没提升。问题出在第一步目标没定清楚。在动手之前有三个问题必须同时回答缺一个都不行。第一个问题优化后的模型跑在什么硬件上这个问题听起来很基础但它直接决定了你后面所有技术手段的选择。同样是量化在服务器CPU上和在移动端NPU上支持的算子、数据布局、量化粒度可能完全不同。我吃过这个亏有一次按照服务器端的经验做了一版 INT8 量化结果部署到目标设备上发现某个关键算子根本不支持 INT8整个模型被拆成好几段中间还要来回做精度转换速度反而更慢了。第二个问题精度容忍度是多少这个问题必须量化。不能说“尽量别掉点”而要说“Top-1 精度下降不能超过 0.5%”或者“召回率不能低于某个阈值”。因为不同的优化手段对精度的影响差异很大有的手段可以做到几乎无损有的手段掉点明显但换来的速度提升也大。没有明确的容忍度你就没法在精度和速度之间做取舍。第三个问题优化的主要瓶颈是什么是模型文件太大装不下是推理延迟太高是内存占用超标还是功耗太高这四个瓶颈对应的优化策略优先级完全不同。体积问题优先考虑量化和剪枝延迟问题优先考虑算子融合和结构重排内存问题可能要动计算图的内存分配策略功耗问题则跟硬件调度和计算密度关系更大。我一般会建议用一个简单的表格把这三个问题的答案写下来贴在项目文档最前面。后面每做一个优化决策都回头看一眼这个表格确保没有跑偏。维度必须明确的内容常见错误目标硬件具体型号、推理框架、支持的算子集只说“移动端”或“服务器”精度底线具体指标、可接受的下降幅度说“尽量无损”核心瓶颈体积/延迟/内存/功耗中的首要项什么都想要没有优先级2.2 基准测试不做这一步后面全是盲猜目标定清楚之后下一步是建立基准。这一步很多人会跳过觉得“我知道现在慢就行了赶紧优化吧”。但如果没有一个准确的基准你根本不知道优化有没有效果也不知道效果有多大。基准测试要测什么至少包括四项模型文件大小、推理延迟单次和批量、内存峰值占用、精度指标。这四项要在目标硬件或者尽可能接近目标硬件的环境上测。如果暂时拿不到目标硬件至少要在同架构的平台上测并且明确记录差异。测延迟的时候有个细节要注意一定要做预热。第一次推理往往包含模型加载、内存分配、算子编译等开销不能算进稳态延迟里。我一般会先跑十次预热然后再测一百次取平均和中位数。中位数比平均值更能反映真实体验因为偶尔的抖动会把平均值拉高。还有一个容易被忽略的点批量大小。很多模型在批量大小为1的时候延迟很高但批量增大后单样本延迟会显著下降。如果你的业务场景是批量推理那基准测试就必须按实际批量来测。反过来如果业务是单张实时推理那批量大小就是1优化策略也要围绕这个来。提示基准测试的结果一定要存档最好连测试脚本一起存。后面每做一次优化都用同一套脚本在同一个环境下复测这样才能做 apples-to-apples 的对比。2.3 优化顺序为什么我建议“先量化后剪枝最后蒸馏”确定了目标和基准之后就要决定先做哪种优化。我的经验顺序是先量化后剪枝最后考虑蒸馏。这个顺序不是随便定的背后有逻辑。量化之所以放第一位是因为它的投入产出比最高。一个训练好的模型做一轮训练后量化PTQ通常能把体积压到原来的四分之一速度提升两到四倍而精度损失在很多任务上可以控制在百分之一以内。而且量化的流程相对标准化工具链成熟不需要重新训练试错成本低。剪枝放第二位是因为它比量化更“伤”模型。剪枝会直接改变模型的结构去掉一些通道或者层虽然也能减小体积和计算量但精度恢复往往需要微调训练流程更长。而且剪枝的效果跟模型结构关系很大有些模型剪完效果很好有些剪完就崩了需要反复试。蒸馏放最后是因为它本质上是一种训练方法需要重新训练一个学生模型成本最高。而且蒸馏的效果高度依赖教师模型的质量和学生模型的结构设计不确定性最大。一般只有在量化和剪枝都达不到目标时才会考虑蒸馏。当然这个顺序不是绝对的。如果你的模型本身已经很小了量化带来的收益有限那可能直接上剪枝更合适。但作为一个默认的决策框架这个顺序能帮你在大多数情况下少走弯路。3. 量化把浮点数变成整数到底发生了什么3.1 量化的本质用整数近似浮点数量化这个词听起来很玄但核心思想一句话就能说清楚用低比特的整数来近似表示高比特的浮点数。比如原来一个权重是 0.7234用 FP32 存储要占 32 位量化之后可能变成整数 185只占 8 位用的时候再乘一个缩放因子还原回大概 0.72 左右。这里的关键是“大概”。量化必然带来精度损失因为整数能表示的数值是离散的而浮点数是连续的。但好消息是神经网络对这点精度损失往往不敏感。为什么因为神经网络本身就有一定的冗余和容错能力权重和激活值里很多信息对最终输出的影响很小稍微变一点没关系。量化的核心参数有两个缩放因子scale和零点zero point。缩放因子决定了整数的步长零点决定了整数 0 对应哪个浮点值。这两个参数的选择直接决定了量化的精度。如果缩放因子选得太大小数值全被压成 0选得太小大数值会溢出。所以量化算法的核心就是怎么根据数据的实际分布选一个合适的缩放因子和零点。3.2 训练后量化PTQ和量化感知训练QAT的取舍量化分两条路训练后量化Post-Training Quantization, PTQ和量化感知训练Quantization-Aware Training, QAT。PTQ 是在模型训练完之后拿一批校准数据跑一遍统计各层的激活值分布然后直接算出量化参数把模型转成量化版本。它的优点是快不需要重新训练几十分钟就能搞定。缺点是精度损失可能比较大尤其是对那些对数值敏感的模型。QAT 是在训练过程中就模拟量化的效果让模型在训练时“感知”到量化带来的精度损失从而调整权重去适应。它的优点是精度保持得好通常能做到几乎无损。缺点是需要重新训练成本高而且训练脚本要改不是所有团队都有这个条件。我的建议是先试 PTQ如果精度达标就用 PTQ不达标再考虑 QAT。因为 PTQ 的成本太低了值得先试。我做过统计在我接触过的模型里大概有六成左右用 PTQ 就能达到精度要求剩下四成里有一部分通过调整校准数据或者量化粒度也能救回来真正需要上 QAT 的不到两成。校准数据的选择是 PTQ 的关键。校准数据不需要标注但必须能代表真实的数据分布。我一般会从训练集或者验证集里随机抽几百到一千个样本作为校准集。样本太少统计不准样本太多浪费时间。五百个左右通常是个不错的平衡点。3.3 逐张量量化和逐通道量化一个容易忽略但影响很大的选择量化粒度是另一个关键决策。逐张量量化per-tensor是整个张量共用一个缩放因子逐通道量化per-channel是每个通道有自己的缩放因子。逐通道量化的精度明显更好因为不同通道的数值分布可能差异很大共用一个缩放因子会顾此失彼。但逐通道量化的计算和存储开销也更大而且有些硬件只支持逐张量量化。我的经验是权重尽量用逐通道量化激活值用逐张量量化。因为权重的分布相对稳定逐通道量化能显著提升精度而激活值在推理时是动态计算的逐通道量化实现复杂收益也没那么大。大多数推理框架的默认设置也是这个组合。量化对象推荐粒度理由权重逐通道分布差异大逐通道精度提升明显激活值逐张量动态计算逐通道实现复杂收益有限偏置通常不量化数量少量化收益小容易引入误差3.4 量化实操中的三个坑第一个坑忽略算子支持情况。不是所有算子都支持量化。有些自定义算子、某些激活函数、某些特殊的归一化层在量化后可能没有对应的实现导致模型被拆成多段中间插入反量化再量化的操作速度反而变慢。所以在量化之前一定要先查目标推理框架的算子支持列表。第二个坑校准数据分布偏移。如果你用训练集做校准但实际推理时的数据分布跟训练集差异很大量化参数就会失准。我遇到过一次校准用的是白天的图片实际推理是夜间图片亮度分布完全不同量化后精度掉得厉害。后来把校准集换成混合了白天和夜间的数据问题就解决了。第三个坑量化后的模型没有做端到端验证。有些人量化完只看了一下模型文件大小和几个层的输出误差觉得没问题就上线了。但量化误差会在层与层之间累积单层误差小不代表整体误差小。一定要拿一批真实数据做端到端的精度对比确认最终指标达标。4. 剪枝去掉冗余但别把有用的也剪了4.1 结构化剪枝和非结构化剪枝的本质区别剪枝的思路很直观神经网络里有很多权重接近零这些权重对输出的贡献很小去掉它们应该影响不大。但剪枝分两种区别很大。非结构化剪枝是把单个权重置零不改变模型结构。这样做的好处是精度损失小因为你可以精细地选择剪哪些权重。但坏处是剪完之后模型还是那么大只是里面多了很多零。除非你的推理框架和硬件专门支持稀疏计算否则速度不会提升内存也不会减少。实际上非结构化剪枝更多是一种压缩存储的手段而不是加速手段。结构化剪枝是直接去掉整个通道、整个卷积核或者整个层。这样做会真正改变模型结构模型文件变小计算量减少速度提升。但精度损失也更大因为你是整块整块地删没有非结构化剪枝那么精细。在实际落地中结构化剪枝是主流因为大多数硬件和推理框架对稀疏计算的支持并不好。非结构化剪枝更多出现在学术研究或者有专门稀疏加速硬件的场景里。4.2 怎么判断哪些通道可以剪结构化剪枝的核心问题是怎么判断哪些通道重要哪些不重要最常用的方法是看通道的权重范数。一个通道的权重范数越小说明这个通道的输出越小对后续层的影响越小越可以剪。这个方法简单有效大多数剪枝工具都支持。但只看权重范数有个问题它忽略了通道之间的相关性。有些通道单独看范数很小但它跟其他通道组合起来可能很重要。所以更精细的方法会考虑通道对最终损失的贡献比如用一阶泰勒展开来估计去掉某个通道后损失会增加多少。这个方法更准但计算量也更大。还有一种方法是基于激活值的统计。如果一个通道在大量输入上的激活值都很小或者很稳定说明它可能冗余。这个方法需要跑一批数据来统计比只看权重多了一步但往往更可靠。我的建议是先用权重范数做一轮粗剪然后用一小批数据做精度验证如果掉点明显再换更精细的方法。不要一上来就追求最优解先跑通流程更重要。4.3 剪枝后的微调为什么不能省剪枝之后模型的精度通常会掉一些。这时候必须做微调让剩下的权重去补偿被剪掉的部分。微调的学习率要设得小一些因为模型已经训练好了只需要微调不需要大改。一般用原来训练学习率的十分之一到百分之一跑几个 epoch 就够了。微调的数据可以用训练集的一个子集不需要全量。我一般用百分之十到百分之二十的训练数据跑五到十个 epoch。这样既能恢复精度又不会花太多时间。有一个细节剪枝和微调要交替进行。不要一次性剪掉很多通道再微调那样精度很难恢复。更好的做法是分多轮每轮剪掉一小部分然后微调恢复再剪下一轮。这样虽然总时间更长但最终能达到更高的剪枝率。注意剪枝率不是越高越好。我见过有人追求极致的剪枝率把模型剪到原来的十分之一结果精度崩了微调也救不回来。一般来说结构化剪枝的剪枝率在百分之三十到百分之五十之间是比较安全的区间超过这个范围就要非常小心。4.4 剪枝实操中的一个反直觉发现我做过一组对比实验发现了一个反直觉的现象在某些模型上剪枝之后不做微调精度反而比做了微调更高。一开始我以为是自己搞错了反复验证了几次发现确实如此。后来分析原因可能是因为这些模型的训练集和验证集分布有差异微调时用的数据反而让模型过拟合到了训练集的某些特性上导致验证集精度下降。而剪枝本身起到了一种正则化效果去掉了一些过拟合的通道反而提升了泛化能力。这个现象不是普遍规律但它提醒我一件事不要默认微调一定有用要用验证集说话。每次剪枝后先测一下不微调的精度再测微调后的精度哪个好用哪个。这个习惯帮我省了不少时间。5. 工具链选型别被工具绑架先想清楚要什么5.1 通用优化工具和专用推理框架的关系Model-Optimizer 这类工具很多时候不是一个独立的软件而是跟推理框架深度绑定的。比如某个推理框架自带量化工具另一个框架自带剪枝工具它们之间不一定兼容。所以在选型之前要先想清楚一件事你的目标推理框架是什么因为优化后的模型最终要在这个框架里跑如果优化工具产出的模型格式跟推理框架不兼容那还得做格式转换转换过程中可能又引入新的问题。我的建议是优先用目标推理框架自带的优化工具。比如你要部署到某个移动端推理框架那就先用它自带的量化工具。这样兼容性最好出了问题也容易排查。只有当自带工具满足不了需求时才考虑用第三方工具然后再做格式转换。5.2 选型时要看的五个指标选优化工具的时候我一般会看五个指标。第一支持的算子覆盖度。你的模型里用到的算子工具是不是都支持量化或者剪枝如果有不支持的能不能自动回退到浮点实现回退之后对性能影响多大第二精度保持能力。这个不能只看文档要自己拿模型试。同一个模型不同工具量化后的精度可能差很多。第三易用性。工具的命令行接口是不是清晰配置文件是不是好写出错的时候报错信息是不是有用这些看起来是小事但实际用起来影响很大。第四社区活跃度。遇到问题能不能搜到答案提 issue 有没有人回版本更新是不是频繁这些决定了你踩坑之后能不能快速爬出来。第五跟现有流程的集成难度。工具能不能嵌入你现有的训练或者部署流水线需不需要改很多代码如果集成成本太高即使工具本身很好也可能不值得用。指标为什么重要怎么验证算子覆盖度决定模型能不能完整优化拿自己的模型跑一遍看有没有回退精度保持决定优化后能不能用用自己的数据和指标实测易用性决定上手速度和排错效率看文档、跑 demo、故意制造错误看报错社区活跃度决定遇到问题能不能解决看 issue 数量和回复速度集成难度决定实际落地成本评估需要改多少代码和流程5.3 一个被低估的环节模型格式转换优化工具和推理框架之间往往需要做模型格式转换。这个环节看起来简单实际上很容易出问题。最常见的问题是算子映射不一致。优化工具里的某个算子在推理框架里可能对应两个不同的算子或者参数顺序不一样。转换的时候如果没处理好模型能加载但输出不对而且这种错误往往很隐蔽不跑端到端测试发现不了。我的做法是每次格式转换后都拿同一批输入对比转换前后模型的输出。不需要完全一致但差异要在可接受范围内。如果差异很大就要逐层排查看是哪一层转换出了问题。还有一个细节转换后的模型要重新做基准测试。因为格式转换可能改变计算图的优化策略延迟和内存占用都可能变化。不要假设转换前快转换后就一定快。6. 踩坑实录那些文档里不会写的教训6.1 量化后精度不降反升的诡异现象前面提到过剪枝后不微调反而更好的情况量化也有类似的反直觉现象。我有一次做一个文本分类模型PTQ 量化之后验证集精度居然比浮点模型高了零点三个百分点。一开始我以为是测试脚本写错了反复检查了几遍确认没问题。后来分析原因可能是量化引入的噪声起到了一种正则化效果抑制了模型在训练集上的过拟合。这个现象在学术界也有讨论叫做“量化正则化效应”。它不是普遍规律但确实存在。这件事给我的启发是不要预设量化一定会掉点。每次量化后都实测一下掉点就调不掉点甚至涨点就更好。不要因为“量化会掉点”这个先入为主的观念而错过了意外之喜。6.2 校准集选错导致的全盘皆输这个坑我在前面提过但值得再展开讲因为它太常见了。我有一个做目标检测的项目模型训练得很好浮点版本精度达标。做 PTQ 的时候我随手从训练集里抽了五百张图做校准。量化后测了一下精度掉了将近五个百分点完全没法用。我一开始以为是量化算法的问题换了好几种校准方法效果都不好。后来仔细看数据才发现训练集里的图片大多是晴天拍的而实际部署场景是全天候的包括阴天、雨天、傍晚。校准集里没有这些场景的图片量化参数完全是按晴天的数据分布算的到了其他场景自然失准。后来我把校准集换成混合了各种天气和光照条件的图片量化后的精度只掉了不到一个百分点。这个教训让我养成了一个习惯校准集一定要覆盖实际部署中可能遇到的各种数据分布宁可多花点时间准备校准集也不要在这上面偷懒。6.3 剪枝率设太高微调也救不回来剪枝率这个参数很多人会设得比较激进觉得剪得越多越好。我一开始也这么想结果踩了大坑。有一次我做一个语音识别模型想把模型压到原来的三分之一。我直接设了百分之七十的剪枝率剪完之后精度从百分之九十五掉到了百分之六十多。然后我开始微调跑了二十个 epoch精度只恢复到百分之八十左右离达标还差得远。后来我改成多轮剪枝每轮剪百分之十剪完微调恢复再剪下一轮。最终剪到百分之五十的时候精度还能保持在百分之九十三以上。虽然总剪枝率比一次性剪百分之七十低但至少模型能用。这件事让我明白一个道理剪枝是一个渐进的过程不是一锤子买卖。一次性剪太多模型的结构被破坏得太厉害剩下的权重根本没有足够的能力去补偿。分多轮剪每轮给模型一个适应的机会最终能达到的剪枝率反而更高。6.4 忽略推理框架的算子融合策略这个坑比较隐蔽但影响很大。很多推理框架在加载模型后会自动做算子融合把多个小算子合并成一个大算子减少内存访问和 kernel 启动开销。这个融合策略对浮点模型和量化模型可能不一样。我有一次量化完一个模型测延迟发现只比浮点模型快了百分之二十远低于预期。排查了很久最后发现是量化后的某个算子组合没有被框架融合导致多了一次内存读写。后来我调整了量化配置让这个算子组合能被正确融合延迟直接降了一半。这个坑的教训是优化后的模型一定要在目标推理框架里实测延迟不能只看理论计算量。理论计算量减少不代表实际延迟减少因为实际延迟还受内存访问、算子融合、调度策略等因素影响。7. 从优化到落地怎么把优化后的模型真正用起来7.1 优化后的模型需要重新做正确性验证模型优化完之后不能直接上线必须做一轮完整的正确性验证。这个验证跟训练阶段的验证不一样重点不是看精度指标而是看行为一致性。具体来说要拿一批输入分别跑浮点模型和优化后的模型对比它们的输出。对于分类模型看预测类别是否一致对于检测模型看检测框的位置和数量是否一致对于生成模型看生成结果的质量是否可接受。允许有差异但差异要在可接受范围内。如果差异很大就要逐层排查看是哪一层的优化引入了问题。这个排查过程可能很耗时但必须做因为优化后的模型一旦上线出问题回滚成本更高。7.2 监控和回滚机制不能省优化后的模型上线之后要有监控机制。监控什么至少包括推理延迟、内存占用、输出分布的统计特征。如果延迟突然升高或者输出分布跟预期偏差很大就要触发告警。回滚机制也要提前准备好。优化前的浮点模型要保留一旦优化后的模型出问题能快速切回去。我一般会保留至少两个版本当前线上版本和上一个稳定版本。这样即使新版本有问题也能快速恢复。7.3 优化是一个持续的过程不是一次性的任务最后想说一点模型优化不是做完一次就结束了。随着业务数据的变化、模型版本的迭代、硬件平台的升级优化的策略和参数都需要重新调整。我一般会建议把优化流程脚本化每次模型更新后自动跑一遍优化和验证。这样虽然不能保证每次优化都达到最优但至少能保证流程是标准化的不会因为人为疏忽而出错。提示优化脚本里要记录每次运行的配置和结果包括量化参数、剪枝率、精度指标、延迟数据。这些记录在排查问题和做对比时非常有用。8. 我个人在实际操作中的几点体会做了这么多轮模型优化有几个体会是反复被验证的。第一优化目标比优化手段重要。我见过太多人花大量时间研究各种量化算法和剪枝策略但连自己的模型到底卡在哪里都没搞清楚。先花半天时间把基准测准把目标定清楚后面能省好几天。第二不要追求一步到位。量化先试 PTQ不行再 QAT剪枝先剪百分之十不行再剪百分之二十。每一步都验证每一步都可回退。这样即使某一步效果不好也不会全盘皆输。第三实测数据永远比文档可靠。文档说某个工具支持某个算子实际用的时候可能发现支持得不好文档说量化后精度损失小于百分之一实际可能掉三个点。所有关键指标都要自己测不要信文档。第四保留完整的实验记录。每次优化的配置、结果、遇到的问题、怎么解决的都记下来。这些记录在下次做类似优化的时候能帮你快速定位问题也能帮团队里的其他人少走弯路。第五优化不是越激进越好。模型能压到多小、能跑多快跟硬件、框架、数据分布都有关系。找到一个满足业务需求的平衡点就够了不需要追求极致的压缩率。过度优化往往意味着精度风险和维护成本。最后再分享一个小技巧如果你不确定某个优化手段有没有效果可以先在一个小模型或者一个子模块上试。比如只量化模型的前几层或者只剪枝某一个卷积块看看效果和问题。这样试错成本低而且能快速积累经验。等摸清楚规律了再应用到整个模型上。