news 2026/10/2 18:23:38

花卉识别大作业实战:Python+CNN从数据集到模型完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
花卉识别大作业实战:Python+CNN从数据集到模型完整方案

简介:这份资源是面向高校学生与深度学习入门者的计算机视觉大作业完整方案,围绕Python、TensorFlow与CNN实现花卉图像识别,适合课程设计、期末大作业及新手练手参考。压缩包共13个文件,约10.82MB,以6个py源码文件为核心,涵盖模型定义、数据读取、训练与GUI界面等模块,另附docx实验报告、pptx演示文稿、yaml与txt环境配置、md说明文档及rar数据压缩包,结构清晰、便于按模块查阅。目前已有615人学习下载,具备一定参考热度。代码含详细注释,读者可据此理解卷积神经网络的数据预处理、模型搭建、训练调参与识别流程,并借助实验报告与演示文稿快速梳理实验思路、撰写文档,降低部署与调试门槛,对需要完成同类图像分类任务的学习者具有较高的实用价值。

1. 花卉识别大作业:从数据集到 CNN 模型,一套能跑通的 Python 方案

做计算机视觉大作业,最怕的不是模型不会写,而是环境装到一半报错、数据集格式对不上、训练完准确率上不去还找不到原因。花卉图像识别这个题目在课程设计里出现频率极高,原因是它同时踩中了几个关键点:类别多但边界清晰、数据量适中、CNN 特征提取能力刚好够用,而且最终效果肉眼可见,答辩时好展示。这套方案基于 Python + TensorFlow + CNN,覆盖从数据准备、模型搭建、训练调参到实验报告撰写的完整链路。适合正在做计算机视觉大作业的本科生,也适合刚入门深度学习、想找一个完整项目练手的开发者。下面按实际动手顺序展开,每一步都给出可复现的代码和参数说明。

2. 数据集准备与预处理:把花卉图片变成 CNN 能吃的张量

2.1 选哪个数据集、为什么

花卉识别最常用的公开数据集是 Oxford Flowers 102,包含 102 类花卉、每类 40 到 258 张不等,总计约 8000 张图片。这个数据集的好处是类别足够多,能体现 CNN 的层次特征提取能力;缺点是类别间样本不均衡,直接训练容易偏向样本多的类。如果大作业要求没那么高,也可以自己从网上爬取 5 到 10 类常见花卉(玫瑰、向日葵、郁金香等),每类 200 张左右,用python爬虫批量下载后人工清洗。自己爬的数据集更贴近实际工程场景,但要注意图片质量和标注准确性。

我一般建议:如果时间充裕,用自建数据集,因为答辩时能讲清楚数据来源和清洗过程;如果时间紧,直接用 Oxford Flowers 102,把精力放在模型和调参上。

2.2 目录结构与数据划分

TensorFlow 的image_dataset_from_directory要求数据按类别分文件夹存放,目录结构如下:

flowers/ ├── train/ │ ├── daisy/ │ ├── rose/ │ ├── sunflower/ │ └── tulip/ ├── val/ │ ├── daisy/ │ ├── rose/ │ ├── sunflower/ │ └── tulip/ └── test/ ├── daisy/ ├── rose/ ├── sunflower/ └── tulip/

划分比例建议 7:1.5:1.5,即训练集 70%、验证集 15%、测试集 15%。注意验证集和测试集要严格分开,验证集用于调参和早停,测试集只在最终评估时用一次。

2.3 用 TensorFlow 加载与增强

import tensorflow as tf IMG_SIZE = (224, 224) BATCH_SIZE = 32 # 训练集:带数据增强 train_ds = tf.keras.utils.image_dataset_from_directory( 'flowers/train', image_size=IMG_SIZE, batch_size=BATCH_SIZE, label_mode='categorical', shuffle=True, seed=42 ) # 验证集:不做增强,只做归一化 val_ds = tf.keras.utils.image_dataset_from_directory( 'flowers/val', image_size=IMG_SIZE, batch_size=BATCH_SIZE, label_mode='categorical', shuffle=False ) # 数据增强层:随机翻转、旋转、缩放 data_augmentation = tf.keras.Sequential([ tf.keras.layers.RandomFlip('horizontal'), tf.keras.layers.RandomRotation(0.2), tf.keras.layers.RandomZoom(0.2), ]) # 归一化:把像素值从 [0,255] 映射到 [0,1] normalization = tf.keras.layers.Rescaling(1./255) # 构建最终输入管道 train_ds = train_ds.map(lambda x, y: (normalization(data_augmentation(x, training=True)), y)) val_ds = val_ds.map(lambda x, y: (normalization(x), y)) # 预取数据,减少 I/O 等待 train_ds = train_ds.prefetch(buffer_size=tf.data.AUTOTUNE) val_ds = val_ds.prefetch(buffer_size=tf.data.AUTOTUNE)

