在实战中打磨模型调优的“手感”——一名AI工程师的成长手记
引言:从模型跑不起来到能跑得动

2021年,我在一家做智能客服的初创公司负责模型训练和优化。那会儿刚加入不久,项目上了一个新版本的产品功能——意图识别模块需要支持多轮对话上下文理解。我们团队决定采用基于Transformer的模型结构来构建一个定制化的意图分类器。
当时的训练流程并不复杂:数据预处理、模型搭建、训练、评估、部署。但我发现,即使是最基本的模型也很难稳定地训练出理想的效果,loss震荡剧烈、准确率在低点徘徊、推理结果忽好忽坏……
那段时间,我几乎每天都在反复修改参数、尝试不同的优化策略、检查数据质量。每次打开TensorBoard都像在抽卡:不知道这次会不会有惊喜,也不知道哪里出了问题。
这篇文章想跟你聊聊我的真实经历,尤其是那些踩过坑之后才慢慢摸索出的“手感” —— 关于模型训练调优的一些技巧、经验教训和心得。
问题描述:模型总学不好怎么办?

我们的核心任务是识别用户输入背后的意图(intent classification),比如:
- 用户说“帮我转人工”,对应意图是“转接人工”
- 用户问“我订单的状态呢?”,对应意图是“查订单状态”
我们构建的数据集大约有5万多条标注数据,涵盖30多个类别。初期采用的是经典的BERT base结构进行fine-tune,在验证集上的F1值大概只有0.65左右,明显低于预期。更糟糕的是,同一个实验多次运行的结果差异很大,有时甚至出现第一次训练收敛得很好,第二次却完全跑崩的情况。
最开始我认为是学习率设错了,调整了几个数值后依然没有明显改善。接着怀疑是数据分布不均衡导致某些类样本太少,做了数据增强也没啥起色。再后来怀疑是否模型过拟合,加了dropout、正则项……总之试了很多方法,但效果始终不稳定。
这时候我才意识到:这不仅仅是参数的问题,而是整个训练流程都需要重新审视和优化。
解决方案:逐步打磨出一套系统性训练调优思路
Step 1:先确保模型基础可训练性
我开始从头梳理训练流程。第一个目标不是追求性能极致,而是要确保模型能稳定地训练出来。为此,我做了以下几个关键动作:
✔️ 使用固定随机种子
我们在代码里加入了:
import torch
import numpy as np
import random
def set_seed(seed=42):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
set_seed()
虽然这个小细节很多文章都提过,但实际项目中如果不统一设置seed,每次训练出来的结果波动非常大,让人根本无法判断到底是参数的问题还是随机性的影响。
✔️ 做一次简化版训练测试
我把模型换成简单的BiLSTM + attention的结构,在同样的训练集上快速跑一次。结果发现,这种轻量级模型居然也能达到0.7的F1,比BERT还好。这一下子把我从对“Transformer就是最好”的执念中拉了出来。
这也让我明白,模型结构不是越复杂越好,适合当前任务才是最重要的。
Step 2:数据质量先行,别急着调参
很多人一上来就改learning rate、weight decay,但在我的经验中,如果数据本身有问题,怎么调都是白搭。
✔️ 数据质量检查:长尾类别的陷阱
我们原始数据中,“查余额”这类高频意图占了60%以上,而一些边缘意图如“投诉建议”只有一两百条。这就导致模型很容易偏向预测这些“万金油”类。
我们采取了两种方式:
类别权重加权:在交叉熵损失函数中,给低频类别更高的loss权重。
weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) criterion = nn.CrossEntropyLoss(weight=torch.tensor(weights, dtype=torch.float).to(device))数据增强:针对低频类别做EDA(Easy Data Augmentation)或同义词替换,使每个类的样本数接近均衡。
做了这两步后,模型开始变得“聪明”了:它不再只是猜“查余额”了。
Step 3:学习率调度器+早停机制双管齐下
我们之前用的是固定学习率,或者手动衰减。后来换成了CosineAnnealingWithWarmup,配合早停机制(EarlyStopping)后,训练过程更加稳定了。
from transformers import get_cosine_with_warmup_schedule
scheduler = get_cosine_with_warmup_schedule(optimizer, num_warmup_steps=500, num_training_steps=num_epochs * len(train_dataloader))
结合early stopping的逻辑大概是这样:
best_loss = float('inf')
patience = 3
counter = 0
for epoch in range(num_epochs):
# 训练
...
# 验证
val_loss = evaluate(...)
if val_loss < best_loss:
best_loss = val_loss
counter = 0
torch.save(model.state_dict(), 'best_model.pth')
else:
counter += 1
if counter >= patience:
print("Early stopping triggered.")
break

