深度学习实战第四篇:model.train() 两行代码背后藏着多少坑?

发布时间:2026/9/1 5:50:46
深度学习实战第四篇:model.train() 两行代码背后藏着多少坑? 超参数调优、早停策略、学习率调度AOI 项目的训练全记录开头训练出来的模型不准不知道调什么参数你有没有过这种经历照着教程写了两行训练代码跑了几个 epoch发现精度只有 70%。你调了半天超参数精度还是上不去。然后你发现ampFalse没加训练出了 NaNcos_lrTrue没开学习率下降太快batch256太大显存不够。model.train() 两行代码背后藏着十几个坑。AOI 项目的训练策略花了两个月才调通。中间踩了无数坑AMP 导致 NaN、EarlyStopping 停在 epoch1、从错误的 run 续训……不是因为训练有多难——而是因为没人告诉你每个参数的「正确姿势」。一、训练的核心 APIfromultralyticsimportYOLO modelYOLO(yolov12n-cls.pt)resultsmodel.train(datadataset/,epochs30,batch256,imgsz224,)两行代码训练完成。但这两行代码背后有十几个参数需要调。二、关键超参数详解参数一览表参数默认值推荐值说明epochs10030-1000训练轮数batch1632-256批大小显存决定上限imgsz640224-640输入尺寸lr00.010.001-0.01初始学习率cos_lrFalseTrue余弦学习率调度ampTrueFalse自动混合精度patience5050-100早停耐心值workers84-8数据加载线程数AOI 项目的训练策略# 极性分类model.train(datadataset/,epochs30,batch256,imgsz224,ampFalse,# 关闭 AMPcos_lrTrue,# 开启余弦学习率flipud0.0,# 禁用增强fliplr0.0,degrees0.0,scale0.0,shear0.0,perspective0.0,bgr0.0,erasing0.0,)# 芯片检测model.train(datadata.yaml,epochs1000,batch128,imgsz320,ampFalse,cos_lrTrue,)# 灯组检测model.train(datadata.yaml,epochs100,batch32,imgsz640,ampFalse,cos_lrTrue,)三、EarlyStopping 的陷阱现象Epoch 1/30: val/loss0.01, bestTrue ← 停在 epoch1 Epoch 2/30: val/loss0.02, bestFalse Epoch 3/30: val/loss0.03, bestFalse ...best 停在了 epoch1后面所有 epoch 都没有超过它。原因验证集太小比如只有 10 张图模型一次就学完了。第一次验证时 loss 就很低后面不可能更低。解法# ❌ 错误用 best.pt 做验收best_modelYOLO(runs/classify/train/weights/best.pt)# epoch1 的权重# ✅ 正确用 last.pt 做验收last_modelYOLO(runs/classify/train/weights/last.pt)# 最后一个 epoch 的权重AOI 项目的经验现场 val 以 a_chip 为主模型一次就学完了。验收用 last不用 best。四、AMP 的坑什么是 AMPAMPAutomatic Mixed Precision 自动混合精度训练。用 FP16 加速训练节省显存。为什么会出 NaN# ❌ 错误默认开启 AMPmodel.train(ampTrue)# 训练到一半出现 NaN# ✅ 正确工业场景关闭 AMPmodel.train(ampFalse)# 用 FP32 训练稳定原因FP16 精度不够某些计算会溢出变成 NaN。工业场景追求稳定建议关闭。五、学习率调度cos_lr 的作用# ❌ 不用余弦学习率model.train(cos_lrFalse)# 学习率线性下降可能下降太快# ✅ 用余弦学习率model.train(cos_lrTrue)# 学习率按余弦曲线下降更平滑学习率曲线对比不用 cos_lr lr |████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░| 0 epoch 用 cos_lr lr |████████████████████████░░░░░░░░░░░░░░░░░░| 0 epoch 余弦曲线前期下降慢后期下降快六、避坑指南坑1AMP 导致 NaN# ❌ 错误model.train(ampTrue)# ✅ 正确model.train(ampFalse)坑2从错误的 run 续训# ❌ 错误从 V2 的 run 续训 V4modelYOLO(runs/train/v2/weights/best.pt)# 数据集版本不匹配# ✅ 正确从同版本的 run 续训modelYOLO(runs/train/v3/weights/last.pt)# V3 last → V4坑3覆盖已有 run 目录# ❌ 错误run 目录已存在会覆盖model.train(nameexisting_run)# 覆盖了之前的训练结果# ✅ 正确拒绝覆盖新建目录ifPath(runs/train/new_run).exists():raiseSystemError(run 目录已存在拒绝覆盖)model.train(namenew_run)坑4batch 太大导致显存不够# ❌ 错误batch512 显存爆炸model.train(batch512)# ✅ 从小 batch 开始逐步增大model.train(batch32)# 先测试model.train(batch64)# 显存够用再增大model.train(batch128)# 继续增大坑5不看训练日志现象训练完了不知道效果怎么样。解法训练完成后查看results.csv关注val/loss和val/mAP50。AOI 项目优秀实践训练脚本参数化所有超参数都可以通过命令行传入run 目录防覆盖拒绝覆盖已有 run保护训练结果版本化权重管理每个 run 有独立目录可追溯AOI 项目可改进之处缺少超参数搜索工具没有 Grid Search 或 Bayesian Optimization缺少训练曲线可视化没有 TensorBoard 或 wandb 集成缺少训练资源监控没有 GPU 显存/利用率监控结尾说回那个「训练出来的模型不准」的故事。后来我发现与其调模型不如调超参数。ampFalse加上NaN 消失了cos_lrTrue加上精度提升了 2%batch256调成batch128显存够用了。不是因为训练有多难——而是因为每个参数都有「正确姿势」。翻翻你的项目你的训练脚本有ampFalse吗你用的是best.pt还是last.pt你的学习率调度是线性的还是余弦的评论区说说你在训练上踩过最深的坑。觉得有用收藏这篇下次训练时翻出来对照。转发给你团队里那个天天被训练折磨的同事。下期预告训练出 .pt 不算完导出 ONNX 才是真正的交付。opset / IR / FP16 / dynamic batch导出参数一个都不能错。下一篇我们聊模型导出——ONNX 是产线部署的「通行证」。本文是《深度学习基础知识与实战技术栈》系列第四篇。