这段代码做了三件事:加载图片并按类别编码标签、对训练集做在线增强、对像素值做归一化。image_dataset_from_directory会自动根据子文件夹名生成类别索引,label_mode='categorical'表示输出 one-hot 编码,配合categorical_crossentropy损失函数使用。RandomFlip、RandomRotation、RandomZoom是三种最基础也最有效的增强手段,能显著降低过拟合。prefetch让 CPU 在 GPU 训练时提前准备下一批数据,避免 GPU 空转。

注意:验证集和测试集绝对不能做数据增强,否则评估结果会失真。归一化则必须做,且训练集、验证集、测试集要用同一个归一化参数。

3. CNN 模型搭建:从三层卷积到迁移学习的选型对比

3.1 从零搭一个 CNN:结构设计与参数含义

from tensorflow.keras import layers, models def build_cnn(num_classes): model = models.Sequential([ # 第一层卷积:提取边缘、纹理等低级特征 layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(224, 224, 3)), layers.MaxPooling2D((2, 2)), # 第二层卷积:提取花瓣形状、颜色分布等中级特征 layers.Conv2D(64, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), # 第三层卷积:提取更复杂的组合特征 layers.Conv2D(128, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), # 第四层卷积:进一步抽象 layers.Conv2D(128, (3, 3), activation='relu', padding='same'), layers.MaxPooling2D((2, 2)), # 全局平均池化:替代 Flatten,减少参数量 layers.GlobalAveragePooling2D(), # 全连接层:做最终分类 layers.Dense(256, activation='relu'), layers.Dropout(0.5), layers.Dense(num_classes, activation='softmax') ]) return model model = build_cnn(num_classes=5) model.summary()

Conv2D的第一个参数是卷积核数量,决定了输出特征图的通道数。3×3 是最常用的卷积核尺寸,在感受野和计算量之间取得平衡。padding='same'保证输出尺寸和输入一致,避免边缘信息丢失。MaxPooling2D每次把特征图尺寸减半,逐步扩大感受野。GlobalAveragePooling2D把每个通道的特征图压缩成一个值,比Flatten参数量少得多,也不容易过拟合。Dropout(0.5)在训练时随机丢弃一半神经元,是防止过拟合的经典手段。

3.2 迁移学习:什么时候该用预训练模型

如果自己搭的 CNN 训练几轮后验证集准确率卡在 60% 上不去,或者训练集准确率远高于验证集,说明模型容量不够或者数据量不足。这时候迁移学习是更务实的选择。用EfficientNetB0或MobileNetV2在 ImageNet 上的预训练权重,冻结卷积基,只训练分类头:

base_model = tf.keras.applications.EfficientNetB0( include_top=False, weights='imagenet', input_shape=(224, 224, 3) ) base_model.trainable = False # 冻结卷积基 model = models.Sequential([ base_model, layers.GlobalAveragePooling2D(), layers.Dropout(0.3), layers.Dense(num_classes, activation='softmax') ]) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss='categorical_crossentropy', metrics=['accuracy'] )

冻结卷积基意味着反向传播不会更新预训练权重,只训练最后的分类层。这样做的好处是训练快、不容易过拟合,适合数据量小于 5000 张的场景。如果数据量超过 1 万张,可以解冻最后几个卷积块做微调,学习率要调小到 1e-5 量级。

3.3 编译与训练:优化器、学习率、早停怎么设

callbacks = [ tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=5, restore_best_weights=True ), tf.keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6 ) ] history = model.fit( train_ds, validation_data=val_ds, epochs=50, callbacks=callbacks )

EarlyStopping在验证损失连续 5 轮不下降时停止训练,并恢复最佳权重。ReduceLROnPlateau在验证损失停滞时把学习率减半,帮助模型跳出局部最优。这两个回调配合使用,基本不需要手动调训练轮数。Adam优化器默认学习率 1e-3 适合从零训练,微调时改成 1e-5。损失函数用categorical_crossentropy对应 one-hot 标签,如果是整数标签则用sparse_categorical_crossentropy。

4. 训练过程避坑:准确率不涨、loss 震荡、显存爆了的排查手册

4.1 训练集准确率 99%,验证集只有 50%

现象:训练几轮后训练集准确率飙升到 99% 以上,但验证集准确率在 50% 到 60% 之间徘徊,验证损失先降后升。

原因:典型过拟合。模型记住了训练集的噪声和细节,没有学到泛化特征。常见诱因是数据量太少、模型参数量太大、没有做数据增强或 Dropout。

解决:先加数据增强(RandomFlip、RandomRotation、RandomZoom),再在卷积层后加 Dropout(0.3 到 0.5),最后考虑减小模型容量或改用迁移学习。如果这三步做完还不行,说明数据本身有问题,检查是否有标注错误或类别混淆。

