
简介面向目标检测入门与课程设计场景这份YOLOv5红花数据集压缩包提供了完整可用的已标注资源适合计算机、电子信息工程、数学等专业学生用于期末作业、课程设计或毕业设计免去自行采集图像、手工标注与格式转换的繁琐流程能够直接聚焦模型训练与调参环节。包内共2000个文件包含1437张JPG红花图像、1437个XML标注文件和1437个TXT标注文件分别对应VOC格式与YOLO格式可直接接入YOLOv5训练流程压缩包整体约125MB目录分类清楚便于按图像、标签和训练脚本批量调用。作者为资深算法工程师在描述中说明资源采用参数化方式组织参数可方便更改、注释明细配合已有标签可快速完成数据集划分、模型训练、精度评估与效果复现。目前已有523人学习下载尤其适合希望快速跑通目标检测全流程、又缺少现成标注数据集的初学者参考使用。1. 红花数据集与 YOLOv5 目标检测现成标注到底能帮你省多少事看到“YOLOv5目标检测红花数据集已标注可以直接使用”这个标题先别急着把它当成一个普通的压缩包资源。真正有价值的是两处标注文件是现成的你不需要再花一两天时间用标注工具去框花另一个是它直接贴着 YOLOv5 的训练流程走从解压到出模型中间只差目录整理和几行命令。适合谁看做红花、中药材或农业田间目标检测的学生和算法工程师以及想借 YOLOv5 快速验证自己数据集的人。下面我按自己的落地习惯把这套流程拆开讲——先验标注数据再喂给模型训练接着调超参数最后做部署前的验证。整个路径上没有玄学只有每一步的检查和可复现的命令。2. 先验货再动手红花数据集的标注格式与目录结构怎么核对2.1 解压后第一件事核对图片与标注文件数量是否一致拿到 rar 包先别急着配环境。我见过太多人直接在目录上跑 train.py训练启动两小时后才发现图少标多。第一步永远是解压和数量核对。Linux 下用 unrar 或者 7zWindows 下用 WinRAR、7-Zip 都可以解压后进目录数文件# 解压 rar若压缩包是 Windows 下制作的注意中文文件名编码 unrar x YOLOv5目标检测红花数据集已标注可以直接使用.rar cd safflower_dataset # 统计图片数量YOLO 训练一般用 jpg也可能有 png find . -name *.jpg -o -name *.png | wc -l # 统计标签数量YOLO 格式是 txt find . -name *.txt | wc -lfind 命令按后缀统计文件数wc -l 输出总行数也就是文件总数。YOLO 格式下每张图片对应一个同名的 txt理想情况两者数量一致。如果图片数是标注数的 1.1 倍左右大概率有一批图漏标了反过来标注比图片多说明某些 txt 没有对应图片训练时不会报错但评估时可能多出无效标签。这两种情况都不影响“能启动训练”但会影响最终 mAP 的可信度所以第一关必须过。为什么说“已标注”也要走一遍核对因为标注文件的格式和内容完全依赖标注者当时用的工具与习惯。有人用 labelImg 导出 YOLO txt有人用脚本从 VOC XML 转成 txt还有人直接从别的项目里拷过来只改了文件名。这些来源转换时都可能丢失个别坐标、改错类别 ID。别人口中的“可以直接使用”到了你手里至少要变成“脚本验证过可以直接使用”才算数。这一步花不了十分钟却是后面所有工作的地基。数量一致后再看目录层级。常见的“已标注可直接使用”数据包有两种摆法一种是图片和 txt 混在同一个文件夹另一种是已经按 images/labels 分好。前者要手动划分后者直接进下一步。无论哪种都要打开一个 txt 标签文件看一眼内容。2.2 看懂 YOLO 标注文件归一化坐标与类别 ID 的意义红花数据集的标注如果符合 YOLO 规范每个 txt 文件里一行代表一个目标框0 0.453 0.312 0.182 0.274从左到右分别是类别 ID、中心点 x 归一化坐标、中心点 y 归一化坐标、宽度归一化值、高度归一化值。中心点坐标和宽高都是 0 到 1 的小数等于实际像素除以图片宽高这样不同分辨率的图片可以共用同一套标注。判断标注工具时也不难无论作者用的是 labelImg 还是 X-AnyLabeling 这类目标检测常用标注工具导出时如果选了 YOLO 格式得到的都是五列数字如果看到的是xmin ymin xmax ymax四个整数加上 XML 标签结构那就是 PASCAL VOC 格式。后者转换公式为 x_center(xminxmax)/(2width)y_center(yminymax)/(2height)w(xmax-xmin)/widthh(ymax-ymin)/height。我处理这类资源包时的经验是自称“已标注可直接使用”的绝大多数已经是 YOLO txt但验过才放心因为转换过程最容易出错的地方就是类别 ID 映射和坐标取整。打开几个文件后用一个脚本把所有标签扫一遍重点查两类异常坐标越界和类别集合不对。import os label_dir labels # 改成实际标签目录 class_ids set() bad_lines [] for root, _, files in os.walk(label_dir): for name in files: if not name.endswith(.txt): continue path os.path.join(root, name) with open(path, r) as f: for idx, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: bad_lines.append((path, idx, line)) continue cid int(parts[0]) vals [float(v) for v in parts[1:]] class_ids.add(cid) if any(v 0 or v 1 for v in vals): bad_lines.append((path, idx, line))脚本遍历标签目录下所有 txt用三个条件过滤异常行内不是 5 个数、第一列不是整数、坐标超出 0 到 1 范围。只要 bad_lines 为空类别集合是从 0 开始的连续小整数这批标注至少可以进入训练流程。如果发现类别集合是 {1} 而不是 {0}那就是典型的标注 ID 从 1 开始问题第 5 章会给出批量修复命令。如果压缩包里是 VOC XML转换完成后也要重新跑一遍这个校验脚本因为坐标换算和类别 ID 映射大多是人工或半自动实现的稍微不留神就会出现某个目标框宽高为 0。XML 里同时记录了图片的 width 和 height转换脚本必须按单张图片的尺寸算不能拿数据集里的最大分辨率代替否则小图上会产生大量越界框。2.3 classes.txt 别删类别顺序决定标注 ID 的映射数据包里如果有 classes.txt里面通常是每行一个类别名比如单独的 safflower或者按花期细分的几个类。classes.txt 的顺序直接对应标注 ID第一行是 0第二行是 1。训练时 yaml 里的 names 列表必须与 classes.txt 顺序保持一致。这个文件最容易被新手当成“说明文档”删掉删掉后你只会损失类别名但如果它本身定义了类别顺序你不知道原标注里的 ID 0 到底代表什么后面做可视化或部署时就会困惑。所以我在拿到数据包后会把 classes.txt 内容先打印出来和标签里实际出现的 ID 对照一遍。如果标签里只有 ID 0而 classes.txt 有两行说明有一类目标没有出现或者标注文件不完整需要回到数量核对那一步重查。把验货这一步做扎实标题里的“可以直接使用”才真正成立。为了直观验证标注质量我还会随机挑几张验证集图片把归一化坐标恢复成像素坐标后画框保存。这一步能看出标注框是否紧贴花瓣、有没有漏标或框得过大。画框脚本如下import cv2 from pathlib import Path img_dir Path(datasets/safflower/images/val) lbl_dir Path(datasets/safflower/labels/val) sample list(img_dir.glob(*.jpg))[0] img cv2.imread(str(sample)) for line in (lbl_dir / (sample.stem .txt)).read_text().strip().splitlines(): cid, x, y, w, h line.split() x, y, w, h map(float, [x, y, w, h]) x1 int((x - w / 2) * img.shape[1]) y1 int((y - h / 2) * img.shape[0]) x2 int((x w / 2) * img.shape[1]) y2 int((y h / 2) * img.shape[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_sample.jpg, img)脚本把中心点坐标和宽高换算回像素坐标再画绿色矩形框。红花和绿叶对比明显如果框和花朵边缘基本贴合标注质量就过关如果大量框只圈住花的一部分或者明显把花枝也包进去了后面训练出来的模型会带着同样的偏差。这一步的观察结果直接决定你对这份数据集标注风格的判断也会影响第 4 章里要不要调整输入分辨率的决策。3. 把红花数据集喂给 YOLOv5目录整理、yaml 与训练命令3.1 环境准备yolov5 源码拉取与 conda 依赖安装YOLOv5 官方仓库对环境要求很宽松Python 3.9 配 PyTorch 1.13 或 2.0 都能跑CUDA 11.8 是比较常见的组合没有独显也能用 CPU 训练只是速度会慢到怀疑人生所以做目标检测最好还是有一张 6G 以上显存的卡。环境搭建的常见做法是三步conda create -n yolov5 python3.9 -y conda activate yolov5 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt这里有个容易出问题的细节pip 安装依赖时会装最新版 torch如果机器本身已有 CUDA 环境但版本与 torch 不匹配训练时会出现 driver 版本过低的报错。我一般会先执行python -c import torch; print(torch.__version__, torch.cuda.is_available())确认输出为 True 再继续。yolov5 源码目录里的 requirements.txt 已经列好了所有依赖装完后不需要再手动补包。环境就绪后先别急着下权重和训练。把第 2 章的校验脚本在目标机器上再跑一遍因为不同环境下 OpenCV 对中文路径、图片编码的容忍度不一样早发现问题比训练中途排查省事。权重文件 yolov5s.pt 会在第一次执行 train.py 时自动下载网络不好就手动下载后放到 yolov5 根目录。3.2 目录整理把红花图片和标注按 images/labels 结构放好YOLOv5 对数据集目录没有硬性规定但用 images/{train,val} 和 labels/{train,val} 的结构最省心因为 yaml 里只需要写两个路径且后续换模型、换机器都容易复现。如果 rar 解压后是混在一起的用下面的脚本按 8:2 划分训练集和验证集import os import random from pathlib import Path src_images Path(all_images) # 解压出的图片目录 src_labels Path(all_labels) # 解压出的标签目录 dst Path(datasets/safflower) val_ratio 0.2 random.seed(42) for sub in [images/train, images/val, labels/train, labels/val]: (dst / sub).mkdir(parentsTrue, exist_okTrue) imgs [p for p in src_images.iterdir() if p.suffix.lower() in {.jpg, .jpeg, .png}] random.shuffle(imgs) val_n int(len(imgs) * val_ratio) for i, img_p in enumerate(imgs): label_p src_labels / (img_p.stem .txt) if not label_p.exists(): print(f跳过无标注图片: {img_p.name}) continue sub val if i val_n else train os.rename(img_p, dst / fimages/{sub} / img_p.name) os.rename(label_p, dst / flabels/{sub} / label_p.name)脚本逻辑是扫描源图片目录按随机种子打乱顺序前 20% 进 val后 80% 进 train每张图片寻找同名的 txt两个文件一起移动。img_p.stem是去掉后缀的文件名它是你找同名标签的唯一依据所以图片命名里不能带点号之外的后缀比如flower.1.jpg和flower.1.txt的 stem 分别是flower.1和flower.1能对上但flower.jpg与flower.JPG后缀大小写不同同名 label 的 stem 还是flower没问题。random.seed(42)保证了每次划分结果一致这也是能复现训练的前提不同的人拿同一份数据跑同一条命令得到一样的训练集。值得一提的是划分时最好以“文件夹”或“拍摄批次”为单位而不是逐张随机分否则同一株花的多个角度照片会同时出现在 train 和 valmAP 虚高。我的做法是先把不同拍摄批次的图片放在不同子目录再按子目录为单位分这样评估结果才可信。这一点在第 5 章有对应排查记录。3.3 写 safflower.yaml 并启动首次训练目录就绪后在 datasets/safflower 下新建 safflower.yaml# 路径相对 yolov5 项目根目录 train: datasets/safflower/images/train val: datasets/safflower/images/val nc: 1 names: 0: safflowernc 是类别数 1names 与 classes.txt 顺序一致。如果数据包里有多个类别比如 0 是红花、1 是花苞nc 改成 2names 往下补。yaml 文件不需要写 test 字段训练用不到。启动训练的最简命令python train.py \ --data datasets/safflower/safflower.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 150 \ --project runs/safflower \ --name exp1参数解释--weights 指定预训练权重yolov5s.pt 是官方 small 版本单类红花检测规模下性价比最高--img 640 是输入分辨率红花是小型目标640 是起步值--batch 16 要看显存8G 卡刚好6G 卡建议降到 816G 可以加 32--epochs 150 是单类数据集常用的收敛区间训练中观察验证 mAP 再决定提前停还是加量--project 和 --name 决定输出目录默认会生成 runs/safflower/exp1里面存权重与曲线。训练开始后不要离开终端太久至少盯三个 epoch。正常情况 loss 稳步下降每轮末会打印 mAP。如果看到等待权重下载、或者打印出 no labels 之类警告先停掉排查这两个现象都有明确原因继续跑只会浪费卡时。第一次跑通后再把 img 提到 896 或者把 s 换成 m 模型都属于常规提点操作。4. 训练前的数据验证与超参数调整红花小而密怎么调4.1 全集标签再校验空标签与数量对不上的排查脚本第 3 章的划分脚本已经保证了 images 和 labels 数量一致但“数量一致”不等于“每个 txt 都有内容”。红花田地里总会有几张过曝、虚焦或花朵被完全遮挡的照片标注者可能保留图片但没标任何框导致 txt 文件 0 字节。YOLOv5 训练时遇到空标签不会崩但会增大负样本采样压力。先把空标签统计出来再做决定from pathlib import Path for subset in [train, val]: label_dir Path(fdatasets/safflower/labels/{subset}) empty_files [p for p in label_dir.glob(*.txt) if p.stat().st_size 0] print(f{subset} 空标签数量: {len(empty_files)})0 字节空标签的处理策略有两种如果占比很小比如 1% 以内直接保留YOLOv5 会把这张图当纯背景负样本喂给网络对红花检测来说其实是好事能减少误检如果占比明显偏高说明标注过程中有整批图漏标要追溯源数据否则训练集里混入大量负样本会把 recall 拉低。经验阈值是 3%超过这个数建议重跑一下标注或者删除这些空标签对应的图片我自己一般会先看图片内容再决定而不是一刀切删掉。空标签的图片如果只是花朵较小但清晰保留能让模型见识更丰富的背景利大于弊。空标签校验完成后还要在训练前做一次全局统计计算数据集中所有目标框的宽高分布。这个统计直接关系到后面 anchor 的匹配程度import os from collections import Counter w_buckets, h_buckets Counter(), Counter() for subset in [train, val]: for p in Path(fdatasets/safflower/labels/{subset}).glob(*.txt): for line in p.read_text().strip().splitlines(): parts line.split() w float(parts[3]); h float(parts[4]) w_buckets[round(w, 2)] 1 h_buckets[round(h, 2)] 1 print(常见目标框宽:, w_buckets.most_common(10)) print(常见目标框高:, h_buckets.most_common(10))看一眼输出如果宽高多数落在 0.05 以下说明目标很小按第 4.3 节的方式处理如果分布均匀但最大框占了图片一大半那大概率有异常标注混在里面。这个脚本几十行却能帮你在训练前排除掉最影响结果的两类问题。4.2 img-size、batch、epochs 三个参数怎么配红花目标的尺寸特征决定了输入分辨率不能随便定。俯拍大田场景里单朵花的像素可能不到整幅图的 5%640 输入下花朵区域很小卷积下采样后特征已经很弱。如果显存允许896 甚至 1280 的效果会明显好于 640但训练时间不是线性增长1280 大约是 640 的 4 倍算力消耗。资源有限时先用 640 跑通流程再加分辨率。batch 参数本质上是显存和收敛速度的权衡。YOLOv5 官方推荐大 batch但显存不足时硬凑 batch 只会让训练不稳定。参考配置如下显存输入尺寸推荐 batch说明6G6408最保守组合先跑通8G64016最常用组合速度与显存平衡16G89616追求小目标精度时选24G128016~32红花密集小目标实验首选显存不足且不想降 batch 时用 --amp 参数启动混合精度训练显存占用能下降接近一半。epochs 不要拍脑袋。单类数据集 150 epoch 通常够用判断标准是训练曲线如果第 120 epoch 的 mAP50 还在明显上升加到 300如果 50 epoch 后 mAP 开始震荡不涨120 提前收工也行。YOLOv5 没有内置早停机制我一般看 runs/safflower/exp1/results.csv 里的最后几行做判断。同样的数据如果以后切到 yolov8 训练这个思路也成立只是 yaml 写法和训练命令略有差异数据集本身不用改结构。4.3 autoanchor 与小目标红花密集场景的特殊调法YOLOv5 的 autoanchor 机制会在训练前自动计算 anchor。对红花数据集我每次都会先跑一次 anchor 评估看匹配率低于 0.9 的原因是不是标注框长宽比异常。命令很简单python utils/autoanchor.py --data datasets/safflower/safflower.yaml --img 640输出会显示新 anchor 和当前默认 anchor 对目标的匹配程度。匹配率低时大部分情况是标注框里有少数异常大框或极端长宽比目标。比如一张图里漏标的一朵花旁边标注者误把花丛也框进去了这个框的宽度可能是正常框的 10 倍k-means 会被拉偏。此时不要直接关掉 autoanchor先查异常框因为异常框本身就会教坏模型。红花场景还有个特殊性花朵密集且相互遮挡视觉特征主要靠红色和边缘目标框之间的重叠度高。这种情况下我除了提高分辨率还会在训练命令里加 --augment让马赛克增强和随机仿射帮模型适应遮挡状态。但这会明显拉长训练时间适合追求精度而不是快速验证的场景。另一个算法层面的小技巧是类别单一的不需要动 loss 权重但如果 classes.txt 里有多个类别且样本数量差异大要在 yaml 里给少数类别配更高权重。这个权重参数在 YOLOv5 中通过模型结构里的 cls_pw 调整对新手来说先不改多数数据集默认值够用改之前先确认你已经看懂了损失函数结构不然只是多一个调参玄学。5. 红花数据集训练 YOLOv5 常见问题排查从解压到评估的五个坑5.1 类别 ID 从 1 开始训练不报错但指标全 0现象train.py 启动正常loss 也在下降但每个 epoch 结束打印的 mAP 全是 0日志里还会间隔出现 “all 0 for all classes” 的警告。原因标注文件里的类别 ID 从 1 开始而 yaml 中 nc 只设了 1ID 1 超出了类别索引范围网络把训练目标当成了无效样本。这种情况在从 1 开始计数的标注工具中很常见转换脚本漏了减 1 就会这样。解决写脚本把 txt 第一列统一减 1from pathlib import Path for subset in [train, val]: for p in Path(fdatasets/safflower/labels/{subset}).glob(*.txt): lines p.read_text().strip().splitlines() fixed [] for line in lines: parts line.split() new_id int(parts[0]) - 1 fixed.append(f{new_id} { .join(parts[1:])}) p.write_text(\n.join(fixed) \n)提示批量修改标签前先备份整个 labels 目录改完再跑第 2 章的校验脚本确认类别集合变成 {0}。5.2 坐标越界或宽高为 0训练时 loss 变 NaN现象第一个 epoch 后 loss 变成 nan重启训练后又能复现或者训练几十轮才突然 nan整轮结果作废。原因标注框中心坐标或宽高中出现了 0 和负数或值略大于 1YOLOv5 的数据增强在随机裁剪、拼接时会把这类越界框放大成异常样本。解决把 2.2 节脚本的输出逐一处理越界的框裁回边界内宽高为 0 的直接删行。实操中直接用一段脚本清洗标签比手改快得多import shutil from pathlib import Path for subset in [train, val]: for p in Path(fdatasets/safflower/labels/{subset}).glob(*.txt): lines p.read_text().strip().splitlines() keep [] for line in lines: parts line.split() if len(parts) ! 5: continue _, x, y, w, h parts x, y, w, h map(float, [x, y, w, h]) if 0 x 1 and 0 y 1 and 0 w 1 and 0 h 1: keep.append(line) if len(keep) ! len(lines): shutil.copy(p, p.with_suffix(.bak.txt)) p.write_text(\n.join(keep) \n)清洗逻辑很简单坐标必须落在 0 到 1 区间内宽高必须大于 0少了一样就丢整行。备份写成了 .bak.txt 而不是直接覆盖这是给自己留后悔药。清洗后最好再数一遍行数避免误删掉整张图的标签。5.3 图片或标注文件名带中文、空格图片加载失败现象训练刚开始日志里大量出现 FileNotFoundError 或 cv2.error打开图片目录发现文件名是红花_01 (1).jpg这种带中文和括号的命名。原因YOLOv5 的数据加载用 OpenCV 的 imread 读文件OpenCV 在 Windows 上对中文路径支持不好括号和空格也会导致解析混乱。解决统一重命名为纯英文数字同时保证图片和 txt 的 stem 同步简单做法是给文件加序号from pathlib import Path for subset in [train, val]: img_dir Path(fdatasets/safflower/images/{subset}) lbl_dir Path(fdatasets/safflower/labels/{subset}) for i, img_p in enumerate(sorted(img_dir.glob(*.*))): new_stem f{subset}_{i:05d} img_p.rename(img_dir / f{new_stem}{img_p.suffix.lower()}) lbl lbl_dir / (img_p.stem .txt) if lbl.exists(): lbl.rename(lbl_dir / f{new_stem}.txt)脚本把图片和标签统一改成 train_00001.jpg 这种风格。之后你做可视化、导出、部署文件名里不再有中文各种工具兼容性都会好很多。5.4 验证集 mAP 很高但实拍效果差数据划分泄漏现象在验证集上 mAP50 到 0.9 以上拿手机在新场景里拍一张就明显漏检尤其光线变化后更严重。原因划分训练集和验证集时按图片逐个随机分导致同一株花的不同角度照片同时落在 train 和 val或者数据本身来源于同一场景短时间内连拍分布太接近验证集虚高。解决重新按拍摄批次或地块划分数据一个文件夹要么全进 train要么全进 val。同时另外采集一批独立场景图片做最终验收不参与训练和调参。这也是第 3.2 节强调“以文件夹为单位划分”的原因事后处理虽然能补救但一开始划分正确才是治本。5.5 解压后目录层级混乱yaml 报路径不存在现象训练启动报路径不存在打开解压目录发现 images 和 labels 前面还套了一层原作者的文件夹名或者 train/val 下面直接叠了两层子目录。原因rar 包中目录结构常见是“根目录/子目录/图片”如果直接写datasets/safflower/images/train就漏掉了一层。解决用tree或find . -maxdepth 3 -type d看实际目录再写 yaml。不要靠猜也不要靠图形界面里的属性复制直接把解压后目录拖到终端里取真实路径这个动作能省下至少半小时的排查时间。我处理过不止一个数据集路径问题占比比想象中高得多。6. 收尾验证指标、ONNX 导出与部署前的一个习惯训练结束后的顺序很重要先打开 runs/safflower/exp1 下的 results.csv 看指标再做一次独立场景推理最后导出部署格式。mAP50 对红花单类目标来说上 0.85 基本可用mAP50-95 更能反映框的质量红花重叠区域如果框总偏半朵花说明标注框本身就不贴边或者分辨率不够。conf 阈值的选择要分场景俯拍检测统计数量时建议 0.3花期巡检这种漏检代价高的场景阈值再低一些做需要精确框的计数或分级就调高到 0.5。这个参数不是模型训练的一部分但直接影响你在新图片上看到的结果值得单独实验。推理验证命令python detect.py --source test_images/ --weights runs/safflower/exp1/weights/best.pt --conf 0.3detect.py 会在 run 目录下输出带框的可视化图。当场看一眼框是不是紧贴花瓣、漏检多少这是模型指标以外最直接的验收。如果可视化效果没问题再导出 ONNXpython export.py --weights runs/safflower/exp1/weights/best.pt --include onnx导出的 best.onnx 可以被 onnxruntime 加载适合树莓派这类算力受限的目标检测设备如果部署端用 TensorRTYOLOv5 官方也支持通过 trt 参数导出。有一点要提醒ONNX 导出的默认 opset 与训练时一致部署端推理框架版本太老会出现不兼容低版本先升级再跑。我自己的习惯是拿到任何“已标注可直接使用”的数据包都会先花十分钟把 2.1 的数量核对、2.2 的坐标校验和 4.1 的空标签统计完整跑一遍再谈训练参数。这一步省下来的调参和查 bug 时间远超十分钟本身。这次红花数据集只要每一步都验到了从解压到 best.pt 的路径其实非常顺。希望帮到你。本文还有配套的精品资源点击获取