简介这份资源面向计算机视觉课程学习者与期末大作业需求者提供一套基于TensorFlow与CNN的花卉图像识别完整项目涵盖数据读取、模型搭建、训练与图形界面预测等环节适合新手理解卷积神经网络在图像分类中的落地流程。压缩包共13个文件约10.82MB以Python源码为主包含模型定义、训练脚本、数据预处理与GUI交互等模块另附docx实验报告、pptx汇报材料、yaml与txt环境配置说明及README文档便于快速还原运行环境。目前已有615人学习下载可作为课程设计或大作业的参考方案。代码含注释结构清晰读者可据此掌握数据集加载、CNN模型构建、训练调参、测试评估与界面调用等关键步骤并借助实验报告与演示文稿梳理实验背景、方法设计与结果分析减少从零搭建的时间成本。1. 花卉识别大作业一份能直接跑通的 TensorFlow CNN 源码包做计算机视觉课程大作业最怕的不是算法难而是环境配到一半报错、数据路径写死、训练完不知道模型到底学没学到东西。这份「Python 基于 TensorFlow 与 CNN 的花卉图像识别源码 实验报告」就是冲着这个场景来的它把数据读取、卷积网络搭建、训练、评估、可视化整条链路打包好配套实验报告说明设计思路适合正在赶计算机视觉大作业的学生也适合想拿一个完整 CNN 项目练手的 Python 入门者。花卉图像识别属于细粒度分类的入门任务类别间差异小、背景干扰多正好能体现 CNN 相对传统方法的优势。下面我按「拿到手怎么跑 → 网络怎么搭 → 坑在哪 → 怎么调」的顺序拆一遍参数和命令都给到能抄的程度。2. 环境与数据准备把 TensorFlow 和花卉数据集装进同一套流程2.1 为什么选 TensorFlow Keras 而不是从零写卷积这份源码走的是 TensorFlow 的 Keras 高层接口tf.keras.layers.Conv2D、MaxPooling2D、Flatten、Dense一层层堆。对课程大作业来说这个选择的核心逻辑是老师看的是你对卷积、池化、全连接、损失函数、优化器的理解而不是你手写反向传播的功力。Keras 把梯度计算、权重更新封装掉你只需要把网络结构和超参数讲清楚实验报告里也更容易对应到理论课上的公式。常见做法是用Sequential顺序模型输入层接Rescaling做归一化然后两三组「卷积 池化」最后展平接全连接。卷积核数量一般从 32 起步翻倍到 64、128池化统一 2×2。这套结构在花卉数据集上跑几十个 epoch 就能到不错的准确率显存占用也友好笔记本的入门独显甚至 CPU 都能扛。2.2 环境安装TensorFlow 版本和 Python 版本要对齐TensorFlow 对 Python 版本挑得比较死装之前先确认版本匹配否则会出现装上了却 import 报错的情况。我一般会先建虚拟环境避免和系统里其他包打架。# 创建并激活虚拟环境Python 版本建议 3.9 到 3.11 python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate # 安装 TensorFlowCPU 版直接装 tensorflow pip install tensorflow # 如果要用 GPU装对应 CUDA 版本的 tensorflow并确认显卡驱动 pip install tensorflow2.15.0 # 常用配套库 pip install numpy matplotlib pillow scikit-learn逻辑说明虚拟环境是为了隔离依赖TensorFlow 体积大、依赖多混装很容易把别的项目搞崩。tensorflow这个包在 2.x 之后已经包含 Keras不需要单独装keras重复安装反而可能版本冲突。参数上tensorflow2.15.0只是一个稳定参考实际以你显卡驱动和 CUDA 版本为准纯 CPU 训练就把版本约束去掉装最新稳定版即可。装完用下面这段验证能打印版本号并跑通一次加法说明环境没问题import tensorflow as tf print(TensorFlow:, tf.__version__) print(GPU 可用:, tf.config.list_physical_devices(GPU)) # 简单张量运算确认计算图能跑 a tf.constant([[1.0, 2.0], [3.0, 4.0]]) print(tf.reduce_sum(a).numpy())如果GPU 可用打印出空列表说明当前是 CPU 模式训练会慢一些但功能不受影响。想用 GPU 就得回头核对 CUDA 和 cuDNN 版本这是新手最容易翻车的地方。2.3 数据组织目录结构决定读取方式花卉数据集通常是按类别分文件夹存放每个文件夹名就是类别标签。源码里一般用image_dataset_from_directory或ImageDataGenerator读取两种方式都依赖这个目录结构。flower_dataset/ daisy/ img_001.jpg img_002.jpg dandelion/ ... rose/ ... sunflower/ ... tulip/ ...用image_dataset_from_directory读取的典型写法import tensorflow as tf IMG_SIZE (224, 224) BATCH_SIZE 32 train_ds tf.keras.utils.image_dataset_from_directory( flower_dataset, validation_split0.2, # 划出 20% 做验证 subsettraining, seed123, image_sizeIMG_SIZE, batch_sizeBATCH_SIZE ) val_ds tf.keras.utils.image_dataset_from_directory( flower_dataset, validation_split0.2, subsetvalidation, seed123, image_sizeIMG_SIZE, batch_sizeBATCH_SIZE ) class_names train_ds.class_names print(类别:, class_names)逻辑说明validation_split按比例切分训练和验证集seed固定后两次调用切分结果一致否则训练集和验证集会重叠。image_size统一缩放到 224×224这是多数预训练网络的输入尺寸自己搭网络时也可以改成 128×128 省显存。batch_size取 32 是折中值显存不够就降到 16 或 8。class_names的顺序由文件夹名的字母序决定实验报告里写类别映射时要按这个顺序来别自己臆断。提示数据量少的时候validation_split切出来的验证集可能每类只有几张图评估波动会很大。常见做法是额外准备一个独立测试集或者用 K 折交叉验证但大作业阶段按 8:2 切分通常够用。3. CNN 网络搭建与训练从卷积层参数到训练曲线3.1 网络结构逐层拆解源码里的 CNN 一般是「特征提取 分类头」两段式。特征提取靠卷积和池化反复压缩空间尺寸、增加通道数分类头把特征展平后接全连接输出类别概率。下面是一个能直接用的结构from tensorflow.keras import layers, models def build_cnn(num_classes): model models.Sequential([ # 输入归一化把 0-255 缩到 0-1 layers.Rescaling(1./255, input_shape(224, 224, 3)), # 第一组卷积提取边缘、纹理等低级特征 layers.Conv2D(32, (3, 3), activationrelu, paddingsame), layers.MaxPooling2D((2, 2)), # 第二组卷积组合成更复杂的局部结构 layers.Conv2D(64, (3, 3), activationrelu, paddingsame), layers.MaxPooling2D((2, 2)), # 第三组卷积高层语义特征 layers.Conv2D(128, (3, 3), activationrelu, paddingsame), layers.MaxPooling2D((2, 2)), # 分类头 layers.Flatten(), layers.Dense(128, activationrelu), layers.Dropout(0.5), # 抑制过拟合 layers.Dense(num_classes, activationsoftmax) ]) return model model build_cnn(len(class_names)) model.summary()逻辑说明Rescaling(1./255)把像素值归一化这一步不做的话训练很难收敛是血泪经验。paddingsame保证卷积后尺寸不变只有池化在降采样方便你算每层输出尺寸。三组卷积核数量 32→64→128 逐层翻倍是经典的通道扩展策略。Dropout(0.5)在全连接前随机丢弃一半神经元花卉数据集样本量不大时能明显缓解过拟合。最后一层神经元数等于类别数softmax输出概率分布。model.summary()会打印每层参数量和输出形状实验报告里可以直接引用。重点看卷积层的参数量公式(卷积核高 × 卷积核宽 × 输入通道 1) × 输出通道全连接层参数量往往占大头这也是为什么加 Dropout 和考虑全局平均池化的原因。3.2 编译与训练优化器、损失函数、回调怎么设model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-3), losssparse_categorical_crossentropy, metrics[accuracy] ) # 回调早停 保存最优模型 callbacks [ tf.keras.callbacks.EarlyStopping( monitorval_loss, patience5, restore_best_weightsTrue), tf.keras.callbacks.ModelCheckpoint( best_flower_model.h5, monitorval_accuracy, save_best_onlyTrue) ] history model.fit( train_ds, validation_dataval_ds, epochs30, callbackscallbacks )逻辑说明Adam学习率默认 1e-3对大多数 CNN 任务都稳收敛快且不太挑初始值。损失函数用sparse_categorical_crossentropy因为标签是整数而不是 one-hot如果标签做了 one-hot 就要换成categorical_crossentropy这两个搞混会直接报维度错误。EarlyStopping监控验证损失连续 5 个 epoch 不下降就停并回滚到最优权重省得你手动盯。ModelCheckpoint把验证准确率最高的模型存下来避免训练后期过拟合把好模型覆盖掉。训练完画曲线是实验报告的必要环节import matplotlib.pyplot as plt plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(history.history[accuracy], labeltrain) plt.plot(history.history[val_accuracy], labelval) plt.title(Accuracy) plt.legend() plt.subplot(1, 2, 2) plt.plot(history.history[loss], labeltrain) plt.plot(history.history[val_loss], labelval) plt.title(Loss) plt.legend() plt.show()看曲线有个判断标准训练准确率一直涨、验证准确率早早停住甚至下降就是过拟合加数据增强或加大 Dropout两条曲线都低且平就是欠拟合加深网络或提高学习率。这个判断逻辑写进实验报告比只贴一张图有说服力得多。3.3 数据增强小数据集提准确率的关键花卉数据集每类往往只有几百张不加增强很容易过拟合。Keras 提供RandomFlip、RandomRotation、RandomZoom等层可以塞进模型前面也可以单独做预处理流水线。data_augmentation tf.keras.Sequential([ layers.RandomFlip(horizontal), layers.RandomRotation(0.1), layers.RandomZoom(0.1), ]) # 在 build_cnn 的 Rescaling 之后插入 data_augmentation逻辑说明水平翻转对花卉识别安全因为花左右翻转还是同一类旋转 0.1 表示 ±10% 角度范围太大可能把花转出画面缩放 0.1 模拟拍摄距离变化。增强只在训练时生效验证和测试不走这层Keras 会自动处理。参数别设太猛否则增强后的图和真实分布差太远反而拖低准确率。4. 避坑与排查跑不通时先看这几条4.1 报错No module named tensorflow现象命令行里import tensorflow直接报找不到模块。原因通常是虚拟环境没激活或者 pip 装到了另一个 Python 解释器下。解决先which pythonWindows 用where python确认当前解释器路径再pip show tensorflow看装在哪。两者不一致就重新在激活的虚拟环境里装一遍。PyCharm 用户还要检查项目解释器有没有指向这个 venv这是高频翻车点。4.2 训练准确率卡在 10% 左右不动现象loss 不下降准确率约等于 1/类别数等于瞎猜。原因多半是标签和损失函数不匹配或者归一化没做。解决确认标签是整数就用sparse_categorical_crossentropy是 one-hot 就用categorical_crossentropy确认Rescaling(1./255)在模型最前面。还有一种可能是学习率太大导致梯度爆炸把1e-3降到1e-4试试。4.3 显存不足OOM或训练中途崩现象ResourceExhaustedError或进程被系统杀掉。原因batch_size太大、输入尺寸太大、模型太深。解决按顺序降batch_size32→16→8再降image_size224→128还不行就减少卷积核数量。GPU 用户可以在训练前限制显存增长gpus tf.config.list_physical_devices(GPU) for gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True)4.4 验证集准确率远高于训练集现象val_accuracy 比 accuracy 还高看着像好事其实反常。原因通常是验证集太小且分布偏或者训练时用了 Dropout 而验证时关闭导致验证表现虚高。解决扩大验证集比例或者换用独立测试集评估。别被这个数字骗了实验报告里要说明评估集怎么来的。4.5 预测时类别名对不上现象模型输出索引 0但你以为是玫瑰实际是雏菊。原因class_names按文件夹字母序排列不是按你心里的顺序。解决预测时用class_names[np.argmax(prediction)]取名字别硬编码索引。实验报告里把class_names打印出来贴上去答辩时老师一问就能对上。5. 进阶技巧迁移学习与模型验证的实操细节自己搭的 CNN 在花卉数据集上通常能到 70%85%想再往上走迁移学习是最省力的路子。用tf.keras.applications里的预训练网络如 MobileNetV2、EfficientNetB0把卷积基冻结只训练分类头几十行代码就能把准确率推到 90% 以上。base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, # 去掉原分类头 weightsimagenet ) base_model.trainable False # 冻结卷积基 model models.Sequential([ base_model, layers.GlobalAveragePooling2D(), # 替代 Flatten参数更少 layers.Dropout(0.3), layers.Dense(len(class_names), activationsoftmax) ]) model.compile( optimizertf.keras.optimizers.Adam(1e-4), losssparse_categorical_crossentropy, metrics[accuracy] )逻辑说明include_topFalse去掉 ImageNet 的 1000 类分类头保留特征提取部分。trainableFalse冻结预训练权重只更新后面的分类头训练快且不容易过拟合。GlobalAveragePooling2D把每个通道压成一个数比Flatten参数量少一个量级是小数据集上的常见选择。学习率降到1e-4因为预训练权重已经很好大步长会破坏它。等分类头收敛后可以解冻最后几个卷积块做微调学习率再降到1e-5。验证模型不能只看一个准确率数字。混淆矩阵能看出哪两类容易混比如玫瑰和郁金香在颜色上接近误判就多。用sklearn.metrics.confusion_matrix配合seaborn热力图实验报告里放一张比干巴巴的准确率有信息量。再挑几张预测错误的图单独看往往能发现是标注错了还是图太糊这些分析写进报告就是加分项。我自己的习惯是每次改完网络结构或超参数先跑 5 个 epoch 看 loss 有没有下降趋势有再跑满没有就回头查数据和归一化别一上来就等半小时。从那以后我每次开新项目都强制先跑一个极小数据集过拟合测试——拿 20 张图训练如果模型连这 20 张都记不住那一定是代码或数据有问题而不是模型不够强。希望帮到你。本文还有配套的精品资源点击获取