4.2 loss 震荡剧烈,准确率忽高忽低

现象:训练损失在 0.5 到 2.0 之间反复跳动,准确率每轮波动超过 10%。

原因:学习率太大,或者 batch size 太小导致梯度估计方差大。另外,如果数据没有打乱,同一批数据顺序固定,也会造成震荡。

解决:把学习率降低一个数量级(从 1e-3 降到 1e-4),batch size 从 16 提到 32 或 64。确认image_dataset_from_directory的shuffle=True只对训练集开启。如果用了ReduceLROnPlateau,观察学习率是否在正常下降。

4.3 GPU 显存不足,报 OOM 错误

现象:训练开始几秒后报ResourceExhaustedError: OOM when allocating tensor。

原因:batch size 太大、图片分辨率太高、模型参数量太大,三者叠加超出显存容量。

解决:按优先级依次尝试——把 batch size 减半、把输入尺寸从 224 降到 128、改用 MobileNetV2 等轻量模型、开启混合精度训练(tf.keras.mixed_precision.set_global_policy('mixed_float16'))。如果显存实在太小,用梯度累积模拟大 batch。

4.4 验证集准确率比训练集还高

现象:前几轮验证集准确率高于训练集,之后才慢慢反转。

原因:训练时开启了 Dropout 和数据增强,验证时关闭了这两者,导致训练集评估更“难”。这是正常现象,不是 bug。

解决:不用处理。只要最终验证集准确率收敛到合理水平即可。如果验证集准确率始终高于训练集且差距很大,检查验证集是否和训练集有重叠图片。

4.5 模型保存后加载,预测结果全错

现象:训练完保存模型,重新加载后对同一张图片预测,结果和保存前不一致。

原因:保存时只保存了权重,没有保存预处理逻辑;或者加载时没有重建相同的模型结构。

解决:用model.save('flower_model.h5')保存完整模型(结构+权重+优化器状态),加载时用tf.keras.models.load_model('flower_model.h5')。如果只保存了权重,必须先用相同的代码重建模型结构,再load_weights。另外,预测时的预处理必须和训练时完全一致,包括归一化参数和图片尺寸。

5. 实验报告怎么写:从准确率曲线到混淆矩阵的完整模板

5.1 训练过程可视化:loss 和 accuracy 双曲线

import matplotlib.pyplot as plt def plot_history(history): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) ax1.plot(history.history['loss'], label='Train Loss') ax1.plot(history.history['val_loss'], label='Val Loss') ax1.set_title('Loss Curve') ax1.set_xlabel('Epoch') ax1.set_ylabel('Loss') ax1.legend() ax2.plot(history.history['accuracy'], label='Train Acc') ax2.plot(history.history['val_accuracy'], label='Val Acc') ax2.set_title('Accuracy Curve') ax2.set_xlabel('Epoch') ax2.set_ylabel('Accuracy') ax2.legend() plt.tight_layout() plt.savefig('training_curve.png', dpi=150) plt.show() plot_history(history)

这张图是实验报告的核心素材。训练损失和验证损失如果同步下降且最终接近,说明模型泛化良好;如果验证损失先降后升,说明过拟合,需要在报告中分析原因并给出改进措施。准确率曲线同理。

5.2 混淆矩阵与分类报告

import numpy as np from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns # 在测试集上预测 test_ds = tf.keras.utils.image_dataset_from_directory( 'flowers/test', image_size=(224, 224), batch_size=32, label_mode='categorical', shuffle=False ) test_ds = test_ds.map(lambda x, y: (normalization(x), y)) y_pred = model.predict(test_ds) y_pred_classes = np.argmax(y_pred, axis=1) y_true = np.concatenate([y for x, y in test_ds], axis=0) y_true_classes = np.argmax(y_true, axis=1) # 混淆矩阵 cm = confusion_matrix(y_true_classes, y_pred_classes) plt.figure(figsize=(8, 6)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel('Predicted') plt.ylabel('True') plt.title('Confusion Matrix') plt.savefig('confusion_matrix.png', dpi=150) plt.show() # 分类报告 print(classification_report(y_true_classes, y_pred_classes, target_names=class_names))

混淆矩阵能直观看出哪些类别容易被混淆。比如玫瑰和郁金香如果互相误判率高,说明两者的颜色和形状特征在 CNN 提取的特征空间中距离较近,可以在报告中分析原因并提出改进方案(增加这两类的训练样本、引入注意力机制等)。classification_report给出每个类别的精确率、召回率和 F1 分数,是实验报告里必须放的表格。

5.3 报告结构建议

实验报告按以下结构写,每部分控制在 300 到 500 字:

