
1. 模型优化器到底在解决什么问题第一次接触 Model-Optimizer 这个概念是在一个推荐系统的排序模型上。当时线上推理延迟卡在 180ms 下不去GPU 利用率却只有 35% 左右典型的“算力没吃满、延迟还超标”的尴尬局面。后来把模型优化器这一层单独拎出来做才意识到很多性能问题根本不是模型结构本身的问题而是优化策略没选对、没调好。Model-Optimizer 这个词字面看是“模型优化器”但它其实包含两层含义。一层是训练侧的优化算法比如 SGD、Adam、AdamW、Lion、LAMB 这些负责根据梯度更新参数另一层是推理侧的模型优化工具链比如量化、剪枝、蒸馏、算子融合、图优化等。这两层经常被混在一起谈但实际工作中它们的关注点完全不同。训练侧关心的是收敛速度、泛化能力、显存占用推理侧关心的是延迟、吞吐、精度损失、硬件适配。这篇文章主要面向三类人一是刚入行做模型训练或部署的工程师想搞清楚优化器选型和调参的门道二是已经能跑通流程、但模型性能上不去的开发者需要系统性地排查优化环节三是对模型压缩和加速感兴趣、想了解工程落地细节的技术人员。我会把训练侧和推理侧的优化都覆盖到重点放在“为什么这么选”和“实际怎么调”上而不是罗列 API 文档。需要提前说明的是模型优化器不是一个“调一个参数就起飞”的东西。它更像是一套组合拳需要根据模型规模、数据分布、硬件条件、业务指标来综合权衡。我踩过的坑包括盲目用 Adam 导致显存爆掉、量化后精度掉点严重、剪枝剪完模型反而更慢等等。这些经验后面会穿插在各章节里讲。2. 训练侧优化器的选型逻辑与调参实战2.1 SGD、Adam、AdamW 到底怎么选很多人一上来就用 Adam觉得自适应学习率省事。但实际项目中优化器选型要看三个维度模型规模、数据稀疏性、训练稳定性要求。SGD 加动量是最经典的组合。它的优势是泛化能力通常更好尤其在大规模图像分类任务上SGD 训出来的模型在测试集上的表现往往比 Adam 略好。原因是 SGD 的噪声更大有助于跳出尖锐的局部极小值找到更平坦的解。但 SGD 对学习率非常敏感需要配合学习率预热和余弦退火调参成本高。Adam 的优势是收敛快、对学习率不敏感适合 Transformer 类模型和稀疏梯度场景。但 Adam 有两个已知问题一是权重衰减的实现方式和 L2 正则不等价二是早期梯度方差大时更新步长不稳定。AdamW 把权重衰减从梯度更新中解耦出来是目前训练大模型的主流选择。我一般按这个逻辑选场景推荐优化器理由小模型 图像分类SGD Momentum泛化好调参空间大大模型 文本生成AdamW收敛稳显存可控稀疏特征 推荐Adam 或 LAMB自适应学习率适配稀疏梯度微调预训练模型AdamW 小学习率避免破坏预训练权重2.2 学习率调度不是越复杂越好学习率调度器LR Scheduler的选择经常被忽视。我见过有人用 Adam 配固定学习率训到 loss 震荡然后怪模型结构有问题。实际上warmup cosine decay 这套组合在大多数场景下都够用。warmup 的作用是让模型在训练初期不要被大梯度带偏尤其是 Transformer 类模型前几百步的梯度方差很大。warmup 步数一般设为总步数的 5% 到 10%。cosine decay 则是让学习率平滑下降到接近零帮助模型在后期精细收敛。有一个细节warmup 的起始学习率不要设成零一般设为峰值学习率的 1/100 到 1/10。设成零会导致前几步没有有效更新浪费计算。另外如果你用的是 AdamW权重衰减系数一般设 0.01 到 0.1。设太大模型欠拟合设太小正则效果不明显。我通常从 0.05 开始试根据验证集表现调整。2.3 梯度裁剪和累积的实操细节梯度裁剪Gradient Clipping是训练稳定性的保险丝。按范数裁剪比按值裁剪更常用阈值一般设 1.0 到 5.0。设太小会限制模型学习能力设太大等于没裁。我一般先跑几百步打印梯度范数的分布取 95 分位数作为裁剪阈值。梯度累积Gradient Accumulation是在显存不够时模拟大 batch 的手段。比如你想用 batch size 256但显存只够 64就累积 4 步再更新一次。这里有个坑BatchNorm 层在累积模式下统计量会不准因为每个 micro-batch 的分布可能不同。解决办法是用 SyncBatchNorm 或者改用 LayerNorm。还有一个容易被忽略的点梯度累积时loss 要除以累积步数否则等效学习率会变大。很多人忘了这一步导致训练不稳定。提示梯度裁剪和梯度累积可以同时用但要注意裁剪是在累积之后还是之前。一般建议在累积之后、更新之前裁剪这样裁剪的是等效大 batch 的梯度。3. 推理侧模型优化的核心技术拆解3.1 量化从 FP32 到 INT8 的精度与速度权衡量化是推理优化里性价比最高的手段。FP32 转 INT8 理论上能带来 4 倍的内存压缩和 2 到 4 倍的速度提升但精度损失是必须面对的问题。量化分两种训练后量化PTQ和量化感知训练QAT。PTQ 不需要重新训练直接对权重和激活值做校准适合快速验证。QAT 在训练时模拟量化误差精度更好但需要额外训练成本。PTQ 的核心是校准Calibration。校准集要从真实数据里采样一般 100 到 500 个样本就够。校准的目的是确定激活值的动态范围也就是 min 和 max。如果校准集分布和线上数据差异大量化后的精度会明显下降。我做过一个对比实验同一个 BERT 模型量化方式精度F1延迟ms模型大小MBFP320.91245440PTQ INT80.89818110QAT INT80.90818110可以看到 PTQ 掉了 1.4 个点QAT 只掉 0.4 个点。如果业务对精度敏感QAT 更合适如果只是快速验证PTQ 够用。量化还有一个坑不是所有层都适合量化。比如 LayerNorm 的输入输出范围很窄量化后误差会被放大。实践中通常保留这些层为 FP16只量化矩阵乘法和卷积。3.2 剪枝结构化与非结构化的选择剪枝的思路是去掉模型中不重要的权重或结构。非结构化剪枝把单个权重置零压缩率高但需要稀疏计算库支持实际加速效果有限。结构化剪枝直接去掉整个通道或注意力头硬件友好加速明显。剪枝的关键是重要性评估。常用方法有基于权重大小、基于梯度、基于激活值。我一般用权重 L2 范数做初筛再用验证集微调。剪枝比例不要一次剪太多建议迭代式剪枝每次剪 10% 到 20%微调后再剪下一轮。有一个经验剪枝后模型变小了但推理速度不一定提升。因为剪枝后的模型结构可能不规整GPU 的并行效率反而下降。所以剪枝一定要配合硬件实测不能只看参数量。3.3 知识蒸馏让小模型学到大师傅的手感蒸馏是用大模型教师指导小模型学生训练。核心是损失函数的设计学生不仅要拟合真实标签还要拟合教师的软标签logits 分布。温度参数 T 控制软标签的平滑程度。T 越大分布越平滑学生能学到更多类间关系。一般 T 设 2 到 10我常用 4。蒸馏损失和真实损失的权重比一般是 0.7:0.3 到 0.9:0.1看任务而定。蒸馏的坑在于教师模型的选择。教师太强学生学不动教师太弱学生学不到东西。一般教师比学生大 3 到 10 倍比较合适。另外蒸馏训练的学习率要比正常训练小因为软标签的梯度更平滑。4. 完整优化流程与关键环节实现4.1 从基线到优化一个推荐模型的实操记录拿一个真实的推荐排序模型举例。基线是 DLRM 结构FP32 推理延迟 120msQPS 800。目标是延迟降到 50ms 以内QPS 提到 2000。第一步做性能剖析。用 profiling 工具看各层耗时发现 embedding 层和全连接层占了大头。embedding 层是因为稀疏查表全连接层是因为矩阵乘。第二步量化。对全连接层做 INT8 量化embedding 层保持 FP16。校准集从线上日志采样 500 条。量化后延迟降到 75msQPS 到 1300。第三步算子融合。把 LayerNorm 激活函数 残差连接融合成一个算子减少 kernel launch 开销。延迟降到 62ms。第四步剪枝。对全连接层做结构化剪枝剪掉 20% 的通道微调 2 个 epoch。延迟降到 48msQPS 到 2100。精度从 0.876 掉到 0.871可接受。这个流程的关键是顺序先量化再融合再剪枝。如果先剪枝量化时的校准范围会变需要重新校准。先量化再剪枝剪枝后的模型可以直接复用量化参数。4.2 参数计算量化缩放因子的推导量化的核心公式是q round(x / scale zero_point) x_float (q - zero_point) * scale其中 scale 是缩放因子zero_point 是零点偏移。对于对称量化zero_point 0scale max(abs(x)) / 127。对于非对称量化scale (max(x) - min(x)) / 255zero_point round(-min(x) / scale)。实际计算时scale 和 zero_point 是按通道或按张量统计的。按通道量化精度更好但计算稍复杂。我一般对权重用按通道量化对激活值用按张量量化。有一个细节scale 要加一个很小的 epsilon 防止除零。另外round 操作要用 round half to even避免统计偏差。4.3 硬件适配不同后端的优化策略差异同样的模型在不同硬件上优化策略不一样。GPU 上重点是算子融合和量化因为 GPU 的并行度高瓶颈在 kernel launch 和内存带宽。CPU 上重点是指令集优化和线程调度比如用 AVX-512 加速矩阵乘用 OpenMP 做多线程。移动端 NPU 上量化是必须的而且要用硬件支持的量化格式。有些 NPU 只支持 per-tensor 量化不支持 per-channel这时候就要在精度和兼容性之间权衡。我遇到过一个坑在 GPU 上量化后精度正常部署到 NPU 上精度掉了很多。原因是 NPU 的量化实现和 GPU 不同对激活值的动态范围更敏感。解决办法是用 NPU 厂商提供的量化工具重新校准。5. 常见问题与排查技巧实录5.1 训练不收敛的排查清单训练不收敛是最常见的问题。我一般按这个顺序排查检查数据管道。有没有标签错位、数据泄漏、预处理不一致。检查损失函数。有没有用错损失、有没有忽略 mask。检查学习率。是不是太大导致震荡或者太小导致不更新。检查梯度。有没有梯度消失或爆炸打印梯度范数看看。检查初始化。权重初始化是不是合理有没有全零初始化。有一个容易被忽略的点随机种子。如果每次跑结果差异很大可能是种子没固定或者数据 shuffle 有问题。5.2 量化后精度掉点的定位方法量化掉点一般从这几个方向查校准集分布是否和线上一致。不一致就重新采样。哪些层对量化敏感。逐层量化看哪一层掉点最多。量化粒度是否够细。per-tensor 换成 per-channel 试试。是否保留了敏感层。LayerNorm、softmax 这些层建议保留 FP16。我通常做一个敏感度分析表层类型量化后精度变化建议卷积-0.2%可量化全连接-0.5%可量化LayerNorm-3.1%保留 FP16Softmax-2.8%保留 FP16Embedding-0.3%可量化5.3 推理速度不达预期的硬件因素模型优化完了速度还是上不去可能是硬件层面的问题内存带宽瓶颈。模型太大数据搬运时间超过计算时间。算子不支持。某些算子没有硬件加速回退到慢速实现。批处理大小不合适。batch 太小 GPU 利用率低batch 太大延迟高。线程配置不对。CPU 上线程数没设对或者绑核没做好。我一般用 roofline 模型判断是计算瓶颈还是内存瓶颈。如果实际性能远低于理论峰值大概率是内存瓶颈需要减少数据搬运。注意优化是一个迭代过程不要指望一次调完就到位。每次只改一个变量记录结果逐步逼近最优。6. 我在实际项目中的几点体会做模型优化这几年最大的体会是不要为了优化而优化。先搞清楚瓶颈在哪再动手。我见过有人上来就量化结果模型本来就不是计算瓶颈量化完精度掉了速度没变。另一个体会是优化要和业务指标对齐。离线指标好看不代表线上效果好。我做过一个模型离线 F1 提升了 2 个点但线上点击率没变因为离线测试集和线上分布有偏差。所以优化效果一定要用线上 AB 测试验证。最后分享一个小技巧建立优化基线库。把每次优化的配置、参数、结果都记录下来形成自己的知识库。下次遇到类似场景直接查表不用从头试。我现在维护了一个表格记录了不同模型结构、不同硬件、不同优化组合的效果省了很多重复劳动。模型优化没有银弹但有方法论。理解原理、动手实测、记录复盘这三步做到位大部分问题都能解决。