ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

131张焊缝图像小样本训练YOLOv8:从数据划分到部署避坑指南

131张焊缝图像小样本训练YOLOv8:从数据划分到部署避坑指南 简介面向yolo系列目标检测算法学习与工业焊缝质检场景的专用数据集包含131张已标注的焊接图像覆盖焊接不良与焊接良好两类典型状态适合新手练习模型训练也可用于实际焊接质量检测方案的快速验证。压缩包共394个文件内含131个jpg原图、131个txt格式yolo标签、131个xml格式voc标签以及1个data.yaml数据集配置文件7.12MB的小体积便于快速下载和部署。标签均按比例归一化保存边界框坐标可直接匹配yolov5、yolov7、yolov8、yolov9、yolov10、yolo11等主流框架无需额外做格式转换。数据集已预先划分好训练集与验证集并配套data.yaml下载后即可开始训练和测试。目前已有231人次学习下载适合作为焊缝缺陷检测、目标检测入门或毕业设计的数据支撑。 从压缩包文件名就能看出来这就是一个标准的小样本工业质检数据集131 张焊缝图像带标签二分类焊接不良 / 焊接良好。很多第一次拿到这种数据的人会直接解压、翻代码、开训练结果往往是被验证集准确率打击一遍。焊缝检测的难点不在“能不能检测出来”而在光照变化、缺陷尺度小、正负样本不均这三个问题上而 131 张图恰好把这些矛盾全部暴露出来。这套数据适合两类人刚接触 YOLO 算法、想用真实工业数据跑通全流程的算法工程师以及想在产线上验证视觉检测可行性的质量负责人。它最大的价值不是数据量而是任务边界足够干净能当你的调参基准线。2. 拆开压缩包之前先弄清标签语义再动目录2.1 焊接不良和焊接良好到底是分类标签还是缺陷框这种焊缝数据集的封装方式市面上常见的有两种。一种是把图像按类别放进不同文件夹welding_bad/和welding_good/各放一堆图标签实际上隐含在路径里另一种是检测格式每张图配一个.txt或.xml标注文件里面写的是缺陷的边界框坐标。文件名里只写了“带标签”和“焊接不良-焊接良好”没有出现 “VOC” 或 “COCO” 字样所以我的处理习惯是优先按分类任务准备。怎么快速确认解压后别急着写训练脚本先看一眼目录树。打开压缩包如果看到的是两个平铺的文件夹每张图就是一张独立样本那这就是 ImageFolder 结构如果看到labels目录或者一堆与图像同名的.txt文件那就要往目标检测方向走。我见过不少人把分类数据集硬塞进检测训练脚本结果报“no labels found”就懵了——问题不在代码在数据格式没对齐。另外焊缝缺陷本身也分很多种气孔、咬边、未熔合、飞溅形态差异很大。二分类数据集里“焊接不良”这一类的内部一致性决定了模型上限。如果不良样本里既有大面积气孔又有细小裂纹那 131 张图里能真正代表“不良”的特征可能只有几十个有效区域模型的泛化压力会明显偏向数据量多的那一类。2.2 建标准目录结构把 131 张摊成 train / val无论原包是哪种组织方式我建议先整理成 YOLO 分类模式能直接读的结构。下面是一个最小目录树data/ ├── train/ │ ├── welding_bad/ │ │ ├── bad_001.jpg │ │ └── ... │ └── welding_good/ │ ├── good_001.jpg │ └── ... └── val/ ├── welding_bad/ └── welding_good/这段结构看起来简单但有一个细节很害人val下的类别子目录必须和train完全同名。YOLOv8 在训练时扫的是 train 和 val 两个根目录它会自动从子目录名里读取类别列表。如果某个类别只在 train 里出现而 val 里缺失训练不会报错但模型评估时所有该类别样本都会被当成未知类别日志里的混淆矩阵直接错位。如果原包已经是检测格式带.txt标签那就需要额外建一个data.yamlpath: . train: train val: val names: 0: welding_bad 1: welding_good注意这里names的索引顺序要和标签文件里第一个数字对上。很多检测数据集翻车都是这个原因标签里第一个数字是 1YAML 里从 0 开始等于两个类别调换了位置模型训练完的结果刚好和直觉相反。2.3 131 张怎么划分先按类别分组再抽验证集131 张做二分类直接随机划分是最大的坑。如果焊接不良只有 40 张焊接良好有 91 张一次全局随机可能把不良样本的 90% 都抽到训练集里验证集只剩 3 张不良图评估结果完全是撞大运。我一般这么写划分脚本import os import random import shutil random.seed(42) # 固定种子保证每次划分结果一致 src raw_data # 解压后的根目录 out data for split in [train, val]: for cls in [welding_bad, welding_good]: os.makedirs(f{out}/{split}/{cls}, exist_okTrue) for cls in [welding_bad, welding_good]: files sorted(os.listdir(f{src}/{cls})) random.shuffle(files) n_val max(1, int(len(files) * 0.2)) # 每类至少留 1 张验证 for f in files[:n_val]: shutil.copy(f{src}/{cls}/{f}, f{out}/val/{cls}/{f}) for f in files[n_val:]: shutil.copy(f{src}/{cls}/{f}, f{out}/train/{cls}/{f})逻辑说明先按类别分组再洗牌避免某类在某个划分中“消失”。固定random.seed(42)后每次执行脚本生成的划分完全一致这样后续不同参数之间的对比才有意义否则每次训练结果波动都归因到划分随机性上后面调参全是玄学。参数说明n_val用的是每类样本量的 20%。如果焊接不良只有 40 张20% 就是 8 张验证图8 张够评估吗勉强够。它只能告诉你模型没崩但给不出可靠的召回率。这时我会把比例降到 15%或者对焊接不良类别做离线增强旋转 90°/180°、镜像后再划分让验证集里每类至少保持 10 张以上。2.4 划分完成后先看数量再开训写个简单的文件统计确认两个 split 下每个类别的样本数再进入训练环节for d in data/train/*; do echo $d: $(ls $d | wc -l); done for d in data/val/*; do echo $d: $(ls $d | wc -l); done这一步能提前暴露两个问题一是某个类别在 train 或 val 中数量为 0二是验证集类别失衡严重。如果验证集里焊接不良只有两张那后续训练曲线的真实性和稳定性都要打个问号务必要重新划分或补数据。3. 从 131 张到第一版模型训练命令与增强参数怎么定3.1 为什么先选 yolov8n-cls.pt而不是直接搬检测模型YOLO 算法在这类小数据集上的落地路径我建议先走 YOLOv8 的 classify 模式而不是一上来就训练检测头。原因很直接131 张图撑不起检测任务对定位标注的需求。分类模式只需要图像和类别标签结构上比检测头少了一个框回归分支参数数量少一个量级在小样本上的过拟合压力小得多。模型选择上用 nano 版本起步也就是官方预训练权重里的yolov8n-cls.pt。这个权重是在大规模公开数据集上预训练过的特征提取层已经能识别纹理、边缘、反光这类通用视觉特征。焊缝图像和常规物体图像域差异不大预训练特征可以直接迁移过来。如果你一上来就用yolov8m-cls.pt或更大模型131 张图大概率训练到第 30 轮就过拟合val 准确率开始掉头向下。训练命令如下yolo classify train \ datadata \ modelyolov8n-cls.pt \ epochs80 \ imgsz640 \ batch16 \ patience20 \ projectruns/classify \ nameweld_first参数说明datadata指向刚才建好的目录结构训练时 YOLO 会自动扫描子目录生成类别列表。epochs80小样本 80 轮足够配合早停机制一般 40 轮左右就能看到明显的收敛趋势。imgsz640YOLO 分类模式的默认输入尺寸。焊缝缺陷区域如果很细小建议训练一个imgsz960的对照组看 val 指标是否提升。batch16要看你的显存6GB 显存 16 batch 基本没问题4GB 降到 8。patience20连续 20 轮 val 指标不提升就提前停止防止过拟合拖到最后一轮。训练日志里会输出每个 epoch 的train_loss、val_loss、top1_acc、top5_acc。对二分类来说只看top1_acc就行。如果前 5 轮准确率从 50% 快速跳到 85% 以上说明预训练权重迁移正常如果准确率一直在 60% 附近徘徊先怀疑类别目录配错再怀疑图像本身像素值异常。3.2 数据增强必须开但 mosaic 在焊缝图上会坏事YOLOv8 分类训练默认会开启一批增强策略随机裁剪、翻转、颜色抖动、mixup 等。对小数据集来说增强不是可选项是必须项。131 张图靠原始样本硬训练准确率不会超过 70%这不是模型问题是数据本身就撑不起泛化需求。但增强参数要按焊缝图像的实际情况调整。以 mosaic 为例它把四张图拼成一张确实能大幅提升模型对遮挡和杂乱背景的鲁棒性。可焊缝图像的特点是背景单一、目标区域集中在焊缝带附近mosaic 拼图后会让焊接不良和焊接良好的上下文特征混在一起模型学到的是拼接边界伪影而不是缺陷本身。我一般在分类模式下把 mosaic 直接关掉# augment.yaml 里修改 mosaic: 0.0 mixup: 0.1 fliplr: 0.5 hsv_h: 0.02 hsv_s: 0.3 hsv_v: 0.3然后在训练命令里通过cacheTrue和cfgaugment.yaml让增强配置生效。hsv_v的全称是色调-饱和度-明度的明度扰动焊接图像在不同采光环境下亮度差异很大把明度扰动开到 0.3 能让模型对明暗变化不那么敏感这一点在焊缝这种高反光表面尤其重要。hsv_h只给到 0.02因为焊缝金属色偏一旦被过度扰动特征分布就偏移了。这个小参数组合是我在类似工业数据上调出来的基准值不一定对所有产线都最优但作为第一版足够稳。3.3 epoch、imgsz、batch 的联动关系不是三段独立参数很多新手把这几个参数当成各自独立的值其实它们在小样本上会互相牵制。epoch 多batch 小模型每轮看到的样本少噪声大收敛速度慢epoch 少imgsz 大每张图一次前向计算量成倍增加训练时间翻倍但收益不一定明显。我习惯的思路是先固定imgsz640和batch16跑 60 个 epoch看训练曲线的形状再决定后续。如果训练集准确率在 10 轮内就接近 100% 而验证集还在 75% 上下说明模型已经开始记忆训练集下一组实验不要把 epoch 调大反而要调小或者干脆把增强力度加大。如果验证集准确率和训练集同步上升但最后稳定在 85% 就不再动了那瓶颈在特征本身下一轮把imgsz拉到 960 试试或者考虑换更大的预训练模型。一句话总结这套联动关系epoch 负责给模型足够的迭代次数batch 负责稳定梯度imgsz 决定特征分辨率。小数据集上最值得花钱的是 imgsz因为它直接决定细小的焊接缺陷能不能在特征图里保留下来。imgsz640下 5 个像素宽的裂纹可能到第 4 层特征图就没了imgsz960能把这类细小缺陷多留一层特征。代价是显存占用上升约 50%7GB 以下的卡建议别硬上。3.4 训练中断和恢复用一个命令避免白跑一晚上小数据训练通常不会太久但如果你同时在调多组参数很容易出现训练中途显存溢出或者断电的情况。YOLOv8 在runs/classify/weld_first/weights/下会保存best.pt和last.pt前者是验证集指标最好的权重后者是最后一个 epoch 的权重。中断后不需要从头开始直接指定resumeTrueyolo classify train resumeTrue modelruns/classify/weld_first/weights/last.pt代码说明resumeTrue会把之前的 epoch 数、学习率调度器状态一并恢复相当于无缝续跑。这里有个坑如果你改了project或name参数resume会找不到原来的训练状态必须在原目录下执行。训练完别急着删last.pt当你后面调完增强参数想对比时它就是那个“后悔药”。4. 训练之后的评判损失函数、精确率、召回率怎么读才算数4.1 别死盯总损失分清分类损失和验证损失YOLO 分类模式的训练日志里train_loss是一个标量但如果你用的是检测模式日志会拆成box_loss、cls_loss、dfl_loss三部分。对焊缝小样本来说最值得盯的是cls_loss它表示类别判断的交叉熵损失。box_loss 是框回归误差在二分类场景里没有意义只有在定位缺陷位置时才相关。YOLO 的损失函数组合里有个细节容易忽视分类损失用的权重比框回归损失高这是对类别辨识的偏向设计。放到焊缝场景就是模型宁可“框偏一点也要类别判对”。如果你的实际需求是“只要判断这条焊缝是否合格不用管缺陷在哪”那分类模式天然匹配如果你需要告诉焊工“问题在哪个位置”那就必须走检测模式看box_loss和dfl_loss的变化。dfl_loss是 distribution focal loss它衡量预测框分布和目标框分布的距离。焊接缺陷框往往很小、长宽比极端细长裂纹dfl_loss在小目标上降得慢是正常的不要因为它不收敛就觉得模型坏了。4.2 混淆矩阵里漏检的代价远大于误检训练结束后的confusion_matrix.png是判断模型能不能上产线的第一份证据。二分类的混淆矩阵就四个格子真良、假良、真不良、假不良。焊接场景里假不良把好焊缝判成不良的代价是停产复检假良把不良焊缝放行的代价是产品质量事故两者完全不是一个量级。所以模型评估不能只看准确率。如果验证集里不良样本 8 个模型判对了 6 个准确率 75%听起来还行但再看误检分布如果漏掉的那 2 个都是细小气孔说明模型对低尺度缺陷的特征提取不足。这时候应该往回调不是调损失函数而是去查这两个漏检样本的原始图像看看缺陷区域在训练集里是否出现过类似样本。我在第一版模型训练完后会单独统计每个类别的召回率而不是只看平均准确率。二分类里如果焊接良好类别有 90 张验证图焊接不良只有 8 张平均准确率会被大类拉高模型对不良类的真实表现可能只有 50%这个数字才是决定要不要继续调参的关键。4.3 置信度阈值默认 0.25 未必适合小样本模型YOLO 分类模式下模型会对每个类别输出一个置信度分数。默认推理时只取最高分的类别但这不等于阈值是 0.250.25 是检测模式中 NMS 的默认阈值。分类模式下你要在部署端自己设一个置信度阈值比如 0.6置信度低于这个值的样本统一判为“需人工复检”。这是工业质检最稳妥的兜底策略。用一张焊缝图跑单张推理时可以用下面的代码手动控制阈值逻辑from ultralytics import YOLO model YOLO(runs/classify/weld_first/weights/best.pt) results model(sample.jpg) prob results[0].probs # 两个类别的置信度 bad_conf prob.data[0].item() # 焊接不良的置信度 if bad_conf 0.6: label welding_bad elif bad_conf 0.4: label welding_good else: label manual_review # 灰色地带交给人工逻辑说明results[0].probs返回的是一个概率分布两类相加为 1。.data[0]对应welding_bad的置信度。中间留了一段 0.4 到 0.6 的灰色地带任何一类置信度落进这个区间都说明模型特征不够清晰送人工复检不强行给结论。小样本模型在边界样本上本身就不稳定这个缓冲区能拦住大部分误检。4.4 131 张数据上做一个完整对照组为了确认当前模型是真的学到了缺陷特征而不是在撞运气我会跑一组对照实验第一组是原图直接训练第二组是开启增强参数后训练第三组是imgsz960再训练。三组模型的验证集准确率、召回率放同一个表里比。如果第一组和第二组差异巨大说明增强参数起到了核心作用如果第二组和第三组差异小说明模型已经接近这个小样本的天花板再调参数的边际收益不高下一步应该去补充数据而不是继续调参。这个对照思路比单跑一个模型看准确率靠谱得多。5. 焊缝检测避坑记录小样本训练最常翻车的五个场景5.1 现象训练集准确率 99%验证集只有 72%这是小样本训练最典型的过拟合信号特征提取层已经记住了训练图像的纹理细节遇到光照偏移或角度变化的验证图就失灵。原因通常是模型参数过多、增强力度不足、验证集样本太少。解决路径按顺序来先关掉 mosaic把hsv_s和hsv_v提高到 0.3 以上再把模型从yolov8m降回yolov8n最后确认验证集每类至少有 10 张以上。如果这三步做完验证集准确率还低于 80%就要回到数据本身找问题而不是继续调参。5.2 现象训练时报 “no labels found” 或 “no images found”这类报错在检测模式下最常见。原因不是代码坏了而是标签文件的命名与图像不匹配或者目录结构要求和 YOLO 预期不符。YOLO 检测模式要求每张图像对应一个同名.txt文件例如bad_001.jpg必须对应bad_001.txt且 txt 里每一行格式是“类别 中心点x 中心点y 宽 高”四个坐标都是 0 到 1 的归一化值。解决方式是写个脚本统一文件后缀并且把标签文件的编码统一成 UTF-8 无 BOM。如果图像是.JPG而标签是.txtLinux 下还好Windows 上偶尔会因大小写匹配不上导致漏读一半标签。5.3 现象混淆矩阵显示大量“焊接不良被判定为焊接良好”这是漏检的核心表现。原因往往是焊接不良样本在训练集里的数量远低于良好样本且缺陷区域像素占比很小。解决方式有三个层次第一层检查训练集中两类数量比例如果悬殊对大类别做下采样或者对小类别做离线增强旋转、亮度扰动、局部裁剪第二层把imgsz从 640 提高到 960让细小缺陷在输入阶段不至于被降采样抹掉第三层针对漏检样本做 hard example mining把验证集里漏检的那几张图重新放回训练集单独多训 20 个 epoch。前两步做完大概率能解决 80% 的漏检问题。5.4 现象训练过程中 val 分支报目录为空训练能启动但每个 epoch 结尾的验证阶段全部是警告val 准确率一直为 0。原因多半是数据划分脚本执行失败val/welding_bad目录没生成或者被压缩包解压时过滤掉了空目录。解决方式很直接训练前先跑一遍统计命令确认每个目录的文件数如果确实为空检查划分脚本里os.makedirs的执行顺序。另一个隐蔽场景是 Windows 下解压 zip 时的长文件名截断极少数压缩包会出现目录结构被截断的情况导致 YOLO 扫描不到子目录换用 7-Zip 重新解压即可。5.5 现象训练曲线看起来正常但实际部署后误检率飙升训练评估没问题一到产线实测就不断报警这种场景我遇到过多次。原因通常是训练图像和产线实拍图像的成像条件差异太大训练图是恒定光源、固定机位拍的产线可能有自然光干扰、工件反光角度变化、甚至镜头脏污。解决方式是在部署前先拍一版产线真实图像流抽 50 张用训练好的模型跑一遍看置信度分布。如果置信度普遍偏低说明域差异大需要补充产线实拍数据微调模型如果置信度很高但分类错误问题出在类别特征定义上要重新检查“焊接良好 vs 焊接不良”的标注标准是否一致别让标注师傅把“工艺合格但不美观”的焊缝标成不良。6. 从 131 张走向产线导出、加速与置信度阈值设置模型训练完下一步要考虑的是怎么让它跑在产线工位上。常见的做法是先把 PyTorch 权重导出为 ONNX再转成 TensorRT 引擎推理速度能比纯 PyTorch 快 2 到 4 倍。T4 这类推理卡上用 TensorRT 跑 YOLO 640×640 输入25fps 的视频流同时跑 4 到 6 路没什么压力焊缝质检这种单路工位场景更是绰绰有余。导出命令很简单yolo classify export modelruns/classify/weld_first/weights/best.pt formatonnx # 先转 ONNX yolo classify export modelruns/classify/weld_first/weights/best.pt formatengine device0 # 再转 TensorRT第二个命令执行时会自动先构建引擎比 ONNX 多了个device0参数指定 GPU。TensorRT 引擎对运行环境的 CUDA 版本很敏感换一台机器跑不起来或者报算子不支持就先删掉.engine文件重新转一次别急着改代码。部署端我最看重的参数就是置信度阈值。训练时你可能觉得 0.5 很好用但真正到产线上我习惯把“焊接不良”的判定阈值设到 0.6 以上落进 0.4 到 0.6 之间的全部转人工复检。原因很简单小样本模型对“边界样本”的置信度本来就不稳定与其让它在临界样本上强行给出结论不如把这部分决策成本交给人。这种做法的代价是复检率提高但换来的是不放走一个可疑焊缝。我还习惯在日志里攒下每个被复检样本的置信度分布攒到 500 条左右做个统计如果大部分复检样本最终被判定为“焊接良好”说明阈值设得偏严适当下调如果复检样本里确实混着不良说明阈值设得太松再往上提。用数据调阈值入味的办法比凭感觉设一个数靠谱得多。唯一的例外是场景过暗或弧光过大轻微的焊接不良可能淹没在高光区里。如果这类样本反复出现漏检或低置信度我会用增强过的离线样本重新微调模型并在训练时把hsv_v的抖动范围加大让模型在亮度极端变化下仍然能保住特征响应。这一步做完131 张数据能发挥的潜力才算是真的榨干了。这类小样本质量检测项目我的一个经验习惯是每次训练完都把best.pt连同当时的训练参数、数据划分 seed 一起备份成一个实验目录。这样翻车时你不用从头猜超参数从哪里开始路走偏的直接回去改就行。这套流程从数据整理到部署推理把每个环节的边界都摸了一遍希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进