ARTICLE DETAIL

资讯详情

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

YOLO11西红柿目标检测:数据集、训练、调参与避坑全攻略

YOLO11西红柿目标检测:数据集、训练、调参与避坑全攻略 简介针对西红柿目标检测任务这份基于YOLO11的完整工程包提供了从数据集到可视化识别的闭环方案。压缩包共1322个文件约143.79MB包含656张JPG原图、326个YOLO格式txt标签、321个XML标注文件以及划分、训练、检测三个Python脚本、预训练权重.pt、data.yaml配置和训练结果csv适合具备一定Python与深度学习基础的学习者快速上手。资源已获得102人学习关注。除标准YOLO格式转换与训练流程外项目自带PyQt5可视化检测界面可点击加载图片并一键识别内置数据划分脚本一键生成训练集与验证集配套requirements.txt环境依赖让复现更省心若想逐行理解代码还可参考作者提供的扩展文档。相比零散教程该包将数据集、标签、配置与代码整合在一起省去大量数据预处理与格式对齐时间目录结构清晰无论是从零重新训练还是直接加载已有权重进行推理都能按需选择便于集中精力调参与优化模型性能。1. 西红柿目标检测为什么绕不开 yolo11一个含数据集的 zip 能省下多少事温室大棚里数西红柿成熟度、无人采摘车识别果串、分拣线上的大小分级这三类需求几乎都会落到同一个技术选型上目标检测。而 yolo11 是当前落地性价比最高的检测算法之一比上一代 yolov8 在同样精度下更快模型文件也更小。标题里这个“西红柿检测-含数据集.zip”本质上是一个把数据集和训练配置打包好的起点包你拿到手之后不用再满网找标注重点是把它拆开校验、把训练跑通、把参数调到自己场景能用的状态。这篇笔记就是按这个顺序讲的适合刚接触目标检测、想用现成数据集快速出第一版模型的工程师也适合已经被数据折磨过一轮、想看看边界在哪的熟手。2. 拆开数据集 zip 之前先对齐 yolo11 的标注与目录约定不管 zip 是从哪来的先别急着训练。yolo11 对数据集的目录和标注格式有一套硬性约定差一个斜杠、差一个类别编号都会让训练在第一个 epoch 就翻车而且报错往往看不出真凶。这一章先用最短路径把数据集校验掉再讲格式转换的边界坑。2.1 解压后的目录结构images 与 labels 必须一一对应拿到 zip 之后第一件事是解压然后看清楚顶层目录长什么样。常见的打包方式是unzip tomato_detection.zip -d ./tomato cd ./tomato tree -L 2一般会看到两种结构一种是直接把images和labels平铺在根目录另一种是已经按train/valid/test切好。yolo11 的 data.yaml 里只认路径不认文件名所以目录结构本身不强制但训练集和验证集的划分必须显式写在 yaml 里。比如# tomato.yaml path: /home/user/tomato train: images/train val: images/valid nc: 1 names: [tomato]这里最重要的是path路径。很多坑都出在这train 写的是images/train但实际目录叫train/images或者 yaml 放在 zip 外面路径用了相对路径运行命令时当前目录一变就找不到数据。我一般会让train和val都写成绝对路径省得后面排查半天。还要顺带确认一件事图片后缀。yolo11 的加载器支持 jpg、png、jpeg、bmp 等常见格式但如果数据包里混着.tif或者大小写不一致的.JPG偶尔会有图片被跳过。数据量少的时候这不明显一旦训练集有一批图没进去mAP 会在某个区间一直上不去属于最难排查的怪问题之一。处理办法很简单进训练前先把图片统一转成小写后缀的 jpg这个动作几十行脚本就搞定。2.2 标注格式的硬性要求归一化坐标与类别从 0 开始yolo11 的每张图片对应一个同名 txt 文件放在 labels 目录下。每一行是一个目标格式固定为class_id x_center y_center width height其中坐标全部是归一化到 0~1 的小数是相对于图片宽高的比例不是像素值。比如一张 1920x1080 的图上一个西红柿中心在 (960, 540)宽 200、高 180那这行应该是0 0.5 0.5 0.1042 0.1667类别编号从 0 开始。如果你的数据集在标注时用了1表示西红柿而 yaml 里nc: 1训练时它会被当成类别 0最后的模型框是对的、但类别名永远错位这种错位最难排查因为整个过程没有任何报错。我一般会先写一个脚本全量检查一遍标注再进训练import os from pathlib import Path def check_labels(labels_dir, images_dir): img_files {p.stem for p in Path(images_dir).glob(*.jpg)} lbl_files {p.stem for p in Path(labels_dir).glob(*.txt)} for stem in sorted(img_files - lbl_files): print(f[缺失] {stem}.jpg 没有对应 txt) for stem in sorted(lbl_files - img_files): print(f[多余] {stem}.txt 没有对应图片) for txt in Path(labels_dir).glob(*.txt): for line in txt.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f[格式错] {txt.name}: {line}) continue cid parts[0] x, y, w, h map(float, parts[1:]) if not (0 x 1 and 0 y 1 and w 0 and h 0): print(f[坐标越界] {txt.name}: {line}) check_labels(labels/train, images/train)这个脚本做的事是“缺图对表”和“越界检查”。images_dir里没有同名 txt 的图会被训练直接跳过但数据集往往不会告诉你坐标里如果混入了像素值比如 960 而不是 0.5归一化后训练会直接崩loss 变成 nan。参数上的关键是检查脚本只认*.jpg如果你的数据集是 png 或 bmp记得把 glob 的后缀一起改掉或者直接写成*.png。2.3 把 VOC/自有标注转成 YOLO txt一个转换脚本与四个边界坑很多拿到的数据集不是 YOLO 格式而是 VOC 的 xml或者 Roboflow 导出的 COCO 格式。标题里这个 zip 大概率已经转好了但你总要面对另一个项目里“转格式”这件事。最常见的转换是 VOC xml 转 YOLO txt一个可直接用的脚本import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, out_dir, class_map): root ET.parse(xml_path).getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue # 跳过不在映射表里的类 bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 防止越界和负宽高导致 loss 变 nan xmin max(0, min(xmin, img_w - 1)) xmax max(xmin 1, min(xmax, img_w)) ymin max(0, min(ymin, img_h - 1)) ymax max(ymin 1, min(ymax, img_h)) w (xmax - xmin) / img_w h (ymax - ymin) / img_h xc (xmin xmax) / 2 / img_w yc (ymin ymax) / 2 / img_h lines.append(f{class_map[name]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(xml_path).stem .txt) out_path.write_text(\n.join(lines)) class_map {tomato: 0, unripe: 1} # 按你自己的类别改 for xml in Path(annotations).glob(*.xml): voc_to_yolo(xml, labels, class_map)四个边界坑都出在坐标处理上第一VOC 的 bndbox 是像素坐标转 YOLO 必须除以图片宽高忘了归一化是最常见翻车点第二xml 里的 xmin/xmax 可能相等标注时手滑宽变成 0会导致 loss 直接 nan所以代码里加了max(xmin 1, ...)的保护第三类别映射表如果少了某个类那一类目标会被静默跳过训练出来的模型对这个类完全不识别第四图片尺寸要以 xml 里的 size 为准不要自己去读图片因为发生过 xml 和实际图片尺寸不一致的情况。转完之后再跑一遍 2.2 的检查脚本确认零报错再进训练。这一步多花五分钟后面少折腾两小时。3. 从零训练西红柿检测模型环境、命令与第一版权重目录和标注确认没问题就到了真正动手的时刻。这一章讲怎么把环境搭起来、怎么用最小命令把第一版权重跑出来以及第一次训练完之后该看什么。3.1 环境版本ultralytics 与 PyTorch 的搭配训练 yolo11 依赖的是 ultralytics 这个 pip 包它把数据加载、网络定义、训练、验证和导出全部封装到了一套命令行里。环境上的坑主要集中在 PyTorch 版本与 CUDA 驱动不匹配另一个坑是 conda 和 pip 混装导致包冲突。常见的做法是建一个新的 conda 环境conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics安装后先跑一句最简单的推理命令验证环境和预训练权重都能用yolo predict modelyolo11n.pt source./test.jpg如果你的数据集 zip 里有样例图直接拿一张当 test.jpg 就行。这条命令能通说明环境和基础权重都没问题接下来才能谈训练。注意yolo11n.pt是 ultralytics 自动下载的预训练权重第一次跑需要联网公司内网机器记得提前把权重文件下载放好。另外明确一点用 CPU 训练可以吗可以但几百张图的数据集CPU 一个 epoch 可能要十几分钟非常煎熬而且模型验证阶段也同样慢。想省时间就直接上 NVIDIA GPU显存 8G 起步12G 更舒服。3.2 最小训练命令先 n 后 s别一上来就 m第一版权重不需要追求精度目的是验证整个流程链路是通的。我的做法是用最小的 yolo11n 模型、短 epochs、小 batch 跑一遍确认 loss 在下降、验证集 mAP 不是零再换大模型去调参。yolo train \ datatomato.yaml \ modelyolo11n.pt \ epochs50 \ imgsz640 \ batch16 \ project./runs \ nametomato_n_first参数说明modelyolo11n.pt表示用 yolo11n 作为预训练权重同时决定网络结构是 nano 版本epochs50是训练轮数第一版不用刻意拉高imgsz640是输入分辨率batch16是每批图片数这个数取决于显存后面细讲project和name控制输出目录建议每次训练都分开 name避免权重互相覆盖。训练过程中终端会实时打印 box_loss、cls_loss、dfl、mAP50 等指标看到 mAP50 从 0 往上爬就说明链路通了。这里有个反复出现的误区不少人一上来就用 yolo11m 或 yolo11l觉得“模型大一定准”。实际上在几百张西红柿图片的小数据集上大模型的过拟合风险远高于收益训练速度慢、显存占用高最后 mAP 往往还不如 nano 版本。先让小模型跑通再按需放大这才是稳妥路线。3.3 训练完之后先看什么weights 文件与训练曲线训练结束不会只有 best.pt 一个文件runs/tomato_n_first 目录下会有 weights/best.pt、weights/last.pt、args.yaml、results.png 以及一堆曲线图。这时候别急着拿视频去测先打开 results.png 看两件事训练 loss 曲线是否平滑下降验证集 mAP50 是不是在稳步上升。如果 loss 曲线像锯齿一样抖动但整体向下属于正常如果 loss 一路向下但 mAP 一直是零那大概率是标注或者数据读取出了问题回到第二章去查。best.pt 是验证集上 mAP 最高的那一轮权重last.pt 是最后一轮的权重。后续做测试和部署都用 best.pt。另外如果你想接着上次的训练继续跑不用重新加载 weightyolo train 命令会自动从 runs/xxx/weights/last.pt 恢复前提是name和之前保持一致。这个机制在数据集临时补了几张图时特别有用但注意恢复训练时要把 epochs 改成“剩余轮数”不是“总轮数”否则实际训练轮数会超出你的预期。4. 把 mAP 从 70 拉到 90yolo11 训练参数与数据增强的调法第一版训练能出 70 左右的 mAP50对这个“含数据集 zip”的场景来说只算及格。真正决定模型能不能用的是后续两轮调参。这一章把调参拆成三块显存与 batch 的制约、数据增强的边界、以及怎么从曲线判断下一步动作。4.1 显存不够怎么调batch、imgsz、workers 的三角关系yolo11 训练占显存的几大项分别是输入图片、特征图、梯度、优化器状态其中梯度占大头。batch 每翻一倍显存消耗大概也翻一倍而 batch 和 imgsz 的乘积近似等于单卡显存的上限。我常用的经验值是显存建议模型imgszbatch8Gyolo11n640812Gyolo11s6401624Gyolo11m6403232Gyolo11l64032~48如果训练时提示CUDA out of memory优先把 batch 减半不要先动 imgsz。因为 imgsz 一旦从 640 降到 480小目标的检测能力会立刻受影响西红柿在画面里算中小目标降分辨率会直接造成漏检。workers 是数据加载线程数默认 8 够用如果 GPU 利用率上不去、一直像在摸鱼可以先调高 workers再检查是不是 CPU 成了瓶颈。yolo train datatomato.yaml modelyolo11s.pt epochs100 \ imgsz640 batch16 workers44.2 数据增强参数mosaic 开多大、颜色抖动调多低yolo11 的默认增强里对西红柿这个场景有一个天然冲突默认的 HSV 颜色扰动会改变红绿比例。西红柿成熟度判断严重依赖颜色如果把色相hue调得幅度太大模型会学到错误的颜色关系比如把青西红柿学成红西红柿。所以我会把 hsv_h 从默认的 0.015 降到 0.005hsv_s 从默认的 0.7 降到 0.3hsv_v 保持 0.4不让饱和度过度漂移。mosaic四图拼接默认是 1.0表示 100% 的概率使用拼接增强。对西红柿这种小目标多的场景mosaic 能大幅增加上下文多样性但也会让小目标变得更小训练初期 loss 容易不稳。如果 50 个 epoch 后 mAP50 还在低位徘徊先把 mosaic 改成 0.5 试试。还有一个是水平翻转 fliplr默认 0.5西红柿没有方向性可以提到 1.0等于强制每一张图都做一次翻转数据量立刻翻倍。这些参数在训练命令里直接传yolo train datatomato.yaml modelyolo11s.pt epochs150 imgsz640 batch16 \ hsv_h0.005 hsv_s0.3 hsv_v0.4 mosaic0.8 fliplr1.0 scale1.0注意scale默认是 0.9控制训练时随机缩放的比例它是缓解小目标漏检的关键。西红柿在真实画面里的像素占比往往不超过 5%把 scale 提到 1.0、让模型多看到近景大果对小目标检测有直接帮助。如果现场拍摄距离远、果串密集这组参数值得反复测。4.3 从 loss 和 mAP 曲线判断该停还是该加训练过程中不要只看 mAP50。mAP50 高不代表模型好mAP50-95 才是更严格的标准它衡量的是不同 IoU 阈值下的综合表现。我在调参时会盯三个信号训练 box_loss、验证 box_loss、以及验证 mAP50-95 的增速。如果验证 loss 开始回升而训练 loss 还在下降这是过拟合信号直接停再加 epochs 没有意义。如果两个 loss 都还在降那就继续加 epochs 或者加数据增强强度。西红柿数据集如果是 600~1000 张的规模150 个 epoch 左右会到平台期再多收益很小。还有一点容易忽略patience参数。默认是 50意思是验证 mAP 连续 50 个 epoch 不提升就提前停止。第一版训练建议设成 30这样 100 epoch 的任务实际跑到 70 左右就能提前结束节省时间。另外可以考虑加cos_lrTrue让学习率余弦衰减后期收敛更稳但要注意初始学习率 lr0 建议从 0.01 降到 0.005否则前期震荡会很明显。5. 西红柿检测避坑指南标注错位、小目标与过拟合的排查记录这一章全是血泪经验。训练西红柿模型时大概率会遇到的问题我按照“现象 → 原因 → 解决”的顺序列出来每一条都是实际项目里真实发生过的事。5.1 现象loss 能降但 mAP 永远是 0loss 曲线看着很漂亮从 2 降到 0.5mAP50 始终是 0偶尔出个 0.001。原因排查下去几乎所有情况都指向同一个地方验证集标注和图片没有对齐。要么是验证集里有一半图片的 txt 是空的要么是某个 txt 里的 class_id 超出了 nc 范围yolo11 在验证时会把这类标注当垃圾直接过滤掉剩下的正样本太少mAP 自然算不出来。解决方法是回到第二章的检查脚本重新扫一遍验证集尤其注意nc是否与 yaml 一致。另外一个隐蔽原因是图片文件名里有中文或空格。ultralytics 在读取这类路径时偶尔会静默跳过训练日志里看不出任何异常但实际进到模型里的图片少了。我踩过一次数据集里有十几张图叫“西红柿-成熟-001.jpg”训练全程无报错mAP 就是比正常低 5 个点最后把文件名全部改成英文字母加数字问题立刻消失。5.2 现象小西红柿全漏检大西红柿全中模型对画面里的大果识别很好对远景的小果完全没反应。这是小目标场景的经典问题核心原因是特征图下采样太多。yolo11 的 P3 特征图是输入尺寸的 1/8对 640 的输入来说一个 16x16 像素的西红柿在 P3 上只剩 2x2 像素特征信息严重不足。解决有三个方向一是训练时用imgsz960等于让小目标在特征图上放大二是推理时把大图切成小块分别检测再把框映射回原图三是在采集阶段让相机离目标近一点或者提高摄像头分辨率。这三个方向里最省事的是用大分辨率推理代价是推理速度变慢现场帧率可能从 30 掉到 15需要结合实际管线取舍。5.3 现象验证 loss 回升训练 loss 还在降这是过拟合的典型形态。如果数据集只有几百张图模型从第 90 个 epoch 开始背训练集验证集上的表现就崩了。解决按优先级排序先加数据增强强度这最便宜如果增强已经加满就加大模型容量从 n 换到 s 或 m配合更强增强再不行就去扩充数据集把标注里的难例遮挡、重叠、逆光单独抽出来做困难样本训练。还有一个很多教程不提的点调低lr0初始学习率0.01 改成 0.005能缓解后期振荡给模型更稳的收敛路径。5.4 现象跑到一半 CUDA out of memory训练过程中突然 OOM而不是一开始就 OOM这种情况多半是 mosaic 增强导致的。mosaic 会把四张图拼在一起拼接后的临时图比单张图大得多如果恰好在这个 epoch 抽到了占比大的图显存就爆了。除了减小 batch还有一个解法加cachedisk。数据集如果全部加载进内存cacheram会占掉大量系统内存系统内存满了会拖累显存分配效率。改成cachedisk后数据从磁盘读速度略慢但更稳定适合在 8G 显存的机器上跑。5.5 现象背景误检严重把落叶、水滴当西红柿训练时没有做难负样本挖掘。yolo11 自带的数据增强里没有专门针对背景的负样本补充模型会把“红色圆形”当成西红柿而温室里这种误检源太多了。解决方法是单独收集一批不含西红柿但有红色圆形物体的图片标注为空文件放进训练集。这类空标注的图片会帮助模型学到“背景模式”显著降低误检。同时检查一下训练集里是不是混入了标注不全的图片很多数据打包为了省事把部分目标漏标了那模型学到的就是“只标大果”小果全成背景。6. 验证不止看 mAP混淆矩阵、PR 曲线与导出部署的收尾技巧训练调参到这里模型已经能用了但别急着收工。这一章讲两件事怎么用验证工具看清模型的真实缺陷以及怎么把权重导出成实际部署要用的格式。用 best.pt 在验证集上跑一遍完整验证yolo detect val datatomato.yaml modelruns/tomato_s/best.pt batch16 imgsz640跑完之后打开runs/tomato_s/val目录里的confusion_matrix.png。单类别模型的混淆矩阵只有两行两列重点看“背景被误检成西红柿”这一格这个数字直接决定误检率。再看PR_curve.png如果曲线往右上方顶得很满说明模型对得分阈值不敏感如果曲线中部塌陷说明有一部分西红柿很难和背景区分你需要回到第四章重新调颜色增强。部署环节导出 ONNX 是最常见做法yolo export modelbest.pt formatonnx imgsz640 opset12导出后拿到best.onnx用 ONNX Runtime 或 TensorRT 接进推理服务。注意 ONNX 导出时imgsz必须和训练时一致否则推理结果会偏移。如果后面要部署到边缘盒子或嵌入式设备可以用formattflite导出量化版本体积小很多代价是 mAP 掉 1~2 个点像 K230 这类带 NPU 的边缘芯片通常也吃 tflite 或 onnx 量化后的权重导出前最好先确认目标平台的算子支持范围省得导出完跑不起来。这套流程做完你应该手里有一个能跑的 best.onnx、一份验证报告、一套从标注到训练到调参都可复现的过程。我个人的教训是凡是拿到数据集 zip先花十分钟做完整校验比训练完再回头查原因省太多时间。希望这个从拆包到部署的路径能帮你少走一轮弯路。本文还有配套的精品资源点击获取
返回列表