章节内容要点
实验目的掌握 CNN 原理、TensorFlow 使用、图像分类流程
数据集介绍来源、类别数、样本量、划分比例、预处理方式
模型结构每层类型、参数、输出尺寸、参数量统计
训练配置优化器、学习率、batch size、epochs、回调策略
实验结果loss/accuracy 曲线、混淆矩阵、分类报告
问题与分析遇到的过拟合/震荡/显存问题及解决过程
改进方向迁移学习、注意力机制、超参搜索等

报告里不要只贴代码,重点写清楚“为什么这样选”和“遇到问题怎么排查”。答辩老师最关注的是你对模型行为的理解,而不是代码本身。

6. 把准确率从 85% 推到 95% 的三个技巧

第一个技巧是分层学习率。用迁移学习时,卷积基的学习率设成 1e-5,分类头设成 1e-3,这样预训练权重只做微调,分类头快速收敛。实现方式是用tf.keras.optimizers.Adam配合参数分组,或者分阶段训练——先冻结卷积基训练 10 轮,再解冻最后 20 层用低学习率训练 20 轮。我一般用后者,代码简单且效果稳定。

第二个技巧是测试时增强(TTA)。对同一张测试图片做多次增强(翻转、旋转、缩放),分别预测后取平均概率。这个技巧在数据量小的时候提升明显,通常能涨 1 到 3 个百分点。代码实现只需要在预测时循环调用增强层,把多次预测结果做平均。

def predict_with_tta(model, image, n_aug=5): preds = [] for _ in range(n_aug): augmented = data_augmentation(tf.expand_dims(image, 0), training=True) pred = model.predict(augmented, verbose=0) preds.append(pred) return np.mean(preds, axis=0)

第三个技巧是类别权重平衡。如果数据集类别不均衡,用class_weight参数给样本少的类别更高权重,避免模型偏向多数类。计算方式是用sklearn.utils.class_weight.compute_class_weight生成权重字典,传给model.fit的class_weight参数。

这三个技巧按优先级排序:先做分层学习率,再做类别权重,最后上 TTA。每一步做完都在验证集上评估,确认有提升再继续。不要一次性全加上,否则出了问题不知道是哪个环节导致的。

我在这个方向上踩过最大的坑是:一开始追求模型复杂度,堆了十几层卷积,结果训练慢、过拟合严重、调参调到怀疑人生。后来换成 EfficientNetB0 加简单的分类头,半天就跑到 95% 以上。教训是——大作业的核心不是模型多深,而是流程完整、分析到位、结果可复现。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 18:23:36

模板代码生成工具实战:从Jinja2到工程骨架自动化

干了十来年开发,写重复代码写到想吐的时候,我就琢磨着搞一个趁手的“模板代码生成工具”。这东西说白了,就是拿一个模板文件、一张配置表,批量生成你想要的代码、配置、文档,把过去那些机械的复制粘贴变成一条命令的事…

作者头像 李华
网站建设 2026/10/2 18:23:28

SAP邮件模板中心实战:用Maintain Email Templates统一企业邮件资产

SAP 做项目,最容易被低估的一件事就是邮件通知。销售订单确认要发邮件,采购催货要发邮件,审批工作流要发邮件,系统预警还要发邮件。以前我们怎么干?要么在 ABAP 代码里把邮件正文直接拼成字符串,要么拿 SO1…

作者头像 李华
网站建设 2026/10/2 18:23:05

NSCT彩色图像融合实战:红外与可见光融合的Python实现与调参指南

简介:这份资源聚焦NSCT(非下采样Contourlet变换)在彩色图像融合中的实现,面向图像处理学习者、科研人员及需要红外与可见光融合方案的开发者。它解决的是如何将红外热辐射信息与可见光色彩纹理信息有效结合、提升目标识别与视觉效…

作者头像 李华
网站建设 2026/10/2 18:22:05

区域架构下CAN XL与10BASE-T1S选型对比分析

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

作者头像 李华
网站建设 2026/10/2 18:21:58

基于YOLOv5的茶叶目标检测:从数据集构建到树莓派5部署实战

简介:本资源面向计算机视觉入门与进阶学习者,提供一套基于YOLOv5的茶叶目标检测完整项目实战方案,可用于农业智能化场景下的茶叶识别、计数与品质分拣等任务,帮助读者掌握从数据配置到模型训练、推理部署的全流程。压缩包共95个文…

作者头像 李华
网站建设 2026/10/2 18:21:51

MATLAB超声探伤信号处理与A/B/C扫成像完整实践指南

简介:面向MATLAB超声探伤学习者的小型示例包,适合无损检测初学者与相关课程实践。压缩包内共两个文件,均为M脚本,整体大小仅5KB,精简易读。其中主要脚本用于生成高斯余弦脉冲信号,模拟超声波短脉冲发射波形…

作者头像 李华