资讯中心

1373张水稻杂草数据集训练YOLO:格式转换与避坑指南

📅 2026/9/28 12:20:05
1373张水稻杂草数据集训练YOLO:格式转换与避坑指南
简介面向目标检测学习与农业智能除草场景的水稻田杂草数据集收录了从行走拍摄录像中截取的1373张清晰图片每张均附带矩形框标注类别统一为weed适合训练轻量级检测模型。压缩包共2000个文件主要包括1373个VOC格式xml标注文件和627个txt文件另附说明文档整体体积约122.61MB目录为图片、标注与标签三类文件夹便于查找。数据同时提供Pascal VOC与YOLO两种标注格式目录按JPEGImages、Annotations、labels三层组织便于直接接入YOLO、SSD等常见检测框架也方便转换为其他格式图片未做增强分辨率清晰可直接作为基础训练集。目前已有187人学习下载。对需要快速获取农业场景目标检测训练数据的团队这套数据可省去采集与标注环节直接用于模型训练、验证和算法研究也可用于迁移学习与模型微调。1. 1373张杂草数据集能训练出什么样的YOLO检测器做农业视觉检测的工程师拿到“水稻中杂草数据集检测yolovoc格式1373张.zip”这类资源时第一反应通常是两个极端要么觉得太少不值得训要么觉得“图片标注都齐了直接跑通就完事”。这两个判断都有问题。1373张图放在目标检测任务里确实属于小规模但对水稻田场景下的杂草识别来说它正好卡在一个有意思的档位——足够覆盖常见杂草类别和田间光照变化又小到必须认真对待每张图的标注质量和训练策略。这套数据集的核心价值不在于“量大”而在于它是yolo和voc双格式交付省去了标注格式转换的前期工作能不能让它发挥价值取决于你是否清楚VOC坐标和YOLO归一化坐标之间的换算关系以及小数据集训练时那些隐蔽的坑。这篇文章直接讲怎么做。2. 从VOC到YOLO双格式标注的底层逻辑与工程目录搭建2.1 VOC和YOLO格式的底层差异一读就懂的标注坐标系VOC格式和YOLO格式描述的是同一个框但坐标系完全不同。VOC的XML文件里记录的是绝对像素坐标四个关键节点是xmin、ymin、xmax、ymax单位是图片的像素。比如一张1920×1080的田间俯拍图一株杂草的框可能是 xmin320 ymin540 xmax480 ymax720。YOLO格式的TXT文件则使用归一化坐标每一行是class_id x_center y_center width height前四个值全部除以图片宽高范围在0到1之间。同样是这个框如果图片宽1920、高1080计算方式是x_center (320 480) / 2 / 1920 0.2083y_center (540 720) / 2 / 1080 0.5833width (480 - 320) / 1920 0.0833height (720 - 540) / 1080 0.1667归一化坐标的好处在于不依赖图像分辨率。YOLO训练时会对输入图片做letterbox缩放原图尺寸变化不影响标注有效性。VOC格式的好处则是可读性强标注工具如LabelImg的原生输出就是XML人工检查边界框时直接看像素值更直观。在这个数据集里同时提供两种格式意味着你已经有了一个天然的交叉验证机会。很多初学者拿到双格式数据直接开训从不检查两种格式是否一致结果训练集和验证集用了不同格式的标注模型性能飘忽不定还找不到原因。我建议拿到压缩包后做的第一件事是抽三到五张图手工比对XML和TXT的框是否对应同一区域这一步能排除掉数据集打包时可能出现的格式转换错误。2.2 目录怎么摆让YOLO不报错的最小工程结构YOLO的训练脚本对数据集目录结构有约定俗成的要求虽然不同版本YOLOv5、YOLOv8、YOLOv11细节略有差异但基本骨架一致。解压这个数据集后建议重建以下目录结构weeds_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── voc_annotations/ │ ├── train/ │ └── val/ ├── data.yaml └── README.mdimages和labels是YOLO训练直接读取的目录voc_annotations保留原始XML用于后续人工检查和重新转换。注意一个关键点images/train里的文件名必须和labels/train里的文件名一一对应扩展名不同没关系——图片是.jpg标签是.txt但主文件名必须完全一致。实际数据集中偶尔会出现标签文件比图片多一个、或者某个图片少了对应标签文件的情况这种不齐会导致训练时随机报错报错信息还往往不直接指向缺文件而是指向索引越界之类非常难排查。划分比例方面1373张图按8:1:1划分比较稳妥训练集约1098张、验证集约138张、测试集约137张。如果追求更充分的训练数据可以把测试集暂时并入验证集先用9:1跑基线模型选型完成后再用完整8:1:1划分做最终评估。小数据集的验证集张数本来就少再扣掉测试集val上的评估波动会很大。2.3 格式转换脚本XML转TXT的完整实现与参数说明虽然数据集声称同时提供YOLO和VOC格式但实际使用中几乎一定会遇到格式不统一的情况——新标注了一批图片只有XML、别人发来的数据集只有TXT、或者需要把YOLO格式转回VOC做人工复核。写一个健壮的转换脚本比手工操作Excel和文件管理器可靠得多。import os import xml.etree.ElementTree as ET from pathlib import Path def voc_xml_to_yolo_txt(xml_path, out_dir, class_names): 将VOC XML标注转换为YOLO TXT标注 Args: xml_path: XML文件完整路径 out_dir: TXT输出目录 class_names: 类别名称列表索引即类别ID os.makedirs(out_dir, exist_okTrue) tree ET.parse(xml_path) root tree.getroot() # 获取图片宽高归一化必须依赖这两个值 img_width int(root.find(size/width).text) img_height int(root.find(size/height).text) txt_path os.path.join(out_dir, Path(xml_path).stem .txt) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_names: # 遇到未知类别直接跳过比崩溃更适合批处理 print(f[WARN] {xml_path} 包含未知类别: {cls_name}) continue cls_id class_names.index(cls_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # VOC的xmax/ymax是包含边框的YOLO计算宽高时建议减1避免边缘漂移 x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height # 归一化结果必须钳位在0~1越界值会直接导致训练loss变NaN x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(max(width, 0.0), 1.0) height min(max(height, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 没有有效目标的XML静默跳过不生成空TXT if lines: with open(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines) \n) # 使用示例 classes [rice_seedling, barnyard_grass, broadleaf_weed] # 以数据集实际类别为准 xml_dir voc_annotations/train txt_out_dir labels/train for xml_file in Path(xml_dir).glob(*.xml): voc_xml_to_yolo_txt(str(xml_file), txt_out_dir, classes)这段脚本里值得注意的有三处。第一img_width和img_height必须从XML的size节点读取不能自己用图像文件的实际尺寸替代——虽然通常这两者一致但有些标注工具会把标注尺寸和图像尺寸写岔以XML为准才是标注的原始语义。第二归一化坐标的钳位处理min(max(...))看起来多余实际很关键。标注框完全落在图像内是理想情况但田间图片经常出现杂草在图像边缘被截断、标注框超出边界的现象不做钳位的话YOLO训练时会出现loss为NaN或边界框回归发散的问题。第三未知类别时用警告跳过而不是抛出异常是为了批处理几百个文件时不中断。如果警告数量超过总文件数的5%说明类别名称和配置不一致需要停下来重新对类别列表。反向转换TXT转XML的原理相同只需要把归一化坐标乘回图片宽高但需要额外处理一件事YOLO格式不记录类别名称只有类别ID转换时必须依赖你维护的class_names列表的索引顺序。这也提醒你训练配置里的类别顺序一旦定下来中途不要修改否则全部标注的语义都会错位。3. 把1373张图喂进YOLO数据配置、训练命令与参数选择3.1 data.yaml 怎么配路径、类别和验证集划分YOLO系列训练的第一步是写好数据配置文件。这个文件决定了训练脚本去哪里找图、去哪里找标注、有几个类别、类别叫什么名字。很多报错都出在这个文件的路径写法上——相对路径和绝对路径混用、Windows反斜杠与Linux正斜杠混用是最高频的翻车原因。# data.yaml path: /home/user/weeds_dataset # 数据集根目录建议写绝对路径 train: images/train # 相对path的训练集图片目录 val: images/val # 相对path的验证集图片目录 test: images/test # 可选有就填没有可删除该行 # 类别名称顺序必须与TXT标签中的class_id一一对应 names: 0: rice_seedling 1: barnyard_grass 2: broadleaf_weed这里最容易被忽略的是names的缩进。YOLOv5的配置支持names: [rice_seedling, barnyard_grass, broadleaf_weed]这种列表写法也支持上面这种键值对写法YOLOv8只用键值对写法。但无论哪种写法顺序就是类别ID。如果数据集里的TXT第一列是0那就代表rice_seedling不是barnyard_grass。改类别顺序等于重标全部数据即便只训练一个模型也会造成评估结果完全不可信。另外需要确认train和val指的是images子目录不是labels。YOLO的训练脚本会依据图片路径自动推导标注路径——把images/train替换为labels/train——如果配置指向了错误的目录层级报错里会出现 “Label not found” 之类的提示但有时也会静默跳过缺失标签的图片导致最终训练只用了部分数据。3.2 训练命令与关键参数解读以YOLOv8为例最小训练命令如下yolo detect train \ --model yolov8n.pt \ --data data.yaml \ --epochs 100 \ --imgsz 640 \ --batch 16 \ --patience 20 \ --project runs/weed_detection \ --name baseline_640拆解参数含义--model yolov8n.pt加载预训练权重。n代表nano是YOLOv8系列里最小、最快的版本。为什么小数据集先用nano而不是large或x因为1373张图不足以支撑大模型的容量大模型在这个数据规模上几乎必然过拟合val mAP反而低于小模型。先用nano跑通基线确认数据没问题后再尝试yolov8s.pt或yolov8m.pt逐步升档。--imgsz 640训练输入尺寸。田间图像如果是高分辨率版本比如1920×1080以上640的输入可以让模型看到更多上下文缺点是杂草目标本身偏小缩小后可能丢失细节。通常先按640跑后续可以对比896等更大分辨率但要留意显存占用。--batch 16批大小。显存不够就降到8或4但BN层的稳定性会变差这点后面避坑章节专门展开。--patience 20早停耐心值。连续20个epoch验证集指标没有提升就自动停止小数据集训练时这个参数特别有用——模型通常在30到50个epoch就收敛或过拟合没必要硬跑满100个epoch。--project和--name把每次实验的输出放到独立目录。实验多了之后会发现这个习惯简直是后悔药不然runs/detect/train被反复覆盖想对比历史结果只能靠记忆。如果你用的YOLOv5命令略有不同python train.py \ --data data.yaml \ --weights yolov5n.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --patience 20 \ --project runs/weed_detection \ --name baseline_640无论在哪个版本训练日志输出的指标才是判断模型好坏的标准而不是loss曲线单方面说了算。YOLOv5的train.py会在每个epoch结束时打印val mAP0.5YOLOv8的CLI也会在终端滚动输出类似信息训练过程中看到mAP开始下降说明已经开始过拟合可以直接提前终止。3.3 训练过程怎么看loss曲线和指标日志训练启动后大多数人盯着终端输出的数字发呆不知道哪些值得关注。这里给个简洁的判断框架分三个层面第一个层面是loss是否收敛。YOLO的loss通常包含三部分box_loss边界框回归损失、cls_loss分类损失、dfl_loss分布焦点损失。训练早期三个loss都高是正常的只要整体呈下降趋势即可。持续上升或剧烈震荡说明学习率设置不当、数据标注问题或BN层崩溃——后者是后面避坑章节的重点。第二个层面是验证集指标。YOLOv8默认在每个epoch结束后跑一次验证输出precision、recall、mAP50、mAP50-95。小数据集上单次验证结果波动很大不要因为某一个epoch的mAP掉了0.05就觉得模型坏了要连续观察5到10个epoch的趋势。第三个层面是拟合状态。训练集loss持续下降而验证集mAP停滞甚至下降这是过拟合的信号在1373张数据规模下几乎必然发生。对应的处置方式是增强正则化、增大数据增强强度、或改用更小的模型而不是继续加训epoch数。4. 杂草数据集训练避坑指南五个必踩的坑与对应处置4.1 类别不平衡稗草多到淹没阔叶杂草水稻田的杂草分布天然不平衡。稗草这类禾本科杂草数量往往远超阔叶杂草反映到数据集里就是某个类别的标注框占了七成以上另一个类别的框寥寥无几。YOLO训练对类别不平衡敏感少量出现的类别很难学到有效特征模型会把所有长得像草的东西都预测为多数类。现象训练出的模型对多数类比如稗草recall很高、precision也还行但对少数类几乎完全不检。 原因多数类样本在batch中反复出现模型参数更新方向被它主导少数类样本太少梯度贡献被淹没。 解决先回原始数据集统计每个类别的实例数。如果最少的类别只有几十个实例优先考虑人工补充标注而不是单纯靠算法硬扛如果分布比例在3:1以内可以通过调整数据增强中对少数类的复制概率来改善更直接的做法是训练时用更高的cls_loss权重YOLOv8里可以手动构造类别权重传入损失函数或者给少数类的图像在采样时提高概率。注意不要用删除多数类样本的方式平衡数据本身才1373张删掉之后信息量更不够模型的整体召回会明显变差。4.2 BN层崩溃小数据集上最隐蔽的loss翻车YOLO训练中BN层崩溃是搜索热词说明踩到的人不少尤其在训练集规模小于2000张、batch size设得又太小时。现象训练到某个epochloss突然从0.1级别跳到几十甚至NaN恢复不了或者训练loss一直下降但val mAP始终在0附近震荡模型输出全是背景。 原因BN层在batch size过小时统计均值和方差不准。默认batch size 16时每个通道只有16个样本参与统计当输入数据里恰好出现几个极端亮度或极端纹理的批次时BN层的running_mean和running_var被推向异常区间后续层输出随之爆炸整个训练过程就废了。 解决最常见的处置是把batch size调回16或32。如果显存不允许保留小batch但关闭BN的track_running_stats或者在模型配置里把BN层换成GroupNorm——但YOLO官方模型没有现成开关需要改网络结构代码。更简单的替代是使用梯度累积把有效batch size维持在16以上。另一个有效办法是降低初始学习率YOLOv8默认lr0在爬升阶段能到0.01以上对小数据集偏激进把它降到0.005以下能让BN统计更平稳。4.3 漏标和错标XML里的人工标注隐患公开下载的数据集不代表标注质量完美。1373张图如果由标注人员手工画框漏标、错标几乎不可避免尤其是杂草幼苗和水稻幼苗形态接近时标注者自己都可能分不清。现象训练后模型在验证集上mAP不错但实际推理时对某些区域频繁误检或漏检或者loss曲线在训练集上表现良好验证集上波动剧烈。 原因XML或TXT中存在以下四类常见问题——某个目标完全没标注漏标框比实际目标大两倍框太松框只框住目标的一半框太紧类别名称标错语义错误。 解决不要直接训练先做一轮彻底的数据清洗。把VOC格式的标注画回图片逐张快速扫一遍重点检查目标密集区域和图像边缘。这一步虽然耗时但在1373张图这个规模上半天能完成收益远大于花两三天排训练出的badcase。如果数据集里存在大量漏标建议补标后再训练如果只是少数可以原谅但验证集里不要包含明显漏标的图像否则指标失真。4.4 过拟合还是欠拟合两者表现相似判断方法不同小数据集训练最常见的困惑是训练集上loss漂亮得像静态图验证集上预测结果稀烂——这到底是过拟合还是欠拟合两者处置方向完全相反判断错了就白调半天参数。现象训练集loss持续下降验证集mAP停滞或下降。 原因模型容量相对于数据量太大记忆了训练样本的细节而非泛化规律同时正则化不足。 解决先看一个关键数字——训练集最终的mAP和验证集mAP的差距。如果训练集mAP是0.95验证集只有0.6差距显著这是典型的过拟合优先做三件事把模型从yolov8m换回yolov8n增加数据增强强度翻转、旋转、色彩抖动增大weight_decay参数从默认0.0005调到0.001。如果训练集mAP本身就不高低于0.7那是欠拟合或数据标注质量问题此时换大模型才有意义。这里有个常见的错误操作看到验证集mAP低就直接换更大的模型结果过拟合更严重val mAP进一步下降。4.5 图像尺寸与GPU显存处理高分辨率田间图田间采集的原始图像经常是几千万像素的航拍或地面高清图。直接拿原始尺寸训练是不可能的必须缩放但缩放策略有讲究。现象程序报错CUDA out of memory或者不报错但训练速度极慢一个epoch要几十分钟。 原因图像尺寸和batch size叠加导致显存超限。田间图像如果来自无人机单张可能在4000×3000以上不做缩放直接进网络单个batch就把显存炸了。 解决先统一下采样到可接受范围。比较好的方式是先用脚本把所有图像resize到宽高不超过1600的尺寸同时同步缩放标注坐标然后训练时设置--imgsz 640。如果你做的是细小的早期杂草检测目标可能只有二三十个像素直接缩到640会让目标几乎不可见这时候建议训练尺寸用960或1280同时把batch size降到4或8并开启梯度累积。区分这两种场景的方式是看目标像素面积占图片总面积的比值比值小于0.005的属于小目标场景优先保分辨率。5. 验证与评估跑通训练后怎么确认检测结果真的可用5.1 mAP50和mAP50-95两个指标各说明什么问题YOLO训练结束后自动输出的results.csv里有精确率、召回率、mAP50、mAP50-95。mAP50判断“检测位置是否大致对了”它要求预测框和真实框的IoU超过0.5就视为正确mAP50-95把阈值从0.5逐步升到0.95再取平均判断“边界框定位是否精准”。杂草检测场景里这两个指标要分别看待。农业机械喷药或人工除草场景只需要知道杂草大致位置mAP50达到0.85以上就可以实用如果要做精确的定向喷药每个喷嘴的喷射范围很小框偏移几十像素就可能喷到水稻苗上这时必须关注mAP50-95至少要0.6以上才算可用。对1373张数据训练的模型如果mAP50在0.7以下先不要急着调整模型结构回看避坑章节的四个排查点——类别是否不平衡、标注是否漏标、是否过拟合、BN是否稳定。综合来看小数据集上提升mAP50-95最有效的手段是精修标注框边界而不是换更强的模型。5.2 用训练好的权重做批量推理可视化badcase评估不能只看数字要把预测结果画回图上逐张看。YOLOv8的predict命令支持直接输出带标注框的图片yolo detect predict \ --model runs/weed_detection/baseline_640/weights/best.pt \ --source data/val_images/ \ --conf 0.25 \ --save_txt \ --save_conf \ --project runs/predictions/ \ --name val_visual_check执行后runs/predictions/val_visual_check下会生成每张图的标注可视化和对应的TXT结果文件。做两件事第一统计每张图的检测框数量和真实标注数量对比差的大的图片单独挑出来看第二逐张扫可视化图重点关注四类badcase——漏检该框没框、误检框到水稻苗上、框偏框偏移但IoU够不上0.5、重复框同一目标多个框。这四类问题的成因各不相同漏检通常是小目标或被遮挡目标误检是类别特征混淆框偏是标注框本身就是歪的重复框是NMS参数不当或模型置信度分布异常。5.3 验证集的划分玄学按田块分还是按图像分这个细节很多人忽略。如果数据集里的1373张图有一部分是从同一块田地的视频帧里抽出来的图像之间会高度相似——相邻帧的杂草位置、光照条件几乎一致。这时如果随机划分训练集和验证集验证集里可能存在与训练集几乎重复的图像看起来指标很漂亮但模型一到新的田块效果就崩。现象验证集mAP漂亮实测到陌生地块效果差一大截。 原因数据划分时没有按采集来源分组导致数据泄漏。 解决检查数据集的图像文件名或目录结构如果文件名包含采集日期、地块编号之类的信息优先按这些字段分组同一来源的图像全部进同一侧。如果文件名没有信息可依据观察图像之间是否存在明显的连续帧关系——画面内容高度相似、时间戳接近的就是同一组。把包含相似内容的图像尽量划到同一侧验证集按地块独立评估。对小数据集宁可缩减验证集张数也要保证验证集来源独立否则指标自欺欺人。6. 数据不够1373张来凑数据增强与迁移学习的进阶用法6.1 迁移学习策略用预训练权重还是从头训练固定从预训练权重开始训练是对的但对这个数据集预训练权重的选择有讲究。YOLOv8官方权重是在COCO数据集上训练的COCO里有80类日常物体没有水稻和杂草那预训练权重还有什么价值有价值的是它底层学到的纹理、边缘、颜色分布等通用视觉特征。迁移学习在小数据集上最大的贡献是提供稳定的初始特征提取器让模型不需要从零学习“什么是草叶边缘”这种基础模式。实操建议是优先用yolov8n.pt预训练权重做迁移训练。不少人喜欢把预训练权重改成公开的田间数据集或高光谱数据集上微调过的版本但对于杂草检测这个垂直场景通用预训练权重已经足够支撑自定义权重反而可能引入与目标场景分布不一致的偏见。加载了预训练权重后一开始冻结backbone层训练几个epoch让head层先适应杂草数据的类别分布之后解冻全部层训练训练稳定性会更好。6.2 数据增强参数怎么开不产生假样本的增强配置YOLO内置的增强参数在训练配置里可以直接控制。针对杂草检测场景四个参数优先调整yolo detect train \ --model yolov8n.pt \ --data data.yaml \ --epochs 100 \ --imgsz 640 \ --batch 16 \ --flipud 0.5 \ --scale 0.3 \ --hsv_h 0.02 \ --mosaic 0.5flipud 0.5开启垂直翻转对田间俯拍图特别有效——水稻田的杂草不会因为上下颠倒就变成别的类别翻转能让模型学习到更鲁棒的位置特征。scale 0.3控制随机缩放的幅度模拟不同采集高度带来的尺度变化但不要超过0.5否则小草目标被缩到看不见。hsv_h 0.02做轻微色相抖动模拟不同光照条件下杂草颜色的变化野外田间的光照变化非常大这一项对泛化能力贡献高。mosaic 0.5是马赛克增强把四张图拼接成一张训练样本对提高小目标检测能力有明显作用但mosaic增强会让样本分布偏离真实场景验证或推理阶段记得关掉。一个容易踩到的大坑增强太激进导致模型学到“假规律”。比如把色相抖动系数设成0.5训练集里的草叶颜色变得五花八门模型为了拟合这种颜色分布会浪费大量参数小数据集下收敛反而更慢。增强参数的设置原则是“模拟真实场景中会出现的变化”而不是“尽量折腾图”。另外一个增强手段是离线生成合成样本。如果数据集中阔叶杂草的实例特别少可以从现有图片里裁剪杂草区域通过旋转、缩放、调色后粘贴到不含该杂草的背景图上生成新的训练样本。这个方法操作门槛不高但对实例数量极度匮乏的类别比如不足50个框效果立竿见影。操作时注意粘贴时要让新样本的边缘做适度模糊或透明度渐变严丝合缝的矩形边缘会让模型学到“有矩形边界就是杂草”这种错误特征。最后分享一个实践习惯每次训练都在项目目录里记一行实验备注写清数据集版本、类别数量、增强参数、mAP结果、badcase截图链接。这个习惯帮我省了大量重复调参的时间。数据集的1400张图也好、你的五万张图也好没有记录的实验等于没做。如果你的数据规模比1373张还小优先补标注而不是换模型如果你的场景从水稻田换到了麦田类别要重定义但整套VOC转YOLO、训练配置和避坑排查步骤可以直接复用。希望帮到你。本文还有配套的精品资源点击获取

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案