ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLO杂草检测实战:6849张带标签图像从数据清洗到训练部署全流程

YOLO杂草检测实战:6849张带标签图像从数据清洗到训练部署全流程 简介这份资源是面向深度学习目标检测方向的杂草检测数据集适合从事农业智能识别、YOLO系列算法训练与验证的开发者及学生使用。数据集共6849张图像并全部带标签已按训练与验证需求划分完毕同时提供data.yaml配置文件可直接对接yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流算法省去自行整理与划分的繁琐流程。压缩包内共2000个文件以xml标注文件为主同时包含yolo格式的txt标签两种标注分别存放于独立文件夹便于按需选用yolo标签采用类别索引与归一化中心点、宽高坐标符合标准检测训练格式。资源包整体约236.6MB目录结构清晰已有201人学习下载。对于需要快速搭建杂草检测基线、验证模型迁移效果或开展对比实验的读者这份带标签数据能直接投入训练与测试减少数据清洗成本提升实验效率。1. 6849 张带标签杂草图像从拿到压缩包到跑通第一轮训练拿到一个名为「yolo算法-杂草检测数据集-6849张图像带标签-杂草.zip」的压缩包时多数人第一反应是解压、翻目录、找 data.yaml然后直接yolo train。我见过太多人卡在这一步图片能打开标签却对不上号类别名写的是中文训练脚本读出来是乱码验证集里同一株草在不同光照下被标成了两个类。杂草检测这个场景的特殊性在于它不像 COCO 那样有统一的标注规范田间图像的光照、遮挡、生长阶段差异极大6849 张这个量级说大不大、说小不小刚好够你验证一套流程能不能跑通但不够你无脑堆 epoch。这个数据集适合三类人一是想用 YOLO 做农业视觉落地、需要快速验证检测头是否work的工程师二是手里有类似田间图像、想找一份带标签数据做迁移学习起点的算法同学三是做边缘部署、需要评估模型在杂草这种细长、密集、类间差异小的目标上到底能到多少 mAP 的开发者。它解决的核心问题不是「有没有数据」而是「这批数据能不能直接喂给 YOLO 系列模型、需不需要清洗、训完能不能用」。下面按我实际处理这类数据集的顺序把选型、清洗、训练、排错和进阶验证拆开讲。2. 先搞清楚这批数据能不能直接喂给 YOLO格式、类别与划分2.1 解压后先看三样东西目录结构、标签格式、类别分布拿到压缩包别急着写训练脚本。我一般先做三件事列目录树、抽 5 张图看标签、统计类别频次。杂草数据集的常见坑是标签格式混用——有的给 VOC XML有的给 YOLO txt还有的给 COCO json。标题写的是「带标签」但没说是哪种标签所以第一步是确认。# 查看目录结构重点看 images 和 labels 是否成对 find . -maxdepth 3 -type d | head -30 # 统计图片数量确认是否接近 6849 find . -name *.jpg -o -name *.png | wc -l # 抽一张标签看格式 head -5 labels/xxx.txt如果labels/下是class_id x_center y_center width height这种归一化数值说明是 YOLO 格式可以直接用。如果是 XML需要转如果是 json需要解析。类别分布用一行 Python 就能看import os, collections counter collections.Counter() for f in os.listdir(labels): with open(os.path.join(labels, f)) as fp: for line in fp: counter[int(line.split()[0])] 1 print(counter)这一步的目的是看有没有某个类别样本极少。杂草检测里常见的是「禾本科杂草」和「阔叶杂草」两类如果某一类只有几十个框训练时几乎必然被另一类压制后面调 loss 权重或做重采样才有依据。2.2 类别名映射中文类别是训练脚本的隐形杀手很多国内采集的杂草数据集类别名写在classes.txt或data.yaml里是中文比如「马唐」「稗草」「狗尾草」。YOLO 训练本身不关心中文但data.yaml的names字段如果编码不对Ultralytics 读出来会变成乱码导致验证时打印的类别名不可读更严重的是某些版本在生成混淆矩阵时会因为编码问题直接报错。我的做法是统一转成英文或拼音并在data.yaml里显式写names列表path: ./weed_dataset train: images/train val: images/val nc: 4 names: [grass_1, grass_2, broadleaf_1, broadleaf_2]注意nc必须和names长度一致且类别 id 从 0 开始连续。如果原始标签里有 id 跳号比如只有 0、2、3要么重映射要么补一个空类否则训练时索引越界。2.3 训练集/验证集划分别用随机划分按场景分6849 张图如果随机 8:2 划分验证集里很可能出现和训练集同一块地、同一时间拍的图mAP 虚高。杂草检测的落地场景是「换一块地还能不能认出来」所以划分要按拍摄批次、光照条件或地块来分。如果数据集本身没有这些元信息至少按文件名前缀或时间戳分。import os, random, shutil random.seed(42) files [f for f in os.listdir(images) if f.endswith(.jpg)] # 按文件名排序后切分避免随机泄漏 files.sort() split int(len(files) * 0.8) train_files, val_files files[:split], files[split:] for phase, flist in [(train, train_files), (val, val_files)]: os.makedirs(fdataset/images/{phase}, exist_okTrue) os.makedirs(fdataset/labels/{phase}, exist_okTrue) for f in flist: shutil.copy(fimages/{f}, fdataset/images/{phase}/{f}) shutil.copy(flabels/{f.replace(.jpg, .txt)}, fdataset/labels/{phase}/{f.replace(.jpg, .txt)})参数说明random.seed固定后如果按文件名排序再切结果可复现split比例根据数据量调整6849 张建议 8:2 或 7:3验证集至少 1000 张才能让 mAP 波动小于 2 个点。如果发现验证集里某些类别一个框都没有说明划分太偏需要分层抽样。3. 用 YOLOv8 在本地跑通第一轮杂草检测训练3.1 环境配置CUDA、PyTorch 和 Ultralytics 的版本对齐杂草检测数据集不大单卡 8G 显存足够跑 YOLOv8n 或 YOLOv8s。环境翻车最多的地方是 PyTorch 和 CUDA 版本不匹配导致torch.cuda.is_available()返回 False训练 silently 跑在 CPU 上一个 epoch 要半小时。# 先确认显卡驱动和 CUDA 版本 nvidia-smi # 创建虚拟环境避免污染全局 conda create -n weed_yolo python3.10 -y conda activate weed_yolo # 安装 PyTorchcu118 对应 CUDA 11.8按 nvidia-smi 右上角版本选 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装 Ultralytics pip install ultralytics # 验证 python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))如果输出True和显卡型号说明环境通了。注意 Ultralytics 版本更新很快不同版本train的参数名有差异建议固定一个版本比如pip install ultralytics8.1.0避免今天能跑的脚本下周就报KeyError。3.2 训练命令与关键参数imgsz、batch、lr0 怎么定第一轮训练不要调太复杂先用预训练权重跑一个 baseline。杂草检测的目标通常偏小且密集imgsz建议 640 起步如果显存够可以上 1024但 6849 张图用 1024 训练时间会翻倍。yolo detect train \ dataweed_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0 \ projectruns/weed \ namebaseline参数逐个说modelyolov8s.pt是 COCO 预训练权重杂草检测属于通用目标检测的迁移用预训练比从头训收敛快至少 3 倍batch16在 8G 显存下 640 分辨率大概能跑到 16如果 OOM 就降到 8 并开ampTruelr00.01是初始学习率YOLOv8 默认用 SGD 时这个值比较稳如果用 AdamW 要降到 0.001patience20表示 20 个 epoch 验证 mAP 不升就早停避免过拟合lrf0.01是最终学习率因子余弦退火到初始的 1%。训练开始后重点看第一屏输出里的Class和Images统计确认类别数和图片数和你的data.yaml一致。如果Class显示的数量不对说明nc写错了。3.3 训练中看什么loss 曲线、mAP 和混淆矩阵的读法训练日志里box_loss、cls_loss、dfl_loss三个值要分开看。杂草检测最常见的是cls_loss降不下去说明类间差异小模型分不清禾本科和阔叶。这时候不要急着加 epoch先看混淆矩阵。from ultralytics import YOLO model YOLO(runs/weed/baseline/weights/best.pt) metrics model.val(dataweed_dataset/data.yaml, imgsz640, conf0.25) print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.confusion_matrix.matrix)conf0.25是验证时的置信度阈值杂草场景如果误检多可以提到 0.4 再看。混淆矩阵里如果某一列预测类几乎全落在背景行说明该类召回极低可能是样本太少或标注框太小。我一般会挑出这些类的图片单独看确认是标注问题还是模型容量不够。提示训练前用yolo detect val跑一遍未训练的预训练模型记录初始 mAP作为 baseline 对比。如果训完 mAP 反而降了说明数据或参数有问题不是模型不行。4. 杂草检测训练里最容易翻车的五个地方4.1 现象mAP 一直卡在 0.1 左右不涨原因标签坐标没归一化解决检查 txt 数值范围YOLO 格式要求x_center、y_center、width、height都在 0 到 1 之间。有些数据集给的是绝对像素坐标直接喂进去模型学不到东西。用一行命令检查awk {if($21 || $31 || $41 || $51) print FILENAME} labels/*.txt | head如果有输出说明存在未归一化的标签需要除以图片宽高重新生成。4.2 现象训练到一半 loss 变 NaN原因学习率过大或某张图标签越界解决降 lr0 并过滤异常框杂草数据集里偶尔会有标注框超出图片边界的归一化后出现负值或大于 1反向传播时梯度爆炸。训练前加一步清洗import os for f in os.listdir(labels): lines open(flabels/{f}).readlines() clean [l for l in lines if all(0 float(x) 1 for x in l.split()[1:])] if len(clean) ! len(lines): open(flabels/{f}, w).writelines(clean)同时把lr0从 0.01 降到 0.005加warmup_epochs3让前几个 epoch 慢慢升。4.3 现象验证集 mAP 高但实际图片检测漏检严重原因验证集和训练集同分布解决按地块重新划分这是最隐蔽的坑。随机划分导致验证集图片和训练集来自同一批拍摄模型只是记住了背景。解决办法是找到图片的 EXIF 或文件名里的批次信息按批次分。如果实在没有至少把连续编号的图片整段划到验证集而不是随机抽。4.4 现象混淆矩阵总合不唯一某些类被重复计数原因类别 id 不连续或 names 顺序错位解决重映射 id 并核对 yaml热词里提到的「yolo混淆矩阵总合不唯一」在杂草检测里很常见因为类别名多、id 容易错位。确保data.yaml的names顺序和标签里的 id 严格对应且 id 从 0 连续到nc-1。如果原始标签有跳号写个映射脚本id_map {0:0, 2:1, 3:2, 5:3} # 原始 id 到新 id for f in os.listdir(labels): lines open(flabels/{f}).readlines() new_lines [] for l in lines: parts l.split() parts[0] str(id_map[int(parts[0])]) new_lines.append( .join(parts) \n) open(flabels/{f}, w).writelines(new_lines)4.5 现象训练中 BN 崩溃loss 突然飙高原因batch 太小或数据增强过猛解决调 batch 和关闭 mosaic「yolo训练中bn崩溃」通常发生在 batch 小于 8 的时候BatchNorm 统计量不稳定。杂草检测如果显存不够宁可降imgsz到 512 也要保batch8以上。另外 mosaic 增强在训练后期可能引入不真实的拼接可以在最后 10 个 epoch 关掉yolo detect train ... close_mosaic10close_mosaic10表示最后 10 个 epoch 关闭 mosaic让模型在真实分布上微调。5. 训完之后怎么验证模型真的能用从 mAP 到田间实拍5.1 用混淆矩阵和 PR 曲线定位薄弱类别训练完不要只看一个 mAP 数字。runs/weed/baseline/下会生成confusion_matrix.png和PR_curve.png。PR 曲线里如果某条线明显低于其他说明该类召回或精度差。杂草检测里阔叶类通常比禾本科好认因为叶片形状差异大禾本科细长、相互遮挡PR 曲线往往更低。针对薄弱类可以单独裁出这些样本做过采样或者调cls损失的权重。5.2 拿手机拍几张田间图做推理看真实场景误检mAP 是实验室指标田间实拍才是试金石。用训好的权重跑单张推理yolo detect predict \ modelruns/weed/baseline/weights/best.pt \ sourcetest_field.jpg \ conf0.3 \ saveTrueconf0.3比验证时的 0.25 略高是为了减少误检。如果发现背景里的土壤纹理被误检成杂草说明负样本不够需要往训练集里加一些纯背景图标签为空 txt 即可。这个技巧在边缘部署时特别有用能显著降误报。5.3 导出 ONNX 或 TensorRT为边缘设备做准备如果最终要部署到 RK3588 或树莓派这类边缘设备训练完的.pt需要转格式。YOLOv8 导出 ONNX 很简单yolo export modelruns/weed/baseline/weights/best.pt formatonnx opset12 simplifyTrueopset12兼容性较好simplifyTrue会做图优化。导出后务必用onnxruntime跑一遍确认输出和 PyTorch 一致。边缘部署监控误检率高很多时候不是模型问题而是预处理没对齐——训练时用的 letterbox 填充部署时如果直接 resize长宽比变了小目标检测会崩。我自己的习惯是每训完一个版本先拿 20 张田间实拍图跑一遍人工数漏检和误检记录在表格里。mAP 涨 1 个点不如田间漏检少一株。杂草检测这个方向数据质量比模型结构重要得多6849 张如果标注干净、划分合理YOLOv8s 足够跑出可用的结果如果标注混乱换再大的模型也是玄学。希望帮到你。本文还有配套的精品资源点击获取
返回列表