ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

YOLO11西红柿目标检测实战:从数据集构建到推理部署全流程

YOLO11西红柿目标检测实战:从数据集构建到推理部署全流程 简介本资源面向深度学习与计算机视觉方向的开发者及学生提供一套基于YOLO11目标检测算法识别西红柿的完整代码与数据集帮助读者快速上手目标检测项目的训练与推理流程。压缩包共1322个文件约143.79MB包含656张jpg图像、321个xml标注、326个txt标签文件以及yaml配置、pt权重、py脚本和csv训练日志等覆盖数据、模型与代码全链路。已有102人学习下载。资源内含数据集划分、模型训练与PyQt可视化推理三个脚本运行01划分数据集.py可将数据转为YOLO格式并生成train.txt、val.txt与data.yaml02train.py用于重新训练模型03pyqt.py则提供图形界面点击加载图片与检测按钮即可完成识别。适合希望掌握YOLO11实战、复用预训练权重或二次开发检测界面的读者参考。1. 西红柿检测这件事难的不是模型而是数据去年帮一个做智慧农业的朋友看他的番茄分拣线他上来就问“YOLO11 能不能直接跑”我让他先把手机里拍的 200 张棚内照片发过来。结果一看逆光、遮挡、青红果混叠、背景全是藤蔓直接推理的漏检率超过四成。这就是西红柿目标检测最真实的起点算法本身早就不是瓶颈YOLO11 目标检测算法在通用数据集上已经足够成熟真正卡住落地的是“你的西红柿数据长什么样”。这个标题对应的方案本质是给你一套从零构建西红柿检测能力的完整路径——包含数据集、训练脚本和推理代码。它适合三类人想入门目标检测但缺真实场景练手的开发者、做农业视觉分拣需要快速验证可行性的工程师、以及带学生做课程设计但不想在数据采集上耗掉半学期的导师。接下来我会把数据组织、YOLO11 训练参数、推理部署和踩坑记录一层层拆开让你拿到这套东西能直接复现而不是对着一个跑不通的压缩包发呆。2. 西红柿数据集怎么组织才能让 YOLO11 吃得下2.1 目录结构与标注格式的硬性约定YOLO11 沿用了 YOLO 系列一贯的数据组织方式但很多人第一次跑翻车就翻在目录层级上。常见做法是建一个tomato_dataset根目录下面分images和labels两个子目录各自再分train、val、test。注意images/train里的abc.jpg必须对应labels/train/abc.txt文件名不含扩展名严格一致差一个字符这条数据就被静默跳过训练日志里不会报错你只会发现 loss 降不下去。标注文件是每行一个目标的纯文本格式为class_id x_center y_center width height后四个值都是归一化到 0~1 的浮点数。西红柿检测通常只设一个类别class_id就是 0。如果你拿到的原始标注是 VOC 的 XML 或者 LabelMe 的 JSON需要先转换。下面这个脚本处理 VOC 到 YOLO 的转换我一般会把它放在数据集根目录下跑一次import os import xml.etree.ElementTree as ET # VOC 标注目录与输出目录 voc_dir ./annotations_xml out_dir ./labels/train os.makedirs(out_dir, exist_okTrue) # 西红柿只有一类类别名到 id 的映射 class_map {tomato: 0} for xml_file in os.listdir(voc_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_dir, xml_file)) root tree.getroot() # 读取图像宽高用于归一化 size root.find(size) img_w float(size.find(width).text) img_h float(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip().lower() if name not in class_map: continue bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转为中心点加宽高并归一化 x_c (xmin xmax) / 2.0 / img_w y_c (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_map[name]} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) if lines: txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines))这段代码的关键点有三个一是class_map只保留西红柿其他类别直接丢弃避免训练时出现未定义类别二是归一化用图像真实宽高不能用固定值否则不同分辨率图片的框会错位三是坐标保留六位小数YOLO11 对精度不敏感但太短的浮点在某些版本里会被解析成 0。转换完记得抽查几条用cat labels/train/xxx.txt看一眼数值是否都在 0~1 之间出现大于 1 的基本就是宽高读反了。2.2 数据划分与增强策略的参数选择数据集划分比例没有绝对标准但西红柿检测我一般按 8:1:1 走训练集至少保证 500 张以上否则 YOLO11 的预训练权重优势发挥不出来。如果原始数据只有两三百张优先做的是补充采集而不是调模型因为小样本下任何增强都是拆东墙补西墙。YOLO11 训练时自带在线增强配置文件里几个参数直接决定模型对西红柿的泛化能力。hsv_h、hsv_s、hsv_v分别控制色调、饱和度、明度扰动西红柿从青到红的颜色跨度大hsv_h可以给到 0.015hsv_s给 0.7hsv_v给 0.4让模型不依赖单一颜色。degrees旋转角度建议 10 以内因为棚内拍摄的西红柿基本是正立或轻微倾斜旋转太猛会引入不存在的姿态。flipud上下翻转设 0fliplr左右翻转设 0.5符合自然场景。mosaic设 1.0 能显著提升小目标召回但最后 10 个 epoch 要关掉否则框的分布和真实场景偏差太大。提示增强参数不是越大越好。我见过把degrees开到 45 的训练模型在验证集上 mAP 很高一到实际分拣线就疯狂误检因为真实摄像头根本不会那样拍。2.3 用 YOLO11 命令行快速验证数据可用性在正式训练前先跑一次数据检查确认 YOLO11 能正确读到所有图片和标签。假设你已经装好 ultralytics 包在数据集根目录下建一个tomato.yamlpath: ./tomato_dataset train: images/train val: images/val test: images/test names: 0: tomato然后执行yolo detect train datatomato.yaml modelyolo11n.pt epochs1 imgsz640 batch4只跑 1 个 epoch目的是看日志里train和val的图片数量是否和你预期一致。如果val显示 0说明val路径下没有图片或者路径写错如果训练中途报No labels found回去检查 labels 目录的层级和文件名。这一步花两分钟能省掉后面半小时的无效训练。3. YOLO11 训练参数怎么调才不浪费显卡3.1 模型尺寸选择与显存匹配YOLO11 提供 n、s、m、l、x 五个尺寸西红柿检测这种单类别、目标形态相对固定的任务yolo11n和yolo11s就够用。我实测在 5000 张棚内西红柿数据上yolo11s比yolo11n的 mAP50 高约 2.3 个点但推理速度慢 40%。如果你的部署端是边缘设备直接选yolo11n如果是服务器批量分拣yolo11s性价比最高。yolo11m以上更适合多类别、小目标密集的场景西红柿检测用不上纯属浪费显存。显存方面imgsz640、batch16时yolo11n大约占 4GByolo11s占 6GByolo11m要 10GB 以上。如果你显卡只有 8GB把batch降到 8同时把accumulate设成 2等效 batch 还是 16梯度更新次数不变只是多花一点时间。这个技巧在显存吃紧时非常实用。3.2 学习率与优化器的实操配置YOLO11 默认用 SGD初始学习率lr00.01最终学习率lrf0.01也就是余弦退火到初始值的 1%。西红柿数据集如果超过 5000 张这个默认值可以直接用如果只有 1000 张左右lr0要降到 0.005否则前期 loss 震荡剧烈容易把预训练权重带偏。momentum保持 0.937weight_decay保持 0.0005这两个值在 YOLO11 里已经调得很稳不要轻易动。训练轮数epochs设 100 到 300 之间。判断何时停的标准不是看 epoch 数而是看验证集 mAP 是否连续 20 个 epoch 不再提升。YOLO11 自带patience50的早停机制但实际用下来 20 到 30 就够了设太大只是浪费电。warmup_epochs设 3让模型在前几个 epoch 用极小的学习率预热避免一开始就大梯度冲击。下面是一份我常用的训练命令参数都标了注释yolo detect train \ datatomato.yaml \ modelyolo11s.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.005 \ lrf0.01 \ warmup_epochs3 \ patience30 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees10 \ fliplr0.5 \ mosaic1.0 \ close_mosaic10 \ device0 \ projectruns/tomato \ nameexp1close_mosaic10表示最后 10 个 epoch 关闭 mosaic 增强让模型在接近真实分布的数据上收尾。device0指定第一块 GPU多卡用device0,1。project和name决定日志和权重的保存路径建议每次实验换个name方便回溯。3.3 训练过程监控与指标解读训练启动后终端会实时打印每个 epoch 的box_loss、cls_loss、dfl_loss和验证集的mAP50、mAP50-95。西红柿检测重点看mAP50因为它对框的位置容忍度更高更贴近分拣线“框住就行”的需求。如果box_loss持续下降但mAP50不动大概率是学习率太小或者数据增强过猛如果cls_loss很快降到接近 0说明类别太单一模型闭着眼都能分类这时候要把精力放在框的回归上。训练结束后runs/tomato/exp1目录下会有weights/best.pt和weights/last.pt。best.pt是验证集 mAP 最高的权重推理用它last.pt是最后一个 epoch 的权重一般不用。results.csv里记录了所有指标用 pandas 读出来画个曲线能直观看到有没有过拟合。如果训练集 loss 还在降但验证集 mAP 开始掉就是过拟合了减少 epochs 或者加大weight_decay。4. 推理部署与效果验证的完整链路4.1 用 Python 脚本跑单张与批量推理训练完拿到best.pt下一步是验证它在真实图片上的表现。YOLO11 的 Python 接口很简洁但有几个参数直接影响结果。下面这段代码同时处理单张和整个文件夹from ultralytics import YOLO import os # 加载训练好的权重 model YOLO(runs/tomato/exp1/weights/best.pt) # 单张推理conf 控制置信度阈值iou 控制 NMS 重叠阈值 results model.predict( sourcetest_images/one.jpg, conf0.35, iou0.5, imgsz640, saveTrue, projectinfer_out, namesingle ) # 批量推理整个文件夹 results model.predict( sourcetest_images/, conf0.35, iou0.5, imgsz640, saveTrue, projectinfer_out, namebatch ) # 打印每张图的检测框数量和类别 for r in results: boxes r.boxes print(os.path.basename(r.path), detected:, len(boxes))conf0.35是我在西红柿场景下的经验值。设太高会漏掉被叶片遮挡的果子设太低会把红色反光误判成西红柿。iou0.5用于非极大值抑制如果同一串西红柿挨得很近可以降到 0.4 让框更分散。saveTrue会把画了框的图片存到infer_out目录方便肉眼核对。4.2 评估指标与业务指标的换算YOLO11 验证时输出的mAP50是算法指标但分拣线关心的是“漏检率”和“误检率”。漏检率等于没被框住的真实西红柿数量除以总数误检率等于框错的果子数量除以总框数。这两个指标和conf直接相关我一般会跑一组不同conf的测试画一条漏检-误检曲线找业务能接受的平衡点。具体做法是准备 200 张有标注的测试图用model.val()得到预测结果然后写个小脚本统计。如果漏检率要求低于 5%conf通常要降到 0.25 左右但误检率会升到 10% 以上。这时候要么补充遮挡样本重新训练要么在业务侧加一道人工复核。没有免费的午餐参数调优只是在两个错误之间找平衡。4.3 导出 ONNX 与推理速度实测如果部署端不是 Python 环境可以把best.pt导出成 ONNXyolo export modelruns/tomato/exp1/weights/best.pt formatonnx imgsz640 simplifyTruesimplifyTrue会做一层图优化去掉冗余算子。导出后在目标机器上用 onnxruntime 加载实测yolo11n在 CPU 上单张推理约 80msyolo11s约 150ms在 GPU 上分别降到 8ms 和 12ms。如果分拣线节拍是每秒 5 个果子yolo11n加 GPU 完全够用。导出时注意imgsz要和训练时一致不一致会导致框的坐标偏移。5. 西红柿检测避坑记录从翻车到稳住5.1 标注框贴边导致训练发散现象训练前几个 epoch loss 正常下降到第 10 个 epoch 突然变成 NaN。原因部分标注框的坐标正好等于 0 或 1归一化后出现边界值YOLO11 在计算宽高损失时对 0 取了对数。解决写个脚本遍历所有 label 文件把小于 0.001 的值改成 0.001大于 0.999 的改成 0.999。改完重新训练loss 平稳下降。5.2 验证集 mAP 虚高但实际漏检严重现象验证集mAP50到 0.92但拿棚里新拍的照片测试漏检一半以上。原因训练集和验证集来自同一批照片的随机划分同一颗西红柿的不同角度可能同时出现在训练和验证里模型记住了背景而不是果子。解决按拍摄批次划分数据集同一批次拍的照片要么全在训练集要么全在验证集。重新划分后mAP50掉到 0.78但这才是真实水平。5.3 推理时框重叠严重现象一串西红柿被框了七八个框密密麻麻叠在一起。原因iou阈值设太高NMS 没有把重叠框抑制掉。解决把推理时的iou从 0.7 降到 0.45同时把conf从 0.25 提到 0.4。如果还有少量重叠可以在后处理里加一道按面积排序的过滤只保留置信度最高的框。5.4 青果被系统性漏检现象红果检测很准青果几乎全漏。原因训练数据里红果占 90% 以上模型学到了“红色等于西红柿”的捷径。解决补充青果样本至少让青红比例到 3:7。如果青果样本实在难采可以在增强里加大hsv_h扰动让红色样本的色调偏移到青绿色区间强迫模型学形状而不是颜色。5.5 导出 ONNX 后框坐标偏移现象PyTorch 推理正常ONNX 推理的框整体偏移几十个像素。原因导出时imgsz和推理时预处理的分辨率不一致或者 letterbox 的填充方式不同。解决导出和推理统一用imgsz640并且在 ONNX 推理前自己做 letterbox保持和 ultralytics 一致的缩放加填充逻辑。如果懒得写直接用 ultralytics 的model.predict加载 ONNX它内部会处理。6. 把西红柿检测推到可交付水平的两个进阶习惯第一个习惯是建立自己的“错题本”。每次在真实场景发现漏检或误检把那张图单独存到一个hard_cases文件夹标注好之后加入训练集重新微调。我一般每积累 50 张错题就重训一次三轮下来模型在棚内的漏检率能从 15% 压到 4% 以内。这个做法比盲目加数据有效得多因为错题代表的是模型当前的盲区针对性最强。第二个习惯是固定一套推理参数并记录版本。西红柿检测的conf、iou、imgsz三个值一旦在业务侧调好就写进配置文件不要每次手动改。同时把对应的best.pt权重文件用日期加版本号命名比如tomato_yolo11s_20240612_v3.pt。我吃过亏有一次分拣线换了新批次西红柿效果突然变差查了半天才发现是有人把推理脚本里的conf从 0.35 改成了 0.5权重没换参数变了。从那以后所有参数都进版本管理改任何一项都要走记录。还有一个技巧是善用 YOLO11 的model.val()做定期体检。每周拿最新采集的 100 张图跑一次验证看mAP50有没有掉。如果掉了超过 5 个点说明数据分布漂移了需要补样本重训。这个习惯花不了多少时间但能避免模型在不知不觉中退化。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

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