深度学习实战-基于CNN卷积神经网络的番茄病害叶片图像识别模型
♂️ 个人主页艾派森的个人主页✍作者简介Python学习者 希望大家多多支持我们一起进步如果文章对你有帮助的话欢迎评论 点赞 收藏 加关注目录1.项目背景2.数据集介绍3.技术工具4.实验过程4.1导入数据4.2数据可视化4.3特征工程4.4构建模型4.5训练模型4.6模型评估4.7模型预测5.总结源代码1.项目背景在智慧农业的全球浪潮下农作物病害的精准监测已成为保障粮食安全与提升耕作效率的核心环节。番茄作为全球范围内栽培最广、经济价值极高的蔬菜作物之一在其生长周期内极易受到细菌、真菌、病毒及虫害的多重威胁。传统的病害辨识高度依赖经验丰富的农技人员进行人工巡检但在面对早疫病、晚疫病、黄化曲叶病毒等 10 余种视觉特征高度相似的病理表现时非专业人员往往难以做出即时且准确的判断。这种诊断的滞后性不仅会导致农药的盲目滥用更可能引发大面积减产严重制约了现代农业的精细化发展。本项目旨在利用卷积神经网络CNN强大的非线性特征提取能力构建一套能够覆盖 11 类典型状态的智能化识别系统。实验不仅涵盖了从实验室受控环境到复杂自然农田场景的 2 万余张影像样本更在算法设计上兼顾了高精度与轻量化的平衡。通过深度卷积层的层级化抽象模型能够自动捕捉病斑边缘、叶面霉层及色彩异变等核心视觉特征。本实战不仅展示了从数据增强、多维监控训练到混淆矩阵深度评估的全流程工程实践更致力于探索一套可离线部署于移动设备的 AI 诊断方案。这不仅是一场算法性能的演练更是为了让每一个手持移动终端的农户都能拥有一位“口袋里的农业专家”将田间病害的防控门槛降至最低。2.数据集介绍本实验数据集来源于Kaggle该数据集是Kaggle 上最大的番茄叶片病害数据集2022 年包含 11 个类别涉及 10 种病害。超过2万张番茄叶片图像涵盖10种病害和1种健康状态。图像采集自实验室环境和自然环境。目标是开发一个轻量级模型用于预测番茄叶片病害并将其部署在可离线使用的移动应用程序上。Classes:Late_blighthealthyEarly_blightSeptoria_leaf_spotTomato_Yellow_Leaf_Curl_VirusBacterial_spotTarget_SpotTomato_mosaic_virusLeaf_MoldSpider_mites Two-spotted_spider_mitePowdery Mildew3.技术工具Python版本:3.9代码编辑器jupyter notebook4.实验过程4.1导入数据在构建深度学习分类流水线时环境的整洁与高效的路径索引是第一步。本阶段我们集成了 TensorFlow 与 Keras 核心库并引入了多种经典的主流预训练模型架构如 MobileNetV2、ResNet50V2 等为后续的迁移学习对比实验做好储备。针对番茄病害数据集由于不同病害类别的图像分布在各自的子文件夹中我们通过os.listdir建立了一套递归索引机制。这一步的关键在于不仅要准确抓取.jpg或.png等常见格式的原始图像路径更要建立起文件路径与病害类别标签之间的逻辑映射。这种“全路径扫描”的方式能够确保我们在不预先加载全部数据到内存的前提下灵活地对海量样本进行乱序、分割与预处理。# --- 1. 环境初始化过滤冗余警告导入核心科学计算与深度学习库 --- import warnings warnings.filterwarnings(ignore) # 忽略版本更迭产生的警告保持控制台整洁 import os import random import numpy as np import matplotlib.pyplot as plt import cv2 import tensorflow as tf from tensorflow import keras from tqdm.auto import tqdm # 进度条工具用于实时监控大规模数据读取 from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay # --- 2. 深度学习组件涵盖模型加载、回调监控及图像增强 --- from tensorflow.keras.models import load_model from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint from tensorflow.keras.preprocessing.image import ImageDataGenerator # --- 3. 预训练架构导入用于迁移学习对比的不同深度网络模型 --- from tensorflow.keras.applications import ResNet50V2, VGG16, VGG19, MobileNetV2 # 导入特定架构对应的预处理逻辑确保输入像素分布的一致性 from tensorflow.keras.applications.mobilenet_v2 import preprocess_input as preprocess_mobilenetv2 from tensorflow.keras.applications.resnet_v2 import preprocess_input as preprocess_resnet50v2 from tensorflow.keras.utils import to_categorical # --- 4. 路径索引递归扫描番茄病害数据集目录 --- main_folder r/kaggle/input/tomato-disease-multiple-sources/train # 初始化列表用于存储所有有效样本的绝对路径 images [] # 遍历主文件夹下的每个病害类别子文件夹 for folder in os.listdir(main_folder): path os.path.join(main_folder, folder) print(f检测到类别目录: {path}) # 筛选有效图像文件排除隐藏文件或非图片格式 for img in os.listdir(path): if img.endswith((.jpg, .png, .jpeg)): images.append(os.path.join(path, img))4.2数据可视化为了建立对数据集的感性认识我们编写了这段随机采样代码。利用random.sample从上万张路径列表中抽取出 16 组典型样本并借助cv2完成了从 BGR 到 RGB 的色彩空间校准——这是因为 OpenCV 默认的读取习惯与 Matplotlib 的显示规范存在色差。通过 4x4 的矩阵排列我们可以清晰地观察到不同类别的番茄叶片形态有的布满了干枯的褐色圆斑如早疫病有的则呈现出脉络不规则的黄化如病毒病。这种视觉核验不仅确认了图像读取逻辑的正确性也让我们确信数据集中包含了足够的形态多样性为 CNN 捕捉病理纹理提供了丰富的素材池。# --- 1. 随机抽样从海量路径库中抽取 16 张代表性图片 --- random_images random.sample(images, 16) # --- 2. 构建可视化画布设置 4x4 的展示矩阵 --- plt.figure(figsize(12, 12)) plt.suptitle(番茄叶片病害样本随机巡检, fontsize20, y1.02) # 利用 tqdm 驱动循环同时监控处理进度 for i, img_path in enumerate(tqdm(random_images, desc正在渲染样本)): # 使用 OpenCV 读取原始图像 img cv2.imread(img_path) # 容错处理跳过损坏或无法读取的文件 if img is None: continue # 色彩空间转换OpenCV 的 BGR 转换为 Matplotlib 兼容的 RGB img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 动态创建子图布局 plt.subplot(4, 4, i 1) plt.imshow(img) plt.axis(off) # 隐藏坐标轴聚焦叶片病斑细节 plt.title(fSample Image {i1}, fontsize10) # 自动调整间距防止标题重叠 plt.tight_layout() plt.show()4.3特征工程本阶段的核心任务是构建一套标准化的数据供给流。首先通过自定义的cnn_preprocess函数将像素值从 [0, 255] 压缩至 [0, 1] 区间这一归一化操作能有效避免梯度爆炸让神经网络的权重更新更加平稳。针对番茄病害特征的复杂性我们利用ImageDataGenerator开启了全方位的空间增强涵盖了模拟拍摄角度偏差的随机旋转、模拟成像畸变的剪切变换以及模拟远近变焦的随机缩放。此外通过validation_split参数我们严谨地从原始训练集中剥离出20%的数据作为“监考官”确保模型在进化过程中时刻接受无偏见性能评估。最终flow_from_directory机制会自动根据子文件夹名称建立病害类别标签将海量零散的叶片影像转化为源源不断的结构化张量流。# --- 1. 路径定义与核心参数配置 --- train_path /kaggle/input/tomato-disease-multiple-sources/train test_path /kaggle/input/tomato-disease-multiple-sources/valid IMG_SIZE 224 # 适配大多数 CNN 的标准输入尺寸 batch_size 32 # 批处理大小平衡内存占用与梯度稳定性 # --- 2. 定义自定义预处理逻辑像素归一化 --- def cnn_preprocess(x): 将图像像素值缩放到 [0, 1] 之间加速模型收敛 return x / 255.0 # --- 3. 构建训练集增强生成器模拟自然环境的多样性 --- cnn_train_datagen ImageDataGenerator( preprocessing_functioncnn_preprocess, # 空间增强策略提升模型泛化性能 rotation_range20, # 随机旋转角度范围 0-20 width_shift_range0.2, # 水平平移 height_shift_range0.2, # 垂直平移 shear_range0.2, # 剪切强度 zoom_range0.2, # 随机缩放 horizontal_flipTrue, # 水平翻转模拟叶片正反面或镜像 fill_modenearest, # 填充变换后的空白区域 validation_split0.2 # 自动划出 20% 用于验证 ) # --- 4. 生成训练与验证数据流 --- cnn_train_generator cnn_train_datagen.flow_from_directory( train_path, target_size(IMG_SIZE, IMG_SIZE), batch_sizebatch_size, class_modecategorical, # 多分类任务采用独热编码标签 subsettraining, # 提取训练子集 shuffleTrue # 打乱顺序防止顺序偏差 ) cnn_val_generator cnn_train_datagen.flow_from_directory( train_path, target_size(IMG_SIZE, IMG_SIZE), batch_sizebatch_size, class_modecategorical, subsetvalidation, # 提取验证子集 shuffleTrue ) # --- 5. 构建测试集生成器仅做标准化不做增强 --- # 测试集必须反映真实的原始输入分布 cnn_test_datagen ImageDataGenerator(rescale1./255) cnn_test_generator cnn_test_datagen.flow_from_directory( test_path, target_size(IMG_SIZE, IMG_SIZE), batch_sizebatch_size, class_modecategorical, shuffleFalse, # 测试时保持顺序以便后续生成混淆矩阵 )通过这套自动化的数据流水线我们成功规避了手动加载数万张图片可能导致的内存溢出风险。特别需要注意的是在测试集Test Set中我们严禁使用旋转、缩放等增强手段仅保留基础的像素归一化Rescale这是为了真实模拟农民在田间手持设备拍摄时的最原始图像输入。随着生成器的就绪模型现在可以接触到成千上万种“变体”后的番茄叶片这种对病斑本质特征的提取能力将是我们在接下来的 CNN 架构搭建中追求的核心目标。4.4构建模型本模型采用典型的Sequential序贯模型构建。架构设计上我们部署了三组“卷积池化”的核心单元前两层使用 64 个 3 x 3 卷积核初步过滤噪声第三层则提升至 128 个卷积核以强化高阶语义表达。为了应对全连接层可能产生的过拟合风险我们在 Flatten 层后引入了比例为0.4的Dropout随机失活机制强制网络不依赖于某些特定的“强特征”路径从而提升泛化性。末端的全连接层采用逐级降维策略128-64-64最后通过Softmax激活函数输出与番茄病害种类等量的概率分布。这种“先提取空间特征、再进行非线性映射”的设计逻辑确保了模型既能认准病斑形状又能通过深度融合做出准确的逻辑判定。# --- 1. 定义 CNN 序贯模型架构 --- cnn_model keras.Sequential([ # 输入层接收 224x224 的 RGB 三通道彩色图像 keras.layers.Input(shape(IMG_SIZE, IMG_SIZE, 3)), # 第一组特征提取模块初步捕获病斑边缘与纹理 keras.layers.Conv2D(filters64, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), # 空间维度压缩提取显著特征 # 第二组特征提取模块加强病理纹理的抽象能力 keras.layers.Conv2D(filters64, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), # 第三组特征提取模块提取更深层的语义特征如复杂的叶斑拓扑 keras.layers.Conv2D(filters128, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), # --- 2. 特征扁平化与正则化 --- keras.layers.Flatten(), # 随机失活防止模型死记硬背训练样本增强抗噪声能力 keras.layers.Dropout(0.4), # --- 3. 分类决策头多层感知机进行非线性推理 --- keras.layers.Dense(units128, activationrelu), keras.layers.Dense(units64, activationrelu), keras.layers.Dense(units64, activationrelu), # 输出层根据病害类别数输出归一化概率 # 使用 softmax 确保所有类别的概率总和为 1 keras.layers.Dense(unitslen(cnn_val_generator.class_indices), activationsoftmax, dtypefloat32) ]) # --- 4. 打印网络拓扑结构 --- # 检查参数分布、特征图尺寸演变以及总参数量 cnn_model.summary()通过summary()我们可以观察到模型在保持高特征分辨率的同时参数量控制在了一个合理的范围内。这种结构不仅兼顾了计算效率更适合在移动端或嵌入式农业监测设备上运行。值得注意的是卷积核的数量从 64 增加到 128体现了“随着视野变小、特征维度增加”的设计哲学这对于识别那些在视觉上极其相似的叶片病害如早疫病与晚疫病的初期对比具有重要的工程意义。4.5训练模型在模型编译阶段我们选用了Adam优化器它能根据梯度的历史表现动态调整学习率这对于处理特征跨度较大的农作物病害样本尤为有效。损失函数采用CategoricalCrossentropy配合精确率Precision和召回率Recall等多维指标全面审视模型在识别各类病害时的灵敏度。为了增强工程稳定性我们配置了两套核心回调CallbacksEarlyStopping设定了 5 个 Epoch 的耐心值一旦验证集损失停止下降即提前终止防止无谓的算力消耗ModelCheckpoint则负责在整个迭代周期内充当“黑匣子”自动锁定并保存验证集损失val_loss最低时刻的.keras完整模型确保我们手中握有的始终是性能天花板。# --- 1. 配置智能监控回调函数 --- callbacks [ # 提前停止策略防止过拟合若 5 轮内验证集损失不降则自动停机 EarlyStopping( monitorval_loss, patience5, restore_best_weightsTrue # 自动回滚到表现最好的权重状态 ), # 最优权重备份实时监控验证集并保存损失值最低的模型 ModelCheckpoint( filepathCNN_best_model.keras, monitorval_loss, save_best_onlyTrue, # 仅保留历史最佳 save_weights_onlyFalse, # 保存完整架构与权重 modemin, # 以最小化损失为优化目标 verbose1 ) ] # --- 2. 编译模型配置优化器、多分类损失函数及多维评估指标 --- cnn_model.compile( optimizerkeras.optimizers.Adam(), losskeras.losses.CategoricalCrossentropy(), # 引入精确率与召回率深入分析各类病害的误报与漏报风险 metrics[ accuracy, keras.metrics.Precision(nameprecision), keras.metrics.Recall(namerecall) ] ) # --- 3. 开启迭代训练注入数据流启动卷积特征学习 --- cnn_history cnn_model.fit( cnn_train_generator, # 带有实时数据增强的训练流 epochs20, # 设置最大迭代轮次 validation_datacnn_val_generator, # 验证集作为性能标尺 callbackscallbacks # 挂载监控组件 )随着fit过程的推进模型开始通过反向传播不断修正卷积核的敏感度。每一个 Epoch 的结束都伴随着精确率与召回率的波动这实际上是网络在不同病害特征如叶缘卷曲与叶面霉层之间寻找区分界限的过程。得益于ModelCheckpoint的存在即便在第 20 轮之后出现了性能回落我们也能精准找回那个在“病斑识别”上表现最平衡的历史时刻。这种严谨的自动化训练闭环是构建工业级农业 AI 诊断工具的必经之路。4.6模型评估评估的第一步是审视训练与验证曲线的演进趋势。通过matplotlib构建的对比图表我们可以清晰地观察到 Accuracy准确率与 Loss损失函数在 20 个 Epoch 间的动态平衡。理想的状态是两条曲线紧密贴合并同步收敛如果在训练后期 Training Accuracy 持续攀升而 Validation Accuracy 陷入停滞甚至下滑则预示着模型出现了过拟合现象。通过这种视觉化的复盘我们可以验证之前的Dropout与数据增强策略是否成功压制了网络对训练样本的“死记硬背”确保了模型是在学习病理纹理的本质。# --- 1. 可视化训练动态评估收敛性与过拟合风险 --- plt.figure(figsize(12, 6)) # 绘制准确率演进图 plt.subplot(1, 2, 1) plt.plot(cnn_history.history[accuracy], label训练准确率 (Training)) plt.plot(cnn_history.history[val_accuracy], label验证准确率 (Validation)) plt.title(训练与验证准确率对比) plt.xlabel(迭代轮次 (Epochs)) plt.ylabel(准确率 (Accuracy)) plt.legend() # 绘制损失函数演进图 plt.subplot(1, 2, 2) plt.plot(cnn_history.history[loss], label训练损失 (Training)) plt.plot(cnn_history.history[val_loss], label验证损失 (Validation)) plt.title(训练与验证损失对比) plt.xlabel(迭代轮次 (Epochs)) plt.ylabel(损失 (Loss)) plt.legend() plt.show()在模型确认收敛后最严苛的考验来自于cnn_test_generator提供的独立测试集。这部分数据在训练过程中从未被模型触达代表了模型在现实农田环境中可能遭遇的未知挑战。由于医学与农业影像数据有时存在截断或编码不完整的问题我们特别引入了ImageFile.LOAD_TRUNCATED_IMAGES补丁以增强读取的工程鲁棒性。通过evaluate方法我们可以得到模型在全测试集上的平均损失与多维指标表现这不仅是对算法精度的量化总结更是对该番茄病害诊断系统可靠性的最终背书。# --- 2. 鲁棒性设置与测试集终极压测 --- from PIL import ImageFile # 开启容错模式允许加载不完整的图像文件确保在大规模数据流中不因异常样本中断 ImageFile.LOAD_TRUNCATED_IMAGES True # 在独立的测试集上运行模型获取最真实的泛化性能指标 test_results cnn_model.evaluate(cnn_test_generator)为了深入挖掘模型对特定病害的辨析能力我们引入了混淆矩阵Confusion Matrix。通过将cnn_model.predict生成的概率分布转化为预测标签并与测试集的真值进行交叉对冲我们可以直观地看到模型在哪些病害之间产生了“迟疑”。例如如果矩阵对角线上的数值分布均匀且高度集中说明模型对各类病害的识别力均衡如果某些非对角线区域出现了明显的数值堆积则暴露了模型在区分如“细菌性斑点”与“晚疫病”时的特征混淆。这种多维度的诊断分析为后续针对特定类别的样本补偿与模型微调指明了方向。# --- 3. 混淆矩阵洞察各类病害的分类精度与误报情况 --- # 获取模型对测试集的原始概率输出 y_pred_probs cnn_model.predict(cnn_test_generator) # 取概率最大的索引作为最终预测类别 y_pred np.argmax(y_pred_probs, axis1) # 提取测试集的真实标签 y_true cnn_test_generator.classes # 获取类别名称映射关系 class_names list(cnn_test_generator.class_indices.keys()) # 计算并生成混淆矩阵 plt.figure(figsize(12, 10)) cm confusion_matrix(y_true, y_pred) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labelsclass_names) # 使用 Blues 色阶进行渲染颜色越深代表匹配度越高 disp.plot(cmapplt.cm.Blues, xticks_rotation45) plt.title(番茄病害分类混淆矩阵 (Confusion Matrix)) plt.show()4.7模型预测为了模拟真实的田间诊断过程我们从测试集中随机抽取了 16 张番茄叶片影像进行实时推理。在这一环节中每一张图像都经历了与训练时一致的重采样Resize与归一化Normalization处理确保输入张量的特征分布落在模型的“认知范围”内。我们通过对比标签的颜色来直观判定结果预测正确的样本以绿色标注而预测偏差的样本则以红色警示。这种可视化策略能让我们一眼发现模型在特定病害如某些相似的真菌感染上的薄弱点从而为后续的针对性数据补强提供第一手参考。# --- 1. 随机抽样从测试集中随机选取 16 个样本索引 --- sample_indices random.sample(range(len(cnn_test_generator.filepaths)), 16) # --- 2. 构建预测对比矩阵布局 --- plt.figure(figsize(15, 15)) plt.suptitle(番茄病害 AI 诊断实战测试集随机样本预测对比, fontsize20, y1.02) for i, idx in enumerate(tqdm(sample_indices, desc执行实时推理)): # 获取图像路径并进行读取校准 img_path cnn_test_generator.filepaths[idx] img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 确保色彩还原真实 # 预处理严格对齐模型输入尺寸 img_resized cv2.resize(img, (IMG_SIZE, IMG_SIZE)) # 归一化将像素值缩放至 [0, 1] 空间 img_normalized img_resized / 255.0 # 维度扩充(H, W, C) - (1, H, W, C)符合 Keras 批处理输入规范 img_input np.expand_dims(img_normalized, axis0) try: # 执行前向传播计算verbose0 禁用冗余预测日志 pred_probs cnn_model.predict(img_input, verbose0) pred_class np.argmax(pred_probs) # 选取概率最高的类别索引 # 获取真实标签与预测标签的文字映射 true_class cnn_test_generator.classes[idx] true_label list(cnn_test_generator.class_indices.keys())[true_class] pred_label list(cnn_test_generator.class_indices.keys())[pred_class] # 动态绘制子图 plt.subplot(4, 4, i1) plt.imshow(img_resized) plt.xticks([]) plt.yticks([]) # 结果反馈匹配正确显示绿色匹配失败显示红色提示 is_correct (true_class pred_class) plt.xlabel(f真值: {true_label}\n预测: {pred_label}, colorgreen if is_correct else red, fontsize10) except Exception as e: print(f处理样本 {img_path} 时发生异常: {str(e)}) continue # 优化视觉布局防止标签文字重叠 plt.tight_layout() plt.show()5.总结本实验依托于Kaggle上规模最大的番茄叶片病害数据集针对涵盖10 种常见病害及 1 种健康状态的 2 万余张影像样本构建并优化了一套专为移动端部署设计的轻量级 CNN 分类模型。实验结果显示该模型在复杂的实验室与自然环境混合数据下表现稳健最终在测试集上取得了0.8831的像素准确率且Precision0.9217与Recall0.8595指标表现均衡证明了其在识别早疫病、晚疫病及各类病毒病等 11 个类别时具备极高的辨析精度。通过混淆矩阵的深度分析可见尽管不同病害在视觉纹理上存在一定的跨类相似性但模型依然能够精准锁定病斑的核心特征有效降低了误诊与漏诊率。这一成果不仅验证了卷积神经网络在智慧农业植保领域的实用性更为开发能够离线运行、秒级响应的移动端番茄病害监测应用提供了坚实的算法内核为农户实时掌控作物健康状态提供了可靠的数字化保障。源代码import warnings warnings.filterwarnings(ignore) import os import random import numpy as np import matplotlib.pyplot as plt import cv2 import tensorflow as tf from tensorflow import keras from tqdm.auto import tqdm from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay from tensorflow.keras.models import load_model from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.applications import ResNet50V2, VGG16, VGG19, MobileNetV2 from tensorflow.keras.applications.mobilenet_v2 import preprocess_input as preprocess_mobilenetv2 from tensorflow.keras.applications.resnet_v2 import preprocess_input as preprocess_resnet50v2 from tensorflow.keras.utils import to_categorical main_folder r/kaggle/input/tomato-disease-multiple-sources/train # Get all image paths images [] for folder in os.listdir(main_folder): path os.path.join(main_folder,folder) print(path) for img in os.listdir(path): if img.endswith((.jpg, .png, .jpeg)): images.append(os.path.join(path, img)) # Pick 16 random images random_images random.sample(images, 16) # Plot them plt.figure(figsize(12, 12)) for i, img_path in enumerate(tqdm(random_images)): img cv2.imread(img_path) if img is None: continue img cv2.cvtColor(img,cv2.COLOR_BGR2RGB) plt.subplot(4, 4, i 1) plt.imshow(img,cmapgray) plt.axis(off) plt.title(fImage {i1}) plt.tight_layout() plt.show() train_path /kaggle/input/tomato-disease-multiple-sources/train test_path /kaggle/input/tomato-disease-multiple-sources/valid IMG_SIZE 224 batch_size 32 def cnn_preprocess(x): return x/255.0 cnn_train_datagen ImageDataGenerator( preprocessing_functioncnn_preprocess, # Augmentation rotation_range20, width_shift_range0.2, height_shift_range0.2, shear_range0.2, zoom_range0.2, horizontal_flipTrue, fill_modenearest, validation_split0.2 # 20% (Validation) ) cnn_train_generator cnn_train_datagen.flow_from_directory( train_path, target_size(IMG_SIZE,IMG_SIZE), batch_sizebatch_size, class_modecategorical, subsettraining, shuffle True ) cnn_val_generator cnn_train_datagen.flow_from_directory( train_path, target_size(IMG_SIZE,IMG_SIZE), batch_sizebatch_size, class_modecategorical, subsetvalidation, shuffle True ) cnn_test_datagen ImageDataGenerator(rescale1./255) cnn_test_generator cnn_test_datagen.flow_from_directory( test_path, target_size(IMG_SIZE,IMG_SIZE), batch_sizebatch_size, class_modecategorical, shuffleFalse, ) cnn_model keras.Sequential([ keras.layers.Input(shape(IMG_SIZE, IMG_SIZE, 3)), keras.layers.Conv2D(filters64, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), keras.layers.Conv2D(filters64, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), keras.layers.Conv2D(filters128, kernel_size(3, 3), activationrelu), keras.layers.MaxPooling2D(pool_size(2, 2)), keras.layers.Flatten(), keras.layers.Dropout(0.4), keras.layers.Dense(units128, activationrelu), keras.layers.Dense(units64, activationrelu), keras.layers.Dense(units64, activationrelu), keras.layers.Dense(unitslen(cnn_val_generator.class_indices), activationsoftmax, dtypefloat32) ]) cnn_model.summary() callbacks [ EarlyStopping( monitorval_loss, patience5, restore_best_weightsTrue ), ModelCheckpoint( filepathCNN_best_model.keras, monitorval_loss, save_best_onlyTrue, save_weights_onlyFalse, modemin, verbose1 ) ] cnn_model.compile(optimizerkeras.optimizers.Adam(), losskeras.losses.CategoricalCrossentropy(), metrics[accuracy,keras.metrics.Precision(nameprecision),keras.metrics.Recall(namerecall) ]) cnn_history cnn_model.fit( cnn_train_generator, epochs 20, validation_data cnn_val_generator, callbacks callbacks ) #Accuracy plt.figure(figsize(12, 6)) plt.subplot(1, 2, 1) plt.plot(cnn_history.history[accuracy], labelTraining Accuracy) plt.plot(cnn_history.history[val_accuracy], labelValidation Accuracy) plt.title(Training and Validation Accuracy) plt.xlabel(Epochs) plt.ylabel(Accuracy) plt.legend() # loss plt.subplot(1, 2, 2) plt.plot(cnn_history.history[loss], labelTraining Loss) plt.plot(cnn_history.history[val_loss], labelValidation Loss) plt.title(Training and Validation Loss) plt.xlabel(Epochs) plt.ylabel(Loss) plt.legend() plt.show() from PIL import ImageFile ImageFile.LOAD_TRUNCATED_IMAGES True test_results cnn_model.evaluate(cnn_test_generator) y_pred_probs cnn_model.predict(cnn_test_generator) y_true cnn_test_generator.classes class_names list(cnn_test_generator.class_indices.keys()) plt.figure(figsize(12, 10)) cm confusion_matrix(y_true, y_pred) disp ConfusionMatrixDisplay(confusion_matrixcm) disp.plot(cmapplt.cm.Blues) plt.title(Confusion Matrix) plt.show() sample_indices random.sample(range(len(cnn_test_generator.filepaths)), 16) plt.figure(figsize(15, 15)) for i, idx in enumerate(tqdm(sample_indices)): img_path cnn_test_generator.filepaths[idx] img cv2.imread(img_path) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_resized cv2.resize(img, (IMG_SIZE, IMG_SIZE)) img_normalized img_resized / 255.0 img_input np.expand_dims(img_normalized, axis0) try: pred_probs cnn_model.predict(img_input, verbose0) pred_class np.argmax(pred_probs) true_class cnn_test_generator.classes[idx] true_label list(cnn_test_generator.class_indices.keys())[true_class] pred_label list(cnn_test_generator.class_indices.keys())[pred_class] plt.subplot(4, 4, i1) plt.imshow(img_resized) plt.xticks([]) plt.yticks([]) plt.xlabel(fActual: {true_label}\nPredicted: {pred_label}, colorgreen if true_class pred_class else red) except Exception as e: print(fError processing image {img_path}: {str(e)}) continue plt.tight_layout() plt.show()资料获取更多粉丝福利关注下方公众号获取