DEIM 微调中的配置、前处理与权重产物
DEIMv2 微调得到的 AP 明显偏低时,问题未必出在模型或学习率。命令里的预训练路径可能没有传到训练器,自动生成的前处理可能与骨干不匹配,导出时也可能选择了与验证不同的权重。这些问题都不会必然阻止训练运行,却会让结果失去可比性。
一次自定义检测任务中,COCO 预训练权重微调得到 AP@0.5:0.95 40.63%。后续使用带 Normalize 的配置,结果降到 27.83%,表面上像是归一化导致退化。核对日志后却发现,后一任务并没有真正进入微调:权重参数在配置传递中丢失了。
本文围绕初始化、骨干前处理和评估权重展开,并将同一份参考延续到 ONNX 导出验证。
一、命令传入权重,不等于训练器加载了权重
这次问题发生在自动训练入口。命令行已经接收 -t/--tuning,但生成配置与运行时参数合并时,把 tuning 当成仅用于生成配置的参数排除了。模型仍按配置正常构建,训练也能继续,最终传入 solver 的却是 tuning=None。
日志中的 Training ViT-Tiny from scratch 提供了直接线索。预训练模型路径出现在外层命令里,不能证明最终的加载分支已经执行;配置生成、参数覆盖和模型初始化之间还有一段传递过程。
核对时需要沿着同一条任务检查:命令行接收的值、生成的配置、运行时覆盖后的 cfg.tuning,以及 solver 打印的加载结果。修复的是参数传递,不能只在 YAML 中增加一行路径,却仍让后续覆盖将它清空。
| 模式 | 权重 | 优化器与调度器 |
|---|---|---|
| 从头训练 | 不加载目标任务的微调起点,骨干初始化另行声明 | 新建 |
| 微调 | 预训练参数,头按类别适配 | 通常新建 |
| 恢复训练 | 完整训练 checkpoint | 恢复 |
微调加载通常允许部分参数缺失,以适配类别数变化。这里也不能只看程序没有报错:分类头形状不同可能是预期行为,大量骨干参数缺失则需要另查。当前适配代码会匹配同名、同形状的参数,并报告 missed 与 unmatched;这些信息应与基础权重版本一起保存。
同一批训练工具还出现过 YAML 科学计数法被解析成字符串的问题,例如 3e-4 最终不是浮点数,直到 AdamW 运算时才失败。配置生成后应重新解析并检查类型、范围与互斥项,不能以“文件写出来了”作为配置正确的依据。微调与 resume 同时出现,也应在启动前明确拒绝。
二、前处理随骨干变化
参数传递修复后,再看 Normalize 才有意义。后续对照记录中,真正加载 COCO 权重的两条任务分别得到:
| 配置 | 记录轮次 | AP@0.5:0.95 |
|---|---|---|
| 不做 ImageNet Normalize | epoch 9 | 64.42% |
| 使用 ImageNet Normalize | epoch 10 | 70.82% |
这组结果没有出现此前所怀疑的大幅退化,原先 27.83% 的结果不能继续用来证明 Normalize 有问题。但两条记录的轮次也不完全相同,不能把相差的 6.40 个百分点全部算作归一化收益。更严格的比较需要固定数据划分、初始化、训练预算和模型选择规则,并观察完整验证曲线。
在这套适配中,ViT/DINOv3 系列采用 RGB、Resize、像素缩放到 s 或输出尺寸推断骨干。
前处理的关键不仅是“有没有 Normalize”,还包括颜色顺序、缩放顺序和几何变换。对采用该归一化的模型,数值变换为:
训练、验证和部署应使用相同的通道规则。推理输入已经除以 255,后面就不能再除一次;图中或平台侧已融合 Normalize,调用侧也不能重复执行。直接 Resize 与 Letterbox 即使输出同样的 shape,也会产生不同的图像与坐标关系。
对于已按另一套前处理训练的历史权重,不能只修改推理端就期待改善。先用训练时的规则建立参考,再判断是否需要重新微调;否则输入分布变化与模型变化会再次混在一起。
三、增强阶段、早停与评测口径
训练前段使用较强增强,后段关闭部分增强进行精调,两段的验证曲线不能完全按同一阶段理解。若一次“连续若干轮不提升”就直接结束,可能在尚未进入后段时停止训练。
适配后的两阶段早停以 COCO bbox AP 为监控指标:第一阶段达到耐心值后提前进入无增强阶段,第二阶段重新计数,仍无提升才结束。归档默认耐心值为 10,但它是该训练入口的默认配置,不是 DEIMv2 对所有数据集的最佳轮数。最小改善量、起始轮次、阶段切换和最终 best 权重都需要在日志中可见。
同样要区分 AP@0.5:0.95、AP50 和某个置信度阈值下的可视化结果。降低展示阈值可以看到更多候选框,却不能据此说明训练已经收敛。比较两次实验,还要固定类别映射、验证集和标注口径;目标框从局部改成整体,或者去重后重新划分数据,旧 AP 就不再是直接基线。
训练速度另行拆分为数据读取与增强、训练迭代、验证和保存。图片缓存减少重复解码,可以缩短整轮时间,但这不等于模型 kernel 更快。比较训练耗时还应保持验证精度模式、数据加载配置和保存频率一致。
四、验证使用哪个权重,导出就保存哪个权重
当前训练实现启用 EMA 时,验证使用 ema.module,而非正在被优化器更新的普通模型。两者即使来自同一 epoch,也不能当成完全相同的参数。若按 EMA 的 AP 选择 best,保存和导出时却取普通 model,就改变了被评测的对象。
产物精简前,一份完整 checkpoint 约 156 MB,包含普通模型、EMA 副本和 AdamW 等训练状态。精简后的 best/last 只保存验证实际采用的模型参数:启用 EMA 时取 EMA,否则取普通模型,并统一放到 model 字段,体积约 39 MB。
这不是降低权重精度或做了量化,而是去掉重复参数和训练状态。模型大小随规格变化,156 MB 与 39 MB 也只是这一份权重的记录。
| 产物 | 保留内容 | 可以继续做什么 |
|---|---|---|
| 完整训练 checkpoint | 模型、EMA(如启用)、优化器、调度器、进度等 | 按原训练入口恢复 |
| 精简 best/last | 选定的一份模型参数 | 验证、推理、导出,或作为新一轮微调起点 |
| ONNX | 固定推理图与参数 | 建立部署参考,不承担训练恢复 |
精简文件仍叫 last.pth,也不意味着它能断点续训。适配后的 resume 入口会检查训练进度字段,对仅含模型参数的文件明确拒绝。若需要长任务容错,应另存完整状态,不能在删掉优化器与调度器后仍称为等价恢复。
导出前再用精简权重复跑固定验证集,确认与被选中的 best 指标一致,然后保存权重哈希、类别映射、前处理与 ONNX 参考输出。这样才能区分训练结果变化和导出、编译引入的变化。
五、将选定权重导出为可核对的推理图
导出时使用验证实际选中的参数,按配套模型代码进入 eval 和部署态。训练 checkpoint、EMA 参数和纯 state_dict 的加载入口需要分别核对;不能只凭 .pth 后缀选择参数所在键。模型规格、类别数与类别顺序也应沿用训练配置,避免模型能够加载却改变了预测头的含义。
本次 DEIMv2 导出将 PostProcessor 放进 ONNX,对外保留 images、orig_target_sizes 两个输入,返回 labels、boxes、scores。静态基线使用 batch=1;类别筛选、TopK 与坐标还原以这份导出实现为准,不再额外套用 YOLO decode 或 NMS。
| 接口 | 本次导出约定 |
|---|---|
images | float32 NCHW,按骨干使用对应前处理 |
orig_target_sizes | int64 [1,2],顺序为 [W,H] |
labels、scores | [1,300] |
boxes | [1,300,4],还原到原图的 xyxy 坐标 |
orig_target_sizes 的顺序来自该 PostProcessor 的坐标缩放实现,不是所有 DETR 导出器共有的约定。用一张非方形图片检查尺寸输入与框还原,比方图更容易发现宽高颠倒。DINOv3 与 HGNetv2 的归一化差异也需要保留,不能为了统一部署接口修改模型训练时的数值规则。
验证时只生成一次正式前处理输入,保存为 NPZ,将相同张量分别送入 PyTorch 部署态模型和 CPU ONNX Runtime。先核对输入输出名称、shape、dtype 与有限值,再比较 scores 和有效检测框。候选经过 TopK 后可能换序,框应按类别和 IoU 建立对应关系,不能只按行号比较;类别编号的余弦也不能作为任务精度指标。
图简化、注意力改写或采样算子替换分别作为新的候选图,逐次与这份参考比较。ONNX checker 通过只说明结构合法,不能证明前处理、坐标和任务结果一致。通过后保存权重与 ONNX 哈希、类别表、前处理及固定输入输出;存在 external data 时,将外部权重与 ONNX 一起保存。
平台数值问题从这份 CPU 参考继续定位。HTP 上的正反向拆图与固定特征探针,见 Qualcomm HTP 上 DEIM 的数值误差与拆图;采样实现的限制与改写取舍,见 RKNN 上 DEIM 的采样语义与部署边界。
六、一些反思
这次排查中,比起单独比较两个 AP,更有效的是确认它们对应的训练条件。Normalize 是最显眼的配置变化,但初始化方式也变了;先核对最终配置和加载日志,才避免继续围绕错误原因调参。
自动训练入口需要减少手动操作,也需要保留检查实际行为的途径。参数传递、骨干前处理、评估权重与产物用途都明确后,后续模型对比和部署误差才有可追溯的起点。