
简介这套基于YOLO11目标检测算法的西红柿检测资源包面向深度学习初学者、农业智能视觉开发者和算法落地工程师以西红柿识别为实战场景解决从数据集划分、标注格式转换、模型训练到可视化界面检测的完整链路问题。压缩包内含1322个文件主要由656张西红柿实拍图像、326份YOLO格式txt标签、321份原始XML标注构成另有Python训练推理脚本、pt预训练权重、yaml配置文件及训练日志等整体大小143.79MB文件组织层级清晰便于快速定位所需文件并投入二次开发。资源已有102人学习下载代码在Python与PyTorch环境下可直接运行既可以重新训练专属模型也能够加载已有权重在图形界面中选择图片完成实时识别能够帮助读者快速掌握YOLO11在农产品检测领域的项目实践适合毕业设计、课程作业或工程预研使用。1. 用 yolo11 目标检测算法做西红柿识别先想清楚这活儿值不值得干大棚里数果、估产、分拣成熟度靠人工一穗一穗数费眼且统计口径不一。用 yolo11 目标检测算法配合一份整理好的西红柿数据集 zip几天内能从零训出一个能框出青果、红果甚至病果的模型这是目前农业视觉落地里性价比最高的一条路。适合做设施农业信息化、采摘机器人视觉、或者毕业设计里「目标检测 数据集」这类课题的人。先说一个反直觉的结论真正卡住你的不是模型训练而是数据集本身的质量——类别怎么定、边界怎么标、小果大果怎么平衡这些才是决定 mAP 能不能上得去的核心。所以这篇会把环境、数据、训练、排查、部署完整走一遍你照着做就行。2. 先把 yolo11 环境跑通Windows 与 Linux 下能推理的最小命令集很多人拿到含数据集的 zip 包第一件事就想立刻开训结果卡在环境上半天。yolo11 的环境配置并不复杂但有几个细节不处理会浪费一下午。这里给一套我常用的最小安装路径Windows 和 Linux 通用。2.1 为什么选 yolo11 而不是从 yolov5 开始yolo11 是 Ultralytics 这条技术路线上的最新接力棒训练接口和 yolov8 一脉相承文档和坑位基本上都能沿用旧经验。你可能会搜到「yolo11 网络结构」相关的讨论说它改了 C2PSA、把 SPPF 做了变体但对做落地项目的人来说这些结构变化对精度的提升远不如你手上的数据质量影响大。选它的核心理由有三个预训练权重覆盖 COCO 类别做西红柿这样的单类检测迁移成本低训练和推理命令行统一不用在不同仓库之间来回切换导出 ONNX/TensorRT 的流程成熟后期上 Jetson 或者工业相机都比较顺。要注意的是yolo11 对环境的要求和 yolov8 基本一致Python 3.10 是稳妥选择PyTorch 版本尽量和你的 CUDA 驱动匹配。这里有个常见误区一上来就装最新版 PyTorch结果 CUDA 版本对不上GPU 推理变 CPU 推理训练速度直接慢十倍。先看nvidia-smi顶部显示的 CUDA 版本再决定装哪个 torch 轮子。2.2 安装 ultralytics 并验证 GPU 真的能用我一般会用 conda 建一个独立虚拟环境避免把系统 Python 搞乱。下面是完整命令# 创建虚拟环境Python 3.10 是稳妥选择 conda create -n yolo11 python3.10 -y conda activate yolo11 # 安装 ultralytics会自动带上 torch 相关依赖 pip install ultralytics # 验证 torch 能不能调用 GPU python -c import torch; print(torch.cuda.is_available())这段逻辑不复杂但有三个点容易踩坑。第一pip install ultralytics会默认拉一个 torch 版本如果你的机器有独立显卡最好先手动安装和 CUDA 匹配的 torch再装 ultralytics否则 pip 可能给你装上 CPU 版 torchtorch.cuda.is_available()输出 False后面训练全靠 CPU 硬扛。第二Conda 里 Python 版本不用追新3.10 足够3.12 和 3.13 反而可能遇到某些依赖没有预编译 wheel 的问题。第三如果你用的是笔记本电脑的核显加独显torch.cuda.is_available()返回 True 不代表训练速度快还要看训练时显存占用是否真的上去了。确认 GPU 可用之后建议顺手跑一次预训练权重推理验证整条链路是通的。2.3 用 yolo11 预训练权重先跑通一次推理环境装好后不要急着处理数据集。先拿一张普通图片验证模型能正常加载和推理这能帮你区分「环境问题」和「数据问题」。from ultralytics import YOLO # 首次运行会自动下载 yolo11n.pt 权重文件 model YOLO(yolo11n.pt) # 对单张图片推理conf 阈值控制框的置信度门槛 results model.predict(sourcetest.jpg, conf0.3) for r in results: # boxes.xyxy 是边框坐标boxes.cls 是类别索引boxes.conf 是置信度 print(r.boxes.xyxy) print(r.boxes.cls) print(r.boxes.conf)source参数可以接收图片路径、视频路径、目录路径甚至摄像头设备号。第一次运行如果网络不畅权重下载可能会卡住你可以检查当前目录下是否生成了yolo11n.pt文件。conf0.3这个阈值不是固定的预训练权重在 COCO 上跑普通图片用 0.25 就能看但后面做西红柿检测时阈值高一点能压掉不少误检低一点能找回更多小果实操时要在验证集上具体扫值。这一步跑通了才进入数据集处理阶段。3. 处理西红柿数据集 zip目录结构、坐标转换与类别平衡拿到「含数据集.zip」第一步不是解压就开始训练而是先搞清楚里面的组织方式。YOLO 系列对数据集的目录结构有约定解压后先看目录是否符合约定能避免后面一堆玄学报错。3.1 数据集解压后先检查这三样东西一份能直接用的西红柿检测数据集解压后通常包含三个部分images目录、labels目录、以及一个描述数据集的 YAML 文件。images 下面按train和val分目录放图片labels 目录与 images 目录结构一一对应每张图片对应一个同名.txt标注文件。YAML 文件里写了类别列表、类别数、以及 train 和 val 的路径。最常见的结构是这样的dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── 0002.jpg │ └── val/ │ ├── 1001.jpg │ └── 1002.jpg ├── labels/ │ ├── train/ │ │ ├── 0001.txt │ │ └── 0002.txt │ └── val/ │ ├── 1001.txt │ └── 1002.txt └── data.yaml先检查三点第一图片和标注文件是否同名后缀不同没关系文件名主体必须一致第二data.yaml 里的类别是「西红柿」单独一类还是细分成「青果、红果、半熟果」多类——这直接决定后面训练的输出维度第三train 和 val 的图片数量比例是否合理常见划分是 8:2 或 9:1如果 val 只有十几张图评估结果波动会很大你得自己重新划分。很多人拿到 zip 后直接跑训练报错「label 文件找不到」八成是 labels 目录下的文件名和 images 对不上或者 YAML 里路径写的是绝对路径解压目录变了之后就失效。我习惯把 data.yaml 里的路径改成相对路径这样整个 dataset 目录移动到哪里都能训练。3.2 把 VOC/JSON 标注转成 YOLO txt归一化坐标脚本如果你的西红柿数据集 zip 里带的是 XMLVOC 格式或者 JSONLabelme 格式那就不能直接喂给 yolo11 训练得先转成 YOLO 的 txt 格式。YOLO 的标注格式是五列类别索引、归一化中心点 x、归一化中心点 y、归一化宽度 w、归一化高度 h。全部坐标都要除以图片宽高做归一化。下面这个脚本可以把 VOC 格式 XML 批量转成 YOLO txtimport os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, class_names): os.makedirs(out_dir, exist_okTrue) tree ET.parse(xml_path) root tree.getroot() # 从 XML 里读图片宽高 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(name) # VOC 坐标是左上角和右下角 bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) # 转 YOLO 格式中心点 归一化宽高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止归一化后出现 0 或 1 的极端值 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: txt_path os.path.join(out_dir, os.path.basename(xml_path).replace(.xml, .txt)) with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) # 使用示例把 VOC 格式的 annotations 转成 labels voc_to_yolo(data/annotations/0001.xml, data/labels, [tomato])这个脚本有三个关键点。第一class_names列表顺序决定了类别索引训练时的 data.yaml 里names顺序必须和这里一致否则类别标号错位模型会学到错误映射。第二坐标归一化后一定要做越界裁剪标注框稍微出界会导致归一化值大于 1训练时损失计算异常表现为 loss 变成 nan。第三if lines这个判断很关键某些 XML 里没有任何有效目标对象如果生成空 txt 文件YOLO 训练会把整张图默认成背景反而影响训练跳过空文件更安全。3.3 统计类别分布与框尺寸识别不平衡问题西红柿检测最隐蔽的坑是类别不平衡。如果你的数据集把西红柿分成「青果」和「红果」两类而红果只占 5%训练出来的模型会对红果召回率极低。同样如果样本里大果占绝大多数、小果稀疏模型对小目标的检测能力会明显偏弱。所以训练前要先做一次统计。import os from collections import Counter label_dir dataset/labels/train class_counter Counter() size_distribution [] for txt_name in os.listdir(label_dir): if not txt_name.endswith(.txt): continue with open(os.path.join(label_dir, txt_name), r, encodingutf-8) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) w float(parts[3]) h float(parts[4]) class_counter[cls_id] 1 size_distribution.append((w * h)) # 归一化面积 print(各类别目标数量, class_counter) print(目标归一化面积分布) for area in sorted(size_distribution): if area 0.01: print(小目标面积 1%, area)统计结果如果显示某一类占比过低有两条路。一是数据增强对少数类做随机翻转、亮度调整、小角度旋转把样本量补上去二是修改 data.yaml 把细分类别合并成「tomato」单类先跑通框架后续再细分级。我见过不少翻车案例都是因为「红果目标只有几十个」却强行训练 100 轮最后的模型把红果全漏了。这个阶段多花 20 分钟做统计比训练完了再回头補数据省时间得多。4. 训练西红柿检测模型超参数设多少、日志怎么看数据准备完毕进入训练环节。yolo11 训练自己的数据集用的是迁移学习思路从预训练权重初始化再用你的西红柿数据微调。这一步的成败不只在命令更在你对参数的理解。4.1 用 yolo11s 作为起点训练命令与核心超参数常见的训练命令长这样yolo train modelyolo11s.pt datadata.yaml epochs100 imgsz640 batch16 device0model参数建议从yolo11s.pt开始而不是yolo11n.pt。n 系列是 nano速度快但精度有限s 是 small在单类检测任务上精度和速度的平衡最好。如果你的显存低于 8G可以退回 n如果显存充足并且目标很小直接上yolo11m.pt也行。imgsz是输入分辨率默认 640但西红柿果实尺寸差异大大棚里远距离拍摄的小果在 640 分辨率下可能只有十几个像素。这种情况下我会把imgsz调到 960 甚至 1280代价是训练时间上浮和显存占用增加。下面这个参数表是我在农业检测项目里常用的起点参数推荐值说明epochs100 起单类检测收敛快100 轮足够看趋势batch16显存不够就降到 8优先保证 batch 4imgsz640960小果多就调大显存不足就调小lr00.01迁移学习常见起始学习率patience30验证集 30 轮不提升就早停节省时间workers4Windows 下如果报错就改 0数据加载线程过多会崩device0指定用第一块 GPU没有 GPU 就写devicecpu。训练时 ultralytics 会在当前目录生成runs/detect/train文件夹里面每轮会写下一次的模型权重和一个results.png曲线图。很多新手只看终端刷的进度条没注意这个文件其实它是判断模型好坏的第一现场。4.2 成熟度检测必调的两个参数关闭 Mosaic 与类别权重训练西红柿检测时有一个参数经常被忽略close_mosaic。Mosaic 数据增强把四张图拼成一张能提升模型对小目标的鲁棒性但对西红柿这种果实密集、排列有规律的场景Mosaic 会把果实随机切碎导致最后几个 epoch 模型反而学不到真实的果实上下文。Ultralytics 支持在训练末尾自动关闭 Mosaicyolo train modelyolo11s.pt datadata.yaml epochs100 imgsz640 batch16 close_mosaic10close_mosaic10的意思是最后 10 轮关闭 Mosaic 增强让模型在接近真实分布的数据上微调。这个参数对西红柿检测的提升在我实际项目里比调整网络结构更明显。另外一个问题是类别权重。如果你分青果和红果两类且数据不平衡yolo11 的官方训练接口没有直接给class_weights参数常见做法是在数据层面解决对少数类做复制增强或者用flipud、hsv_h这类轻增强单独作用于少数类样本。我在实践里的经验是当一类样本少于另一类的三分之一时不要在损失函数层面做文章直接补数据更有效。补不了数据就合并类别先保证单类检测的精度稳定。4.3 训练日志怎么读别只看 loss要盯 P、R、mAP50训练跑起来之后终端会打印每组 epoch 的损失值和指标但这堆数字容易让人迷惑。西红柿检测场景里我主要看三个指标精确率 P、召回率 R 和 mAP50。loss 下降是正常的但不代表模型在变好尤其当训练 loss 和验证 loss 出现背离时优先怀疑过拟合。.txt训练日志里还有一组中间产物results.png曲线图。你会看到train/box_loss平稳下降metrics/precision和metrics/recall逐步上升metrics/mAP50(B)是最终衡量。对于西红柿单类检测mAP50-95 的波动比较大因为 95 的 IoU 阈值对密集重叠的果实太苛刻实际估产场景只要 mAP50 能到 0.9 以上漏检率在可接受范围内模型就能用了。我倾向于用召回率作为主要监控指标因为农业测产场景里漏检一个果比多框一个无关物体代价更大。如果你发现 R 值一直上不去先回头检查数据标注而不是急着换更大的模型。5. 西红柿检测的 5 个翻车现场排查从数据到推理逐一排雷训练和部署过程中会遇到一些看起来很「玄学」的问题其实背后都有具体的成因。这里把我在西红柿检测项目里常遇到的五类问题整理成排查清单每一条都是现象、原因、解决三步。5.1 绿果和叶子融为一体召回率一直上不去现象模型在验证集上把大量青果漏检但红果检测正常。看检测结果图绿果区域没有任何框或者框很小且置信度低。原因青果的颜色纹理与背景叶片高度相似模型没有学到足够的区分特征。另一个放大因素是标注不一致——有些标注框把青果连同遮挡它的叶子一起框进去了等于主动给模型灌入噪声。解决先做一轮标注清洗重新检查绿色果实的边界紧贴果实边缘重新标注其次把训练图片里的绿色通道增强或做 HSV 色彩抖动提高模型对色相差异的敏感度最后考虑把青果单独作为一个类别训练而不是和红果混在一起避免模型为了拟合红果而忽略绿果。5.2 果实重叠严重NMS 把小果的框压掉了现象一串西红柿里挨在一起的几个果实模型只输出一个框靠外的果实漏检。原因后处理 NMS 的 IoU 阈值过高重叠的框被视为同一个目标被合并另外标注阶段如果重叠果实被标注成一个框模型默认学到的就是「一个框包含多个果实」。解决训练后推理时把iou阈值从默认的 0.7 调到 0.4 或 0.5允许算法输出更多重叠框同时手动检查 labels 里是否有面积异常大的框——如果一串果实的整体框远大于单个果实说明标注源就有问题。更彻底的办法是对密集小果做切片推理也就是把大图切成 640×640 的块分别预测再把结果合并回原图坐标。5.3 训练 loss 降了但验证 mAP 停滞不动现象训练曲线里 box_loss 一路下降但 mAP50 在 60 轮之后几乎不再变化波动也不收敛。原因过拟合模型在训练集上拟合得很好但对验证集的泛化停滞还有一种情况是验证集本身太难包含大量遮挡、逆光的图片。解决先看验证集图片数量和分布如果 val 里全是严重遮挡的样本mAP 上不去是正常的重新划分验证集保留一部分简单样本作为基线其次给参数加正则把weight_decay默认的 0.0005 适当提高到 0.001或者减少epochs让训练早停最后做一次数据清洗把标注明显错误、图片过于模糊的样本直接从训练集剔除。5.4 把圆形红色物体误判成西红柿现象推理时辣椒、苹果甚至红色的包装盒被框成 tomato置信度还不低。原因单类模型只知道「红色圆形物体」是西红柿没有负样本做约束。训练集里如果只包含西红柿的图片模型缺乏「这个不是西红柿」的样例。解决最直接的办法是构造负样本——去网上找一批红色辣椒、苹果、番茄酱包装盒等图片放入数据集目录生成空的标签文件然后在训练命令里保留这些背景图。YOLO 训练会把无标注对象的图片当作背景参与学习。我通常把负样本比例控制在总样本的 10% 到 20%既能压误检又不干扰正样本学习。5.5 大棚膜反光和逆光导致半边果实变白检测结果抖动现象同一朵花上的西红柿顺光时稳定检测逆光或反光时时而检测到时而检测不到置信度在两个阈值之间来回跳。原因训练数据里光照多样性不足模型把高光区域的特征和西红柿特征做了错误关联。解决训练阶段使用hsv_h、hsv_s、hsv_v增强参数默认值在 ultralytics 里分别是 0.015、0.7、0.4可以把hsv_v调到 0.6 以上增加亮度扰动推理阶段对输入图片做 CLAHE 对比度增强或者直接换成在 HSV 空间训练的数据。最后一种办法是采集更多逆光时段的数据补进去农业场景光照变化大单纯靠增强很难完全兜住。6. 把模型收尾导出部署格式用验证集扫一遍置信度阈值训练完拿到best.pt只是第一步真正要投入使用还需要把它导出成适合推理的格式。如果你打算在 Windows 上跑 CPU 推理best.pt直接用就行如果要在 Jetson、工业相机嵌入式设备上跑或者用 OpenCV C 调模型就要导出 ONNX 或 TensorRT engine。# 导出 ONNX适合 CPU 或通用推理框架 yolo export modelbest.pt formatonnx imgsz640 opset12 # 导出 TensorRT engine适合 NVIDIA 嵌入式设备 yolo export modelbest.pt formatengine imgsz640 device0opset12是为了兼容性部分老旧的部署环境对高版本 ONNX opset 支持不好12 是一个安全选择。imgsz必须和训练时保持一致否则导出后的模型在推理时会有精度损失。导出成功后用onnxruntime或者 TensorRT 跑一次推理对比和 PyTorch 推理结果的一致性。如果框的位置和置信度差异明显先检查导出的imgsz是否写错。最后一步是固定置信度阈值。很多人直接用默认conf0.25对西红柿场景而言这个阈值通常偏低容易带出背景误检。我习惯在验证集上扫一组阈值找精确率和召回率的平衡点yolo val modelbest.pt datadata.yaml conf0.3 iou0.5 yolo val modelbest.pt datadata.yaml conf0.5 iou0.5看这两次输出里的 P 和 R。如果是大棚测产用我会选召回率更高的低阈值比如 0.3如果是分拣机械臂用误检会直接导致抓空我会选精确率更高的 0.5 甚至 0.6。这个判断没有标准答案取决定义在业务端。我做这类农业检测项目最大的教训是调了三天的网络结构不如花一天重新整理西红柿数据集的边界标注。模型结构是放大器数据质量才是原底。无论你用的是 yolo11 还是未来的新版本这条规律都不会变。希望这篇能帮你少走一段弯路把精力放回真正出效果的地方。本文还有配套的精品资源点击获取