新闻详情

新闻详情

首页 / 资讯中心 / 详情

花卉识别数据集与深度学习模型训练:从零跑通可复现流水线

发布时间:2026/10/2 2:46:03来源:尧图网络
花卉识别数据集与深度学习模型训练:从零跑通可复现流水线
简介本资源面向深度学习图像分类的学习者与开发者提供一套可直接上手的花卉识别训练方案解决从数据到模型落地的完整链路问题。包内包含64种花卉、共32000张224×224彩色图像训练集25600张、测试集6400张均为手机实地采集而非网络爬虫图类别均衡且贴近真实拍摄场景。配套卷积神经网络训练代码专为图像分类设计实现了resnet、vgg、inception、mobilenet、densenet、efficientnet、squeezenet等37种主流模型可自由切换骨干网络进行对比实验。资源共2000个文件以jpg图像为主辅以txt说明、py训练脚本与pyc缓存压缩包约194.92MB目录结构清晰便于按类别检索。目前已有1646人学习下载适合课程设计、竞赛baseline搭建与迁移学习练手能帮助读者快速完成数据加载、模型训练与精度评估的全流程实践。1. 花卉识别数据集与深度学习模型训练从零跑通一条可复现的流水线手里有一批花朵照片想做一个能认出品种的模型这件事听起来简单真正动手时卡人的往往不是网络结构而是数据。花卉识别数据集、深度学习花卉识别、花卉识别模型训练代码、花朵数据集这几个词凑在一起指向的其实是一条完整链路拿到花朵数据集清洗成统一格式选一个 backbone把花卉识别模型训练代码跑通最后验证精度。我做过几次类似的项目最深的体会是——模型本身是黑匣子数据才是那个决定上限的东西。这篇笔记面向两类人刚入门深度学习、想找一个真实数据集练手的同学以及已经会写训练脚本、但没系统处理过细粒度图像分类的工程师。我会把数据组织、增强策略、迁移学习、参数设置和排查方法按顺序讲清楚代码可以直接抄参数可以按你的显存和类别数改。整条路线在单卡 8G 显存上就能跑不需要云平台也能起步。2. 花朵数据集怎么选、怎么读、怎么切成训练集2.1 常见花朵数据集的类别规模与适用场景花卉识别属于细粒度分类类间差异小、类内差异大同一品种不同角度拍出来可能比两个品种还像。选数据集时先看三件事类别数、每类样本数、图像分辨率。常见做法是先用一个中等规模、类别均衡的数据集把流程跑通再换自己的数据。下面这张表是我整理过的几类常见花朵数据集的典型特征具体数字以你实际下载到的版本为准不要照搬。数据集类型类别数每类样本量级分辨率适合阶段经典花卉数据集100 上下几十到几百不等多为中低分辨率入门跑通扩展花卉数据集100 以上每类数十张中高分辨率迁移学习验证自采花朵数据集按业务定极不均衡手机拍摄为主落地部署选型理由很直接入门阶段不要碰类别极不均衡、标注噪声大的自采数据否则你会把大量时间花在怀疑模型上而不是定位数据问题。经典数据集类别均衡、标注干净适合先把花卉识别模型训练代码调通。等你对学习率、batch size、增强强度有手感了再迁移到自己的花朵数据集。2.2 用 torchvision 读取并按比例切分训练验证集拿到数据集后第一步是确认目录结构。常见做法是按类别分文件夹每个文件夹里放该类别的图片。下面这段代码用ImageFolder读取再按 8:2 切分训练集和验证集同时统计每个类别的样本数方便你发现不均衡。import os from torchvision import datasets, transforms from torch.utils.data import random_split, DataLoader data_dir ./flowers_dataset # 每个子文件夹是一个类别 # 训练和验证用不同的 transform验证集不做随机增强 train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), # 随机裁剪缓解过拟合 transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) val_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) full datasets.ImageFolder(data_dir) print(类别数:, len(full.classes)) print(总样本:, len(full)) # 统计每类样本数快速发现长尾 from collections import Counter counts Counter(full.targets) for idx, cls in enumerate(full.classes): print(cls, counts[idx]) val_ratio 0.2 val_size int(len(full) * val_ratio) train_size len(full) - val_size train_set, val_set random_split(full, [train_size, val_size]) # 注意random_split 后两个子集共享同一个 transform需要手动替换 train_set.dataset.transform train_tf val_set.dataset.transform val_tf train_loader DataLoader(train_set, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_set, batch_size32, shuffleFalse, num_workers4)逻辑说明ImageFolder依赖目录名作为标签所以你的花朵数据集必须先整理成「一个类别一个文件夹」。RandomResizedCrop和RandomHorizontalFlip是细粒度分类里性价比最高的两个增强前者让模型见到不同尺度后者几乎不改变语义。参数上scale(0.7, 1.0)表示裁剪面积占原图的 70% 到 100%如果你的花朵在图中占比很小可以下调到 0.5。Normalize用的是 ImageNet 的均值和方差因为后面要用预训练权重这一步必须对齐否则迁移学习效果会打折。提示random_split之后直接改dataset.transform是个取巧写法多个子集共享同一个 dataset 对象时更稳妥的做法是自定义 Dataset 包装类分别传入 transform。样本量大时不要用这种写法容易在并发读取时出问题。2.3 数据清洗里最容易被忽略的三件事第一件是损坏图片。手机拍的照片、网络爬的图经常有截断文件ImageFolder读到会直接抛异常中断训练。我一般会先跑一遍校验脚本把打不开的图挪走。第二件是重复图同一张图换个文件名出现在训练集和验证集里验证精度会虚高这种坑在自采花朵数据集里特别常见。第三件是标签错位文件夹名和实际内容对不上模型怎么调都上不去最后发现是标注阶段就错了。这三件事都不难但漏掉任何一件你后面调参的时间基本白费。3. 花卉识别模型训练代码迁移学习与参数设置3.1 为什么细粒度分类优先用预训练 backbone花卉识别的难点在于区分相似品种比如不同颜色的玫瑰、不同瓣型的菊花。从零训练一个 CNN在几千张图的数据集上几乎必然过拟合因为卷积核学不到通用的纹理和边缘特征。常见做法是加载 ImageNet 预训练权重把最后的全连接层换成你的类别数先冻结 backbone 训练分类头再解冻做微调。ResNet 系列是稳妥选择resnet34和resnet50在花卉数据集上都验证过前者更快、显存占用更低后者精度略高。如果你显存紧张从resnet34起步完全够用。3.2 用 resnet34 预训练权重搭一个可训练的分类头下面这段代码加载预训练resnet34替换分类层并设置只训练分类头的第一阶段。import torch import torch.nn as nn from torchvision import models num_classes len(full.classes) # 你的花朵类别数 model models.resnet34(weightsmodels.ResNet34_Weights.IMAGENET1K_V1) # 冻结 backbone 参数第一阶段只训练分类头 for param in model.parameters(): param.requires_grad False # 替换最后的全连接层 in_features model.fc.in_features model.fc nn.Sequential( nn.Dropout(0.3), # 细粒度任务加 dropout 抑制过拟合 nn.Linear(in_features, num_classes) ) device torch.device(cuda if torch.cuda.is_available() else cpu) model model.to(device) criterion nn.CrossEntropyLoss() # 只把分类头参数交给优化器 optimizer torch.optim.Adam(model.fc.parameters(), lr1e-3)逻辑说明冻结 backbone 后反向传播只更新model.fc的参数训练速度快、显存占用低适合先让分类头收敛到一个合理位置。Dropout(0.3)是经验值类别数少、样本少时可以加到 0.5。优化器用 Adam、学习率 1e-3是因为分类头是随机初始化的需要较大的步长。等你看到验证集准确率不再上升再解冻 backbone 做第二阶段微调学习率要降到 1e-4 甚至更低否则预训练权重会被大梯度破坏。3.3 两阶段训练循环与关键参数含义第一阶段训练分类头第二阶段解冻全部参数微调。下面是一个精简但完整的训练循环。def train_one_epoch(model, loader, criterion, optimizer, device): model.train() total_loss, correct, total 0.0, 0, 0 for imgs, labels in loader: imgs, labels imgs.to(device), labels.to(device) optimizer.zero_grad() outputs model(imgs) loss criterion(outputs, labels) loss.backward() optimizer.step() total_loss loss.item() * imgs.size(0) correct (outputs.argmax(1) labels).sum().item() total imgs.size(0) return total_loss / total, correct / total def evaluate(model, loader, criterion, device): model.eval() total_loss, correct, total 0.0, 0, 0 with torch.no_grad(): for imgs, labels in loader: imgs, labels imgs.to(device), labels.to(device) outputs model(imgs) loss criterion(outputs, labels) total_loss loss.item() * imgs.size(0) correct (outputs.argmax(1) labels).sum().item() total imgs.size(0) return total_loss / total, correct / total # 第一阶段只训练分类头 for epoch in range(5): tr_loss, tr_acc train_one_epoch(model, train_loader, criterion, optimizer, device) val_loss, val_acc evaluate(model, val_loader, criterion, device) print(f[Head] epoch {epoch} train_acc {tr_acc:.4f} val_acc {val_acc:.4f}) # 第二阶段解冻 backbone用小学习率微调 for param in model.parameters(): param.requires_grad True optimizer torch.optim.Adam(model.parameters(), lr1e-4) for epoch in range(15): tr_loss, tr_acc train_one_epoch(model, train_loader, criterion, optimizer, device) val_loss, val_acc evaluate(model, val_loader, criterion, device) print(f[Finetune] epoch {epoch} train_acc {tr_acc:.4f} val_acc {val_acc:.4f})参数说明第一阶段 5 个 epoch 通常足够分类头收敛第二阶段 15 个 epoch 是起步值实际看验证集准确率是否还在涨。batch_size32在 8G 显存上跑resnet34加 224 输入基本安全显存不够就降到 16同时把学习率按比例下调。num_workers4取决于你的 CPU 核数设太大反而会因为进程切换拖慢读取。判断过拟合的信号是训练准确率持续上升、验证准确率停滞甚至下降这时候优先加增强、加 dropout而不是继续加 epoch。注意第二阶段解冻后如果验证准确率突然大幅下降多半是学习率太大把预训练权重冲掉了。先把学习率降到 1e-5 试一个 epoch再决定是否回调。4. 训练过程中的避坑与排查清单4.1 损失不下降先查数据再查模型现象训练几个 epochloss 一直在 2.3 附近晃准确率接近随机猜。原因最常见的是标签和图像没对齐或者Normalize的均值和预训练权重不匹配。解决先拿 8 张图过一遍模型打印预测类别和真实类别肉眼确认输入图没被读错再检查 transform 里的 mean/std 是否和预训练模型一致。如果这两步都对把学习率调大一个量级试一个 epoch。4.2 验证准确率远高于训练准确率现象训练准确率 60%验证准确率 85%看起来反常。原因训练时开了RandomResizedCrop和翻转验证时只做中心裁剪验证集难度天然更低另外model.train()和model.eval()切换会影响 dropout 和 batchnorm 的行为。解决这是正常现象不用慌。想看得更真实可以在验证时也加一点轻微增强或者单独留一个不做任何增强的测试集。4.3 显存溢出OOM的三种降级路径现象训练中途报 CUDA out of memory。原因batch size 太大、输入分辨率太高、或者num_workers过多导致内存碎片。解决按顺序试——先把 batch size 减半再把输入从 224 降到 192最后把num_workers降到 2。不要一上来就换更小的模型很多时候只是 batch 设置问题。4.4 类别不均衡导致小类全错现象整体准确率还行但样本少的几个品种几乎全部分错。原因交叉熵损失对每个样本一视同仁小类梯度被大类淹没。解决给CrossEntropyLoss传weight参数按类别样本数的倒数加权或者对小数类别做重采样。加权是最省事的做法改一行代码就能试。4.5 验证集精度虚高的隐蔽原因现象验证准确率 95%换一批新图测试掉到 60%。原因训练集和验证集存在重复图或高度相似图模型记住了而不是学会了。解决切分前先做一遍去重用感知哈希或简单的文件 MD5 都行自采数据里连拍的多张图要按拍摄批次切分不能随机打散。5. 把花卉识别模型推到能用的程度验证、导出与一个提点技巧训练跑通只是起点真正决定这个花卉识别模型能不能用的是验证方式和导出格式。我一般会留一个完全不参与训练和调参的测试集按拍摄来源切分比如用 A 手机拍的做训练、B 手机拍的做测试这样得到的准确率才接近真实场景。如果测试集精度比验证集低 10 个点以上基本可以判定模型过拟合到了训练数据的拍摄风格上这时候要做的是补充不同来源的花朵数据集而不是继续调网络。导出方面如果只是本地推理直接保存state_dict就够如果要部署到移动端或边缘设备常见做法是转成 ONNX再用对应推理引擎加载。下面这段是导出 ONNX 的最小代码注意input_names和dynamic_axes的设置前者方便你在推理时定位输入节点后者让模型支持动态 batch。import torch model.eval() dummy torch.randn(1, 3, 224, 224).to(device) torch.onnx.export( model, dummy, flower_resnet34.onnx, input_names[input], output_names[logits], dynamic_axes{input: {0: batch}, logits: {0: batch}}, opset_version12 )参数说明opset_version12兼容性较好太新的版本部分推理引擎不支持。dynamic_axes里把 batch 维标成动态导出后可以用任意 batch 推理。导出完一定要用onnxruntime跑一张图和 PyTorch 的输出对比误差在 1e-4 以内才算导出成功这一步是后悔药能省掉后面部署时的大量扯皮。最后分享一个提点技巧细粒度分类里把输入分辨率从 224 提到 320往往比换更大的 backbone 更有效因为花瓣纹理、花蕊结构这些判别信息在高分辨率下才看得清。代价是显存和训练时间上升可以先在验证集上试一个 epoch看准确率有没有明显提升再决定是否全量重训。我自己踩过的最大坑是过早追求复杂结构花了两周调各种注意力模块最后发现把数据清洗干净、把分辨率提上去收益比换模型大得多。先把这条基础流水线跑稳再谈优化。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

