ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLO11自定义网络使用AdamW训练报错,换成SGD却正常:优化器兼容性与参数分组排查

YOLO11自定义网络使用AdamW训练报错,换成SGD却正常:优化器兼容性与参数分组排查 最近我在做一个圆环产品的工业视觉检测遇到了一个比较绕的问题数据里只标注了一种缺陷测试时却出现了其他类别的误检而且有些框出现在产品旁边的背景区域。当时我的标注类别编号是1部署软件固定保留020共21个类别。我的需求很明确只检测目标缺陷并让软件按照业务类别1处理结果。但实际测试中既有类别1的命中也出现了类别0的误检。同一张图片反复测试结果还出现过不一致。排查过程中我补充过误判图片也尝试关闭 AMP。关闭 AMP 后我当时再次验证推理之前的问题没有再出现结果恢复正常。不过“调整后恢复正常”和“已经证明唯一根因”是两回事。这篇文章记录我遇到的现象以及这次排查中需要分清的几个问题训练类别编号、部署类别映射、预训练权重和混合精度。一、先把实际问题说清楚这个项目要检测的是圆环产品上的螺纹特征。按照当时的判定标准无螺纹以及允许范围内的浅纹属于合格品达到不良标准的螺纹才是需要检测的目标。我遇到的情况主要有下面几个项目当时的情况实际标注内容一种目标缺陷标签文件中的类别编号1软件中的类别列表020共21类模型初始化使用预训练权重异常表现合格品或背景区域出现0类误检同图测试结果出现过不一致排查中的变化关闭 AMP 后当次验证推理恢复正常我最初怀疑过是不是预训练模型原本有很多类别训练后还保留了其他类别的识别能力所以会冒出0类要判断这个猜测首先得弄清楚我说的“只训练一类”到底是只标了一类还是模型实际上只有一个输出类别。二、只标注一种缺陷不等于模型只有一个类别这是这次问题里最容易混淆的地方。在普通的 YOLO 检测训练中类别编号从0开始。如果没有启用single_cls等类别重映射逻辑可以这样理解数据配置与标签含义配置1个类别标签编号为0正常的单类别配置配置1个类别标签编号为1编号越界需要修正配置或标签配置21个类别标签只使用1声明了21个类别只给其中一类提供了正样本第三种情况不能叫“模型只有一类”。模型不会因为标签文件只出现过1就自动把其他20个输出类别全部删掉。反过来声明21类也不能直接证明它就是误检的原因。Ultralytics 的检测数据集格式说明明确要求类别编号从0开始。对于真正只有一种目标的检测任务我会使用下面这种配置# 示例按实际数据目录修改 path path: /data/ring_thread train: images/train val: images/val nc: 1 names: 0: thread_defect对应的检测标签可以是0 0.500000 0.500000 0.200000 0.100000第一列是类别编号后面四个数是归一化后的框中心坐标、宽和高。这一行只是格式示例实际坐标要来自标注。这里还要强调一点**YOLO检测里的类别0不是自动预留的“背景类”。**在上面的单类别配置中0就是thread_defect。正常图片没有目标应当没有目标框而不是专门画一个框标成0。所以如果我把模型正确改成了单类别之后出现0类检测框本身完全正常。需要判断的是它有没有框到真正的缺陷。三、软件固定21类训练标签是不是就必须用1我当时的实际限制是软件已经保留了21个类别业务上希望使用类别1。这就需要把两套编号分开看模型类别编号模型内部用来区分检测目标业务类别编号软件用来显示、统计、输出判定结果。如果软件接口允许适配我更倾向于让训练端保持单类别再在识别结果进入业务逻辑之前做映射环节编号及含义数据标注0 thread_defect模型检测结果class_id 0软件业务结果business_class_id 1映射逻辑本身很简单# 仅示意编号转换实际要接入软件的结果处理流程 model_to_business {0: 1} model_class_id 0 business_class_id model_to_business[model_class_id]但这里有一个现场限制不能省略。如果软件只是界面上保留21个业务类别可以考虑在结果层做映射如果底层推理代码把输出按21类写死就必须同时调整输出解析。后一种情况下只改标签或者只改names并不能让旧软件正确读取新模型。要先确认模型输出形状、类别数和后处理接口再安排训练与部署一起修改。单类别加业务映射是我建议的整理方向不能把它当成这次已经完成全部现场验证的修复结果。四、使用预训练权重会不会把原来的类别带进来我当时确实怀疑过预训练权重但不能只凭“用了官方权重”就下结论。在标准的 Ultralytics 检测训练流程中模型会依据目标数据集的类别数构建再加载可用的预训练权重。官方的检测训练器实现可以看到这个流程。因此一个正确构建的单类别检测模型不会因为初始化来自多类别权重就在输出里自动多出其他类别。比起猜测我会先检查实际加载的文件、类别表和检测头import torch import ultralytics from ultralytics import YOLO # 在能够加载该模型自定义模块的原环境中运行 model YOLO(best.pt) print(Ultralytics版本, ultralytics.__version__) print(PyTorch版本, torch.__version__) print(类别表, model.names) print(类别表数量, len(model.names)) # 适用于常见的 Ultralytics YOLO11 检测模型结构 head model.model.model[-1] print(检测头nc, getattr(head, nc, 请按自定义结构核对))如果类别表仍然有21项就需要结合检测头的nc、训练日志和输出形状继续核对。如果模型确认只有一类标准解析得到的类别ID应当是0软件却显示其他编号就要追踪是不是业务映射、错误解析或者加载了其他模型文件。**修改model.names只是修改类别名称信息不能把一个21类模型直接变成单类别模型。**对于改过网络或训练器的项目我会以本地源码和实际输出为准。五、AMP是什么为什么我会尝试关闭它AMP 是 Automatic Mixed Precision也就是自动混合精度。按照 PyTorch 的说明它会让不同运算使用合适的数值类型。例如在常见的 CUDA FP16 混合精度训练中一部分运算使用 FP16一部分仍使用 FP32训练时还会配合梯度缩放。它的用途是提高计算效率、减少部分显存开销并不是“开了就会误检”的选项。不过混合精度会改变部分计算的数值行为。如果网络中存在对数值精度比较敏感的计算就值得把它列为排查变量。这是一个需要验证的方向不能直接当作我这次已经证明的底层原因。在 Ultralytics 训练中可以通过下面的参数关闭训练 AMPampFalse参数含义可参考官方训练文档。不同版本的接口可能变化项目里应以实际安装版本为准。这次关闭 AMP 后我当时验证推理正常这是一个有用的结果。但如果要进一步确认原因还需要把数据、初始权重、其他训练参数和推理设置固定下来再比较开启与关闭 AMP 的结果。尤其不能忽略这一点重新训练会得到另一组权重。两次训练的结果不同不等于已经找到了某个算子的精度错误。另外训练日志里的AMP checks passed也不是项目验收结论。官方的 AMP 检查实现包含通用模型和示例图片的对照并没有用我的全部产品数据验证最终效果。训练AMP和部署FP16要分别检查这两个设置容易混在一起但它们作用在不同阶段阶段检查内容影响范围训练model.train()中的amp训练计算过程以及得到的权重验证、预测当前版本的推理精度设置例如half等参数这一次运行使用的计算精度TensorRT部署引擎构建时的精度配置已构建引擎的执行行为推理精度的参数名称需要查对应版本的预测文档。在训练脚本里改成ampFalse不会自动修改已经存在的best.pt也不会改变已经构建好的 TensorRT 引擎。重新训练后的权重如果要用于现场还需要重新导出、构建并完成部署验证。六、如果再做一次严格排查我会怎么对照我会先保存当前能正常工作的模型和配置再建立一组可以重复的对照实验。第一步确认类别配置合法。核对data.yaml、实际标签、训练日志、模型类别表和部署映射。只有一个类别时不能一边配置nc1一边继续使用标签1。如果修改了标签还需要确认训练实际重新扫描了修改后的数据。必要时清理对应数据集的标签.cache缓存让它重新生成。第二步只改变AMP这一项。下面是关闭 AMP 的训练示例模型路径、图片尺寸和训练参数需要按项目调整from ultralytics import YOLO if __name__ __main__: model YOLO(yolo11n.pt) model.train( datadata.yaml, imgsz1024, batch2, epochs100, device0, ampFalse, seed0, deterministicTrue, resumeFalse, namering_amp_off, )这段代码演示参数位置不能把里面的默认模型和参数当成我的现场最优配置。实际对照时两组都要使用相同的项目结构、初始权重、数据划分和其他训练参数只改变amp并用不同实验名称保存。如果一组用自定义网络另一组改用官方网络或者同时换了优化器、batch和数据就又增加了变量。两组都应该从同一份初始权重开始不能一组从头训练另一组接着前一组的best.pt继续训练。固定随机种子有助于比较但也不能保证跨版本、跨硬件完全复现具体限制可参考 PyTorch 的可复现性说明。第三步把两组权重放在同一推理设置下比较。我会固定测试图片、输入尺寸、置信度阈值、NMS参数和推理精度再对比误报与漏检。这样才能减少“训练设置和推理设置一起变了”的干扰。如果需要排查推理精度则保持同一份权重再单独比较不同推理精度的结果。第四步单独检查同图重复推理。同一张图片的结果明显反复变化不能只用“训练时开过AMP”来解释。我会先在固定环境中用同一模型、同一张本地图片、单路推理重复测试记录原始类别ID、置信度和框坐标。可以连续运行100次作为一次复现测试但这不是最终稳定性验收标准。如果单路稳定、接入视觉软件后才异常我会重点追踪输入是否被改动、模型是否混用以及并发任务有没有共用输入输出缓冲区等问题。七、补充负样本时不能把正常区域也标成缺陷排查过程中我补充过误判图片。这一步有价值但要先分清图片里到底有没有需要检测的目标。以这次圆环检测为例我会分别整理无螺纹的合格产品在验收标准允许范围内的浅纹产品曾经引发误报的背景、反光或纹理区域真正达到不良标准的螺纹产品。对于确实没有目标缺陷的图片应该作为负样本处理。在 Ultralytics 的 YOLO 检测数据格式中无目标图片可以没有对应标签文件使用空标签文件时也要确认标注和数据处理工具能够正确识别。**不能为了“告诉模型这张图是好的”就在正常区域画一个框并标成0。**如果0代表目标缺陷这个操作等于告诉模型正常区域也是缺陷。如果一张图里既有真实缺陷又有容易误检的背景我会保留真实缺陷的标注不会把整张图当成负样本。还有一点容易让验证结果看起来很好把误判图片加入训练后又只拿同一批图来证明模型提升。这些图片适合做回归检查但还需要另外保留没有参与训练的正常品和不良品。划分时我也会尽量让同一件产品的连续拍摄图片留在同一组避免相似图片同时进入训练集和测试集。八、最后我会看哪些结果对于工业检测我更关心最终有没有把正常品误判成不良以及真实缺陷有没有漏掉。下面这张表是我给这类问题整理的复查清单检查项我会怎样判断类别编号标签、模型类别表、检测头与部署映射是否一致正常品误报无目标缺陷的图片是否仍被判为不良不良品漏检达到判定标准的目标是否仍然能被检出旧问题回归原来出错的图片重新测试是否正常新样本表现没有参与训练的图片是否同样稳定同图重复推理类别、框和置信度是否出现无法解释的明显变化部署一致性同一批图片在本地模型与现场软件中的结果是否一致统计时也要统一口径。按图片统计的误报率和产线上按整件产品统计的误剔率不一定是同一个数。多相机项目尤其需要说明结果如何汇总。我也不会只靠提高置信度阈值来判断问题是否解决。误报可能少了但边界缺陷的漏检也可能增加两边都要看。这次我能确认的是**关闭 AMP 后当次验证推理恢复正常。**类别编号、软件映射和精度设置是后续需要分别核对的环节现有结果还不足以证明它们共同构成了唯一根因。以后再遇到“只标了一类却出现其他类别”的情况我会先确认模型到底有几个输出类别再去追踪类别映射和数值精度。对于目前已经验证正常的配置我会先保留它是否重新开启 AMP则用固定测试集和重复对照的结果来决定。
返回列表