简介面向需要训练YOLO模型的目标检测开发者和学习者这份中草药图像数据集按YOLOv5目录结构整理已划分训练集、验证集和测试集可直接用于YOLO检测训练。数据包含8个类别如Cardamom、Cumin、Neem等采用YOLO相对坐标标注每张图片对应一个txt标签文件内容为类别和归一化后的边界框坐标。整套资源共2000个文件主要包括txt标注文件和一个可视化py脚本压缩包约209.51MB。其中训练集约2600张验证集约190张测试集约100张规模适中适合快速跑通实验。附带的可视化脚本无需任何修改随机传入一张图片即可绘制并保存标注框图像便于直观检查标注质量或用于展示。目前已有1017人学习下载适合作为中草药目标检测课程设计、论文实验或入门练习的数据基础。1. 中草药 YOLO 目标检测数据集我把它当做一个「能直接跑通」的标注样本集很多做农业识别、药材检测的团队卡在第一步不是模型选型而是标注数据的数量和质量。这份中草药图像目标检测数据集按 YOLOV5 文件夹规范保存训练集约 2600 张、验证集约 190 张、测试集约 100 张包含 Cardamom、Cumin、Neem 等 8 个类别自带类别 class 文件和数据可视化脚本。你把它下载解压后不用改目录结构写好一个 yaml 就能丢进 YOLOv5 训练。我拆过这个资源后发现它真正的价值不在「数据集有多大」而在「标签格式是否干净、可视化能否快速验证」这两件事。很多从 Roboflow 导出的数据集都有标签文件名错位、类别索引漂移的问题这份数据从文件名前缀.rf.来看同样来自 Roboflow 渠道所以拿到的第一步不是训练而是先解析标签内容确认坐标是不是合理范围再谈跑模型。下面我从目录结构、可视化检查、训练配置到验证排查完整走一遍。2. 解析数据集结构与 YOLO 标签格式classes 文件、相对坐标与目录坑2.1 目录结构为什么 images/labels 分离更利于训练先看整个数据集的保存方式它遵循 YOLOv5 的标准布局datasets/ ├── images/ │ ├── train/ # 约 2600 张 │ ├── val/ # 约 190 张 │ └── test/ # 约 100 张 ├── labels/ │ ├── train/ # 与 train 同名 .txt │ ├── val/ │ └── test/ ├── classes.txt # 8 个类别一行一个 └── show.py # 可视化脚本images 和 labels 分开存放是 YOLOv5 从 v5.0 开始推荐的做法。训练器通过图片路径推断 label 路径规则是把/images/替换为/labels/把图片后缀.jpg/.png替换为.txt。这里有两个坑值得注意。第一train/val/test 三个集合必须在 images 和 labels 下都有同名目录哪怕某个集合为空也要建目录否则脚本扫描时容易报dataset not found或label not found。第二数据集里给出的 test 集标注本身是存在的但很多 YOLOv5 自定义数据集流程里 test 不被使用我们通常把 val 当作验证集test 留作最终评估。2.2 class 文件与标签文件的对应关系classes.txt的内容是 YOLO 格式中类别索引的唯一依据。以本数据集为例打开后大约是Cardamom Cumin Neem ...每一行对应一个类别行号从 0 开始所以 Cardamom 的 class_id 是 0Cumin 是 1。标签文件里每一行格式是class_id x_centre y_centre width height例如2 0.531997 0.639688 0.216372 0.304687表示该目标属于索引为 2 的类别边界框中心点在图片相对坐标的 (0.532, 0.640) 处宽高分别占图片的 21.6% 和 30.5%。这里全部采用相对坐标取值范围应在 0 到 1 之间。我一般拿到标签后第一件事是按类别统计数量确认没有类别断层。比如有 8 个类别但标签里的 class_id 最大是 7如果出现 8 或 -1大概率是 classes.txt 顺序和标注顺序没对齐导致的。常见做法是用一条 Python 脚本扫描所有 labelimport os from collections import Counter label_root datasets/labels/train class_counter Counter() invalid_files [] for name in os.listdir(label_root): if not name.endswith(.txt): continue path os.path.join(label_root, name) with open(path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: invalid_files.append((name, field error)) continue cls_id int(parts[0]) if cls_id 0 or cls_id 8: invalid_files.append((name, fclass {cls_id} out of range)) else: class_counter[cls_id] 1 print(类别统计:, dict(sorted(class_counter.items()))) print(异常文件:, invalid_files[:10])这段脚本会把所有标签聚合到 8 个桶里同时找出字段数不对、类别索引越界的文件。判断标准很简单class_id 必须在[0, 7]区间坐标值必须在[0, 1]区间允许边界为 1但大于 1 就是越界。如果出现大量class_id为 0 且集中在某几个文件很可能是导出时 classes 文件损坏导致顺序错位需要重新对照源标注。2.3 重点验证标签坐标是否越界YOLO 相对坐标的越界问题在 Roboflow 导出的数据集中比较常见。原因通常是图片经过缩放或自动定向后原始标注没跟着变换。检测方法很简单def check_bounds(label_path): errors [] with open(label_path) as f: for i, line in enumerate(f): cls, x, y, w, h map(float, line.split()) if not (0 x 1 and 0 y 1): errors.append((i 1, center out of range)) if w 0 or h 0 or w 1 or h 1: errors.append((i 1, size out of range)) return errors运行后把异常的 label 记录到列表再结合可视化脚本逐张确认。对于轻微越界比如 x 为 1.02YOLOv5 的 dataloader 在训练时会自动 clip 到 1.0但这会造成目标框与原标注不一致对于严重越界比如负值则会在计算 loss 时产生异常梯度轻则 mAP 下降重则 loss 变成 nan。所以这一步不能省。3. 用数据可视化脚本检查标注质量先看懂 show.py 再改业务3.1 脚本运行方式与「随机取一张」的实现思路数据集自带的show.py设计成「随机传入一张图片即可绘制边界框并保存在当前目录」。它的循环逻辑大概是读取指定图片解析同名 txt 中的每一行用 OpenCV 或 PIL 在图上绘制矩形最终保存结果图。核心代码思路如下import cv2 import numpy as np import random import glob img_path random.choice(glob.glob(datasets/images/train/*.jpg)) txt_path img_path.replace(images, labels).replace(.jpg, .txt) img cv2.imread(img_path) h, w img.shape[:2] colors [(0, 0, 255), (0, 255, 0), (255, 0, 0)] # 示例颜色 with open(txt_path) as f: for line in f: cls, x, y, bw, bh map(float, line.split()) # 还原为像素坐标 cx, cy int(x * w), int(y * h) box_w, box_h int(bw * w), int(bh * h) x1, y1 cx - box_w // 2, cy - box_h // 2 x2, y2 x1 box_w, y1 box_h cv2.rectangle(img, (x1, y1), (x2, y2), colors[cls % 3], 2) cv2.putText(img, str(cls), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[cls % 3], 1) cv2.imwrite(show_output.jpg, img)这段代码的核心在于把 YOLO 相对坐标反算成像素坐标中心点乘图片宽高得到像素位置再以中心点为基准偏移宽高的一半。脚本注释里写「无需更改」确实可以直接运行但它有个隐藏限制如果没有设置随机种子每次运行结果都不一样不好复现问题图片。我建议运行前先random.seed(42)保证排查时多次运行能看到同一张图。3.2 改成指定目录批量检查的常见做法原脚本只随机看单张适合快速确认数据集不是全黑或全空。但要系统检查几百张验证集的标注质量我会改成「按目录扫描 输出拼图」的方式import os import cv2 def draw_one(img_path, txt_path, out_dir): img cv2.imread(img_path) if img is None: return False h, w img.shape[:2] with open(txt_path) as f: boxes [list(map(float, line.split())) for line in f] for cls, x, y, bw, bh in boxes: x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) basename os.path.basename(img_path) cv2.imwrite(os.path.join(out_dir, basename), img) return True # 遍历验证集 for name in os.listdir(datasets/images/val): if not name.endswith(.jpg): continue img_path os.path.join(datasets/images/val, name) txt_path os.path.join(datasets/labels/val, name.replace(.jpg, .txt)) draw_one(img_path, txt_path, vis_val)这样批量生成可视化图后随便挑几十张混排就能看出标注框是否贴合药材边界。批量检查的目的不是在屏幕前一张张看而是快速发现「空标注」和「异常框」两类问题。3.3 从可视化里能看出的常见标注意外第一类是标签存在但图片里几乎看不到目标这在中草药图片里很常见因为很多图是白底商品图目标颜色和背景非常接近第二类是同一个目标被重复标注比如一片 Neem 叶子被标了 3 个框训练时会让模型对同一区域输出重叠预测第三类是目标过小框只有十几个像素这类样本占比过高会拉低整体 mAP0.5:0.95。我用这个数据集时发现它的 photo studio 风格图片比较多背景干净、光线均匀模型在验证集上容易跑出高 mAP但放到真实货架或野外拍摄场景性能会明显回落。可视化脚本只能验证「标注对不对」不能验证「数据够不够真实」。这也是后面训练时要把数据增强加足的原因。4. 把数据集接入 YOLOv5 / YOLOv8 训练yaml 配置与命令行参数4.1 from「按 YOLOV5 文件夹保存」到训练数据的目录映射这份数据集既可以直接在 ultralytics/YOLOv5 仓库里用也能迁移到 YOLOv8。区别只在于 yaml 的写法。YOLOv5 的train.py期望传入一个.yaml路径里面写明train、val、test的绝对或相对路径以及names列表。目录结构不需要调整但建议把整个数据集放到与yolov5/同级的目录下保持相对路径稳定。4.2 编写 herbl.yaml 并核对 classes 顺序在数据集根目录创建herbl.yaml内容如下train: datasets/images/train val: datasets/images/val test: datasets/images/test nc: 8 names: [ Cardamom, Cumin, Neem, Turmeric, Holybasil, Fenugreek, Ginger, Cinnamon ]注意names里的顺序必须和classes.txt完全一致否则模型训练的类别和标注的 class_id 会错位。一个最常见的翻车写法是为了方便把所有类别名写成了拼音或中文导致训练代码在加载预训练权重时类别数对不上报错num_classes mismatch。本数据集的类别名是英文直接复制 classes.txt 即可。test字段可选如果只做训练和验证test 那一行可以删掉。4.3 训练命令、超参与显存取舍在 YOLOv5 仓库目录下训练命令是python train.py --data herbl.yaml --weights yolov5s.pt --img 640 \ --batch-size 16 --epochs 100 --project runs/train --name herb_run推荐用yolov5s.pt作为预训练权重而不是从零训练。中草药数据只有 2600 张属于小规模数据集迁移学习能显著降低对样本量的需求。参数含义如下--img 640训练时缩放图像尺寸。图片分辨率越高模型能学习到更多细节但显存占用成倍增长。--batch-size 16单卡 16 是中等配置8GB 显存建议降到 86GB 以下建议用--batch-size 4加梯度累积。--epochs 100小数据集训练 100 轮足够收敛继续增加容易过拟合。--project和--name指定保存目录方便多个实验对比。显存batch-size模型建议6GB4yolov5s开启--cache预加载数据8GB8yolov5s默认即可12GB16yolov5s / yolov5m可用--cos-lr提升收敛24GB32yolov5m可加--multi-scale如果改用 YOLOv8则命令变化不大yolo detect train dataherbl.yaml modelyolov8s.pt imgsz640 batch16 epochs100YOLOv8 会要求 yaml 路径、图片路径都是绝对路径或者在当前终端使用相对路径时确保datasets目录能被模型包识别。一个快速替代方案是把datasets目录移动到 YOLOv8 安装包内部的datasets文件夹下避免路径解析问题。我习惯在项目根目录写一个软链接而不是复制整个数据集节省磁盘空间ln -s $(pwd)/datasets /path/to/ultralytics/datasets这里处理的重点不是命令本身而是数据规模。2600 张图片对 8 类目标来说平均每类只有 300 多张训练时--augment参数默认开启的 mosaic、flip、hsv 变换会起到很大作用。不要因为验证集 mAP 高就关闭增强否则在真实场景中退化明显。5. 模型跑通的最后一公里验证集指标、标签错位与 loss 异常的排查5.1 验证集指标怎么看mAP0.5 与 PR 曲线训练完成后runs/train/herb_run/下会生成results.png、confusion_matrix.png和val_batch*.jpg。重点关注mAP0.5是否超过 0.9以及mAP0.5:0.95是否在 0.7 以上。如果 mAP0.5 很高但 0.95 很低说明模型对目标定位不够精细框偏大或偏小这时应检查标签框和真实目标边缘的贴合度。验证集指标我一般配合测试集使用python val.py --data herbl.yaml --weights runs/train/herb_run/weights/best.pt --task test用自己的测试集而不是训练时的验证集才能评估真实泛化能力。中草药数据集里的测试集只有 100 张统计波动大最好同时记录每次实验的混淆矩阵看看是哪些类别之间互相误检。5.2 标签、索引错位loss 为 nan图片无目标时的排错训练中最常见的三类问题第一loss 直接为 nan。原因通常是标签里有越界坐标或某些类别样本量极少导致局部梯度爆炸。解决方法是按 2.3 的脚本扫描所有标签同时检查每个类别的样本数样本数小于 10 的类别要慎重参与训练。第二训练能跑起来但 mAP 为 0。优先检查 yaml 里nc是否正确。如果 classes.txt 有 8 类但herbl.yaml里误写为 5训练过程不会报错只是输出结果全部错位。我通常用一个简单脚本打印预测结果里的类别索引results model(img) print(results.boxes.cls.unique())如果输出的是 0-4 但数据集里实际是 0-7基本就是 nc 错了。第三验证时提示No labels found in ...多半是 labels 目录下的子目录名与 images 不一致或者 label 扩展名不是.txt。用find datasets/labels -name *.txt | wc -l对照图片数量即可定位。5.3 用 val.py 导出错例做反向修正最后分享一个我拿到这类小数据集时必做的动作把验证集预测结果保存成带标签的图再人工快速扫一遍。python val.py --data herbl.yaml --weights runs/train/herb_run/weights/best.pt \ --save-txt --save-conf --project runs/val_inspect在runs/val_inspect/下的labels/里每个 txt 文件保存了预测的类别、置信度和坐标。我把这些 txt 和 Ground Truth 并排对比找出漏检最严重的图片如果同一张图连续多轮都漏检就回到可视化脚本重新看标注很多时候是标注框覆盖了目标的一半导致模型学到错误的边界。这种从预测到标注的反向修正在小样本数据集上带来的收益比调整损失函数更明显。本文还有配套的精品资源点击获取
