简介:面向目标检测入门与课程设计场景,这份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 或者 7z,Windows 下用 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=(xmin+xmax)/(2width),y_center=(ymin+ymax)/(2height),w=(xmax-xmin)/width,h=(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 python=3.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(parents=True, exist_ok=True) 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 / f"images/{sub}" / img_p.name) os.rename(label_p, dst / f"labels/{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 和 val,mAP 虚高。我的做法是先把不同拍摄批次的图片放在不同子目录,再按子目录为单位分,这样评估结果才可信。这一点在第 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 是类别数 1,names 与 classes.txt 顺序一致。如果数据包里有多个类别,比如 0 是红花、1 是花苞,nc 改成 2,names 往下补。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 卡建议降到 8,16G 可以加 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(f"datasets/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(f"datasets/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 | 说明 |
|---|---|---|---|
| 6G | 640 | 8 | 最保守组合,先跑通 |
| 8G | 640 | 16 | 最常用组合,速度与显存平衡 |
| 16G | 896 | 16 | 追求小目标精度时选 |
| 24G | 1280 | 16~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 只设了 1,ID 1 超出了类别索引范围,网络把训练目标当成了无效样本。这种情况在从 1 开始计数的标注工具中很常见,转换脚本漏了减 1 就会这样。解决:写脚本把 txt 第一列统一减 1:
from pathlib import Path for subset in ["train", "val"]: for p in Path(f"datasets/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 和负数,或值略大于 1,YOLOv5 的数据增强在随机裁剪、拼接时会把这类越界框放大成异常样本。解决:把 2.2 节脚本的输出逐一处理,越界的框裁回边界内,宽高为 0 的直接删行。实操中直接用一段脚本清洗标签比手改快得多:
import shutil from pathlib import Path for subset in ["train", "val"]: for p in Path(f"datasets/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(f"datasets/safflower/images/{subset}") lbl_dir = Path(f"datasets/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 目录下输出带框的可视化图。当场看一眼,框是不是紧贴花瓣、漏检多少,这是模型指标以外最直接的验收。如果可视化效果没问题,再导出 ONNX:
python export.py --weights runs/safflower/exp1/weights/best.pt --include onnx导出的 best.onnx 可以被 onnxruntime 加载,适合树莓派这类算力受限的目标检测设备;如果部署端用 TensorRT,YOLOv5 官方也支持通过 trt 参数导出。有一点要提醒:ONNX 导出的默认 opset 与训练时一致,部署端推理框架版本太老会出现不兼容,低版本先升级再跑。
我自己的习惯是,拿到任何“已标注可直接使用”的数据包,都会先花十分钟把 2.1 的数量核对、2.2 的坐标校验和 4.1 的空标签统计完整跑一遍,再谈训练参数。这一步省下来的调参和查 bug 时间,远超十分钟本身。这次红花数据集只要每一步都验到了,从解压到 best.pt 的路径其实非常顺。希望帮到你。
本文还有配套的精品资源,点击获取