♂️ 个人主页艾派森的个人主页✍作者简介Python学习者 希望大家多多支持我们一起进步如果文章对你有帮助的话欢迎评论 点赞 收藏 加关注目录1.项目背景2.数据集介绍3.技术工具4.实验过程4.1导入数据4.2数据可视化4.3特征工程4.4构建模型4.5训练模型4.6模型评估5.总结1.项目背景随着计算机视觉技术的快速发展基于深度学习的图像识别方法在农业生产、食品检测以及智能零售等领域得到了越来越广泛的应用。传统的水果识别方式通常依赖人工经验进行分类不仅效率较低而且在面对大量样本时容易受到主观因素影响难以保证稳定性和准确性。借助卷积神经网络CNN等深度学习模型可以从图像中自动学习到具有判别力的特征从而实现对不同水果类别的自动识别这为智能化农产品管理提供了新的技术路径。在实际场景中例如智能分拣系统、电商平台商品识别以及无人零售设备都需要对水果种类进行快速而准确的识别。如果能够构建一个稳定可靠的水果图像分类模型不仅可以减少人工成本还能够提升生产和管理效率。因此本项目基于卷积神经网络构建水果图像分类模型通过对水果图像数据进行预处理、特征学习与模型训练使模型能够自动识别多种不同类别的水果并通过实验评估其分类性能为后续在实际应用场景中的部署提供一定的参考。2.数据集介绍本实验数据集来源于Kaggle原始数据集共有22495张水果/蔬菜图像。训练集大小16854 张图像每张图像代表一种水果或蔬菜。测试集大小5641 张图片每张图片代表一种水果或蔬菜。班级数量33水果和蔬菜。图片尺寸100x100像素。训练数据文件名格式[水果/蔬菜名称]_[id].jpg例如 Apple Braeburn_100.jpg。许多图像也经过旋转处理以辅助训练。测试数据文件名格式[4位数字ID].jpg例如0001.jpgtrain - 训练文件夹包含 33 个子文件夹每个子文件夹内都存放着每种水果/蔬菜的训练图像。总共有 16854 张图像。test- 测试文件夹包含 5641 张测试图像。sampleSubmission.csv- 格式正确的示例提交文件包含 ID 编号和字符串标签。3.技术工具Python版本:3.9代码编辑器jupyter notebook4.实验过程4.1导入数据在开始模型训练之前需要先导入实验所需的Python库并加载数据集。本部分主要完成两个任务一是导入数据处理、图像处理、深度学习建模以及结果评估等相关依赖库二是确定数据集在本地或Kaggle环境中的存储路径并读取训练集目录下的类别信息。水果图像数据集按照类别存放在不同文件夹中因此可以通过读取文件夹名称自动获取所有水果类别这也为后续模型训练和分类任务提供了标签信息。# --- Core Python Libraries --- # 导入Python基础库用于文件管理、随机数生成以及数据处理 import os import random import numpy as np import pandas as pd # --- Visualization --- # 导入可视化相关库用于绘制图表和展示图像 import matplotlib.pyplot as plt import matplotlib.image as mpimg import seaborn as sns # --- Image Handling --- # 导入PIL库用于读取和处理图像数据 from PIL import Image # --- TensorFlow / Keras --- # 导入TensorFlow及Keras相关模块用于构建和训练深度学习模型 import tensorflow as tf from tensorflow.keras.models import Sequential, load_model from tensorflow.keras.layers import ( Conv2D, MaxPooling2D, Flatten, # 卷积层、池化层、展平层 Dense, Dropout, BatchNormalization # 全连接层、Dropout层、批归一化层 ) from tensorflow.keras.preprocessing.image import ImageDataGenerator # 图像数据增强工具 # --- Evaluation --- # 导入模型评估相关函数用于生成分类报告和混淆矩阵 from sklearn.metrics import classification_report, confusion_matrix from tensorflow.keras.callbacks import EarlyStopping # 早停机制 # --- Jupyter Widgets --- # 导入交互组件用于在Notebook环境中进行交互式展示 import ipywidgets as widgets from IPython.display import display # 定义数据集的基础路径 base_path /kaggle/input/fruit-recognition # 定义训练集和测试集的具体路径 train_path os.path.join(base_path, train/train) test_path os.path.join(base_path, test/test) # 从训练集目录中读取所有类别名称 # 每个文件夹名称通常对应一种水果类别 class_names sorted(os.listdir(train_path)) # 输出类别名称 print(Classes:, class_names) # 输出类别总数 print(Total number of classes:, len(class_names))4.2数据可视化在训练模型之前首先对数据集的整体结构进行简单统计以了解每个水果类别所包含的图像数量。通过遍历训练集目录可以统计每个类别文件夹中的图像数量并将结果整理为表格形式进行展示。这样的统计有助于观察数据集中不同类别之间的样本分布情况判断是否存在样本数量差异较大的情况同时也可以计算数据集的总体规模为后续实验提供参考。# 统计每个类别中的图像数量 class_counts { # cls 表示类别名称对应训练集目录中的每个子文件夹 # os.listdir 用于读取该类别文件夹中的所有图像文件 cls: len(os.listdir(os.path.join(train_path, cls))) for cls in class_names } # 将统计结果转换为DataFrame方便后续展示和处理 df_counts pd.DataFrame(class_counts.items(), columns[Class, Count]) # 按图像数量进行降序排序方便观察样本最多的类别 df_counts df_counts.sort_values(byCount, ascendingFalse) # 添加序号列 df_counts.insert(0, sl.no, range(1, 1 len(df_counts))) # 输出每个类别的图像数量统计表 print(Image counts per class:) print(df_counts.to_string(indexFalse)) # 统计数据集中所有图像的总数量 total_images df_counts[Count].sum() # 输出图像总数 print(f\nTotal number of images: {total_images})接着为了更直观地了解数据集中图像的实际内容可以从每个类别中随机选取一张样本图像进行展示。通过可视化方式查看不同类别的水果图像可以帮助确认数据集标签是否正确同时也能够观察图像的分辨率、背景情况以及类别之间的差异特征这对于后续模型设计和训练具有一定的参考意义。# 获取训练集中的所有类别名称 class_names sorted(os.listdir(train_path)) # 创建6×6的子图网格用于展示不同类别的样本图像 fig, axes plt.subplots(6, 6, figsize(20, 20)) # 设置整体标题 fig.suptitle(Sample Image from Each Fruit Class, fontsize24, y1.02) # 将二维坐标轴数组展平成一维数组方便循环遍历 axes axes.ravel() # 遍历每一个类别 for i, class_name in enumerate(class_names): # 获取该类别对应的文件夹路径 class_dir os.path.join(train_path, class_name) # 读取该类别下的所有图像文件 image_files os.listdir(class_dir) # 如果该类别中存在图像文件 if image_files: # 随机选择一张图像 image_path os.path.join(class_dir, random.choice(image_files)) # 读取图像 img mpimg.imread(image_path) # 在子图中显示图像 axes[i].imshow(img) # 设置子图标题为类别名称 axes[i].set_title(class_name, fontsize12) # 关闭坐标轴显示 axes[i].axis(off) # 如果类别数量少于子图数量将多余的子图隐藏 for j in range(len(class_names), len(axes)): axes[j].axis(off) # 自动调整子图布局 plt.tight_layout() # 显示图像 plt.show()4.3特征工程1构建基础数据生成器并划分训练集与验证集在模型训练之前需要对图像数据进行预处理并将数据划分为训练集和验证集。本部分主要通过Keras中的ImageDataGenerator读取训练目录中的图像数据并对图像进行统一尺寸调整和像素值归一化处理。同时利用validation_split参数按比例划分训练数据和验证数据其中80%的样本用于模型训练20%的样本用于模型验证。通过这种方式可以在训练过程中实时评估模型的泛化能力。# 设置输入图像的尺寸以及每批次训练的样本数量 img_width, img_height 100, 100 batch_size 32 # 创建图像数据生成器 # rescale1./255 表示将像素值从0-255缩放到0-1之间便于神经网络训练 # validation_split0.2 表示将数据按比例划分为80%训练集和20%验证集 datagen ImageDataGenerator( rescale1./255, validation_split0.2 ) # 构建训练数据生成器80%的数据用于训练 train_generator datagen.flow_from_directory( train_path, # 训练数据目录 target_size(img_width, img_height), # 将图像统一缩放到100×100 batch_sizebatch_size, # 每批次加载32张图像 class_modecategorical, # 使用one-hot编码形式的多分类标签 subsettraining # 指定为训练数据 ) # 构建验证数据生成器20%的数据用于验证 validation_generator datagen.flow_from_directory( train_path, target_size(img_width, img_height), batch_sizebatch_size, class_modecategorical, subsetvalidation # 指定为验证数据 ) # 输出训练集、验证集以及类别数量信息 print(fTraining images: {train_generator.n}) print(fValidation images: {validation_generator.n}) print(fNumber of classes: {train_generator.num_classes})2加入数据增强的数据生成器为了进一步提高模型的泛化能力可以在数据加载过程中加入数据增强操作。数据增强通过对原始图像进行随机旋转、平移、缩放、亮度变化以及水平翻转等变换在不改变图像语义的前提下生成更多训练样本从而增加数据的多样性。这样能够减少模型对训练数据的依赖使模型在面对新的图像时具有更好的识别能力。# 再次设置图像尺寸和batch大小 img_width, img_height 100, 100 batch_size 32 # 创建带有数据增强功能的图像生成器 datagen ImageDataGenerator( rescale1./255, # 像素归一化 rotation_range25, # 随机旋转角度范围 width_shift_range0.2, # 水平平移范围 height_shift_range0.2, # 垂直平移范围 shear_range0.2, # 剪切变换 zoom_range0.2, # 随机缩放 horizontal_flipTrue, # 随机水平翻转 brightness_range[0.8, 1.2],# 随机亮度变化 fill_modenearest, # 空白区域填充方式 validation_split0.2 # 保留20%作为验证集 ) # 构建训练数据生成器带随机增强 train_generator datagen.flow_from_directory( train_path, target_size(img_width, img_height), # 调整图像尺寸 batch_sizebatch_size, class_modecategorical, subsettraining, shuffleTrue # 训练数据随机打乱 ) # 构建验证数据生成器 validation_generator datagen.flow_from_directory( train_path, target_size(img_width, img_height), batch_sizebatch_size, class_modecategorical, subsetvalidation, shuffleFalse # 验证数据保持顺序 ) # 输出训练集与验证集信息 print(fTraining images: {train_generator.n}) print(fValidation images: {validation_generator.n}) print(fNumber of classes: {train_generator.num_classes})4.4构建模型在完成图像数据的预处理与增强之后需要构建卷积神经网络模型以实现图像分类任务。本研究基于TensorFlow / Keras框架搭建卷积神经网络CNN模型通过多层卷积与池化结构逐步提取图像的深层特征并最终通过全连接层实现分类输出。为了提高训练稳定性并兼顾不同硬件环境的适配性模型训练过程采用MirroredStrategy进行设备管理从而在多GPU环境下能够实现并行训练。模型结构整体由四个卷积模块和一个全连接分类模块组成。卷积模块主要用于提取图像的空间特征每个模块均包含卷积层与最大池化层其中卷积层负责提取图像局部特征而池化层用于降低特征图的空间维度减少参数数量并提升模型的泛化能力。随着网络层数加深卷积核数量逐渐增加使模型能够学习到更加复杂和抽象的图像特征。在卷积特征提取完成后模型通过Flatten层将二维特征图展开为一维向量并输入至全连接层进行高层语义特征学习。同时为了降低模型过拟合风险在全连接层之前加入Dropout层以随机丢弃部分神经元连接提高模型的泛化能力。最终通过Softmax激活函数输出各类别的概率分布实现多分类任务。模型编译阶段使用Adam优化器进行参数更新并采用categorical_crossentropy作为损失函数以适应多类别分类问题。同时以accuracy作为模型性能评价指标用于衡量模型在训练过程中的分类准确率。# 获取数据集中的类别数量以及图像尺寸 num_classes train_generator.num_classes img_width, img_height 100, 100 # 使用MirroredStrategy以支持多GPU训练或更稳健的设备分配 strategy tf.distribute.MirroredStrategy() # 在策略作用域内构建模型 with strategy.scope(): # 构建卷积神经网络模型 model tf.keras.Sequential([ # 第一层卷积模块提取低层次图像特征如边缘、纹理等 tf.keras.layers.Conv2D(32, (3, 3), activationrelu, input_shape(img_width, img_height, 3)), tf.keras.layers.MaxPooling2D((2, 2)), # 降低特征图尺寸 # 第二层卷积模块提取更复杂的图像特征 tf.keras.layers.Conv2D(64, (3, 3), activationrelu), tf.keras.layers.MaxPooling2D((2, 2)), # 第三层卷积模块进一步增强特征表达能力 tf.keras.layers.Conv2D(128, (3, 3), activationrelu), tf.keras.layers.MaxPooling2D((2, 2)), # 第四层卷积模块提取高层语义特征 tf.keras.layers.Conv2D(128, (3, 3), activationrelu), tf.keras.layers.MaxPooling2D((2, 2)), # 将多维特征图展开为一维向量 tf.keras.layers.Flatten(), # Dropout层防止过拟合 tf.keras.layers.Dropout(0.5), # 全连接层进行高层特征学习 tf.keras.layers.Dense(512, activationrelu), # 输出层使用softmax实现多类别分类 tf.keras.layers.Dense(num_classes, activationsoftmax) ]) # 编译模型 model.compile( optimizeradam, # Adam优化器 losscategorical_crossentropy, # 多分类交叉熵损失函数 metrics[accuracy] # 评估指标分类准确率 ) # 输出模型结构 model.summary()4.5训练模型在模型结构构建完成后需要利用训练数据对模型进行训练使模型能够学习图像特征与类别之间的映射关系。本研究通过调用model.fit()方法对卷积神经网络进行训练并在训练过程中设置训练轮数epochs、验证集以及回调函数以提高模型训练的稳定性并防止过拟合。首先设定模型训练的轮数为 20 次即模型将完整遍历训练数据集 20 轮。在实际训练过程中如果模型在验证集上的性能不再提升继续训练可能会导致过拟合。因此本实验引入EarlyStopping提前停止机制。该机制通过监控验证集损失函数val_loss的变化情况当验证损失在连续若干轮patience3内没有明显下降时训练过程将自动终止并恢复到验证集表现最好的模型权重从而避免模型在后期训练中出现性能退化。在训练过程中模型每一轮都会从train_generator中按批次读取图像数据进行训练并在validation_generator提供的验证集上进行性能评估。其中steps_per_epoch表示每一轮训练需要执行的批次数计算方式为训练样本数量除以批大小validation_steps则表示验证阶段的批次数。# 设置训练轮数 epochs 20 # EarlyStopping回调函数当验证集损失在连续3轮内不再下降时提前停止训练 early_stop EarlyStopping( monitorval_loss, # 监控验证集损失 patience3, # 容忍3个epoch没有提升 restore_best_weightsTrue # 恢复验证集效果最好的模型权重 ) # 开始训练模型 history model.fit( # 训练数据生成器 train_generator, # 每个epoch训练的步数批次数 steps_per_epochtrain_generator.samples // train_generator.batch_size, # 训练轮数 epochsepochs, # 验证数据生成器 validation_datavalidation_generator, # 验证阶段的步数 validation_stepsvalidation_generator.samples // validation_generator.batch_size, # 回调函数列表 callbacks[early_stop] )4.6模型评估在模型训练完成后需要对模型的分类性能进行系统评估以判断其在验证数据上的识别能力和泛化效果。本实验从多个角度对模型进行评估包括验证集整体性能指标、训练过程变化趋势、分类指标报告以及混淆矩阵分析。通过这些评估方法可以较为全面地了解模型在水果图像分类任务中的表现。首先通过读取训练历史记录history中保存的指标数据提取模型在最后一个训练周期对应的验证集准确率Validation Accuracy和验证损失Validation Loss。该结果能够直观反映模型在验证数据上的整体表现其中准确率用于衡量模型分类正确的比例而损失值则反映预测结果与真实标签之间的误差程度。# 从训练历史记录中获取最终的验证集评估指标 final_accuracy history.history[val_accuracy][-1] final_loss history.history[val_loss][-1] # 输出最终验证集准确率和损失值 print(fFinal Validation Accuracy: {final_accuracy:.4f}) print(fFinal Validation Loss: {final_loss:.4f})为了进一步观察模型在训练过程中的收敛情况需要对训练集和验证集的准确率与损失变化趋势进行可视化。通过绘制训练轮次Epoch与准确率、损失值之间的变化曲线可以直观判断模型是否稳定收敛以及是否存在明显的过拟合或欠拟合现象。如果训练准确率持续上升而验证准确率停滞或下降则可能存在过拟合问题。# 从训练历史记录中提取准确率与损失数据 acc history.history[accuracy] val_acc history.history[val_accuracy] loss history.history[loss] val_loss history.history[val_loss] # 生成训练轮次序列 epochs_range range(len(acc)) # 绘制训练集与验证集的准确率和损失变化曲线 plt.figure(figsize(15, 6)) # 绘制准确率曲线 plt.subplot(1, 2, 1) plt.plot(epochs_range, acc, labelTraining Accuracy) plt.plot(epochs_range, val_acc, labelValidation Accuracy) plt.title(Accuracy) plt.xlabel(Epochs) plt.ylabel(Accuracy) plt.legend(loclower right) plt.grid(True) # 绘制损失曲线 plt.subplot(1, 2, 2) plt.plot(epochs_range, loss, labelTraining Loss) plt.plot(epochs_range, val_loss, labelValidation Loss) plt.title(Loss) plt.xlabel(Epochs) plt.ylabel(Loss) plt.legend(locupper right) plt.grid(True) # 调整布局并显示图像 plt.tight_layout() plt.show()除了整体准确率指标之外还需要对模型在各个类别上的分类效果进行细致分析。因此本实验利用模型对验证集进行预测并将预测结果与真实标签进行比较从而生成分类报告Classification Report。该报告包含precision精确率、recall召回率和 F1-score等指标可以更全面地评估模型在不同类别上的分类性能。# 获取验证集真实标签 validation_labels validation_generator.classes # 计算验证阶段需要执行的步数 validation_steps validation_generator.samples // validation_generator.batch_size # 使用训练好的模型对验证集进行预测 predictions model.predict(validation_generator, stepsvalidation_steps) # 获取预测类别概率最大的类别 predicted_labels np.argmax(predictions, axis1) # 获取类别名称 class_labels list(validation_generator.class_indices.keys()) # 生成并输出分类报告 report classification_report( validation_labels[:len(predicted_labels)], predicted_labels, target_namesclass_labels ) print(\nClassification Report:\n, report)为了进一步分析模型在各类别之间的混淆情况本实验构建混淆矩阵Confusion Matrix并进行可视化。混淆矩阵能够展示真实类别与预测类别之间的对应关系其中对角线上的数值表示被正确分类的样本数量而非对角线位置则表示分类错误的情况。通过该图可以直观识别模型容易混淆的水果类别从而为后续模型优化提供依据。# 计算混淆矩阵 cm confusion_matrix( validation_labels[:len(predicted_labels)], predicted_labels ) # 使用热力图方式可视化混淆矩阵 plt.figure(figsize(20, 18)) sns.heatmap( cm, annotTrue, # 显示数值 fmtd, # 整数格式 cmapBlues, # 颜色风格 xticklabelsclass_labels, yticklabelsclass_labels ) # 设置图表标题和坐标轴标签 plt.title(Confusion Matrix, fontsize20) plt.xlabel(Predicted Label, fontsize16) plt.ylabel(True Label, fontsize16) # 调整刻度显示 plt.xticks(rotation90) plt.yticks(rotation0) # 自动调整布局并显示 plt.tight_layout() plt.show()最后可以保存模型model.save(my_fruit_model.h5)5.总结本实验基于卷积神经网络构建了一个水果图像分类识别模型并利用水果图像数据集对模型进行了训练与验证。在实验过程中通过图像归一化、数据增强以及训练集与验证集划分等数据预处理步骤提高了模型对不同水果图像特征的学习能力同时通过多层卷积与池化结构逐步提取图像的空间特征并结合全连接层完成多类别分类任务。实验结果表明模型在验证集上取得了0.9851的准确率损失值为0.0512整体表现较为稳定。从分类报告来看大多数水果类别的precision、recall和F1-score均接近或达到1.00说明模型在识别不同水果类别方面具有较高的准确性仅在个别类别上存在轻微的识别偏差。综合混淆矩阵和评价指标可以看出该模型能够有效学习水果图像的特征信息具有较好的分类性能和一定的实际应用价值。资料获取更多粉丝福利关注下方公众号获取