尧图精选

YOLOv10缺陷检测实战:预训练权重推理、阈值调优与避坑指南

🕒 发布时间:2026/10/2 8:37:29 📁 来源:尧图网络
简介这套YOLOv10快递包裹与包装盒缺陷检测权重包面向物流仓储、电商质检和计算机视觉开发者模型已完成训练可直接对Box、Box_broken、Open_package、Package等四类目标进行推理检测适合快速搭建包裹外观缺陷识别方案。配套1200余张标注图像标签为txt格式并已预先划分好train、val、test数据集附有data.yaml配置文件除YOLOv10外YOLOv5、YOLOv7、YOLOv8、YOLOv9等算法也能直接使用同一数据集进行训练。资源共2000个文件其中包含1002个xml标注、982个txt标签、15个md说明文档及1个py脚本压缩包整体76.86MB目录结构清晰便于按模块查阅和替换权重。已有121人学习使用适合需要快速落地快递包裹缺陷检测、训练对比不同YOLO版本或进行二次开发的工程师参考。1. 接到一个YOLOv10缺陷检测项目包先别急着写训练脚本快递包裹和包装盒的缺陷检测多数时候并不需要从零训练模型。一个训练好的YOLOv10权重文件加上1200多张带标注的数据集意味着你拿到的是别人已经踩过一轮坑的成果标注格式、训练参数、类别体系都定好了。直接推理检测省下的是三周到一个月的数据准备和调参时间你的活从“训模型”变成了“用模型、调阈值、查边界”。这个方案适合谁一类是产线上的视觉工程师想快速验证YOLOv10在包裹表面缺陷上的可行性另一类是刚接触目标检测的开发者手里有图片目录但要先跑通一个能出框的推理流程再谈优化。两者共同的诉求是先看到结果再决定要不要投入。这篇就按“包里面有什么 → 怎么跑起来 → 参数怎么调 → 哪里会翻车 → 怎么验收”的顺序拆开讲后面每一章都有可以直接抄的代码和配置。2. 训练好的权重和数据包长什么样先拆文件再动代码2.1 .pt权重文件里装的不只是参数结构、类别表和超参数都在里面你拿到的YOLOv10权重文件通常是.pt格式和YOLOv8、YOLOv11一样走Ultralytics生态。这个文件内部用pickle序列化装了三层东西模型结构定义、训练好的权重张量、还有训练时用的超参数和类别信息。正因为结构定义打包在权重里加载时不需要额外拿一个yaml文件来描述网络直接YOLO(best.pt)就能把模型建出来。这点和旧版YOLOv5不同。v5的权重文件只存state_dict加载时还得分两步先给模型类再灌权重。YOLOv10沿用了v8的封装思路一个文件全搞定对使用者友好得多。不过这也带来一个误解有人以为pt文件就是纯参数改了文件名换个后缀就能部署——不行里面还有Python对象结构部署到生产环境得用ONNX或TensorRT导出。权重文件的类别表是从训练数据集继承的。拿到手第一件事就是确认它认哪几类缺陷。常见做法是写一行代码打出来from ultralytics import YOLO model YOLO(weights/best.pt) print(model.names) # 预期输出类似 {0: scratch, 1: dent, 2: tear, 3: stain}这段代码做的事情是读取模型内嵌的类别名称字典键是类别索引值是类别名。YOLO的类别索引必须从0开始连续编号如果你的数据集只在data.yaml里写了两类但权重文件声称有三类推理时就会出现索引越界。打印result出来后先核对names后面所有标注、过滤、统计都依赖这个映射。2.2 1200多张标注图片的数据集目录结构、TXT标注和划分逻辑数据集部分一般按YOLO格式组织拿到手应该是这样的目录结构dataset/ ├── data.yaml ├── train/ │ ├── images/ │ │ ├── 00001.jpg │ │ └── 00002.jpg │ └── labels/ │ ├── 00001.txt │ └── 00002.txt └── val/ ├── images/ └── labels/图片和标注文件靠文件名一一对应没有同名标注的图片在训练时会被自动跳过但在推理阶段不受影响。标注文件每行是五个数字class x_center y_center width height坐标全部归一化到0到1之间用图片宽高做分母。如果你用LabelImg或X-AnyLabeling标注时把坐标保存成了Pascal VOC的XML格式需要先转成YOLO格式再谈训练。1200多张图说多不多说少不少。对缺陷检测这种小目标、高相似度的场景够跑出一个能用的模型但想覆盖所有产线异常这量还是紧张。你拿到包后要做的第一件事不是训练是拿val目录里的图跑一遍推理看模型在没见过的图上表现如何这在一定程度上反映了数据的泛化能力。注意数据划分是训练前就定死的。原包提供的data.yaml里的train和val路径如果和你本地路径不一致加载时会报文件不存在这时要么改yaml里的绝对路径要么在代码里指定data参数覆盖。2.3 配置文件data.yaml怎么创建路径、类别数、类别名三件套不少人在网上搜“yolov10 yaml文件怎么创建”实际上这东西不需要从零写你只需要一个三轮车大小的文本文件。YOLO训练和验证都会读这个文件三组关键信息缺一不可path: /absolute/path/to/dataset # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 4 # 类别总数 names: [scratch, dent, tear, stain]path字段要注意Ultralytics加载数据集时会把path和train拼接成完整路径。如果你把train写成train/images程序会去找path/train/images拼接逻辑是固定的不是你想写就写。nc必须和names列表长度一致也和标注文件里的最大类别索引加一对齐。不一致时报错很隐晦后面避坑章节会细说。如果你的包是从网上下载的压缩包路径往往是别人机器上的路径解压后一定要改path字段。还有一个容易忽略的点win和Linux的路径分隔符不同yaml文件里统一用正斜杠/最稳妥反斜杠会被当成转义字符。3. 跑通第一次推理环境、加载权重和批量检测的完整步骤3.1 环境装到什么程度算够ultralytics包和它背后的依赖链推理环境比训练环境好搭得多。先说结论CPU也能跑但640分辨率下单张图大概1到3秒产线实时检测必须用GPU。装依赖用pip一行搞定但有几个版本坑要提前知道pip install ultralytics这个包会自动带上torch、torchvision、numpy、opencv-python等依赖。注意它会装最新版PyTorch如果你的机器是旧显卡CUDA版本跟不上后面加载权重时会提示找不到GPU。稳妥做法是先去PyTorch官网装匹配你显卡的torch版本再装ultralytics避免后者用pip把torch顶成不兼容的新版。Python版本建议3.9到3.11之间。我遇到过3.12装老版本ultralytics后模型加载时卡在torch.load的反序列化环节报错信息完全看不出来是版本问题。如果你用的是conda环境直接新建一个干净的conda create -n yolodet python3.10 conda activate yolodet pip install ultralytics onnx onnxruntimeonnx和onnxruntime不是推理必须但导出模型和排查模型结构时会用到提前装上省得后面补。装完后验证环境是否正常的唯一标准是把权重加载出来折腾半天环境不如早跑一行代码。3.2 最小推理代码三行代码出结果但你要知道每个参数在干什么这是整套方案的入口。把下面的代码存成detect.py放在和weights目录平级的位置from ultralytics import YOLO model YOLO(weights/best.pt) # 权重路径按你实际位置改 results model.predict( sourcetest_images/, # 放图片的目录或单张图片路径 conf0.25, # 置信度阈值低于此值的框被丢弃 iou0.45, # NMS的IoU阈值控制重叠框的保留 imgsz640, # 推理分辨率和训练时一致 saveTrue, # 保存标注后的图片 projectruns/detect, # 输出父目录 namefirst_run, # 输出子目录 )逻辑拆解一下YOLO(weights/best.pt)从pt文件里重建模型结构并加载权重predict方法的source参数接受目录路径时会自动扫描目录下所有图片conf和iou是影响结果最直接的两个参数后面专门讲imgsz640是指把输入图片缩放到640×640再喂给模型注意这会造成非正方形图片的变形模型训练时也是这么处理的所以推理时必须用同样的尺寸否则特征图尺度对不上小缺陷容易漏检。saveTrue时结果图片会写到project/name目录下。第一次跑完一定要去看一眼输出图这比看任何指标都直观。如果框全画在正常区域说明阈值太低或模型对这类缺陷的区分度不够如果一个框都没有可能不是模型问题而是conf设得太高。3.3 批量检测目录递归、结果导出和代码里取坐标的写法实际使用中不会只测一张图。产线验证阶段往往要跑几百张这时要把结果结构化导出方便后面统计漏检误检。下面的脚本演示了如何遍历目录、打印检测结果并保存数据from ultralytics import YOLO from pathlib import Path model YOLO(weights/best.pt) source_dir Path(production_samples) for img_path in source_dir.rglob(*.jpg): # rglob递归所有子目录 result model.predict(str(img_path), conf0.3, iou0.5, verboseFalse)[0] # result.boxes里存了所有检测框信息 boxes result.boxes for i in range(len(boxes)): cls_id int(boxes.cls[i].item()) conf float(boxes.conf[i].item()) x1, y1, x2, y2 [float(v) for v in boxes.xyxy[i].tolist()] # xyxy是左上角和右下角的绝对像素坐标 print(f{img_path.name} 类别{cls_id}({model.names[cls_id]}) f置信度{conf:.2f} 坐标[{x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f}]) # 结果保存到指定目录idea文件和标注同名的txt可用于后续分析 result.save_dir # 这行只是告诉你结果默认输出位置rglob(*.jpg)会遍历所有子文件夹适配你的图片分散在多个目录的情况。boxes.xyxy给出的是绝对坐标而YOLO训练时标注是归一化坐标如果你要把推理结果转成标注格式做半自动标注记得除以图片宽高。result.save_dir在saveFalse时不生效想要保存可视化结果就把saveTrue加进predict参数里。这里提醒一点批量跑几百张图时不要每张图都重新加载一次模型。上面代码把model放在循环外这是基本常识但我见过不少人把YOLO()写进循环里每个文件都重新加载权重速度直接慢几十倍。4. 从“有框”到“框得准”置信度、IoU和类别过滤的调参经验4.1 置信度阈值conf缺陷检测建议从0.25起步不要一上来就0.5很多人习惯把conf设成0.5认为低于0.5的检测结果不可信。这在通用目标检测上没问题但在缺陷检测场景这一套会漏掉大量真实缺陷。原因在于缺陷的视觉特征往往比较微妙一道浅划痕、一点污渍模型给出的置信度只有0.3到0.4但它确实是一个需要判别的缺陷点。我一般会先用0.25跑一批图把结果都画出来肉眼过一遍看漏检多还是误检多。如果框明显比实际缺陷多再逐步上调到0.3、0.35。如果你做的是产线初筛宁可多标几个框让后续人工复核也不要漏检到下游工位。漏检的机会成本远大于误检——误检顶多多看两眼漏检直接把坏品放过去了。# 调阈值时用这句观察不同置信度下的框数量 model.predict(sourcetest_images/, conf0.25, iou0.45, saveTrue, nameconf_025)跑完后打开runs/detect/conf_025目录看看框的分布。如果一张图上重叠框很多说明这类缺陷有多个响应区域需要继续调IoU而不是死磕conf。4.2 IoU阈值从0.45调到0.6同一个缺陷框两遍的解决思路IoU是NMS非极大值抑制阶段的参数控制重叠程度多高的两个框会被合并。YOLO默认0.45意思是两个框的交集面积除以并集面积大于45%时置信度低的那个会被去掉。缺陷检测里有个典型问题同一个凹痕被模型响应了两个相邻框一个0.5置信度一个0.48置信度且两者高度重叠这时NMS会帮你保一个扔一个。如果你发现输出图上同一个位置画了两个几乎重合的框说明IoU阈值设得不够激进重叠部分没超过0.45。把它调到0.6到0.7重合框就会被合并。反过来如果两个缺陷贴得很近比如两道平行的划痕IoU太大会把它们错误合并成一个框这时要降低IoU保留两个独立框。python detect.py # 假设你的脚本里写死了iou # 或直接用命令行覆盖参数 yolo detect predict modelweights/best.pt sourcetest_images/ conf0.25 iou0.6命令行方式和Python调用的区别在于命令行一次就跑完适合快速试参数Python方式方便接后续处理逻辑。实际调参时我习惯写一个循环把conf从0.2到0.5、iou从0.4到0.7全部跑一遍每个组合的框数量和保存的图片数量统计出来直接看哪个组合最匹配实际缺陷分布。4.3 类别过滤只留包装盒封口破损别让污渍干扰统计训练好的模型同时检测好几种缺陷类别时你的下游工序可能只关心其中一类。比如包装盒表面有污渍但产线只把封口破损算作报废项污渍框会影响统计。这时用classes参数只保留需要的类别from ultralytics import YOLO model YOLO(weights/best.pt) # 假设第二类(索引1)是want关注的分割破损 seal_break results model.predict( sourcetest_images/, conf0.25, classes[1], # 只保留类别索引为1的检测结果 saveTrue, nameonly_seal_break, ) for result in results: # 所有box现在都只属于类别1 print(result.boxes.cls)classes参数接收一个列表支持多个类别同时保留比如classes[0, 2]只保留索引0和2的框。这个过滤发生在NMS之后所以不会影响其他类别的框参与抑制过程。一个隐藏坑是如果你不知道类别索引对应什么先按2.1节的model.names打印出来再设参数。5. 避坑指南加载权重和批量推理里我踩过的六个坑5.1 坑一RuntimeError类别索引超范围模型和数据对不上现象加载权重后跑推理代码报RuntimeError: Class values are not in [0, Class-1]或者训练时提示标签错误。原因标注文件里出现了小于0或大于nc-1的类别索引。常见于数据集标注时有一张图的类别写错了或者你用的data.yaml的nc写小了。解决先按2.1节的代码打印model.names确认类别数再写一段扫描脚本找出所有标注文件里的最大索引值import os from pathlib import Path label_dir Path(dataset/train/labels) max_cls -1 bad_files [] for txt in label_dir.glob(*.txt): for line in txt.read_text().splitlines(): cls_id int(line.split()[0]) if cls_id max_cls: max_cls cls_id if cls_id 0: bad_files.append(txt.name) print(最大类别索引:, max_cls) print(包含负索引的文件:, bad_files)如果是某一张标注文件写错了直接改txt里对应行的第一个数字如果整体偏移比如类别名和索引错了一位修改data.yaml里的names顺序即可不用动标注。5.2 坑二推理结果一张框都没有但训练时指标不错现象验证集mAP看着有0.8但新图片跑出来一个框都不出。原因你推理时的conf设太高。训练时的mAP是在多个置信度阈值下综合计算的结果不代表每个检测框的置信度都能到0.5。缺陷目标小、对比度低置信度普遍偏低是常态。解决先把conf降到0.1看有没有框出现。如果有说明模型学到了特征只是响应较弱逐步上升到0.25找平衡点。另外检查imgsz如果你训练时用640推理时用1280模型看的东西变了检测结果自然面目全非。5.3 坑三显存占用看着不高但FPS就是上不去现象batch size从1调到8显存占用从600M涨到2G但每秒处理图片数几乎没变。原因你用的可能是CPU推理GPU完全没参与或者CUDA没被PyTorch识别静默回退到CPU。这是最常见也最隐蔽的坑。解决推理前先打印一行import torch print(torch.cuda.is_available()) # 必须是True print(torch.cuda.get_device_name(0)) # 打印显卡名称如果第一行是False重新安装匹配CUDA的PyTorch版本。如果True但速度还是慢用device0参数强制指定GPUmodel YOLO(weights/best.pt) results model.predict(sourcetest_images/, device0)5.4 坑四中文路径一碰就碎图片读不出或保存失败现象图片路径或输出目录带中文时代码要么报找不到文件要么保存的图片是损坏的。原因OpenCV在Windows上的imread/imwrite对非ASCII路径支持很差Ultralytics内部调用了OpenCV。这不是YOLO的问题是底层库的历史遗留。解决把所有路径改成纯英文包括项目根目录、图片目录、输出目录。如果你的数据集已经在中文目录里写代码时用pathlib.Path管理路径并在读取图片时用cv2.imdecode配合np.fromfile做兼容处理但最省事的是在项目规划阶段就别用中文路径。5.5 坑五检测框和得出来的坐标跟原图画不上现象你用OpenCV把boxes.xyxy坐标画到原图上发现框的位置偏了或者框比目标大一圈。原因推理时图片被缩放到imgsz尺寸模型输出的坐标是缩放后的坐标但Ultralytics的result对象里boxes.xyxy已经还原到原图坐标系一般不会出错。出错往往是因为你用letterbox方式处理了图片YOLO的缩放是等比例缩放加灰边填充你自己再做一次resize就会引入二次偏差。解决直接用result.plot()画图或者用result.boxes.xyxy去画不要自己重新处理图片。如果你确实要在原图上叠加框做后处理参考这个写法from PIL import Image import numpy as np result model.predict(test.jpg, conf0.25)[0] img np.array(Image.open(test.jpg)) boxes result.boxes.xyxy.cpu().numpy().astype(int) for x1, y1, x2, y2 in boxes: cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)5.6 坑六特征太小的缺陷在640分辨率下根本看不清现象快递面单上的小破损、包装盒边角的轻微压痕人眼都费劲模型也漏。原因训练时用的是640分辨率小目标在缩放到640后可能只有几个像素。标注时如果这些目标小于10×10像素YOLOv10的特征提取能力就到瓶颈了。解决训练和推理时把imgsz提到1280或更高。推理时提分辨率有效果但注意训练时如果是640推理时1280会让模型处于分布外状态效果可能反而变差。更好的路子是拿到包以后用新增的小缺陷样本做增量训练把高分辨率缺陷图补进去。6. 从推理到验收30分钟评估这套预训练权重值不值得用拿到权重先别急着部署用三个步骤判断它适不适合你的场景。第一步跑验证集指标。如果你的包里有val目录且配置好了data.yamlfrom ultralytics import YOLO model YOLO(weights/best.pt) # metrics model.val(datadataset/data.yaml, splitval) metrics model.val(datadataset/data.yaml) print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.box.maps) # 每个类别的mAP50-95mAP50看的是IoU阈值50%下的平均精度缺陷检测通常要求mAP50在0.7以上才算可用。如果只有0.5左右说明模型对这个数据集的学习不充分要么数据量不够要么标注不一致。注意每类缺陷的mAP差异很大有一个类特别低而其他类高优先怀疑那一类的标注边界不统一。第二步拿你自己采集的真实产线图片做盲测。找20到50张现场图先人工标注一遍缺陷位置再用模型推理对比两个结果。看两个量漏检率——模型没框出来但人眼能看到的缺陷数量除以总缺陷数误检率——模型框了但人眼确认不是缺陷的数量除以总框数。漏检率超过10%的模型不建议直接上线误检率高可以靠conf阈值压下去。第三步做个鲁棒性测试。同一种缺陷在不同光照、不同角度、不同包装底色下模型能不能稳定检出。快递包裹的材质千差万别白色泡沫箱、黄色纸箱、灰色塑料袋模型如果只在一种材质上学得好换材质就翻车。拿三种不同底色的图片各跑10张统计框的置信度分布如果某一类材质的置信度全面走低需要补数据继续训练。我自己的习惯是把推理脚本和参数固定下来参数写进一个配置文件而不是散落在代码里。比如conf、iou、imgsz、类别过滤列表都放进yaml或JSON每次跑实验只改配置不碰代码这样不同批次的实验结果有可比性。后面要做模型压缩或量化时这套评估结果也能当基准线用。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →