简介:面向花卉图像分类与yolov8模型训练需求,该数据集包含daisy、dandelion、roses、sunflowers、tulips五个常见类别,适用于图像分类、目标检测及迁移学习等任务,也可支撑高校实验、园艺品种筛选和植物科普展示。资源共2000个文件,其中1999张jpg图像提供多场景、多姿态的花卉样本,另含1个py脚本用于数据集划分、格式转换或训练辅助,压缩包整体约218.93MB。已有622人学习下载,适合刚接触分类任务的学生或需要快速搭建花卉识别模型的开发者。数据集图片按类别组织、命名规范,视觉差异明显,便于开展数据增强与泛化能力评估;结合yolov8训练流程可快速获得基线结果,为后续扩充花卉品类、优化分类精度以及植物学教学演示提供了直接可用的数据基础。花卉分类在植物多样性保护、园艺选种和科学普及中应用广泛,这份数据可作为相关系统开发与验证的标准化输入。
1. 5类花卉YOLOv8数据集:拿到手先认清它是什么,能省多少事
如果你手头攒了几千张花的照片,想训练一个能分清 daisy、dandelion、roses、sunflowers、tulips 这五类的小模型,最卡壳的往往不是模型选型,而是数据格式:图片放在哪个目录、类别怎么映射成数字、train 和 val 按什么比例切、坏图会不会让训练中断。这个 5 类花卉 YOLOv8 格式数据集解决的就是这件事——把五类花卉图像按 YOLOv8 分类任务的目录约定整理好,train/val 已经划好,类别顺序固定,拿到手第一条训练命令就能跑通。对刚入门 YOLOv8 分类的新手,它省掉了最磨人的数据准备阶段;对已经在跑检测或分割任务的老手,它也能当一份干净的 baseline 数据,用来验证自己的训练流水线、对比增强策略,或者测试不同骨干网络在细粒度图像分类上的表现。下面从数据集格式开始拆,一路讲到训练参数、评估指标和最常见的几个坑。
2. 目录结构与格式解析:从原始照片到YOLOv8训练的准备工作
2.1 YOLOv8分类数据集的标准目录约定
YOLOv8 的分类任务(classify)和检测任务(detect)在数据组织上完全不同。检测需要 txt 标注文件和 data.yaml,里面写类别列表和路径;分类任务直接沿用了 ImageFolder 风格的目录结构:数据根目录下放 train 和 val 两个子目录,每个子目录里每类花一个文件夹,文件夹名就是类别名。这种设计对新手非常友好,因为标签就是文件夹名,肉眼扫一眼目录树就能完成核对。
flowers/ ├── train/ │ ├── daisy/ │ │ ├── daisy_001.jpg │ │ ├── daisy_002.jpg │ │ └── daisy_003.jpg │ ├── dandelion/ │ ├── roses/ │ ├── sunflowers/ │ └── tulips/ └── val/ ├── daisy/ ├── dandelion/ ├── roses/ ├── sunflowers/ └── tulips/训练时把 data 参数直接指向 flowers 这个根目录,框架会自动扫描 train 下的子目录,并按字母序生成类别映射:daisy=0、dandelion=1、roses=2、sunflowers=3、tulips=4。这里的 tu 就是 tulips 的缩写,正式使用时我建议文件夹名写全称。原因很简单:推理阶段打印类别名时,全称可读性高,也不会因为“tu”到底代表 tulips 还是 tulip 产生歧义。
实际整理时还有几个容易忽略的点。一是目录里不要混入多余的隐藏文件,比如 macOS 的 .DS_Store、Windows 的 Thumbs.db,以及操作时误拷贝的空文件夹。框架扫描子目录生成类别表时,多一个非预期文件夹就会多出一个类别,训练日志里类别数会从 5 变成 6 甚至更多。二是路径尽量不要带中文和空格。YOLOv8 对带空格路径多数情况能处理,但一旦在 Windows 环境下出现转义问题,报错会非常难查。三是 train 和 val 的子目录名必须完全一致,如果 val 里写成了“Daisy”或者“daisy 副本”,类别映射就会对不上。
2.2 坏图清洗与图像尺寸筛查:别让一张坏图毁掉整轮训练
原始图像在进入上面这个目录结构之前,必须过一遍坏图检查。真实场景里最常见的三类问题:扩展名是 jpg 但文件实际已损坏的;下载过程被截断导致解码失败的;以及某些 20x20 缩略图混进数据集的。坏图的危险在于训练时偶发抛错,表现为“跑着跑着突然崩掉”或者某个 epoch 卡住不动,定位起来非常痛苦。
我一般会在划分目录之前跑一个全量校验脚本,用 PIL 做两级检查:
from PIL import Image import os def inspect_images(root_dir, min_side=32): problems = [] for dirpath, _, filenames in os.walk(root_dir): for fn in filenames: if not fn.lower().endswith((".jpg", ".jpeg", ".png")): problems.append((os.path.join(dirpath, fn), "bad_extension")) continue path = os.path.join(dirpath, fn) try: with Image.open(path) as im: im.verify() with Image.open(path) as im: im.load() if min(im.size) < min_side: problems.append((path, "too_small")) except Exception as e: problems.append((path, repr(e))) return problems issues = inspect_images("./raw_images") for path, reason in issues: print(path, "->", reason)逻辑说明:第一遍用 im.verify() 只解析文件头部,开销很小,用来快速淘汰扩展名伪造的假图片;第二遍用 im.load() 强制把像素数据读进内存,这一步能暴露头部正常但像素区损坏的文件。只做 verify 不做 load,会让一批“能打开但一解码就崩”的文件漏过去。
参数说明:min_side 指宽高中较短一边低于 32 像素就标记为 too_small。这个阈值要按任务调整——如果图片里花占比很大,32 已经够看;如果花很小、要靠局部细节区分,建议放宽到 16;反过来,如果都是高清原图,阈值设 128 可以顺带清掉一批低质缩略图。脚本只输出问题列表而不直接删文件,我会先人工扫一眼列表,再批量移到 quarantine 目录,防止把格式特殊但能正常用的图误删。
2.3 按比例划分train/val的脚本与类别映射逻辑
拿到原始图像后,第一个动作通常是做 train/val 划分。最常见做法是按文件随机打乱后切分,固定随机种子,否则每次划分结果都不同,实验之间没法比较。另一个容易被忽略的点是:划分粒度应该是“文件批次”而不是“单张文件”。如果你同一个花的多张连拍内容高度相似,它们要么全进 train,要么全进 val,否则就会出现数据泄露,后面 val 精度虚高。
import os import random import shutil src_root = "./raw_images" dst_root = "./flowers" categories = ["daisy", "dandelion", "roses", "sunflowers", "tulips"] val_ratio = 0.2 random.seed(42) for cat in categories: src_dir = os.path.join(src_root, cat) if not os.path.isdir(src_dir): continue files = [f for f in os.listdir(src_dir) if f.lower().endswith((".jpg", ".jpeg", ".png"))] random.shuffle(files) val_count = round(len(files) * val_ratio) val_set = set(files[:val_count]) for f in files: split = "val" if f in val_set else "train" dst_dir = os.path.join(dst_root, split, cat) os.makedirs(dst_dir, exist_ok=True) shutil.copy(os.path.join(src_dir, f), os.path.join(dst_dir, f)) print(cat, "train:", len(files) - val_count, "val:", val_count)逻辑说明:脚本对每个类别独立切分,保证 val 里五类的分布比例和原始数据一致,而不是把图片全局混洗后再切。全局混洗的问题在于:如果某类原始数据只有 200 张,另一类有 1000 张,全局切分后 val 里各类比例与训练集比例不一致,小类在 val 里的样本可能少到算不出稳定的精度。这里用的 copy 而不是 move,是为了留一份原始图像做后悔药;磁盘实在不够再改成 move,但建议至少保留一个清单文件,记录每张图属于哪个 split。
参数说明:val_ratio=0.2 是大多数图像分类任务的经验值。几千张图时,20% 的 val 足够算出稳定的 top1/top5 精度;如果总量只有几百张,建议提到 0.3,并且考虑做交叉验证来选模型。random.seed(42) 保证不同机器、不同时间跑出来的划分一致,这是实验可复现性的基础。
如果数据有明显来源批次,例如同一天、同一机位、同一个花圃拍摄的一批图,上面这个脚本还是不够稳。更稳妥的做法是先按来源分组,再对分组做切分。我常用的一种变通方案是:按文件名里的序号前缀或拍摄时间戳做桶,以桶为单位 shuffle 和划分,桶内图像天然属于同一次拍摄批次,这样能有效减少泄露。这个细节在第 5 章还会专门展开。
3. 用YOLOv8训练花卉分类模型:最小命令、骨干选型和四个必调参数
3.1 一行命令启动训练:分类任务的data指向与命令行写法
数据目录就绪后,训练本身非常简单。以 YOLOv8 的 CLI 方式为例:
yolo classify train data=./flowers model=yolov8n-cls.pt epochs=50 imgsz=224 batch=32这行命令做三件事:加载 yolov8n-cls.pt 预训练权重;扫描 flowers/train 下的五个子目录生成类别表;用 224x224 输入在默认增强策略下训练 50 轮。训练产生的权重、曲线图和参数配置全部落在 runs/classify/train 目录下,不会污染数据目录,也不会覆盖旧实验。
这里最关键的是 data 参数的指向:分类任务里 data 必须是指向同时包含 train 和 val 两个子目录的根目录,而不是某个类别文件夹,也不是一个 yaml 文件。这是 classify 和 detect 任务最大的区别。检测任务必须提供 data.yaml,里面写 train/val 路径和 names 列表;分类任务只需要目录路径,类别由子目录名称自动生成。我见过不少第一次用的人把 data 指到了 train 目录,结果 val 扫描阶段直接报错,提示找不到验证集。
如果更喜欢在 Python 脚本里控制训练流程,等价的写法是:
from ultralytics import YOLO model = YOLO("yolov8n-cls.pt") results = model.train( data="./flowers", epochs=50, imgsz=224, batch=32, lr0=1e-3, patience=10, )参数说明:epochs=50 是花卉分类比较稳的起点。预训练权重来自大规模通用图像集合,花卉这种细粒度任务通常 20 到 30 轮就能收敛,50 轮留出了观察曲线形状的富余空间。patience=10 表示连续 10 轮 val 精度不再提升就提前停止,防止后半段刷过拟合。lr0=1e-3 是对预训练权重做微调时比较安全的学习率;官方的某些默认策略在启动时会到 1e-2 量级,小数据集上容易看到 loss 震荡。
训练开始后,终端会按 epoch 打印 train loss、val loss、top1_acc、top5_acc 等指标。第一次跑的时候不用太纠结每一行的波动,先看整体趋势。如果前 5 轮里 top1_acc 能快速从几十爬到 80 以上,说明数据和预训练权重是匹配的;如果一直趴在 20% 附近(五类任务的随机水平),优先怀疑学习率设置或者数据路径是否正确。
3.2 骨干网络选型:n/s/m/l对花卉分类的性价比
YOLOv8 分类系列按规模从轻到重有 n、s、m、l 几个档位,对应 yolov8n-cls.pt、yolov8s-cls.pt 等预训练权重。对 5 类花卉这种任务,我的建议是:先用 n 跑通全流程,确认数据没问题,再用 s 作为最终模型。只有当 val 精度卡住不动、且混淆矩阵显示某两类确实难分时,才考虑上 m 或 l。
原因很直接:花卉分类的瓶颈通常不在模型容量,而在数据多样性。几千张图,每类几百到一两千张,n 模型在 224 输入下已经能到 90% 以上的 top1。换 l 模型,计算量和显存翻几倍,精度提升可能只有 1 到 2 个百分点,对部署价值有限。从显存角度看一个经验参考:batch=32、imgsz=224 时,n 模型在 6G 显存卡上没问题;s 模型建议 8G 以上;m、l 就老实把 batch 降到 16 或 8。小显存不是不能跑大模型,是训练速度慢到不值得。
骨干选择的另一个维度是输入分辨率。n 模型配合 imgsz=320 往往比 m 模型配合 imgsz=224 更能解决细粒度分辨问题,因为花的细节是空间信息,提高分辨率比增加通道数更直接。所以我一般把“先提分辨率、再升骨干”作为调优顺序。
3.3 必调参数:imgsz、epochs、lr0、batch与早停patience
训练中最值得手动调的四个参数可以浓缩成下面这张表:
| 参数 | 常见范围 | 我的默认 | 说明 |
|---|---|---|---|
| imgsz | 224 / 320 / 640 | 224 | 花卉占画面主体时 224 够用;花很小或要分辨花蕊纹理时上 320 |
| epochs | 30 ~ 100 | 50 | 配合早停使用,给足就行,不必死等 |
| lr0 | 1e-4 ~ 1e-2 | 1e-3 | 迁移学习默认 1e-3,数据很少时降到 1e-4 防震荡 |
| batch | 8 ~ 64 | 32 | 太小会让 BN 统计不稳定,太大对精度提升有限 |
先解释 imgsz。分类模型的输入分辨率决定它能看到多少细节。daisy 和 dandelion 的区别有一部分在花瓣形态和叶片形状上,224 能看清整体结构,但如果原图里花朵很小、只占画面的一半都不到,模型会拿大量背景区域做判断。这时把 imgsz 提到 320,等效于把花放大 1.4 倍再看,精度提升往往比换骨干更明显。代价是训练时间大约增加 1.5 倍,显存也跟着涨。
epochs 和 patience 是一对。分类训练最怕的不是轮数太少,而是你盯不住曲线、任它跑完 100 轮刷出一个过拟合模型。我的习惯是 epochs 给到 100,patience 设为 10。框架每个 epoch 结束会在 val 上算一次 top1/top5,连续 10 轮没有提升就停,最终保留的是 val 精度最高那一轮的权重 best.pt。这个机制下,epochs 给大点没有坏处。
lr0 的调节要看训练日志前几轮的表现。跑了 3 轮,如果 train loss 几乎不降、val acc 一直在 20% 上下晃,大概率是学习率不合适。学习率过高时,loss 曲线会出现“降一点、涨一点”的锯齿。1e-3 在微调场景下是安全起点,翻车概率最低。batch 的调整则跟着显存走:出 OOM 就把 batch 减半,同时把 lr0 对应调低一点,否则相同学习率在小 batch 上显得步子太大。训练过程中的监控只需要盯两个数字:每个 epoch 末尾的 val/top1_acc 和当前的 train loss。top1_acc 在 30 轮后还在匀速上涨,说明没到瓶颈,可以继续等;已经横盘 10 轮,早停会帮你收工。所有曲线在 runs/classify/train 目录下的 results.png 里都能看到,包含 loss 和 top1/top5 两组曲线。
4. 评估与推理验证:从val结果到能用的预测脚本
4.1 val模式的输出文件怎么读
训练完成后,weights 目录下会保存 best.pt 和 last.pt 两个权重。best.pt 是 val 精度最高那一轮的产物,last.pt 是训练结束时的产物。实际使用一律用 best.pt,除非你明确知道 last 这一轮泛化更好——这种情况很少见,但确实偶尔发生。
对训练好的模型做一次完整验证,用下面这条命令:
yolo classify val model=runs/classify/train/weights/best.pt data=./flowers imgsz=224val 命令会重新扫描 val 目录,逐张做预测,最后在终端打印 top1_acc 和 top5_acc,同时在同一目录下更新 confusion_matrix.png、results.csv 等指标文件。这个独立 val 过程和训练时“每轮末尾的验证”用的是同一套数据加载逻辑,但它更精确:训练过程中的 val 会受数据增强的随机性影响,独立 val 则是把增强关掉、逐张稳定评估,结果更可信。新手容易以为训练日志里的 val 就够了,省掉这一步。实际上两个数值之间偶尔会差 1 到 2 个点,单论调参你该信独立评估的结果。
参数说明:data 指向和训练时相同的数据集根目录;imgsz 要和训练时保持一致。如果训练用了 320、这里用 224 来验证,模型输入分辨率变了,精度会掉一点,尤其从高分辨率降到低分辨率时比较明显。所以这条命令里的 imgsz 最好复制训练命令里的值,不要随手改。
4.2 混淆矩阵:daisy和dandelion的分不清在哪一目了然
val 跑完,打开 confusion_matrix.png 能看到一张 5x5 的矩阵热力图。行是真值,列是预测值,对角线越亮越好。花卉场景里最常见的问题就是 daisy 和 dandelion 互相串:这两类都是白色小菊花头,花瓣形态也很接近,混淆矩阵里对应格子总是特别亮。
看到这种情况,我的处理顺序是:先不动模型结构,回到数据看两个方向。第一,val 里这两类的样本质量是否足够。如果 daisy 的 val 图大多是背景虚化严重、花头占画面不到 20% 的图,模型拿到的有效特征太少,误判很正常。第二,看训练增强是否覆盖了这两类的共性差异。如果照片里只有 daisy 有密集重瓣、dandelion 全是单层花瓣,这种分布差异会在训练时强化模型把“重瓣”当作 daisy 的特征,泛化就很弱。
如果数据没问题,再调训练策略。一个便宜有效的做法是把 imgsz 从 224 提到 320,让花蕊和花瓣边缘进入感受野;另一个做法是做困难样本挖掘——把 val 里预测置信度在 0.5 到 0.8 之间的图挑出来人工看一遍。如果发现这些图背景相似度极高,就补充一些“不同背景下同种花”的训练样本,比单纯堆数据更高效。
4.3 单图与批量推理脚本:把模型变成可调用的服务
评估通过后,最常见的用法是把模型接进批量打标脚本或本地服务。用 Python API 做单图预测:
from ultralytics import YOLO model = YOLO("runs/classify/train/weights/best.pt") results = model.predict("test_flowers/001.jpg", imgsz=224) probs = results[0].probs top1 = probs.top1 top1_conf = probs.top1conf print(model.names[top1], round(float(top1_conf), 3)) print("top5:", [model.names[i] for i in probs.top5])逻辑说明:分类任务的 predict 返回值里,probs 是预测概率对象。top1 是最高概率对应的类别索引,top1conf 是它的置信度;top5 是概率前五的类别索引列表。这里不要尝试用 results[0].boxes,那是检测任务的结果结构,在分类任务里是空的,取出来只会拿到 None。model.names 保存了类别名列表,打印出来能看到类似 {0: 'daisy', 1: 'dandelion'} 的映射。
批量预测同样简单,传一个目录路径就会递归扫描所有图片:
yolo classify predict model=runs/classify/train/weights/best.pt source=./test_flowers save_txt=True每条命令会为每张图生成一个同名 txt 文件,内容格式是“类别索引 置信度”,对应关系去 model.names 里查。适合给一组没有标注的新照片快速打标,比如刚从相机里导出的花圃照片。
如果你的场景是把模型接进 web 服务,我一般不用 CLI,而是在进程启动时加载一次模型,之后每个请求直接调用 predict,并把 imgsz 固定住,避免重复初始化推理上下文。另一个实用技巧是传 device="0" 把推理放到 GPU;没有 GPU 时模型自动落到 CPU,imgsz 保持 224 的情况下,单张推理通常能到几十毫秒量级,已经够很多演示场景用。
5. 花卉分类数据集常见坑:不平衡、过拟合、背景干扰与脏标签
5.1 类别样本数差三倍:模型悄悄偏向多数类的现象与修正
现象:训练日志里整体 top1_acc 到了 92%,按类别细看,daisy 的 recall 是 98%,tulips 只有 76%。原因是 tulips 的样本数只有 daisy 的三分之一,模型在低置信度区间的预测倾向被多数类带偏,统计先验把模糊样本推向了训练集中更常见的类别。
原因:随机采样构建 batch 时,多数类在每个 batch 里出现概率高,梯度更新方向被多数类主导。花卉数据集中 dandelion 和 daisy 外观本来就接近,模型在两者间犹豫时,更容易把模糊样本判成数据量更大的那一类。
解决:先统计五个类别的文件数。如果最大类和最小类相差超过 2 倍,优先补数据,而不是调权重。补数据不方便时,常见做法是在训练前对少数类做简单增强复制——水平翻转、轻度旋转、调饱和度,把少数类扩到多数类的 70% 以上再训练。YOLOv8 分类任务里没有直接暴露类别权重参数,但通过这个办法同样能达到类似加权采样的效果。要注意,增强复制出来的样本不是新信息,扩太多反而容易让模型对复制样本过拟合,一般扩到接近多数类就够了。
这条坑的教训是:只看 top1_acc 会掩盖少数类崩盘。我习惯在调参前单独打印每个类别的 recall,再对照样本数看,很多“精度上不去”的问题本质上只是数据不平衡。
5.2 过拟合信号:train_acc高而val_acc低的处理路径
现象:训练到第 45 轮,train loss 降到 0.02,train top1 到了 99.8%,但 val top1 停在 86% 上不去了。这不是模型没学会,是它把训练集里每张图的构图、光照、甚至 JPEG 压缩痕迹都背了进去。
原因:花卉数据天然容易过拟合。同一批花可能在同一个晴天、同一个角度被拍了很多张,这些图内容高度相似,模型不需要泛化也能在 train 上拿高分。另一个因素是数据量小的时候,模型容量相对过剩,记忆比泛化更容易。
解决:按顺序处理三个环节。第一,看增强是否够强。YOLOv8 分类默认开启轻度增强,如果 val 精度从第 20 轮开始就不动,可以考虑在预处理阶段加更明显的色彩抖动和随机裁剪。第二,加 dropout。YOLOv8 分类任务支持在训练时设置 dropout=0.2,对分类头做随机失活,通常能在 val 精度上换回 1 到 3 个点。第三,检查划分里有没有数据泄露——如果 val 里某张图和 train 里另一张图肉眼几乎完全一样,这个 val 精度本身就是虚高的,修划分比调模型更紧急。
经验:过拟合的典型曲线是 train_acc 一路向上、val_acc 在第 25 轮左右见顶后横盘。不要指望跑满 100 轮能突破,patience=10 的早停通常会在精度峰值后第 10 轮把你拉出训练,保留的 best.pt 就是峰值权重。
5.3 背景干扰:模型学的是花瓣还是花盆?
现象:模型在 val 上对某种花的判断受画面背景影响很大。测试图改成“花卉特写但背景里有其他植物”时,预测概率出现明显下降。人工检查训练图后发现,大量样本是带花盆、带完整植株的全身照,模型很可能直接学了花盆轮廓和陶土色纹理,而不是花瓣。
原因:分类模型会利用所有能帮助它降 loss 的特征,包括背景。当某几类花的背景高度一致、而花本身的差异集中在花头时,模型更容易捡起背景这个“捷径”,因为背景比花瓣特征更稳定、更好学。
解决:掺入方向。一是在数据准备阶段做显著区域裁剪,把花朵主体裁到画面中心再训练;如果原始图是全身照,不用手动抠图,用增强里的随机裁剪和翻转就能弱化位置关联。二是补充背景多样性,给每类花补充不同场地、不同光线、不同容器的样本,破坏背景与类别的强关联。想判断模型是否在走捷径,有个很简单的测试:把 val 图四周裁掉 10%,如果精度掉得比预期多,说明模型依赖了花头以外的区域。
5.4 脏标签与数据泄露:换文件夹名也是一种标注
现象:某开发者 A 同学跑完 val 后抽查,发现 sunflowers 类别里有 3 张图实际是雏菊,被误放进了 daisy 文件夹;还有一批“向日葵特写带蜜蜂”的图在 train 和 val 里各出现一份。
原因:分类任务的标签由文件夹位置决定,人工整理时的拖拽错误、重复下载产生的重复文件,都会形成脏标签和数据泄露。脏标签的隐蔽性在分类任务里比检测任务高,因为模型能容忍少量错误标签而表现正常,只有当精度卡住或你做人工抽检时才会暴露。
解决:训练前用脚本检查绝对重复,计算每个文件的 md5,把哈希相同的文件列出来人工裁决;然后用“置信度抽检”流程找脏标签——用训练完的模型对 val 全量预测,挑出 top1 置信度低于 0.6 的图,人工过一遍,确认标签错了就移动文件重训。这个流程成本很低,通常只需要看几十张图就能发现一批问题。划分环节则建议按来源批次分组切分,而不是文件级随机切分。我在 2.3 节提过按文件名哈希分桶的做法,本质是把“同一时间拍的连拍图”分组到同一个桶,再以桶为单位划分,能有效避免同一来源的图像一半进 train、一半进 val 的泄露。
6. 让花卉分类模型更耐打:增强、导出与蒸馏的进阶收尾
当基础流程跑通、val 精度也满意了,决定这个模型能不能真正落地的还有三件事。
第一是增强的精细化调整。YOLOv8 分类默认增强已经覆盖翻转和色彩抖动,但花卉这种类别间差异小的任务,可以针对性加入随机擦除:把一张图里随机一块矩形区域填成纯色或模糊,强迫模型不要只盯着一小片花瓣纹理做判断。对花瓣方向不敏感的花,轻度旋转也很有帮助。这些增强参数大多能在训练配置里直接调,不需要自己改写数据流水线。
第二是权重导出。best.pt 只适合 Python 环境,换到边缘设备或低延迟场景前,先用一行代码导出:
model.export(format="onnx", imgsz=224)导出的 onnx 文件不再依赖训练框架,可以交给常见推理后端加载,CPU 上的推理速度通常比原框架快一些。导完后要用推理工具确认输入输出节点,再拿一张样本图对比导出前后 top1 是否一致,这一步能拦截多数格式转换导致的隐性问题。
第三是模型蒸馏。如果最终必须用 n 模型部署在嵌入式设备,但 s 模型在 val 上比 n 高 2 到 3 个点,可以把 s 模型当教师,用它的预测概率做软标签去精调 n 模型。具体做法是先用教师模型对训练集全量预测,保存每个样本的五类概率分布,然后把 n 模型的训练目标改成“同时拟合真实标签和教师概率”。花卉这种五类任务,蒸馏收敛很快,n 模型通常能追回教师模型一大半的精度差距。
我自己的习惯是:任何花卉分类项目,第一版永远是 n 模型加 224 输入加 50 轮,先跑通全流程确认数据没有暗坑,再谈精度优化。多数时候瓶颈在数据不在模型,先把 val 混淆矩阵看明白,比盲目升级骨干省时间得多。希望这些细节能帮你在自己的数据集上少走一圈弯路,训练顺利。
本文还有配套的精品资源,点击获取