做目标检测这几年,我跑过的 YOLO 训练任务没有一千也有几百次了,从最早的 v3 到现在的 v8、v11、v12 系列,真正卡住人的地方从来不是把命令敲对。命令在官方文档里抄一遍就能跑,难的是模型训练完之后那一堆曲线和数字摆在你面前:box_loss 收敛了但 mAP 不涨,val 的 cls_loss 一路往上飘,mAP@0.5 到 0.92 了但 mAP@0.5:0.95 只有 0.6,这些问题文档里不会写。这篇东西就是把我自己看训练结果那套流程摊开讲一遍——哪些指标该看、曲线的形状对应什么毛病、怎么从 results.csv 里把结论挖出来、以及哪些结论其实是数据的问题而不是模型的问题。不管你是刚跑通第一个 YOLO 目标检测 demo 的新手,还是已经在调小目标检测和实例分割的老手,这套分析思路都能直接套用。
1. 训练结果分析到底在看什么:先把指标体系理清楚
很多人第一次训练完,只看屏幕上最后打印的那行 mAP,觉得数字高就万事大吉。这个习惯得改。YOLO 系列在一次模型训练结束后,实际会产出至少三大类信息:损失曲线、验证指标曲线、以及一批可视化的验证结果图。这三类信息是互相印证的,单看任何一个都会被误导。
1.1 损失、指标、学习率三组数据的各自职责
损失曲线负责回答"模型有没有在学"。它看的是训练集和验证集上的误差下降趋势,是最早能反映问题的信号。指标曲线负责回答"学得好不好",也就是精度、召回率、mAP 这些业务上真正关心的东西。学习率曲线负责回答"这一轮训练的安排合不合理",因为 YOLO 默认用了带 warmup 的余弦退火或者线性衰减,学习率的变化节奏直接决定了模型能不能在训练后期稳定收敛到最优点。
我的习惯是先扫一眼学习率曲线确认调度正常,再横向对比 train 和 val 两条损失,最后才去看指标。顺序反过来很容易出现"mAP 掉了就急着改结构"的情况,其实八成是学习率尾巴太长或者数据增强关得太晚。这里有个容易被忽略的点:YOLO 的验证是在每个 epoch 结束时在验证集上跑的,验证集本身的分布、大小、标注质量,直接决定了指标曲线的平滑程度。验证集只有两三百张图的时候,mAP 上下抖动 3 到 5 个百分点非常正常,别拿这种抖动当训练事故处理。
1.2 mAP@0.5 和 mAP@0.5:0.95 的分工要搞清楚
这两个数字经常被混着用,但它们的用途完全不同。mAP@0.5 用的是 IoU 阈值 0.5,只要预测框和真实框重叠一半以上就算命中,所以它反映的是"框有没有大致框对地方",数值通常比较好看,适合用来判断模型是不是学到了目标的位置。mAP@0.5:0.95 是把 IoU 从 0.5 到 0.95 每隔 0.05 取一个阈值,算十个阈值的平均值,它对框的贴合精度极其敏感,是衡量定位质量的核心指标。
实际分析的时候,我会把这两个值放在一起看。如果 mAP@0.5 已经很高,比如 0.93,但 mAP@0.5:0.95 只有 0.58,说明模型的定位精度不够,框是找到了但边缘不稳,这种情况下改分类头或者加更多训练数据基本没用,真正该动的是回归分支和标注质量。反过来,如果两个值都低,那就是模型压根没学到东西,问题在数据或者训练配置上。这个判断方法我用下来准确率很高,能省掉大量无效调参。
1.3 训练日志字段速查,不同版本别搞混
YOLO 不同大版本的日志字段差异不小,v5 系列是 obj_loss,v8 之后的系列换成了 dfl_loss,很多人从 v5 的教程迁移到 v8 会一脸懵。下面这张表是我整理出来的常见字段对照,看日志的时候可以直接对号入座。
| 字段名 | 出现版本 | 含义 | 异常时的典型表现 |
|---|---|---|---|
| train/box_loss | 全系列 | 边框回归损失 | 长期不降说明标签框有问题 |
| train/cls_loss | 全系列 | 分类损失 | 类别不平衡时居高不下 |
| train/obj_loss | v3-v5 | 目标置信度损失 | 与正负样本分配策略强相关 |
| train/dfl_loss | v8 及以后 | 分布式边框回归损失 | 数值偏高常见于小目标场景 |
| metrics/precision | 全系列 | 精确率 | 与置信度阈值强相关,需同步看 |
| metrics/recall | 全系列 | 召回率 | 漏检多则偏低 |
| metrics/mAP_0.5 | 全系列 | IoU 0.5 下的平均精度 | 反映定位大致命中率 |
| metrics/mAP_0.5:0.95 | 全系列 | 多阈值平均精度 | 反映定位精细程度 |
| lr/pg0 | 全系列 | 各参数组学习率 | 检查 warmup 和衰减是否生效 |
有一点值得强调:precision 和 recall 都是跟置信度阈值绑定的,默认报告里用的是让 F1 最大的那个阈值。所以看到 precision 掉了一点不要太慌,先去看 F1 曲线和 PR 曲线,可能只是阈值往召回率方向偏移了。这个细节我在带新人的时候反复讲,因为它是导致"指标看起来退化了但其实模型更强了"这类误判的头号原因。
2. 读懂 YOLO 损失函数曲线:三个分支各管什么
训练结果分析里含金量最高、也最容易看错的就是损失曲线。YOLO 的损失不是一个数字,而是几个分支加权求和的结果,每个分支的异常形态对应的问题完全不一样。搞清这一点,你就能从曲线上直接定位到病因,而不是盲目地调学习率。
2.1 box、cls、dfl 三个分支的职责划分
从 v8 系列开始,YOLO 的训练损失主要拆成三块:box_loss 管边框回归,负责把预测框拉向真实框;cls_loss 管分类,负责把目标的类别分对;dfl_loss 是分布式焦点损失,它把边框的四个坐标值离散成一组概率分布再做回归,相比直接回归一个连续数值,对边界模糊的目标更稳。
这三个分支的数据来源是同一个 head 的输出,但优化难度差别很大。box_loss 的下降往往最平滑,因为位置回归的梯度信号比较连续;cls_loss 在类别数多、类别样本量差异大的数据集上会抖得厉害,尤其当你有几个类别只有几十个样本的时候,它的曲线会呈现明显的台阶状;dfl_loss 对目标尺度分布特别敏感,如果你的数据集里同时有几十像素的小目标和上千像素的大目标,这条曲线通常不会太平滑。
理解了分工,看曲线的思路就清晰了:box_loss 正常但 cls_loss 爆炸,去查类别分布和标注的类别 id;三条都好但指标不涨,去查验证集和训练集的分布是否一致。
2.2 常见曲线形态对应的问题速查
我把过去踩过的坑整理成了一张对照表,看曲线的时候可以直接比对。这张表里的判断不是绝对的,但命中率相当高。
| 曲线形态 | 大概率原因 | 优先处理动作 |
|---|---|---|
| train 和 val 损失同步缓降,指标稳步涨 | 正常训练 | 继续跑,看 patience 是否触发早停 |
| train 持续降,val 从某点开始上升 | 过拟合 | 加强增强、加数据、提前停 |
| 三条损失都很高且几乎不降 | 数据或标签问题 | 用可视化工具检查标签 |
| box_loss 波动明显呈锯齿状 | 学习率偏大或 batch 太小 | 降 lr0、加 batch、开梯度累积 |
| cls_loss 长期在 1.0 以上 | 类别严重不平衡或标注错类 | 重采样、改损失权重 |
| dfl_loss 数值很大(>2.0) | 小目标多、定位难度高 | 提高输入分辨率 |
| 损失变成 NaN | 学习率过大或脏数据 | 降 lr、开 AMP 调试、查异常框 |
| 最后几十轮 mAP 突然掉 | 增强关闭后模型不适应 | 调整 close_mosaic 时机 |
"最后几十轮 mAP 突然掉"这一条我想多讲两句,因为太多人在这里翻车。YOLO 默认在训练末段关闭 mosaic 增强,让模型在接近真实分布的数据上做最后的收敛。这个设计本身是对的,但如果你的数据集本身很小、模型已经过拟合,关闭增强相当于抽掉了最后一道正则化屏障,指标就会掉头往下。解决办法是把关闭的轮数调小,或者干脆保持增强开到最后。
2.3 用数据量反推训练轮数和迭代步数
分析结果之前,得先确认训练轮数是不是够。很多人拿网上抄来的 epochs=300 直接套在自己的数据集上,结果要么欠拟合要么浪费算力。合理的做法是从迭代步数倒推。
假设你的训练集有 N 张图,batch size 为 B,训练轮数 E,那么模型总共会更新 N/B × E 次参数。经验上,一个中等难度、几万张图的目标检测任务,模型需要至少 5 万到 10 万次参数更新才能收敛。代入公式:如果 N=8000,B=16,那么一轮只有 500 次更新,要跑到 10 万次更新需要 200 轮。如果 N 有 20 万张,B=32,一轮就是 6250 次更新,跑 20 轮就够了。
所以看到别人的配置是 epochs=300 就想抄,先算一下自己的数据量。数据量小的时候,轮数要拉长;数据量大的时候,轮数可以缩短,而且更重要的是保证一个 epoch 里每个类别都能被采样到足够多次。我自己在小数据集(几千张)上常用的配置是 epochs=300、patience=50,让早停机制去兜底。
3. 实操:从训练输出到可视化诊断的完整流程
前面讲的是判读逻辑,这一节讲具体怎么落地。我平时做一次完整的训练结果分析,大概分三步:跑训练拿到产物、解析 results.csv 出图和表、做验证可视化归类错误样本。整个过程不依赖任何特定平台,本地一套脚本就能搞定。
3.1 训练命令和关键参数怎么定
下面这条命令是我在单卡环境下最常用的模板,参数都是按中等规模数据集配的,你拿到之后主要改 data、model、batch 三项。
yolo detect train \ data=datasets/mydata/data.yaml \ model=yolo11s.pt \ imgsz=640 \ epochs=200 \ batch=16 \ workers=8 \ optimizer=SGD \ lr0=0.01 \ lrf=0.01 \ momentum=0.937 \ weight_decay=0.0005 \ warmup_epochs=3.0 \ cos_lr=True \ close_mosaic=20 \ patience=50 \ cache=disk \ amp=True \ device=0 \ project=runs/mydata \ name=exp_yolo11s_640几个参数的选择理由值得说清楚。optimizer 用 SGD 而不是 AdamW,是因为在检测任务上 SGD 的泛化表现通常更稳,尤其在数据量不大时不容易过拟合;lr0=0.01 是 SGD 的常见起点,如果换成 AdamW 就要降到 0.001 左右。lrf 是最终学习率相对初始学习率的比例,设成 0.01 意味着学习率会衰减到 0.0001,配合余弦调度形成一条平滑的下降曲线。warmup_epochs=3.0 是让学习率在前三轮从接近 0 慢慢爬升,防止一开始梯度太猛把预训练权重打乱。cache=disk 是把图片缓存到磁盘,对反复读取的小数据集能明显提速,但如果数据集超过几十 GB 就别开了,容易把 IO 吃满。
注意:如果显存不够导致 batch 只能开到 4 或者 8,此时 lr0 要按比例下调,否则等效学习率偏高会让损失剧烈震荡。经验公式是 lr0 与 batch 大致成正比,batch 减半,lr 也要减半。
另外提一句冻结训练。如果你下载了预训练模型做微调,而自己的数据集类别和预训练类别差别很大,可以先用 freeze=10 冻结主干跑一段,让检测头先适应新类别,再解冻整体训练。这个技巧在样本量少的时候特别有效,能避免主干被少量数据带偏。
3.2 解析 results.csv 画诊断图
训练结束后,产物目录里会有一个 results.csv,记录了每个 epoch 的全部损失和指标。看官方自带的曲线图当然可以,但我更习惯自己画,因为可以按需组合,比如把 train 和 val 的同名损失画在同一张图里对比,官方图不一定这么排。
import pandas as pd import matplotlib.pyplot as plt # 列名在不同版本里可能带空格,先清理 df = pd.read_csv("runs/mydata/exp_yolo11s_640/results.csv") df.columns = [c.strip() for c in df.columns] fig, axes = plt.subplots(2, 2, figsize=(14, 9)) # 图一:训练与验证的 box_loss 对比 axes[0, 0].plot(df["epoch"], df["train/box_loss"], label="train_box") axes[0, 0].plot(df["epoch"], df["val/box_loss"], label="val_box") axes[0, 0].set_title("Box Loss") axes[0, 0].legend() # 图二:两条 mAP 曲线 if "metrics/mAP_0.5" in df.columns: axes[0, 1].plot(df["epoch"], df["metrics/mAP_0.5"], label="mAP@0.5") axes[0, 1].plot(df["epoch"], df["metrics/mAP_0.5:0.95"], label="mAP@0.5:0.95") axes[0, 1].set_title("mAP") axes[0, 1].legend() # 图三:精确率与召回率 axes[1, 0].plot(df["epoch"], df["metrics/precision"], label="precision") axes[1, 0].plot(df["epoch"], df["metrics/recall"], label="recall") axes[1, 0].set_title("Precision & Recall") axes[1, 0].legend() # 图四:学习率调度是否正常 lr_cols = [c for c in df.columns if c.startswith("lr/")] for c in lr_cols[:1]: axes[1, 1].plot(df["epoch"], df[c], label=c) axes[1, 1].set_title("Learning Rate") axes[1, 1].legend() plt.tight_layout() plt.savefig("diag.png", dpi=150) # 顺手打印几个关键结论 best = df.loc[df["metrics/mAP_0.5:0.95"].idxmax()] print("最佳 epoch:", int(best["epoch"])) print("最佳 mAP@0.5:0.95:", round(best["metrics/mAP_0.5:0.95"], 4)) print("最后 20 轮 mAP@0.5 均值:", round(df["metrics/mAP_0.5"].tail(20).mean(), 4)) print("指标波动标准差:", round(df["metrics/mAP_0.5"].tail(50).std(), 4))这个脚本里最后两行输出特别有用。看最后 20 轮的 mAP 均值和尾段标准差,能快速判断训练是不是已经进入平台期。如果尾段 50 轮的标准差小于 0.005,说明模型基本稳定,再跑下去收益很低;如果标准差超过 0.02,说明验证集太小或者数据噪声大,这时候把 mAP 的小幅波动当成趋势来解读是不靠谱的。
3.3 验证结果可视化和错误样本归类
数字看完了,必须回到图上看。YOLO 的验证会输出一批带预测框的图片,我一般会挑三类样本重点看:漏检的、误检的、框歪的。这三类对应的病因完全不同。
漏检通常出现在小目标、密集目标、遮挡目标上。如果小目标漏得多,先量一下目标在 640 分辨率下的实际像素尺寸,小于 16 像素的目标在默认配置下基本很难检出来,处理办法是提高 imgsz 到 1280 或者用切片推理。误检最常见的原因是背景样本和正样本长得像,比如把路面的斑马线当成某种细长目标,这种要回去看标注,通常是标注时把模糊样本标得太随意。框歪的情况则多半指向标注框本身不贴合,或者目标有旋转、透视变形而标注框还是水平矩形。
我有个习惯是每次分析都把错误样本按类别统计一遍,做成一个小表。如果某个类别的漏检率显著高于其他类别,那基本可以断定是这个类别的数据出了问题,而不是模型整体不行。这个统计做起来很简单,验证后用预测结果和标注做匹配,按类别汇总漏检和误检数量就行。做多了你会发现,很多所谓"模型能力不足"的问题,追到底都是某一个类别拖了后腿。
4. 典型问题排查:训练结果异常怎么办
实际训练中遇到的问题千奇百怪,但归纳下来无非那么几类。这一节我按"现象、原因、动作"的结构整理,配合一张速查表,方便你直接照着排查。
4.1 指标异常速查表
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| mAP 一直是 0 | 类别 id 与 names 顺序不一致 | 检查 data.yaml 与标注文件 |
| mAP 一直是 0 | 标注框坐标不是归一化值 | 确认格式为 YOLO txt 归一化 |
| 损失正常但指标极低 | 验证集图片路径配置错误 | 打印验证集加载数量 |
| precision 高 recall 极低 | 置信度阈值偏高 | 看 PR 曲线选合适阈值 |
| 训练几百轮指标不涨 | 学习率过小或主干被冻结 | 检查 lr 曲线和 freeze 参数 |
| 某一类别 AP 明显偏低 | 该类样本量过少 | 统计类别分布,补充数据 |
| 验证损失突然 NaN | 出现了宽高为 0 的标注框 | 脚本扫描异常标签 |
| 显存溢出 | imgsz 或 batch 过大 | 降分辨率或用梯度累积 |
| 训练速度极慢 | 未开缓存、workers 设置不当 | 开 cache、调 workers |
| 多卡训练指标反而下降 | batch 增大导致等效学习率变化 | 按比例调整 lr0 |
这张表里"mAP 一直是 0"的两个原因是最坑新人的。YOLO 的标注格式要求类别 id 从 0 开始连续编号,并且坐标是相对于图片宽高的归一化值(0 到 1 之间)。如果你的标注工具输出的是绝对坐标,或者类别从 1 开始编号,训练过程不会报错,损失甚至看起来在降,但指标永远是 0。我建议在正式训练前先跑一次带可视化标签的检查,把标注框和类别画在图上确认一遍,这一步花十分钟能省掉后面几小时的白跑。
4.2 小目标漏检和密集目标的处理思路
小目标检测是这个领域公认的难点,也是被问得最多的。处理思路从成本和收益看,我一般按这个顺序来。
第一步是提高输入分辨率。把 imgsz 从 640 提到 1280,小目标的像素面积变成原来的四倍,特征提取效果好很多。代价是显存占用大约翻四倍、速度下降一半多,所以要权衡。第二步是调整数据增强,减少会让小目标进一步缩小的增强,比如大幅度的随机缩放和 mosaic 拼接会制造出大量极小目标,反而干扰学习。第三步才考虑结构层面的调整,比如增加高分辨率特征层的权重,或者引入专门的小目标检测头。
密集目标场景有个额外的坑:当目标重叠严重时,非极大值抑制会把邻近的框误删。这时候调大 NMS 的 IoU 阈值能缓解,但同时会引入更多重复框。我的经验是先在验证阶段把置信度和 IoU 阈值画成网格搜索,找到 F1 最高的组合,再去考虑模型层面的事。很多时候最佳的阈值就是 0.5 上下,不需要动模型。
顺带说一个跟硬件相关的实践:如果手头只有 AMD 显卡,跑 YOLO 的路径和常规方案不同,一般走的是特定推理框架的转换流程。这时候要注意训练结果和推理结果的指标会有差异,因为后端的算子实现和精度处理不完全一致。所以我建议凡是换过推理后端的项目,都要在目标后端上重新跑一遍验证集,拿真实指标做基准,别拿训练时的 mAP 当交付指标。
4.3 容易被忽略的环境与硬件坑
环境问题虽然跟模型能力无关,但它会严重污染你的训练结果分析。最常见的是随机种子没固定,两次训练同样的配置指标差好几个点,你还以为是模型不稳定。YOLO 提供 deterministic 参数,开启后能保证卷积算法可复现,代价是速度略降,但在做消融实验对比的时候必须开。
第二个坑是数据加载的 workers 设置。workers 设成 0 的时候数据加载在主进程做,速度慢但不会出错;设得太高(比如 32)在容器环境下容易触发共享内存不足,导致训练中途静默退出或者加载到损坏的图片。我的经验值是 8 到 16 之间,容器里最好把共享内存调大。
第三个坑是混合精度。开启 AMP 能省显存提升速度,但在某些显卡和驱动组合下会出现损失震荡甚至 NaN。如果你看到损失曲线在某几个 epoch 突然尖刺,先关掉 AMP 跑一轮对比,能快速定位是不是精度问题。这个排查动作我用了很多次,几乎每次都能说明问题。
5. 从分析结论到下一轮迭代:把实验管起来
分析结果的目的不是得出一个"这个模型好/不好"的结论,而是决定下一步改什么。这一节讲怎么把一次分析变成一次有效的迭代。很多人的训练记录就是一堆名字混乱的文件夹,跑了几十次之后完全记不清哪个配置对应哪个结果,最后只能凭感觉选模型,这是很浪费的。
5.1 消融实验要一次只动一个变量
这是最老生常谈也最容易违反的原则。我见过太多人一次同时改了输入分辨率、学习率和增强策略,结果指标涨了 3 个点,完全不知道是哪一项起的作用,下次换个数据集就没法迁移经验。
我的做法是每轮实验固定一个基线配置,然后建一张表记录每一次改动和结果。表大概长这样。
| 实验编号 | 相对基线的改动 | mAP@0.5 | mAP@0.5:0.95 | 结论 |
|---|---|---|---|---|
| base | 无,imgsz=640,lr0=0.01 | 0.912 | 0.634 | 基线 |
| exp01 | imgsz 提到 960 | 0.938 | 0.681 | 明显有效,代价是显存 |
| exp02 | lr0 降到 0.005 | 0.907 | 0.629 | 无改善 |
| exp03 | 关掉 mixup | 0.901 | 0.622 | 负向,保留 mixup |
| exp04 | close_mosaic 从 20 改到 10 | 0.919 | 0.642 | 小幅正向 |
有了这张表,你在下一个项目里就有可复用的先验:分辨率提升对小目标任务收益大,mixup 在小数据集上不能随便关。这比任何教程都有价值,因为它是你自己数据分布上跑出来的结论。
5.2 先改数据,再改模型结构
这一点我想强调得重一些。当分析结果显示模型性能不足时,绝大多数人的第一反应是换个更大的模型或者把主干换掉,但经验告诉我,数据侧的优化收益通常远大于结构侧。具体包括:补充那些漏检严重类别的样本、把标注框重新精修一遍、清理掉标错的样本、把模棱两可的样本单独拎出来处理。
我做过一次对比:同一份数据,把标注质量提升(重新精修 2000 张图的框)后,mAP@0.5:0.95 涨了 6 个百分点;而把主干从 s 换成 m 只涨了 2 个点,推理速度还慢了一倍。这个对比结果我记了很久,之后凡是遇到效果瓶颈,我都会先去翻数据和标注,而不是先去翻模型列表。
至于模型选型,如果你的部署环境对参数量和计算量有严格限制(比如需要在边缘设备上跑,模型体积和计算量只有几 MB 和几 GFLOPs 的预算),那就必须在轻量级模型里选,这时候数据质量和输入分辨率的优化就是唯一的提升空间了。这种场景下不要幻想通过换结构获得大突破,把数据做扎实比什么都强。
5.3 版本选择和部署前的一致性核对
YOLO 的版本迭代很快,各种命名让人眼花缭乱,网上也流传着不少版本号的说法。我的建议是以你要使用的那个官方代码库为准,不要被传闻中的版本号带偏。选版本的时候看三点:一是社区活跃度和文档完整度,这决定了遇到问题能不能搜到答案;二是推理生态,也就是你的部署目标平台对这个版本的支持程度;三是模型规模是否覆盖你的算力预算,从 n 到 x 逐级放大,选够用就行。
部署前有一项核对绝对不能省:训练时的预处理和推理时的预处理必须完全一致。包括图片的缩放方式、填充策略、归一化参数、颜色通道顺序。这些细节任何一项不一致,都会导致部署后的精度明显低于训练验证时的 mAP。我习惯的做法是拿训练验证集里的一批图,走一遍完整的部署推理路径,然后把预测框和训练验证时的预测框叠在一起比对,如果框的位置有系统性偏移,那基本就是预处理不一致。
还有个小细节是类别顺序。训练时 data.yaml 里的 names 顺序,必须和部署时模型输出的索引顺序对齐。这个坑我在嵌入式部署上踩过,模型输出索引 0 对应的是"人",但后处理代码里把它当成了"车",结果所有框的标签都是错的,检测框位置还对,排查了半天才反应过来。
6. 分析流程里的几个实操习惯
最后说几个我自己养成的习惯,看起来不起眼但很省事。
第一个是训练开始后先别走开,看前 5 到 10 个 epoch 的日志。如果损失从一开始就不降,或者验证集加载数量跟你预期的不一致,这时候停下来比跑完 200 轮再发现问题划算得多。我一般会在训练脚本里加一个断言,检查数据集加载的图片数和标注文件数是否匹配,数量对不上直接报错退出。
第二个是给每次实验的目录名带上关键参数,比如 exp_yolo11s_960_sgd,这样一眼就能看出用的什么配置。靠记忆管理实验是最不可靠的,两三周之后你绝对记不住 exp_v3 和 exp_v7 的区别。
第三个是把每次分析的结论写成两句话记下来,一句是"这次看到了什么现象",一句是"下次要试什么改动"。这两句话积累到几十条之后,你会发现自己的调参直觉明显变好了,因为每一条都有实际数据支撑,而不是从别人的经验帖里抄来的。
这套流程我从早期做简单的四分类识别模型的时候就在用,后来扩展到目标检测、实例分割,乃至多模态的目标检测任务,骨架始终没变:先看损失确认模型在学,再看指标判断学得好不好,最后回到图上定位到底哪里错了。真正需要经验的地方不在于流程本身,而在于同一组曲线摆在面前时,你能多快把现象映射到原因上——这个只能靠一次次跑、一次次记录、一次次复盘攒出来。我现在看一条 dfl_loss 曲线,基本能判断出这个数据集里小目标占多大比例,就是这么练出来的。