这套组合拳下来,不仅加快了收敛速度,还避免了过度训练(overfitting)的风险。
Step 4:模型蒸馏(Distillation)与集成学习
为了进一步提升泛化能力,我们采用了知识蒸馏的方式:让一个更复杂的teacher model去指导轻量级student model的学习。
具体来说:
- Teacher使用ensemble of BERT models + CRF head
- Student使用轻量版BERT + linear head
- 在训练过程中,除了原始标签监督,还用KL散度约束Student输出尽可能接近Teacher输出
这部分技术难度稍高,但对于资源受限场景非常有价值。最终我们成功把推理时间缩短了将近一半,同时F1还能保持在0.8左右。
此外,我们还尝试了多模型集成(Ensemble),将不同epoch保存下来的多个checkpoint取平均或投票,提升了模型鲁棒性。
效果总结:从跑不动到稳得住,再到准得出

经过这番折腾,最终效果如下:
| 指标 | 初始阶段 | 优化后 |
|---|---|---|
| F1值 | 0.65 | 0.82 |
| 训练稳定性 | 波动大 | 稳定收敛 |
| 推理时延 | 150ms | 90ms |
| 部署成功率 | 不稳定 | 99.9% |
更重要的是,模型训练的过程变得更加可控:一旦出现问题,我能迅速定位是数据、参数、结构还是其他原因导致的。
经验分享:关于模型训练调优的几点真知灼见
在我这几年参与过的NLP、CV、推荐等多个项目中,逐渐总结出了以下几点调优的经验,希望能帮你在项目中少走弯路:
✅ 1. 不要迷信“调参能解决一切问题”
参数确实重要,但前提是你已经有一个可训练的基础。很多时候,训练不稳是因为:
- 数据分布不均衡
- 标签噪声太多
- 输入特征提取不合理
这些才是“本”,参数是“末”。
✅ 2. 尽可能使用现成的工具链
现在有很多开源工具可以大大提升效率,例如:
- Transformers库自带丰富的预训练模型+微调接口
- Optuna、Ray Tune用于自动超参搜索
- WandB/TensorBoard做可视化追踪
不要自己重复造轮子。工具用得好,事半功倍。
✅ 3. 学习率是灵魂,不能死磕一个值
我曾一度认为只要找到一个合适的学习率就够了。实际上,动态调度器(scheduler)是训练稳定的保障。特别是当数据量大、模型深时,cosine退火比step decay更友好。
✅ 4. 多跑几遍,别怕耗时
有时候为了节省时间,只跑一遍训练就下结论。其实,同一组参数训练三次,结果可能完全不同。特别是在数据量较小的情况下。一定要多试几次看趋势,而不是单次表现。
✅ 5. 适当做一点“暴力搜索”,胜过盲目猜测
如果你实在不知道从哪下手,不妨设定几个关键参数范围,做个网格搜索或贝叶斯优化,反而比瞎猜更高效。我自己常用的方法是:
for lr in 1e-5 3e-5 5e-5; do
for batch_size in 16 32; do
python train.py --lr $lr --batch_size $batch_size --output_dir exp/$lr-$bs
done
done
然后用WandB记录每一轮的表现,挑最优的继续调细粒度。
写在最后:调优不是魔法,是手艺活
在AI领域,模型调优这件事有点像厨艺:配方告诉你盐一勺糖两勺,但真正好吃的菜,靠的是火候和感觉。你得不断尝味道、观察反应、积累经验。
回想起当年那个天天盯着loss曲线抓耳挠腮的我,现在我已经能比较从容地应对各种训练中的波折。当然,AI的世界日新月异,模型越来越复杂、数据越来越大,挑战也越来越多。
但有一点永远不会变:扎实的基本功和细致的观察力,才是真正的“调优之魂”。
希望这篇基于亲身经历的文章能给你带来一些启发。如果你正在经历模型训练的痛苦,请相信我——你不是一个人。我们曾经一起走过那段黑暗时期,也一定能共同走向更好的明天。
📌 欢迎关注我的公众号/知乎/B站:深度智选实验室(ID: DeepSelectionLab),更多实战干货持续更新中~

评论 0