OpenRig开源铝型材赛车模拟器支架:从设计到组装全攻略 2026/10/2 5:20:50

OpenRig开源铝型材赛车模拟器支架:从设计到组装全攻略

OpenRig 这个名字,你在开源社区搜一圈,大概率会落在“DIY 赛车模拟器支架”这个分支上。说白了,它不是一个品牌机型,而是一类可以下载图纸、自己买铝型材、自己组装的赛车驾驶舱支架方案。如果你刚好在玩 ACC、iRacing 或者神力科…

阅读更多 →
带WebUI的Unity3D游戏分析工具:核心能力、部署与实战指南 2026/10/2 5:20:50

带WebUI的Unity3D游戏分析工具:核心能力、部署与实战指南

说到逆向分析 Unity3D 游戏,不少人的第一反应还是命令行工具、十六进制编辑器、反编译脚本挨个翻。这次我们要聊的不是某个具体的游戏破解教程,而是一类正在变流行的工具形态:带美观 WebUI 的 Unity3D 游戏分析工具。这类工具把过去散落在命令…

阅读更多 →
算法设计与分析:从复杂度到四大范式与图算法实战 2026/10/2 5:20:50

算法设计与分析:从复杂度到四大范式与图算法实战

算法设计与分析这门课,很多人是在期末前一周才翻开书的。我当年也一样,背了一堆伪代码,考完就忘。真正让我回头重新系统梳理这套东西,是工作第三年做一个任务调度模块的时候——明明需求不复杂,写出来的东西却在大数据…

阅读更多 →
Agent判断器设计实战:Laya与Jev选型及云端到边缘部署指南 2026/10/2 5:20:50

Agent判断器设计实战:Laya与Jev选型及云端到边缘部署指南

1. 从“能跑”到“跑得对”:为什么 Agent 需要一个判断器做 Agent 开发的人大概都有过这种体验:模型能调通、工具能挂载、流程能跑起来,但一到真实场景就开始“胡说八道”。明明该调用搜索工具的时候它偏要自己编,明明该拒绝的请求…

阅读更多 →
QuickBlue:企业级AI应用底座,统一模型接入与RAG开发实践 2026/10/2 5:20:49

QuickBlue:企业级AI应用底座,统一模型接入与RAG开发实践

1. 从一堆散装 AI 项目说起:QuickBlue 到底想解决什么问题过去一年多,我陆陆续续帮几家公司做过 AI 功能的落地,从最简单的智能客服问答,到稍微复杂点的文档解析加知识库检索,再到把大模型能力嵌进已有的业务系统里。每…

阅读更多 →
Jmeter压力测试完整实战指南:从脚本设计到结果分析 2026/10/2 5:20:43

Jmeter压力测试完整实战指南:从脚本设计到结果分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