ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

草莓成熟度目标检测数据集:3类530张图YOLOv8训练全流程

草莓成熟度目标检测数据集:3类530张图YOLOv8训练全流程 简介这份草莓成熟度目标检测数据集面向农业视觉算法开发者、高校实验室与农业机器人团队针对红色果实与背景区分困难、成熟度过渡模糊、果实成簇遮挡及公开数据类别粗糙等痛点提供细粒度三分类标注方案。资源包共1060个文件由530张高分辨率田间JPG图像与530个同名JSON标注文件一一对应压缩包约35.62MB标注覆盖unripe、semi-ripe、fully-ripe三个等级可直接用于YOLO、RT-DETR、Faster R-CNN等检测模型训练。图像包含叶片遮挡、果实重叠与多角度拍摄场景有助于提升模型在真实采摘环境中的鲁棒性其中半熟阶段对判断最佳采摘窗口尤具决策价值。该数据集规模适中既适合从头训练轻量级检测器也可作为大模型微调的高质量领域数据帮助资源有限的团队快速启动实验。目前已有69人学习下载。1. 草莓成熟度目标检测数据集3 类 530 张图能跑出什么结果草莓采摘季最头疼的不是没果子而是分不清哪颗能摘、哪颗还得等。熟过头的一碰就烂没熟的摘下来酸得没法卖。人工分拣靠肉眼一天下来眼睛发花标准还不统一。这份草莓成熟度目标检测数据集就是冲着这个场景来的——3 个类别、530 张标注图直接对应未熟、半熟、成熟三种状态拿来就能训 YOLO 系列模型。它不是那种动辄几万张的通用数据集规模不大但胜在场景聚焦、类别干净。适合谁用做农业视觉落地的算法工程师、想跑通目标检测全流程的学生、需要快速验证采摘机器人感知模块的团队。530 张图不算多但如果你正好卡在“找不到垂直场景数据”这一步它省掉的是最耗时的采集和标注环节。下面我从数据拆包、格式转换、训练配置到避坑把这条链路走一遍。2. 拆开这份数据集目录结构、标注格式与类别定义2.1 530 张图到底怎么分布的拿到一个目标检测数据集第一件事不是急着写训练脚本而是先搞清楚它的目录长什么样、标注文件在哪、类别编号怎么对应。这份草莓成熟度数据集常见的组织方式是按类别分文件夹或者按 train/val 划分后统一放 images 和 labels。我一般会先跑一段脚本把整体情况摸清楚避免后面训练时才发现某个类别样本少得可怜。import os from collections import Counter # 数据集根目录按实际解压路径改 root ./strawberry_dataset # 统计图片数量和标注文件数量 img_dir os.path.join(root, images) lbl_dir os.path.join(root, labels) img_files [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png, .jpeg))] lbl_files [f for f in os.listdir(lbl_dir) if f.endswith(.txt)] print(f图片总数: {len(img_files)}) print(f标注文件总数: {len(lbl_files)}) # 检查是否有图片没有对应标注 img_stems {os.path.splitext(f)[0] for f in img_files} lbl_stems {os.path.splitext(f)[0] for f in lbl_files} missing_lbl img_stems - lbl_stems missing_img lbl_stems - img_stems print(f缺标注的图片: {len(missing_lbl)}) print(f缺图片的标注: {len(missing_img)}) # 统计每个类别的框数量 cls_counter Counter() for lf in lbl_files: with open(os.path.join(lbl_dir, lf), r) as f: for line in f: parts line.strip().split() if len(parts) 5: cls_counter[int(parts[0])] 1 print(各类别框数量:, dict(cls_counter))这段脚本干的事很直接数图片、数标注、查配对、统计类别分布。参数方面root指向你解压后的数据集根目录img_dir和lbl_dir按实际结构调整。跑完之后重点看两个数一是缺标注的图片数量如果不是 0说明有图没标训练时要么剔除要么补标二是各类别框数量如果某一类只有几十个框后面训练时这一类大概率学不好需要做数据增强或者调整损失权重。530 张图按 3 类分平均下来每类不到 200 张。实际分布往往不均匀成熟和半熟可能占大头未熟样本偏少。这不是数据集的问题是真实场景就这样——草莓成熟过程中未熟状态持续时间短拍到的机会少。知道这个分布后面评估模型时心里有数。2.2 标注格式YOLO txt 还是 COCO json这份数据集大概率是 YOLO 格式的 txt 标注每行class_id x_center y_center width height坐标是归一化后的值。为什么我判断是 YOLO 格式因为关键词里带了“目标检测”和“yolov8训练自己的数据集”这类热词而且 530 张这个量级用 COCO json 有点重。但也不排除原始标注是 VOC xml 或者 LabelMe json需要转换。先确认格式再决定要不要转。用下面这段脚本快速判断import json import xml.etree.ElementTree as ET # 检查标注文件的实际格式 sample_lbl os.path.join(lbl_dir, lbl_files[0]) print(f样本标注文件: {sample_lbl}) with open(sample_lbl, r) as f: first_line f.readline().strip() print(f第一行内容: {first_line}) parts first_line.split() if len(parts) 5: print(格式判断: YOLO txtclass_id 归一化坐标) elif len(parts) 5: print(格式判断: 可能是其他格式需要进一步确认)如果第一行是 5 个值且后四个都在 0 到 1 之间那就是 YOLO 格式可以直接用。如果是 xml 文件那就得走 VOC 转 YOLO 的流程。转换逻辑不复杂读 xml 里的bndbox坐标做归一化按类别映射表写 txt。常见做法是用xml.etree.ElementTree解析然后逐文件写。注意转换时类别映射表一定要和data.yaml里的names顺序一致否则训练出来的模型会把成熟草莓识别成未熟的这种错误在推理时很难发现因为框的位置是对的只是标签错了。2.3 类别定义与 data.yaml 配置3 个类别对应草莓的三种成熟状态。具体命名可能是unripe、half_ripe、ripe也可能是immature、mature、overripe。不管原始命名是什么你需要在data.yaml里统一。这个文件是 YOLO 训练的入口配置路径和类别名都从这里读。# data.yaml path: ./strawberry_dataset # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 3 # 类别数 names: 0: unripe # 未熟 1: half_ripe # 半熟 2: ripe # 成熟path是根目录train和val是相对于path的子路径。nc必须和names的长度一致names的键从 0 开始连续。如果原始标注里的类别编号不是 0、1、2 而是 1、2、3那要么改标注文件要么在names里把 0 留空——但 YOLO 不允许留空所以必须改标注。这个坑我踩过训练时 loss 不降查了半天才发现类别编号从 1 开始模型把背景当成了 0 类。3. 用 YOLOv8 跑通训练从环境到第一轮推理3.1 环境搭建与依赖版本YOLOv8 用 ultralytics 包安装不复杂但版本兼容性有讲究。我一般会固定几个关键包的版本避免今天能跑明天就报错。# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装核心依赖 pip install ultralytics8.1.0 pip install torch2.1.0 torchvision0.16.0 --index-url https://download.pytorch.org/whl/cu118 # 验证安装 yolo checksultralytics版本选 8.1.0 是因为这个版本对 YOLOv8 的支持稳定API 没有大改。torch的版本看你的 CUDA 版本cu118 对应 CUDA 11.8。如果没 GPU用 CPU 也能跑就是慢。yolo checks会输出环境信息重点看 CUDA 是否可用、版本是否匹配。提示如果你之前装过其他版本的 ultralytics先pip uninstall ultralytics再装避免残留文件导致 import 报错。这个坑很常见尤其是从 YOLOv5 切过来的时候。3.2 训练命令与关键参数训练命令本身不复杂但参数怎么设直接决定模型能不能收敛、多久收敛。yolo detect train \ data./data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ project./runs/strawberry \ nameexp1逐项说data指向刚才配好的 yamlmodel用yolov8n.pt预训练权重n 是最小版本530 张图用 n 就够了用 l 或 x 反而容易过拟合epochs100是上限实际可能提前停imgsz640是输入尺寸草莓目标不算特别小640 够用如果图片里草莓占比很小可以提到 1280但显存翻倍batch16看显存调8G 显存跑 640 尺寸 16 差不多lr00.01是初始学习率YOLOv8 默认 0.01如果 loss 震荡厉害可以降到 0.001patience20是早停耐心值20 轮验证集指标不提升就停。训练过程中重点看三个输出box_loss、cls_loss、dfl_loss。box_loss降不下去说明框回归有问题可能是标注框不准确cls_loss降不下去说明分类有问题可能是类别不平衡或者标注标签错dfl_loss是分布焦点损失YOLOv8 特有的一般跟着 box_loss 一起降。3.3 训练结果解读与推理验证训练结束后runs/strawberry/exp1目录下会有weights/best.pt和weights/last.pt。best.pt是验证集指标最好的那个 epoch 的权重推理用它。# 单张图片推理 yolo detect predict \ model./runs/strawberry/exp1/weights/best.pt \ source./test_images \ conf0.25 \ saveTrueconf0.25是置信度阈值低于这个值的框不显示。草莓成熟度检测里如果漏检比误检更严重可以把conf降到 0.1如果误检太多提到 0.5。source可以是单张图、文件夹、视频甚至摄像头。推理结果会保存在runs/detect/predict下。验证集指标重点看mAP50和mAP50-95。mAP50是 IoU 阈值 0.5 时的平均精度这个数据集规模下能到 0.85 以上算不错。mAP50-95更严格一般会比mAP50低 10 到 20 个点。如果mAP50高但mAP50-95很低说明框的位置不够准可能是标注框松紧不一致。4. 避坑与排查530 张图训练时最容易翻车的五个点4.1 现象训练 loss 从第一轮就不降原因最常见的是data.yaml里的路径写错了模型读不到图片每轮都在学空白。其次是标注文件里的类别编号超出了nc的范围比如nc3但标注里出现了4。解决先跑一遍第 2 章里的统计脚本确认图片和标注能配对、类别编号在 0 到 2 之间。然后在data.yaml里用绝对路径试一次排除相对路径解析问题。如果路径没问题检查标注文件里有没有空行或者格式不对的行YOLO 读到空行会跳过但格式错的行会报错。4.2 现象某一类别的 mAP 始终为 0原因这一类样本太少或者标注时把这一类全标成了另一类。530 张图里如果未熟草莓只有 30 个框模型很难学到特征。解决先确认这一类到底有多少个框。如果确实少两个办法一是用数据增强对这一类图片做翻转、裁剪、色彩抖动扩充到和其他类差不多二是在训练时给这一类加权YOLOv8 支持通过cls_pw参数调整类别权重但效果不如直接补样本。如果框数量不少但 mAP 还是 0那就是标注错了回去检查标注文件里这一类的class_id是不是写成了别的。4.3 现象推理时框的位置对但标签全错原因data.yaml里names的顺序和标注文件里的class_id对应不上。比如标注时 0 是成熟、1 是未熟但names里 0 写成了未熟、1 写成了成熟。解决打开几个标注文件看class_id对应的实际类别然后调整names的顺序。这个错误在训练指标上可能看不出来因为mAP是按类别算的标签错了但框对了mAP可能还是高的只有推理可视化时才能发现。4.4 现象训练到一半显存爆了原因batch设大了或者imgsz设大了。YOLOv8 训练时显存占用和batch * imgsz^2成正比。解决先把batch减半如果还爆就降imgsz。另外workers参数设太大也会占显存一般设 4 或 8 就行。如果用的是共享 GPU别人也在跑任务显存不够是常态用nvidia-smi看实时占用挑空闲时段跑。4.5 现象验证集指标比训练集低很多原因过拟合。530 张图不算多如果模型参数量大、训练轮数多很容易过拟合。解决换更小的模型比如从yolov8s换到yolov8n加数据增强YOLOv8 默认开了 mosaic 和 mixup可以调大mosaic的概率加 dropout但 YOLOv8 的 dropout 在 backbone 里不好单独调最直接的是早停patience设小一点比如 10验证集不提升就停。5. 把 530 张图用透小数据集的增强策略与迁移技巧530 张图训一个三分类检测模型数据量是偏紧的。但小数据集有小数据集的打法核心思路是“让每一张图发挥出三张图的价值”。我一般会从三个层面下手离线增强扩样本、在线增强调参数、迁移学习锁 backbone。先说离线增强。YOLOv8 训练时自带的 mosaic、mixup、HSV 抖动是在线增强每轮随机变。但有些增强适合离线做比如对未熟这一类样本做针对性扩充。具体做法是把未熟样本单独拎出来做水平翻转、垂直翻转、随机裁剪、亮度对比度调整每张生成 3 到 5 个变体然后混回训练集。这样未熟的框数量能从几十个提到两三百个类别不平衡问题缓解很多。import cv2 import numpy as np import os import random # 对指定类别的图片做离线增强 def augment_minority_class(img_dir, lbl_dir, target_cls, augment_times3): img_dir: 图片目录 lbl_dir: 标注目录 target_cls: 需要增强的类别 id augment_times: 每张图生成几个变体 aug_img_dir os.path.join(img_dir, augmented) aug_lbl_dir os.path.join(lbl_dir, augmented) os.makedirs(aug_img_dir, exist_okTrue) os.makedirs(aug_lbl_dir, exist_okTrue) for lbl_file in os.listdir(lbl_dir): if not lbl_file.endswith(.txt): continue lbl_path os.path.join(lbl_dir, lbl_file) with open(lbl_path, r) as f: lines f.readlines() # 判断这个标注文件里是否包含目标类别 has_target any(int(l.split()[0]) target_cls for l in lines if l.strip()) if not has_target: continue img_name os.path.splitext(lbl_file)[0] .jpg img_path os.path.join(img_dir, img_name) if not os.path.exists(img_path): continue img cv2.imread(img_path) h, w img.shape[:2] for i in range(augment_times): # 随机水平翻转 if random.random() 0.5: aug_img cv2.flip(img, 1) new_lines [] for l in lines: parts l.strip().split() cls_id parts[0] x, y, bw, bh map(float, parts[1:]) x 1.0 - x # 水平翻转后 x 坐标取反 new_lines.append(f{cls_id} {x:.6f} {y:.6f} {bw:.6f} {bh:.6f}\n) else: aug_img img.copy() new_lines lines # 随机亮度调整 factor random.uniform(0.8, 1.2) aug_img np.clip(aug_img * factor, 0, 255).astype(np.uint8) # 保存增强后的图片和标注 aug_name f{os.path.splitext(lbl_file)[0]}_aug{i} cv2.imwrite(os.path.join(aug_img_dir, aug_name .jpg), aug_img) with open(os.path.join(aug_lbl_dir, aug_name .txt), w) as f: f.writelines(new_lines) print(f增强完成目标类别 {target_cls} 的变体已保存) # 对未熟类别假设 id0做增强 augment_minority_class(./strawberry_dataset/images/train, ./strawberry_dataset/labels/train, target_cls0, augment_times3)这段脚本的逻辑是找到包含目标类别的标注文件对对应的图片做翻转和亮度调整同时同步修改标注坐标。水平翻转时x_center要变成1 - x_center其他三个值不变。亮度调整不影响坐标。增强后的图片和标注存到augmented子目录训练时把data.yaml里的train路径改成包含增强数据的目录就行。参数方面augment_times3表示每张原图生成 3 个变体加上原图一共 4 张。如果未熟样本特别少可以提到 5。factor的范围 0.8 到 1.2 是亮度系数太大会导致颜色失真草莓的红色变成暗红或粉红反而干扰模型学习。再说在线增强的参数调整。YOLOv8 的默认增强参数在ultralytics/cfg/default.yaml里但训练时可以通过命令行覆盖。我一般会调这几个mosaic1.0保持默认mixup0.1稍微开一点hsv_h0.015、hsv_s0.7、hsv_v0.4是默认值如果草莓颜色差异大可以适当调大hsv_h。flipud0.5和fliplr0.5是上下和左右翻转概率草莓图片上下翻转后不太自然我一般把flipud降到 0.1。最后说迁移学习。YOLOv8 的预训练权重是在 COCO 上训的COCO 里没有草莓但有大量圆形物体和红色物体底层特征是可迁移的。我一般会冻结 backbone 的前几层只训 head 和后面的层。具体做法是在训练命令里加freeze10表示冻结前 10 层。530 张图这个量级冻结 10 层能明显降低过拟合风险同时训练速度也快不少。验证增强效果的方法很简单训两个模型一个用原始数据一个用增强数据对比验证集上的mAP50和各类别的recall。如果未熟类的recall从 0.5 提到了 0.7 以上说明增强有效。如果所有类的指标都降了说明增强过头了把augment_times降到 1 或者只做翻转不做亮度调整。从那以后我每次拿到小数据集都强制走一遍“统计分布 → 离线增强 → 冻结训练 → 对比验证”这个流程不再直接怼默认参数。希望帮到你。本文还有配套的精品资源点击获取
返回列表