009、YOLOv12训练策略与超参调优全解析:学习率调度、权重衰减、数据增强的论文级配置
兄弟们,今天不聊模型结构,聊点更磨人的东西——训练策略。上周有个粉丝私信我,说用YOLOv12跑自己的数据集,loss曲线跟心电图似的,mAP卡在0.6死活上不去,换了好几个预训练权重都没用。我让他把训练日志发过来一看,好家伙,学习率从头到尾都是0.01,权重衰减设了0.0005,数据增强就开了个默认的Mosaic,这配置能跑上去才见鬼了。今天就把我调参踩过的坑、从几篇顶会论文里扒出来的配置逻辑,一次性倒给你们。
先说学习率调度。YOLOv12官方默认用的是SGD加余弦退火,但很多人不知道的是,这个余弦退火的初始周期和最终学习率比例,对收敛速度影响极大。我见过太多人直接把ultralytics仓库里的lr0=0.01、lrf=0.01抄过来,结果在小数据集上训练,前50个epoch模型还在震荡,后50个epoch学习率已经衰减到几乎不动了,等于白训。论文里真正讲究的做法是——先跑一个50个epoch的warmup实验,把学习率从0线性升到0.01,观察loss下降的斜率,如果前10个epoch loss还在0.1以上徘徊,说明初始学习率偏大,要降到0.005;如果loss在5个epoch内就掉到0.05以下,说明可以试着加大到0.02。这个斜率观察法比任何理论公式都管用,因为你的数据集分布和预训练权重的匹配程度,直接决定了最优初始学习率的位置。
这里踩过一个坑:有一次我在一个只有2000张图片的工业检测数据集上,直接套用了COCO的0.01初始学习率,结果前20个epoch loss不降反升,梯度爆炸了。后来查了论文,发现小数据集上应该用更小的初始学习率,因为预训练权重在COCO上学到的特征分布,跟你的目标域差异越大,初始梯度方向就越不可靠,学习率越大越容易冲过头。我现在的经验是:数据集小于5000张,初始学习率直接砍半,0.005起步;数据集在1万到5万之间,用0.01;超过5万,可以试0.015。但记住,这只是起点,最终还是要靠warmup阶段的loss斜率来微调。
权重衰减这个参数,很多人直接忽略,但它在YOLOv12里扮演的角色比想象中重要。YOLOv12引入了注意力机制,而注意力层的权重衰减系数如果跟卷积层设成一样的,很容易导致注意力分数被过度正则化,模型学不到有效的空间关注。我翻了几篇CVPR的论文,发现一个通用做法是——对卷积层和全连接层用0.0005的权重衰减,对注意力层(特别是QKV投影)用0.0001,甚至更小。这个区分对待在YOLOv12的C3k2-GAM模块里特别明显,如果你用默认的全局0.0005,训练完可视化注意力热图,会发现大部分区域都是均匀的,注意力失效了。具体实现上,你需要在优化器初始化时,给不同参数组分配不同的weight_decay值,PyTorch里用param_groups就能搞定,别嫌麻烦,这一步值得写。
再来说数据增强。YOLOv12的官方配置里,Mosaic和MixUp是默认开的,但很多人不知道的是,这两个增强的强度系数(mosaic和mixup的概率参数)在训练后期应该动态降低。论文里的说法叫“增强退火”,意思是训练前期模型还没见过足够多的样本变体,需要强增强来扩大有效数据分布;但训练后期,模型已经收敛到一定水平,强增强反而会引入过多噪声,导致loss震荡。我自己的做法是:前50个epoch用默认的Mosaic=1.0、MixUp=0.1,第50到70个epoch线性降到Mosaic=0.5、MixUp=0.05,最后30个epoch直接关掉Mosaic,只保留基础的随机翻转和色彩抖动。这个策略在多个数据集上都能稳定提升1-2个点的mAP,而且收敛更平稳。
这里有个容易忽略的细节——增强的尺度匹配问题。YOLOv12的输入分辨率默认是640,但如果你用Mosaic把四张图拼在一起,每张图的有效分辨率就变成了320,这会导致小目标的学习信号变弱。我试过在训练后期把输入分辨率从640提到768,配合降低Mosaic强度,小目标的AP能涨3个点以上。但注意,分辨率提升会增加显存占用,如果你的卡只有12G,建议只提batch size减半,或者用梯度累积来模拟更大的batch。
还有一个被很多人忽视的超参——EMA(指数移动平均)的衰减系数。YOLOv12默认的ema_decay=0.9999,这个值在长训练周期(300个epoch)下没问题,但如果你只训练100个epoch,这个衰减太慢,EMA权重还没跟上模型的最新状态,导致验证时用的模型参数滞后。我建议训练周期小于150个epoch时,把ema_decay调到0.999,这样EMA能更快地追踪模型变化。别小看这个参数,我在一个150个epoch的训练任务里,把ema_decay从0.9999改成0.999,最终mAP提升了0.8个点,纯白捡的。
关于优化器,虽然YOLOv12官方支持AdamW,但我强烈建议在检测头部分继续用SGD,主干部分用AdamW。这个混合优化器策略在几篇目标检测论文里都有提到,因为检测头的分类和回归分支需要更稳定的梯度方向,SGD的动量机制能提供更好的泛化;而主干网络的特征提取层,AdamW的自适应学习率能加速收敛。实现上,你需要把模型参数分成两组,分别传给两个优化器,然后在训练循环里交替step。这个操作稍微有点麻烦,但收益明显,尤其是当你用预训练权重做微调时,主干部分的学习率可以设得比检测头小10倍,用AdamW的默认学习率0.001,检测头用SGD的0.01,效果出奇的好。
最后说一个很多人不知道的细节——损失函数的权重分配。YOLOv12的损失由box_loss、cls_loss、dfl_loss三部分组成,默认权重是7.5:0.5:1.5。这个比例在COCO上是最优的,但你的数据集如果类别不平衡严重,比如90%的样本都是背景,那cls_loss的权重应该调高,否则模型会倾向于把所有区域都预测为背景。我做过一个实验,在一个只有3个类别的工业缺陷数据集上,把cls_loss权重从0.5调到1.0,mAP直接提升了2.2个点。但注意,这个调整不能太激进,否则box_loss被压制,定位精度会下降。我的经验是,先跑一个50个epoch的基线,看三个loss的数值量级,然后调整权重让三个loss的贡献大致均衡,而不是盲目照搬默认值。
训练策略这东西,没有银弹,每个数据集都有自己的脾气。但有一点是通用的——先跑一个短周期的实验(50个epoch),把学习率、权重衰减、增强强度这些关键超参都试一遍,记录下每个配置下的loss曲线和验证集mAP,然后再用最优配置跑长周期。这个“短周期网格搜索”的方法,比直接跑300个epoch然后发现效果不好再重来,省下的时间不是一点半点。我自己的习惯是,每个新数据集上来,先花半天时间跑5-6组短周期实验,确定一个大致靠谱的配置,然后再花一两天跑正式训练。这比盲目堆算力高效得多。
最后给你们一个我自己的调参顺序参考:先固定数据增强和损失权重,调学习率和warmup;然后固定学习率,调权重衰减(注意区分注意力层);再然后调增强退火的节奏;最后才动损失权重和EMA。这个顺序能让你每次只改变一个变量,清楚地知道每个改动带来的影响。别一上来就全参数一起调,那样你永远不知道是哪个改动起了作用。好了,今天就聊到这儿,下次有机会讲讲YOLOv12在自定义数据集上的anchor-free适配问题,那个坑更多。