资讯动态

深度学习实战-基于ResNet50V2的农作物图像分类识别模型

发布时间:2026/10/23 4:36:57 来源:尧图企业网站定制
‍♂️ 个人主页艾派森的个人主页✍作者简介Python学习者 希望大家多多支持我们一起进步如果文章对你有帮助的话欢迎评论 点赞 收藏 加关注目录1.项目背景2.数据集介绍3.技术工具4.实验过程4.1导入数据4.2数据可视化4.3特征工程4.4构建模型4.5训练模型4.6模型评估4.7模型预测5. 总结源代码1.项目背景在当今现代农业自动化与智慧农业发展的浪潮中精准识别农作物品种对于农田管理、产量评估以及病虫害监测有着至关重要的作用。然而不同农作物在不同生长阶段的形态、颜色和叶片纹理差异巨大且野外采集的图像往往受到复杂光照、背景杂草干扰以及拍摄角度多样等因素的影响这使得传统的图像特征提取手段难以取得理想的分类精度。随着计算机视觉与深度学习技术的日益成熟利用深度卷积神经网络进行大规模农作物图像的自动化分类已成为提高农业生产效率的关键途径。针对农作物图像特征繁杂且部分类别相似度极高的特点本项目基于 ResNet50V2 预训练网络利用其更优的残差连接结构与特征传递机制构建了一套高效的农作物图像分类识别系统。结合针对性的数据增强策略与数据流式加载技术在极大地缩短模型收敛时间的支撑下实现了多类农作物的高精度智能识别为智慧农业落地应用提供了切实可靠的技术方案。2.数据集介绍本实验数据集来源于Kaggle该数据集包含30种不同类型的农作物图像水稻、甘蔗、玉米、柠檬、香蕉、椰子、黄麻等分别存储在不同的文件夹中。3.技术工具Python版本:3.9代码编辑器jupyter notebook4.实验过程4.1导入数据在搭建农作物识别模型前我们需要配置好基础的数据处理与可视化工具库并对存放农作物图像的目录结构进行初步扫描。通过遍历不同作物类别的文件夹我们可以提取出数据集包含的所有农作物名称并统计各类别下的图像数量将其组织为结构化的 DataFrame 形式以便直观掌控数据规模。import numpy as np # 用于进行线性代数与数值计算 import pandas as pd # 用于数据处理与表格构建如读取和操作 CSV 文件 import seaborn as sns # 基于 matplotlib 的高级统计数据可视化库 import matplotlib.pyplot as plt # 绘图与可视化核心库 %matplotlib inline # 在 Jupyter Notebook 环境中直接嵌入显示绘制的图像 import tensorflow as tf # 深度学习核心框架 # 指定农作物图像数据集所在的本地主路径 Agricultural_Crops_folder ../input/agricultural-crops-image-classification/Agricultural-crops/ # 扫描文件夹按字母顺序获取所有农作物分类的名称列表 Crops_label sorted(os.listdir(Agricultural_Crops_folder)) # 遍历各个类别文件夹统计每个分类目录下的图像文件数量 count_Crops_image [len(os.listdir(os.path.join(Agricultural_Crops_folder label))) for label in Crops_label] # 将农作物类别名称及其对应的图片数量整合构建为 Pandas DataFrame Crops_image_df pd.DataFrame({Crops_label:Crops_label, count_Crops_image:count_Crops_image}) # 打印并查看数据集统计表的前几行数据 Crops_image_df.head()4.2数据可视化数据分布的直观呈现有助于评估数据集的类别平衡情况。这里使用 Seaborn 绘制柱状图将各个农作物类别的图像数量集中展示以便直观判断是否存在严重的类别不平衡问题为后续模型训练调优提供参考依据。# ---------------------------------------------------------------------- # 1. 绘制农作物各类别图像数量统计柱状图 # ---------------------------------------------------------------------- plt.figure(figsize(12,3)) # 设置画布尺寸 # 基于前面提取的表格数据绘制条形图 sns.barplot(data Crops_image_df, x Crops_label, y count_Crops_image) plt.title(Number of pictures of each category, fontsize 15) # 设置图表标题与字号 plt.xticks(rotation45, haright) # 将 X 轴类别标签旋转 45 度并靠右对齐防止重叠 plt.show() # 显示图表查看各类别的数据量分布后进一步抽取不同类别下的实际图片进行可视化展示。通过定义图像读取函数将 OpenCV 默认的 BGR 格式转为标准的 RGB 格式并利用循环展示每个农作物分类下的前五张样本能更好地检查图像质量与色彩特征。# ---------------------------------------------------------------------- # 2. 随机/批量展示各农作物类别的样本图像 # ---------------------------------------------------------------------- import pathlib from glob import glob import cv2 # 定义数据集目录路径对象 path ../input/agricultural-crops-image-classification/ data_dir pathlib.Path(path) # 定义图像读取与格式转换函数 def read_image(path): image cv2.imread(path, cv2.IMREAD_COLOR) # 以彩色模式读取图像 image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 将 BGR 转换为 RGB 色彩通道 return image # 遍历所有农作物类别分别展示各个类别下的样本图片 for label in Crops_label: f, ax plt.subplots(figsize(15,15)) # 创建绘图画布 files glob({}/Agricultural-crops/{}/*.*.format(data_dir, label)) # 获取当前类别下所有图像路径 ax.remove() # 移除主图的坐标轴框架 # 循环读取并展示当前类别下的前 5 张图像 for x in range(5): plt.subplot(1, 5, x1) # 创建 1 行 5 列的子图网格 image read_image(files[x]) # 读取图像并转换色彩 plt.imshow(image) # 渲染图像 plt.axis(off) # 隐藏子图坐标轴 plt.show() # 显示当前类别的图像组 print(label) # 打印输出对应的类别名称4.3特征工程为了提升模型的泛化能力并防止过拟合我们需要在数据准备阶段引入数据增强策略。通过 Keras 提供的ImageDataGenerator可以对原始图像进行像素归一化、随机旋转以及水平翻转等多项实时数据增强操作同时按照比例将数据集自动切分为训练集和验证集以构建高效的数据加载生成器。# 初始化图像数据生成器配置归一化与数据增强参数 from keras.preprocessing.image import ImageDataGenerator as ImgDataGen # 实例化生成器将像素值缩放到 [0, 1] 范围设置随机旋转角度上限为 20 度启用水平翻转并划分 10% 用于验证 gen ImgDataGen(rescale1./255, rotation_range20, horizontal_flipTrue, validation_split0.1) # 加载训练集数据生成器 train_ds gen.flow_from_directory(Agricultural_Crops_folder, class_modebinary, shuffleTrue, batch_size32, target_size(256,256), subsettraining) # 加载验证集数据生成器 valid_ds gen.flow_from_directory(Agricultural_Crops_folder, class_modebinary, shuffleTrue, batch_size32, target_size(256,256), subsetvalidation)通过配置上述数据生成器图像在批量输入模型前完成了尺寸统一裁切256x256、数据增强与像素标准化从而保证了训练集与验证集的高效流式加载。4.4构建模型在模型搭建环节采用了迁移学习的策略以预训练的 ResNet50V2 作为骨干特征提取网络。通过冻结骨干网络的权重参数可以在保留底层通用视觉特征的同时大幅降低计算资源消耗随后在主干网络之上接入全局平均池化层、全连接层与 Dropout 抑制过拟合结构最后根据农作物分类标签的实际数量搭建 Softmax 输出层。# 导入预训练网络架构与网络层组件 from tensorflow.keras.applications import ResNet50V2, InceptionV3, Xception # 预训练模型库 from tensorflow.keras.applications.vgg16 import VGG16 # VGG16 预训练模型 from keras.models import Sequential # 序列模型容器 from keras.layers import GlobalAvgPool2D as GAP, Dense, Dropout # 包含全局平均池化、全连接层及 Dropout 层 from keras.callbacks import EarlyStopping, ModelCheckpoint # 回调函数库 # 加载在 ImageNet 数据集上预训练的 ResNet50V2 模型不包含顶层的全连接分类器并指定输入维度 base_model ResNet50V2(weightsimagenet, include_top False, input_shape(256,256,3)) # 冻结预训练骨干网络的权重使其在训练过程中保持不变 base_model.trainable False # 构建自定义分类模型架构 model Sequential([base_model, # 主干特征提取网络 GAP(), # 全局平均池化将特征图降维压缩 Dense(1024, activationrelu), # 第一个全连接隐层节点数为 1024激活函数为 ReLU Dropout(0.5), # Dropout 正则化随机丢弃 50% 节点防止过拟合 Dense(1024, activationrelu), # 第二个全连接隐层节点数为 1024 Dropout(0.5), # 再次使用 Dropout 正则化 Dense(len(Crops_label), activationsoftmax)], nameResNet50V2) # 最终分类输出层对应作物类别数 # 编译模型设置损失函数为多分类稀疏交叉熵优化器使用 Adam评估指标指定为准确率 model.compile(losssparse_categorical_crossentropy, optimizeradam, metrics[accuracy]) # 打印输出模型整体结构与参数量汇总 model.summary()通过模型的编译与参数量打印不仅明确了网络中可训练参数与冻结参数的分配情况也完成了基于 ResNet50V2 的农作物图像分类网络构建为下一步的模型训练打下了基础。4.5训练模型在完成模型构建与编译后我们需要配置适当的训练策略并启动模型训练。为了防止模型在训练后期出现过拟合或无效迭代通过引入早停EarlyStopping回调函数在验证集损失连续若干轮不再改善时自动终止训练并自动恢复到最佳权重状态从而确保保存的模型具备最优的泛化能力。# ---------------------------------------------------------------------- # 1. 配置回调函数列表 # ---------------------------------------------------------------------- # 配置早停策略监控验证集性能若连续 3 个 Epoch 评估指标无改善则提前终止训练并恢复最优模型权重 cbs [EarlyStopping(patience3, restore_best_weightsTrue)] # ---------------------------------------------------------------------- # 2. 启动模型训练 # ---------------------------------------------------------------------- # 使用训练集和验证集数据生成器进行模型拟合设置最大训练轮数为 10并传入早停回调函数 history model.fit(train_ds, validation_datavalid_ds, epochs10, callbackscbs)4.6模型评估训练结束后通过对训练过程中的损失Loss和准确率Accuracy曲线进行可视化分析可以直观地评估模型的收敛情况与拟合效果。将训练集与验证集的性能指标绘制在统一图表中便于及时察觉模型是否存在过拟合现象或收敛瓶颈。# 绘制训练过程中的损失与准确率变化曲线 plt.figure(figsize(12, 8)) # 创建大尺寸图表画布 # 绘制损失曲线子图 plt.subplot(2, 2, 1) # 构建 2x2 布局中的第 1 个子图 plt.plot(history.history[loss], labeltrain loss) # 绘制训练集损失变化趋势 plt.plot(history.history[val_loss], labelval loss) # 绘制验证集损失变化趋势 plt.legend() # 显示图例 plt.title(Loss Vs Epoch) # 设置损失图表标题 # 绘制准确率曲线子图 plt.subplot(2, 2, 2) # 构建 2x2 布局中的第 2 个子图 plt.plot(history.history[accuracy], labelaccuracy) # 绘制训练集准确率变化趋势 plt.plot(history.history[val_accuracy], labelval accuracy) # 绘制验证集准确率变化趋势 plt.legend() # 显示图例 plt.title(Accuracy Vs Epoch) # 设置准确率图表标题 plt.show() # 展示评估曲线图4.7模型预测在模型训练与评估完成后为了直观验证模型的实际推理能力与分类效果我们需要从验证集中随机抽取批量图像进行预测测试。通过将图像输入训练好的网络获取预测概率矩阵并利用 argmax 函数提取预测类别索引最终把预测标签与真实标签统一标注在图像上方以此可视化展示模型的真实预测结果。# ---------------------------------------------------------------------- # 验证集图像分类预测与结果可视化 # ---------------------------------------------------------------------- i 1 # 初始化子图计数器 plt.figure(figsize(20,20)) # 创建大尺寸显示画布 # 遍历验证集数据生成器中的批次图像 for images, labels in valid_ds: id np.random.randint(len(images)) # 从当前 Batch 中随机选择一张图片的索引 image, label images[id], labels[id] # 提取对应的图像数据与真实标签 # 对单张图像扩充 Batch 维度后输入模型预测并取最大概率对应的索引作为预测类别 pred_label np.argmax(model.predict(image.reshape(-1,256,256,3))) plt.subplot(6,5,i) # 构建 6 行 5 列的网格子图填充第 i 张图 plt.imshow(image) # 展示图像内容 # 动态拼接真实标签与模型预测标签并设为子图标题 plt.title(fLabel : {Crops_label[int(label)]}, Pred : {Crops_label[int(pred_label)]}) plt.axis(off) # 隐藏子图坐标轴 i 1 if i 31: # 当展示满 30 张预测结果图像时跳出循环 break plt.tight_layout() # 自动调整子图间距防止标题叠压 plt.show() # 展示可视化预测面板5. 总结本实验针对多类农作物图像的智能识别需求基于包含 30 种常见农作物如水稻、甘蔗、玉米、香蕉等的图像数据集成功构建了基于 ResNet50V2 迁移学习的分类模型。通过引入数据增强策略与标准化数据预处理流程有效提升了数据的丰富度与模型泛化性能。在 10 个轮次的训练迭代中模型展现出良好的收敛性训练集损失值逐步降低至约 0.3972准确率稳定提升至 87.19% 左右同时验证集准确率最终达到约 73.61%损失值也保持在较合理区间。可视化预测与综合评估结果表明该模型能够较为精准地提取多类农作物的特征具备出色的分类识别能力为农业领域的图像智能诊断与精准管理提供了高效可靠的实践方案。源代码import numpy as np # linear algebra import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv) import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline import tensorflow as tf Agricultural_Crops_folder ../input/agricultural-crops-image-classification/Agricultural-crops/ Crops_label sorted(os.listdir(Agricultural_Crops_folder)) count_Crops_image [len(os.listdir(os.path.join(Agricultural_Crops_folder label))) for label in Crops_label] Crops_image_df pd.DataFrame({Crops_label:Crops_label, count_Crops_image:count_Crops_image}) Crops_image_df.head() plt.figure(figsize(12,3)) sns.barplot(data Crops_image_df, x Crops_label, y count_Crops_image) plt.title(Number of pictures of each category, fontsize 15) plt.xticks(rotation45, haright) plt.show() import pathlib from glob import glob import cv2 path ../input/agricultural-crops-image-classification/ data_dir pathlib.Path(path) def read_image(path): image cv2.imread(path, cv2.IMREAD_COLOR) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) return image for label in Crops_label: f, ax plt.subplots(figsize(15,15)) files glob({}/Agricultural-crops/{}/*.*.format(data_dir, label)) ax.remove() for x in range(5): plt.subplot(1, 5, x1) image read_image(files[x]) plt.imshow(image) plt.axis(off) plt.show() print(label) # Intialize Generator from keras.preprocessing.image import ImageDataGenerator as ImgDataGen gen ImgDataGen(rescale1./255, rotation_range20, horizontal_flipTrue, validation_split0.1) # Load Data train_ds gen.flow_from_directory(Agricultural_Crops_folder, class_modebinary, shuffleTrue, batch_size32, target_size(256,256), subsettraining) valid_ds gen.flow_from_directory(Agricultural_Crops_folder, class_modebinary, shuffleTrue, batch_size32, target_size(256,256), subsetvalidation) from tensorflow.keras.applications import ResNet50V2, InceptionV3, Xception # pre-Trained Learning Model from tensorflow.keras.applications.vgg16 import VGG16 # pre-Trained Learning Model from keras.models import Sequential from keras.layers import GlobalAvgPool2D as GAP, Dense, Dropout from keras.callbacks import EarlyStopping, ModelCheckpoint # load ResNet50V2 for Transfer Learning base_model ResNet50V2(weightsimagenet, include_top False, input_shape(256,256,3)) base_model.trainable False # Model Architecture model Sequential([base_model, GAP(), Dense(1024, activationrelu), Dropout(0.5), Dense(1024, activationrelu), Dropout(0.5), Dense(len(Crops_label), activationsoftmax)], nameResNet50V2) # Compile Model model.compile(losssparse_categorical_crossentropy, optimizeradam, metrics[accuracy]) model.summary() # Callbacks cbs [EarlyStopping(patience3, restore_best_weightsTrue)] # Model Training history model.fit(train_ds, validation_datavalid_ds, epochs10, callbackscbs) # plot loss and accuracy Vs Epoch plt.figure(figsize(12, 8)) plt.subplot(2, 2, 1) plt.plot(history.history[loss], labeltrain loss) plt.plot(history.history[val_loss], labelval loss) plt.legend() plt.title(Loss Vs Epoch) plt.subplot(2, 2, 2) plt.plot(history.history[accuracy], labelaccuracy) plt.plot(history.history[val_accuracy], labelval accuracy) plt.legend() plt.title(Accuracy Vs Epoch) plt.show() i1 plt.figure(figsize(20,20)) for images, labels in valid_ds: id np.random.randint(len(images)) image, label images[id], labels[id] pred_label np.argmax(model.predict(image.reshape(-1,256,256,3))) plt.subplot(6,5,i) plt.imshow(image) plt.title(fLabel : {Crops_label[int(label)]}, Pred : {Crops_label[int(pred_label)]}) plt.axis(off) i1 if i31: break plt.tight_layout() plt.show()资料获取更多粉丝福利关注下方公众号获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