简介:这是一份面向农业智能化与计算机视觉方向的杂草检测目标检测数据集,适合正在做YOLO系列算法训练、课程设计或科研实验的开发者与研究生使用。数据集共6847张图像并全部带标签,已按训练与验证需求划分完毕,同时提供data.yaml配置文件,可直接对接yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流框架,省去自行标注与划分的繁琐流程。压缩包内共2000个文件,以xml标注文件为主要类型,对应VOC格式的类别与边界框信息,另附YOLO格式的txt标签,采用归一化中心点与宽高表示,方便不同训练管线直接读取。资源包整体约238.8MB,体积适中,便于本地解压与快速迭代实验。目前已有308人学习下载,说明其在同类数据集中具备一定参考价值。对于需要验证杂草识别模型、对比不同YOLO版本性能或搭建农业视觉原型的读者,这份数据可提供从标注到配置的完整起点,减少前期数据准备成本。
1. 杂草检测数据集到底能省多少事:6847 张带标签图像的落地价值
如果你正在做农业视觉相关的目标检测,大概率经历过这样的循环:找公开数据集、发现类别不对、自己爬图、标了三百张就崩溃、模型训出来 mAP 惨不忍睹。杂草检测这个场景尤其折磨人——田间光照变化大、杂草和作物幼苗形态高度相似、遮挡严重,随便凑几百张图根本训不出能用的模型。这份 6847 张图像的杂草检测数据集,价值就在于它把最耗人力的标注环节直接跳过了,而且同时给了 YOLO 格式(txt)和 VOC 格式(xml)两套标签,不管你用的是 yolov5、yolov8 还是更新的 yolo11,拿到手改一下 data.yaml 的路径就能开跑。它适合两类人:一是想快速验证杂草检测方案可行性的算法工程师,二是拿它做课程设计或毕设的学生——数据已经划分好,不用自己写 split 脚本,省下来的时间可以花在模型改进上。下面我从数据组织、格式转换、训练配置到踩坑排查,把这份资源完整拆一遍。
2. 数据集结构与两种标签格式:先搞清楚手里有什么
2.1 目录组织与文件命名规律
拿到压缩包解压后,你会看到图像文件和标签文件是分开存放的。从项目正文给出的文件名来看,标注文件采用img_XXXX_YYYY.xml的命名方式,其中XXXX是图像序号,YYYY是该图对应的标注序号。这种命名说明原始标注可能是在多轮标注或多人协作下产生的,同一个图像编号下出现了多个 xml 文件。
常见做法是图像放在images/目录下,标签按格式分别放在labels_yolo/和labels_voc/两个文件夹中。数据集已经预先划分好训练集、验证集和测试集,目录结构大致如下:
weed_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels_yolo/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels_voc/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml提示:解压后先别急着训练,用
find . -name "*.xml" | wc -l和find . -name "*.txt" | wc -l分别统计两种标签的数量,确认和图像总数 6847 是否对得上。如果某个 split 下标签数量少于图像数量,说明存在漏标,需要先排查。
2.2 YOLO 格式与 VOC 格式的对应关系
YOLO 格式的 txt 文件每行代表一个目标框,格式为<class> <x_center> <y_center> <width> <height>,五个值之间用空格分隔。其中 class 是类别索引从 0 开始,后面四个值都是归一化到 0 到 1 之间的比例值,分别表示边界框中心点的 x 坐标、y 坐标以及框的宽度和高度。这种归一化设计的好处是模型输入分辨率改变时不需要重新计算坐标。
VOC 格式的 xml 文件则保留了绝对像素坐标,结构如下:
<annotation> <filename>img_0100.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>weed</name> <bndbox> <xmin>120</xmin> <ymin>85</ymin> <xmax>310</xmax> <ymax>290</ymax> </bndbox> </object> </annotation>两种格式的换算关系很直接:x_center = (xmin + xmax) / 2 / width,y_center = (ymin + ymax) / 2 / height,w = (xmax - xmin) / width,h = (ymax - ymin) / height。如果你后续要接入 MMDetection 或 Detectron2 这类框架,VOC 格式会更方便;如果直接用 ultralytics 系列,YOLO 格式是首选。
2.3 data.yaml 配置文件的关键字段
数据集自带的data.yaml是 ultralytics 框架训练时的入口配置,核心字段包括:
path: ./weed_dataset train: images/train val: images/val test: images/test nc: 1 names: - weedpath是数据集根目录,train/val/test是相对于根目录的图像路径,nc是类别数,names是类别名称列表。这里nc: 1说明当前数据集只标注了一个类别“weed”,如果你的任务需要区分不同杂草种类,需要回到标注阶段重新处理。names的顺序必须和标签文件中的 class 索引严格对应,否则模型学到的类别会完全错乱。
注意:不同版本的 ultralytics 对
path字段的解析行为有差异。yolov5 时期path可以是相对路径,但 yolo11 更推荐写绝对路径,避免因为工作目录变化导致找不到数据。我一般会在训练脚本里用os.path.abspath()动态生成绝对路径再传给 YAML。
3. 从零跑通训练:yolov8 与 yolo11 的配置差异
3.1 环境准备与依赖安装
训练之前先把环境搭好。ultralytics 系列对 PyTorch 版本有要求,yolov8 和 yolo11 都建议用 PyTorch 2.0 以上版本。以下是我在 Ubuntu 22.04 + CUDA 12.1 环境下验证过的安装流程:
conda create -n weed_yolo python=3.10 -y conda activate weed_yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics安装完成后用yolo checks命令验证环境,它会输出 PyTorch 版本、CUDA 是否可用、GPU 型号等信息。如果 CUDA 显示不可用,先检查驱动版本和 PyTorch 的 CUDA 版本是否匹配,这是新手最容易翻车的地方。
3.2 用 yolov8 跑第一轮基线训练
环境就绪后,先跑一轮基线训练确认数据和配置没问题。以下命令用 yolov8n 预训练权重做迁移学习:
yolo detect train \ data=./weed_dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=weed_runs \ name=baseline_v8n参数说明:data指向 data.yaml 路径;model指定预训练权重,yolov8n 是最小的 nano 版本,适合先验证流程;epochs=100是训练轮数,杂草检测这种单类别任务通常 100 到 200 轮足够收敛;imgsz=640是输入分辨率,和大多数预训练权重一致;batch=16在 8GB 显存下比较稳妥,显存不够就降到 8;device=0指定第一块 GPU;project和name控制输出目录。
训练过程中重点关注三个指标:box_loss是否稳定下降、mAP50是否在 50 轮后开始收敛、cls_loss是否出现异常波动。如果box_loss在前 10 轮就降到很低但 mAP 上不去,大概率是标签格式有问题,需要回头检查 txt 文件内容。
3.3 切换到 yolo11 的注意事项
yolo11 在 ultralytics 中的调用方式和 yolov8 几乎一致,主要区别在于模型权重文件和部分超参数默认值:
yolo detect train \ data=./weed_dataset/data.yaml \ model=yolo11n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ project=weed_runs \ name=baseline_v11nyolo11 的 nano 版本在同等参数量下 mAP 通常比 yolov8n 高 1 到 2 个点,但训练时间会略长。如果你用的是 yolov5,配置文件格式稍有不同,yolov5 的 data.yaml 需要额外指定train和val为 txt 列表文件路径,而不是目录路径。这一点在跨版本迁移时经常被忽略,导致训练直接报错找不到文件。
3.4 验证与推理:确认模型真的学到了东西
训练结束后,用验证集跑一次评估:
yolo detect val \ model=weed_runs/baseline_v11n/weights/best.pt \ data=./weed_dataset/data.yaml \ imgsz=640 \ batch=16输出会给出每类的 Precision、Recall、mAP50 和 mAP50-95。单类别杂草检测如果 mAP50 低于 0.6,说明要么数据标注质量有问题,要么训练轮数不够。我一般会先用yolo detect predict在几张测试图上做可视化推理,直观看看框的位置和置信度:
yolo detect predict \ model=weed_runs/baseline_v11n/weights/best.pt \ source=./weed_dataset/images/test \ conf=0.25 \ save=Trueconf=0.25是置信度阈值,低于这个值的检测框会被过滤掉。杂草检测场景下如果漏检严重,可以降到 0.15 试试;如果误检太多,就提高到 0.4 以上。推理结果默认保存在runs/detect/predict/目录下。
4. 避坑与排查:标注、路径、显存这三类问题最要命
4.1 标签文件存在但训练报“no labels found”
现象:训练启动后日志显示no labels found in ...,但你去对应目录下看,txt 文件明明存在。
原因:ultralytics 在加载 YOLO 格式标签时,会按照图像路径自动推导标签路径。默认规则是把图像路径中的images替换为labels。如果你的目录结构是images/train/和labels_yolo/train/,框架找不到labels/train/就会报这个错。
解决:要么把labels_yolo改名为labels,要么在 data.yaml 中显式指定labels字段的路径。我一般直接改目录名,省得配置文件写得太复杂。
4.2 训练 loss 正常但 mAP 始终为 0
现象:box_loss 和 cls_loss 都在下降,但验证时 mAP50 一直是 0。
原因:最常见的情况是类别索引不匹配。比如 data.yaml 里写了nc: 1,但标签文件中的 class 值不是 0 而是 1 或其他数字。另一种可能是坐标没有归一化,txt 文件里存的是绝对像素值而不是 0 到 1 的比例值。
解决:随机抽几个 txt 文件,用cat看一下内容。正常的 YOLO 标签应该是类似0 0.523 0.412 0.156 0.238这样的格式,所有数值都在 0 到 1 之间。如果看到0 335 198 100 152这种,说明是绝对坐标,需要写脚本转换。
4.3 显存溢出导致训练中断
现象:训练跑了几十个 epoch 后突然报 CUDA out of memory。
原因:ultralytics 默认开启 AMP 混合精度和缓存机制,长时间训练后显存碎片化会累积。另外如果batch设得太大,前期能跑但后期验证阶段加载额外数据时就会爆。
解决:把batch降到 8 或 4,或者在训练命令中加cache=False关闭数据缓存。如果还是不行,用amp=False关闭混合精度,代价是训练速度会慢一些。8GB 显存跑 640 分辨率、batch=16 是临界值,建议直接设 batch=8 更稳。
4.4 VOC 格式 xml 中的 size 字段与实际图像不符
现象:用 VOC 格式标签做转换时,发现转换后的 YOLO 坐标超出 0 到 1 范围。
原因:部分 xml 文件中的<width>和<height>记录的是标注时的图像尺寸,但实际图像可能被裁剪或缩放过了,导致尺寸不一致。
解决:转换脚本中不要直接读 xml 里的 size,而是用 PIL 或 OpenCV 读取实际图像的宽高来计算归一化坐标。这样即使 xml 元数据有误,转换结果仍然正确。
4.5 训练集和验证集图像分布不一致
现象:训练集 mAP 很高但验证集 mAP 低很多,差距超过 15 个点。
原因:数据集虽然预先划分好了,但如果划分时没有做分层采样,可能出现训练集里某种光照条件的图像多、验证集里另一种条件多的情况。杂草检测对光照和背景非常敏感,这种分布偏移会直接反映在指标上。
解决:先可视化对比训练集和验证集各抽 20 张图,看光照、密度、背景是否有明显差异。如果差异大,用sklearn.model_selection.train_test_split按图像亮度或绿色像素占比做分层重新划分。这一步多花半小时,能省掉后面调参的很多玄学时间。
5. 进阶技巧:用标签格式转换脚本打通 VOC 与 YOLO 双通道
实际项目中经常遇到的情况是:数据集给了两种格式,但你的训练框架只认其中一种,或者你需要把这份数据和其他 VOC 格式的数据集合并使用。这时候一个可靠的格式转换脚本就是刚需。下面这个脚本同时支持 VOC 转 YOLO 和 YOLO 转 VOC,并且处理了前面提到的 size 不一致问题。
import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): """将 VOC xml 转为 YOLO txt 格式,返回写入的行列表""" tree = ET.parse(xml_path) root = tree.getroot() # 用实际图像尺寸而非 xml 中的 size,避免元数据不一致 img = Image.open(img_path) img_w, img_h = img.size lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text if cls_name not in class_map: continue cls_id = class_map[cls_name] 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) # 归一化并限制在 0-1 范围内 x_center = max(0, min(1, (xmin + xmax) / 2 / img_w)) y_center = max(0, min(1, (ymin + ymax) / 2 / img_h)) w = max(0, min(1, (xmax - xmin) / img_w)) h = max(0, min(1, (ymax - ymin) / img_h)) lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") return lines def batch_convert(voc_dir, img_dir, out_dir, class_map): """批量转换,保持文件名对应关系""" os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(voc_dir): if not xml_file.endswith('.xml'): continue stem = os.path.splitext(xml_file)[0] # 尝试匹配常见图像扩展名 img_path = None for ext in ['.jpg', '.jpeg', '.png', '.bmp']: candidate = os.path.join(img_dir, stem + ext) if os.path.exists(candidate): img_path = candidate break if img_path is None: print(f"跳过 {xml_file}:找不到对应图像") continue lines = voc_to_yolo(os.path.join(voc_dir, xml_file), img_path, class_map) out_path = os.path.join(out_dir, stem + '.txt') with open(out_path, 'w') as f: f.write('\n'.join(lines)) if __name__ == '__main__': # 类别映射:根据 data.yaml 中的 names 顺序定义 class_map = {'weed': 0} batch_convert( voc_dir='./weed_dataset/labels_voc/train', img_dir='./weed_dataset/images/train', out_dir='./weed_dataset/labels_yolo/train', class_map=class_map )脚本的逻辑分三层:voc_to_yolo负责单个文件的解析和坐标换算,batch_convert负责批量遍历和文件名匹配,主程序定义类别映射后调用。几个关键参数需要根据实际情况调整:class_map必须和 data.yaml 中的names顺序一致,否则类别索引会错位;img_dir要和voc_dir下的文件名能对应上,脚本会自动尝试四种常见图像扩展名。
转换完成后,建议写一个校验脚本抽查转换结果:
import os def validate_yolo_labels(label_dir, num_classes=1): """检查 YOLO 标签的格式合法性""" issues = [] for txt_file in os.listdir(label_dir): if not txt_file.endswith('.txt'): continue path = os.path.join(label_dir, txt_file) with open(path) as f: for line_no, line in enumerate(f, 1): parts = line.strip().split() if len(parts) != 5: issues.append(f"{txt_file}:{line_no} 字段数={len(parts)}") continue cls_id = int(parts[0]) if cls_id < 0 or cls_id >= num_classes: issues.append(f"{txt_file}:{line_no} 类别越界={cls_id}") for val in parts[1:]: v = float(val) if v < 0 or v > 1: issues.append(f"{txt_file}:{line_no} 坐标越界={v}") return issues if __name__ == '__main__': problems = validate_yolo_labels('./weed_dataset/labels_yolo/train') if problems: for p in problems[:20]: print(p) print(f"共发现 {len(problems)} 处问题") else: print("标签校验通过")这个校验脚本会检查每行是否恰好 5 个字段、类别索引是否在有效范围内、坐标值是否在 0 到 1 之间。我一般会在每次转换后跑一遍,确认没有越界或格式错误再开始训练。从那以后我每次拿到新数据集,不管它声称格式多标准,都强制走一遍校验脚本再进训练流程,这个习惯帮我省下了至少三次通宵排查标签问题的时间。希望帮到你。
本文还有配套的精品资源,点击获取