尧图精选

YOLOv5实战:苹果橘子梨三类别数据集标注与训练全攻略

🕒 发布时间:2026/10/1 6:18:26 📁 来源:尧图网络
简介苹果、橘子、梨三种水果目标检测数据集按YOLOv5目录格式整理内含训练集与验证集可直接用于YOLOv5系列模型训练无需额外格式转换适合目标检测入门练习和实际项目部署。数据集共2000个文件主要由1397个txt标签文件、602个jpg图像文件及1个py可视化脚本组成压缩包约226.87MB图像为1080×810的RGB彩色图片每张包含多个目标边界框标注完整可作为小型水果检测训练数据。训练集有1117张图片及对应标签验证集有279张图片及对应标签类别信息通过txt文件说明目录结构清晰图片与标签文件名一一对应方便直接读取。附带可视化脚本可直接运行随机传入一张图片即可绘制边界框并保存到当前目录无需修改任何参数便于快速检查标注质量。平台已有518人学习下载资源上手门槛低适合目标检测入门与实战。1. 苹果橘子梨三类别数据集把目标检测从黑匣子拉回地面目标检测入门最崩溃的时刻不是模型训练不起来而是你下载了一个数据集却不知道图片和标注该怎么组织才能喂给 YOLOV5。这个三种水果检测数据集就是能把这件事拉通的最小样例类别只有 apple、orange、pear 三个目标大、边缘清晰、互相遮挡少训练集验证集已经按 YOLOV5 的约定分好。新手可以用它跑通「数据集 → 训练 → 验证 → 部署」的完整链路老手可以拿它当试验田验证标注转换脚本、超参数改动和迁移学习策略。下面按我平时拿到这种数据集后动手的顺序从目录结构、标注格式、划分逻辑到踩坑记录一次讲清楚。2. 先搭YOLOV5目录结构把三种水果的图片和标签放进该放的位置2.1 images 与 labels 双轨目录YOLOV5 数据集的标准骨架YOLOv5 训练自己的数据集时对目录结构的要求其实很死板但也因此很省心。标准骨架是把图片和标签放在两个互相平行的目录树里图片归图片标签归标签靠文件名一一对应。datasets/ └── fruit/ ├── images/ │ ├── train/ │ │ ├── apple_001.jpg │ │ ├── orange_002.jpg │ │ └── pear_003.jpg │ └── val/ │ ├── apple_011.jpg │ └── ... └── labels/ ├── train/ │ ├── apple_001.txt │ ├── orange_002.txt │ └── pear_003.txt └── val/ ├── apple_011.txt └── ...注意两个关键点。第一images 和 labels 下的训练目录名不必完全一致YOLOv5 实际上只认 data.yaml 里配置的路径但社区惯例是 train 对 train、val 对 val你按这个惯例组织最不容易把自己绕晕。第二同名图片和同名 txt 是一一对应的apple_001.jpg 必须配 apple_001.txt扩展名不同、前缀完全一致YOLOv5 在加载时就是按这个前缀去匹配标签的。如果有人给你的压缩包里 images 和 labels 目录对不上训练时会出现大量「WARNING: image without labels」日志这就是形态没组织好的典型翻车。先建目录再放文件是规避这类问题最省事的办法。2.2 labels/train 里的 txt 长什么样一行一个目标YOLOv5 的标签文件不是 XML也不是 JSON而是纯文本 txt每行代表一个目标框。拿 apple_001.jpg 对应的 apple_001.txt 来说内容大致是0 0.6230 0.4521 0.1802 0.2345 1 0.1209 0.7811 0.1504 0.2600 2 0.5012 0.3333 0.2015 0.1789这一真实格式里每行五个数字分别是类别编号、目标中心点 x 坐标、目标中心点 y 坐标、目标框宽度、目标框高度。注意三点。类别编号从 0 开始计数这里的 0 对应 data.yaml 里 names 列表的第一个名称1 对应第二个2 对应第三个顺序由你在 names 里定义的顺序决定坐标全部是归一化到 0~1 之间的浮点数也就是用像素坐标除以图片宽高不是原始像素值坐标是框中心点加宽高不是左上角加右下角。这套约定的好处是图片无论缩放到多大标签都不用改训练时 YOLOv5 内部会统一做 scale 处理。验证标签是否合法有个土办法随便挑一张训练图读一下图片宽高把 txt 里的五个数乘回去看能不能还原成框在图上正常范围内的合理位置。如果还原出来的 x、y 在 0~1 之外或者宽高为负数说明标注或转换脚本出了问题直接拿这种标签去训练loss 大概率发散。2.3 用 Python 脚本把图片与标签同步拆进 train 和 val很多三类别小数据集下载下来是图片和标签全混在一个目录里的需要你自己划分。我一般会用按文件名散列、可复现的脚本拆而不是纯随机抽这样同一批数据无论跑几次train/val 的成员都不会变。import os import random import shutil random.seed(42) # 固定种子保证每次划分结果一致 src_images fruit_source/images src_labels fruit_source/labels dst_root fruit split_ratio 0.85 # 85% 训练15% 验证 img_files [f for f in os.listdir(src_images) if f.lower().endswith((.jpg, .png, .jpeg))] random.shuffle(img_files) split_idx int(len(img_files) * split_ratio) for i, img_name in enumerate(img_files): prefix img_name.rsplit(., 1)[0] label_name prefix .txt is_train i split_idx split_name train if is_train else val # 同步移动图片和标签 img_src os.path.join(src_images, img_name) label_src os.path.join(src_labels, label_name) img_dst os.path.join(dst_root, images, split_name, img_name) label_dst os.path.join(dst_root, labels, split_name, label_name) shutil.copy(img_src, img_dst) shutil.copy(label_src, label_dst) print(ftrain: {split_idx}, val: {len(img_files) - split_idx})这个脚本看起来简单但有两个细节很容易忽略。一是 label_src 必须用和图片相同的前缀去拼所以图片是 PNG、标签 txt 的基名也要一致常见翻车是图片叫 apple_001.JPG 大写后缀txt 按小写拼出来匹配不上二是这里用了 copy 而不是 move是因为我不想在划分阶段就把源数据破坏掉等确认训练跑通了再统一删源目录也来得及。split_ratio按你的实际图片量调图片总量超过 2000 张时用 0.9 也不怕低于 300 张时不要分太低验证集太少会导致 mAP 波动大得没法看。2.4 data.yamltrain、val、nc、names 四行把数据连起来YOLOv5 不靠硬编码扫描所有图片而是通过 data.yaml 告诉训练程序去哪里找图、有几个类别、类别叫什么。fruit.yaml 最简版本是这样# data/fruit.yaml train: fruit/images/train val: fruit/images/val nc: 3 names: 0: apple 1: orange 2: pear路径这里最容易有歧义。train和val的路径是相对于你执行 train.py 时的工作目录来解析的。如果你在 yolov5 仓库根目录下执行python train.py --data data/fruit.yaml那fruit/images/train就是仓库根目录下的fruit/images/train。如果你在别的位置执行建议直接写绝对路径或者写成../datasets/fruit/images/train这种相对路径。我见过太多人把数据集放在 D 盘然后写train: E:/fruit/images/train一旦换机器就全部失效这类路径问题很玄学但几乎人人遇到过。nc必须和 names 列表长度一致names 的默认顺序就是训练时类别编号的顺序你有三种水果那 0、1、2 的顺序就写死为 apple、orange、pear千万不能中途换顺序。这套目录结构和 data.yaml 说明对 YOLOv8、YOLOv11 同样成立新框架几乎都保留了这套数据约定。3. 把标注转成YOLO格式VOC、COCO与手工标注的落地转换3.1 三种标注来源怎么选拿到三类别水果数据集标注形式不一定直接是 YOLOv5 txt。常见来源有三种LabelImg 手工标注输出 VOC XML 格式LabelMe 输出 JSON公开检测数据集或 CVAT 导出常用 COCO json 格式。目标检测常用的标注工具对比大致如下标注工具输出格式转 YOLO 难度适用场景LabelImgVOC XML低少量数据手工标注LabelMeJSON(多边形)中需要分割或复杂形状CVAT 导出COCO json中团队协作、批量标注现成公开数据集COCO json低直接复用已有数据对三种水果这种小目标、边界规则的数据集LabelImg 人手标几百张是最快的。但无论哪种来源最后你都得有一个统一的转换脚本。下面两节给出两种最常见格式的转换代码我每次换数据集都是直接改类别名列表复用这两段。3.2 从 COCO json 转 YOLO txt类别顺序是第一个坑COCO 格式里每个标注是一个 bbox形如[x, y, width, height]单位是像素坐标是框左上角。转成 YOLO 需要换算成中心点加宽高、再除以图片宽高归一化。转换脚本里最大的坑是类别编号映射。import json import os def coco_to_yolo(coco_json, img_dir, label_dir, class_names): with open(coco_json, r, encodingutf-8) as f: coco json.load(f) # 关键按类别名称排序把 COCO 的 category_id 映射成连续的 0,1,2 cat_id_to_new {} sorted_names sorted(class_names) # 例如按苹果、橘子、梨的字母序 for new_id, name in enumerate(sorted_names): for cat in coco[categories]: if cat[name] name: cat_id_to_new[cat[id]] new_id break img_id_to_info {img[id]: img for img in coco[images]} anns_by_img {} for ann in coco[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) for img_id, anns in anns_by_img.items(): img_info img_id_to_info[img_id] img_w img_info[width] img_h img_info[height] prefix img_info[file_name].rsplit(., 1)[0] label_path os.path.join(label_dir, prefix .txt) with open(label_path, w, encodingutf-8) as out: for ann in anns: new_id cat_id_to_new[ann[category_id]] x, y, w, h ann[bbox] # 左上角宽高 - 中心点宽高并归一化 x_center (x w / 2) / img_w y_center (y h / 2) / img_h w_norm w / img_w h_norm h / img_h out.write(f{new_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n) coco_to_yolo(fruit_annotations.json, fruit_images, fruit_labels, [apple, orange, pear])这里最重要的参数是class_names列表它决定了你最终 YOLO 标签里每个数字代表什么。很多公开数据集的 category_id 不是从 0 开始可能出现 apple 的 id 是 3、orange 的 id 是 1、梨的 id 是 7YOLOv5 完全不认这种跳号必须映射成 0、1、2。我按sorted(class_names)来做映射是为了让函数脱离具体数据集写死但你也可以直接写死为一个固定字典比如{apple:0, orange:1, pear:2}效果一样。要注意如果 COCO 里的命名和你的 class_names 不完全一致cat[name] name匹配不上会导致部分标注被丢弃转换后统计一下每个类别的框数量是最快的检查办法。3.3 从 VOC XML 转 YOLO归一化坐标的四个换算LabelImg 默认输出 VOC 格式 XML里面记录的是xmin, ymin, xmax, ymax同样是绝对像素。转换的四个换算公式是固定的我用 xml.etree.ElementTree 解析不依赖额外库。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_dir, label_dir, class_names): for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_name)) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) prefix xml_name.rsplit(., 1)[0] label_path os.path.join(label_dir, prefix .txt) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue class_id class_names.index(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) # 四个核心换算公式 x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h w_norm (xmax - xmin) / img_w h_norm (ymax - ymin) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n) with open(label_path, w, encodingutf-8) as f: f.writelines(lines) voc_to_yolo(fruit_xmls, fruit_labels, [apple, orange, pear])这段代码里容易出问题的是 bbox 解析。部分标注工具的节点名不是bndbox而是boundingBox或直接叫boxobj.find(bndbox)会返回 None程序直接报错。另一个边界情况是xmin, xmax是像素小数但 XML 里存成整数除法没问题唯独要注意个别工具把坐标存成相对宽高的百分比这种情况下就不能再除以 img_w。转完后我习惯顺手跑一个循环读取 txt 每行检查五个数是否都在 0~1 以内有过界的立即定位到对应 XML 手查。3.4 越界修正与空标签兜底标注框不该落在图外手工标注很容易把框拖到图片边缘外几个像素或者因为误操作画出一个宽度为 0 的框转换脚本如果不做兜底后期训练会随机出 NAN。我一般在转换脚本末尾统一做一次清洗代码不长但能省很多调试时间。import os def clean_yolo_labels(label_dir, img_dir): for txt_name in os.listdir(label_dir): if not txt_name.endswith(.txt): continue txt_path os.path.join(label_dir, txt_name) with open(txt_path, r) as f: lines f.readlines() clean_lines [] for line in lines: parts line.strip().split() if len(parts) ! 5: continue # 丢掉格式损坏的行 cls int(parts[0]) xc, yc, w, h map(float, parts[1:]) # 宽高必须为正否则丢弃 if w 1e-6 or h 1e-6: continue # 将中心点和宽高裁剪到合法范围并重新限制尺寸 xc min(max(xc, 0.0), 1.0) yc min(max(yc, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) clean_lines.append(f{cls} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}\n) with open(txt_path, w) as f: f.writelines(clean_lines) clean_yolo_labels(fruit_labels, fruit_images)这里的裁剪逻辑要说明一下直接粗暴 clip 到 0~1 并不是最严谨的因为中心点在 0~1 外但框本身有一大部分在图内的目标clip 后框位置会失真。更好的做法是先判断中心点是否在图内中心点越界但宽高很大的框直接丢弃中心点在 0~1 内而框边略微越界才用 clip 修正。上面这个脚本是按大多数三类别水果图写的「保底方案」你先存下修改前的 txt 再跑对比一下被修了哪些框能帮你反过来发现标注工具的惯性问题。空标签文件也同样要兜底如果一个 txt 清洗后一行都不剩会造成 YOLOv5 加载时报空标签警告这种图片最好直接从训练集里剔除不要留着凑数量。4. 划分训练集验证集三种水果该怎么分才不翻车4.1 按文件散列划分而不是按随机抽第 2 章提到了用固定 random 种子的划分方式实际项目里我更推荐按文件名散列来划分因为不依赖random.shuffle对列表顺序的改动哪怕未来往目录里新增图片已经划出去的文件不会变。import hashlib import os import shutil def hash_split(src_images, src_labels, dst_root, train_ratio0.85): for img_name in os.listdir(src_images): if not img_name.lower().endswith((.jpg, .png, .jpeg)): continue prefix img_name.rsplit(., 1)[0] # 用 md5 散列的前两位来决定归属稳定且可复现 digest hashlib.md5(prefix.encode(utf-8)).hexdigest() is_train int(digest[:2], 16) / 255 train_ratio split_name train if is_train else val src_img os.path.join(src_images, img_name) src_lbl os.path.join(src_labels, prefix .txt) shutil.copy(src_img, os.path.join(dst_root, images, split_name, img_name)) shutil.copy(src_lbl, os.path.join(dst_root, labels, split_name, prefix .txt)) hash_split(fruit_source/images, fruit_source/labels, fruit, 0.85)散列划分的好处是验证集不会因为哪次 shuffle 顺序变了而变化。但用md5[:2]这种方式时样本量小到 100 张以内划分比例可能偏离 85% 比较多因为散列值的分布并不保证每 100 个文件均匀 0~255。样本量超过 500 张时基本稳定。如果你想严格保证比例那还是回到第 2 章的 random.seed 版本两者各有侧重散列法侧重增量可复现固定种子法侧重比例精确。三类别水果这种小数据集我用固定种子法更多。4.2 按图片抽还是按场景抽采样泄漏是 mAP 虚高的元凶划分训练集和验证集时最常见误区是单独把每一张图随机分边而没有考虑图片之间的相似度。三种水果数据集如果是连续拍摄的比如同一堆苹果在传送带上连续拍了 200 张这些图背景几乎相同、目标位姿几乎相同如果一部分进训练集一部分进验证集模型在验证集上的 mAP 会虚高因为它已经提前见过几乎一样的背景。正确的做法是按「场景批次」划分。如果你知道哪些图来自同一个视频或同一次拍摄把整个批次划到一边。如果没有批次信息保守做法是把图片按时间戳前缀或采集批次命名分组再把整个组放进 train 或 val。对苹果橘子梨这类目标检测小数据集我还会额外检查验证集里是否有跟训练集一模一样的重复文件用文件 md5 对比一遍重复的图必须从一边删掉。这一步成本极低但对结果可信度影响极大。4.3 类别分布检查梨只有 200 张时别硬按 85% 分三类别数据集经常出现类别不均衡比如苹果 5000 张、橘子 4500 张、梨只有 800 张。这时候如果整体按 85% 随机切验证集里梨可能只有 100 张出头mAP 对梨的评估会非常不稳定。我会按类别分别统计后再决定是否分层采样。import os from collections import Counter def count_class_instances(label_dir): counter Counter() for txt_name in os.listdir(label_dir): with open(os.path.join(label_dir, txt_name), r) as f: for line in f: parts line.strip().split() if len(parts) 5: counter[int(parts[0])] 1 return counter train_counter count_class_instances(fruit/labels/train) val_counter count_class_instances(fruit/labels/val) print(train:, train_counter) print(val:, val_counter)这个脚本输出每个类别在训练集和验证集里的目标框总数。我要强调的是划分时看的是「目标框数」不是「图片数」因为一张图里可能同时有苹果和橘子。如果发现验证集某一类占比明显低于训练集该类占比比如训练集里梨占 8%验证集里梨只占 3%那就应该手动从梨比较多的剩余图片里再抽补一些进验证集或者干脆对梨的图片做一次复制粘贴增强后再划分。类别不均衡直接决定最终模型对梨的检出率这个锅不能甩给模型结构多半是划分阶段就埋下的。4.4 训练命令与五条快速验证命令先跑 1 个 epoch 再决定要不要全量训目录结构、划分、data.yaml 都就绪后我建议不要直接--epochs 300开训先跑一个 epoch 做冒烟验证。# 冒烟测试1 个 epoch确认数据加载无报错 python train.py --data data/fruit.yaml --weights yolov5s.pt --epochs 1 --img 640 --batch-size 16 # 训练完成后验证模型质量 python val.py --data data/fruit.yaml --weights runs/train/exp/weights/best.pt --plots # 用验证集图片做实际推理可视化 python detect.py --source fruit/images/val --weights runs/train/exp/weights/best.pt --conf 0.25 --save-txt这三个命令里第一个命令如果顺利跑完说明 images 和 labels 能对上、data.yaml 路径正确、类别配置无误。--epochs 1不是为了出效果是为了让数据加载、loss 计算、反向传播全链路快速过一遍任何标注格式问题都会在这个环节爆出来。第二个命令会输出 mAP0.5 和 mAP0.5:0.95同时--plots会生成混淆矩阵和 PR 曲线验证集能不能用一眼就清楚。第三个命令把验证集真实跑一遍输出的 txt 和图片能直接看到漏检和误检。五条命令里最重要的其实是第一条和第二条一个保证能训一个保证能评。5. 常见问题与避坑三类别小数据集最容易踩的五个坑5.1 能训练但 mAP 始终低于 0.5类别编号整体错位现象训练 loss 能正常下降但验证集 mAP0.5 一直在 0.3~0.4 徘徊无论训多久都上不去。看检测结果图发现模型把橘子框出来但类别写成 apple或者梨写成了 orange。原因标注 txt 里的类别编号和 data.yaml 的 names 顺序不一致。常见于从 COCO json 转换时没有重新映射 category_id导致原本的 id 1、2、3 直接当作 YOLO 的 0、1、2 写进去和 names 列表错位。解决先用统计脚本遍历 labels 目录确认每个 txt 里类编号的最大值必须小于 nc。然后随机挑 3~5 个 txt手动打开看第一列编号再对照原图做一次人眼复核。修改映射关系后重新转换标注不要试图在 data.yaml 里通过调整 names 顺序去迁就地错位的编号那是给后面挖更大的坑。5.2 验证集 loss 正常而 mAP 波动剧烈验证集混入了训练图片现象每次训练完跑验证mAP 一会儿 0.7、一会儿 0.4同一份训练权重两次验证结果差异巨大。更诡异的是训练 loss 很平稳完全看不出异常。原因验证集里混入了几张和训练集重复或几乎相同的图片。第一次验证时这些重复图出现在检测正确的区间mAP 被抬高第二次模型对同类图稍微没检出mAP 又被打回去。三类水果的小数据集如果划分时按无序的目录直接切极容易出现同批连拍的相似图分到两边。解决对 train 和 val 的图片各算一次 md5找出两边重复的文件从验证集里删除。再按第 4 章说的场景分组检查一次连续帧图片原则上不能跨边。验证集数量不足时不要降低验证集比例硬填而是收集更多新场景数据补上验证集脏了比验证集小更可怕。5.3 训练到一半 loss 突然变 NAN标注坐标越界或出现负数现象训练前几十个 epoch 正常某个 epoch 开始 loss 输出为nan模型权重基本报废中断后无法继续。查看本 epoch 的日志正常 epoch 的box_loss通常在 0.05 左右出现 nan 的那一轮直接变成nan或者大数。原因标签 txt 里存在越界坐标或非法的极大值。平时这些坏标签的梯度贡献不明显等某次数据增强恰好把对应区域放大坏坐标的 loss 瞬间爆炸。多数情况下是转换脚本没有对归一化坐标做范围检查比如把像素值除以了错误的宽高得到 2.5 或 -0.3 这种值。解决按第 3 章的clean_yolo_labels统一清洗一遍全部标签把五列数值都在0~1区间的行留下其余删除。清洗后再跑一次python val.py如果数据加载阶段报出没有标签或标签异常说明还有漏网之鱼。为了让问题提前暴露而不是训到一半才发现训练时加上--cache ram有时候会触发更早的数据校验但最根本的做法是清洗脚本每次转换后必须跑。5.4 梨的类别总是检测不到小类别样本不足不是模型问题现象混淆矩阵里 apple 和 orange 的正确率都在 0.9 以上但 pear 那一行的召回率在 0.2 以下。检测验证集图片梨子要么被漏掉要么被标成 apple。原因梨的标注数量明显少于另外两类模型在训练时对梨的特征贡献权重很低。三类别水果数据集里这往往不是算法问题而是样本数量分布问题。如果梨只有几十张再好的结构也学不出稳定的类别特征。解决先做类别统计确认不均衡程度。梨严重偏少时先对梨的图片做随机旋转、亮度变化、水平翻转的数据增强在增强后再重新划分 train/val。更稳的做法是修改训练超参数把--hyp data/hyps/ hyp.scratch.yaml里的cls损失权重调高一点但最根本的还是去补拍箱子里不同成熟度、不同光照的梨增加样本覆盖。超参数只是把模型注意力往梨上拨不能从无中生有变出特征。5.5 验证集为空或路径报错data.yaml 的相对路径与 labels.cache 缓存现象训练开始时日志输出train: ... images/train... val: ...但后面跟了0 images或直接报AssertionError: train: No labels in...。另一种情况是修改了目录结构后再次训练仍然读取旧数据。原因第一data.yaml 里 val 路径写错或写成了valid而目录名是val第二YOLOv5 首次加载数据会生成labels.cache文件之后直接读缓存如果你删掉或调整了部分标注文件缓存里还是旧记录第三路径相对执行目录解析出错。解决先删除数据集目录下所有.cache文件再检查 data.yaml 的train和val是否指向真实存在的目录。在 yolov5 根目录下用ls fruit/images/val确认能看到图片。最后把 data.yaml 里的路径改成绝对路径试一次如果绝对路径正常而相对路径异常那就是执行位置不对把命令固定到 yolov5 根目录或在 data.yaml 里写死绝对路径即可。这个坑和标注格式无关纯粹是路径解析但出现频率非常高尤其是从压缩包解压后目录层级变化时。6. 训练前必做用可视化把三种水果的每一框看一遍6.1 先跑一次短训练用 --plots 生成带框预览图拿到任何新数据集我第一步都不是直接调参而是用最小代价跑几个 epoch 后生成可视化标注图。具体做法是在正常训练命令里加--plots训练过程会在runs/train/exp/下生成val_batch0_labels.jpg和val_batch0_pred.jpg这类文件前者是真实标注画在图上后者是模型预测结果。python train.py --data data/fruit.yaml --weights yolov5s.pt --epochs 50 --img 640 --batch-size 16 --plotsval_batch0_labels.jpg会随机挑一批验证集图把每个真实框和类别标签画上去。我一般盯这个文件看三件事框有没有明显偏移目标类别名和物体是否对得上有没有漏标或误标的目标。比看训练曲线快得多数据问题在这一步暴露三分钟就能看明白而不是等训练完才发现。6.2 小数据集迁移学习从 yolov5s.pt 起步更省心三类别水果这种小规模数据集不要从随机权重开始训直接拿yolov5s.pt做迁移学习。水果检测和 COCO 预训练特征高度相关预训练权重能提供骨干网络的通用特征训练几轮后收敛速度肉眼可见地快。常见做法是保持默认超参数先把模型训起来等验证 mAP 稳定后再针对低召回的那个类别去调cls损失权重而不是一上来就改一堆超参数。我自己拿到三类别水果或类似小数据集时习惯先跑一遍默认配置把底线摸清楚再看混淆矩阵决定下一步到底补数据还是调参数这个过程几乎不会翻车。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →