1.项目背景
随着全球突发传染性疾病防控压力的不断增加,猴痘(Monkeypox)作为一种人畜共患的病毒性疾病,其早期精准诊断与快速筛查对于遏制疫情扩散具有重要意义。然而,猴痘在发病早期的皮肤病变特征与水痘、麻疹等常见发疹性疾病高度相似,传统的人工临床肉眼鉴别极易受限于诊疗经验与主观判断,特别是在医疗资源紧缺地区容易造成误诊或漏诊。近年来,深度学习与计算机视觉技术在医学影像分析领域的蓬勃发展,为自动化皮肤病变辅助诊断提供了全新的解决方案。通过构建基于高效卷积神经网络的图像分类模型,能够深层次挖掘病变区域的微观纹理与形态表征,实现对猴痘及其他类似皮肤病变的高精度识别。这不仅有助于提升基层医疗机构的初步筛查效率,降低对高水平专家经验的依赖,还能为传染病早期预警与数字医疗辅助决策体系的建设提供坚实的技术支撑。
2.数据集介绍
本实验数据集来源于Kaggle,数据集中有 3 个文件夹。
1) 原始图像:共包含228 张图像,其中 102 张属于“猴痘”类,其余 126 张代表“其他”类,即非猴痘(水痘和麻疹)病例。
2) 增强图像:为了辅助分类任务,我们使用 MATLAB R2020a 应用了多种数据增强方法,例如旋转、平移、反射、剪切、色调、饱和度、对比度和亮度抖动、噪声、缩放等。虽然可以使用 ImageGenerator 或其他图像增强工具轻松完成这些操作,但为了确保结果的可复现性,我们在此文件夹中提供了增强后的图像。增强后,图像数量增加了约 14 倍。“猴痘”和“其他”类别分别包含 1428 张和 1764 张图像。
3) Fold1:三折交叉验证数据集之一。为避免训练过程中出现任何偏差,我们采用了三折交叉验证。原始图像被划分为训练集、验证集和测试集,比例约为 70:10:20,同时保持患者独立性。根据常用的数据准备方法,我们仅对训练集和验证集进行了数据增强,而测试集仅包含原始图像。用户可以选择直接使用这些折,也可以使用原始数据并采用其他算法进行数据增强。
此外,还提供了一个包含 228 行两列的 CSV 文件。该表格包含所有 ImageID 及其对应标签的列表。
3.技术工具
Python版本:3.9
代码编辑器:jupyter notebook
4.实验过程
4.1导入数据
在构建猴痘皮肤病变图像识别模型之前,首先需要完成基础开发环境的依赖库加载以及数据集的流式导入。本阶段通过调用 TensorFlow 提供的图像预处理工具,将存储于不同目录下的训练集、验证集与测试集自动构建为高性能的 Dataset 对象,统一将图像分辨率调整为标准的 224x224 像素,并按 Batch 进行批处理操作。需要注意的是,为了保障评估结果的可复现性与准确性,验证集与测试集关闭了数据打乱(shuffle)功能。
# ----------------------------------------------------------------------# 依赖库导入与数据集构建# ----------------------------------------------------------------------import tensorflow as tfimport matplotlib.pyplot as pltimport randomfrom tensorflow.keras import layers, Modelfrom sklearn.metrics import accuracy_score, classification_report, confusion_matriximport seaborn as sns# 定义数据集路径与统一图像尺寸train_dir = "/kaggle/input/monkeypox-skin-lesion-dataset/Fold1/Fold1/Fold1/Train/"val_dir = "/kaggle/input/monkeypox-skin-lesion-dataset/Fold1/Fold1/Fold1/Val/"test_dir = "/kaggle/input/monkeypox-skin-lesion-dataset/Fold1/Fold1/Fold1/Test/"IMG_SIZE = (224, 224) # 设定输入网络的图像目标分辨率# 构建训练集数据流(默认开启数据打乱)train_data = tf.keras.preprocessing.image_dataset_from_directory(directory=train_dir,image_size=IMG_SIZE,label_mode="binary", # 二分类标签模式batch_size=32)# 构建测试集数据流(关闭打乱,确保预测评估顺序一致)test_data = tf.keras.preprocessing.image_dataset_from_directory(directory=test_dir,image_size=IMG_SIZE,label_mode="binary",batch_size=32,shuffle=False)# 构建验证集数据流(关闭打乱,用于训练过程监控)val_data = tf.keras.preprocessing.image_dataset_from_directory(directory=val_dir,image_size=IMG_SIZE,label_mode="binary",batch_size=32,shuffle=False)
数据导入成功后,系统完成了对文件夹结构的自动扫描与标签映射,将皮肤病变图像转化为支持 GPU 迭代计算的批次数据流。这种基于目录结构的加载方式避免了将海量图像一次性全量读入内存的开销,为后续的数据增强与网络训练打下了高效规范的数据基础。
4.2数据可视化
在对图像数据进行模型训练前,对原始样本进行直观的数据可视化分析是必不可少的环节。通过编写自定义的可视化函数,从特定的数据集目录与类别文件夹中随机抽取样本图像进行网格展示,有助于直观观察皮肤病变图像的色彩分布、病灶形态以及背景复杂程度,为后续的数据增强与特征提取提供直观的样本认知。
# ----------------------------------------------------------------------# 随机样本可视化展示# ----------------------------------------------------------------------# 定义随机绘制样本图像的函数def visualize_random_images(dataset_type="train", label_type="Others"):sample = 9 # 设定绘制样本数量plt.figure(figsize=(15, 8)) # 设置显示画幅尺寸type_dir = train_dir if dataset_type=="train" else test_dir # 根据输入类型选择数据集根路径base_dir = os.path.join(type_dir, label_type) # 拼接具体类别的完整文件夹路径images = random.sample(os.listdir(base_dir), 9) # 随机从目录中抽取 9 张图片文件名# 循环读取并绘制子图for i, image in enumerate(images):plt.subplot(3, 3, i+1) # 创建 3x3 的网格布局img = plt.imread(os.path.join(base_dir, image)) # 读取图像文件plt.imshow(img) # 渲染图像内容# 调用函数随机展示训练集中 Monkeypox(猴痘)类别的样本图像visualize_random_images("train", "Monkeypox")
4.3构建模型
在分类任务的网络架构设计中,模型采用了迁移学习(Transfer Learning)策略,以 EfficientNetB3 作为主干特征提取网络。为了充分利用大模型在大规模通用数据集上预训练得到的丰富边缘与纹理特征,同时适配特定皮肤病变图像的细粒度表达,代码将 EfficientNetB3 的顶层全连接分类器移除,并对主干网络进行微调(Fine-tuning)设置——冻结除最后 5 层之外的所有底层特征提取层,仅允许高层抽象特征层参与梯度更新。基于主干网络提取的特征图,后续顺序堆叠了 Flatten 展开层、Dense 隐藏层以及两组 Dropout 层(丢弃率设为 0.5),以降低模型参数量过大带来的过拟合风险,最后通过 Sigmoid 激活函数输出单维度二分类概率。
# ----------------------------------------------------------------------# 基于 EfficientNetB3 的迁移学习分类网络构建# ----------------------------------------------------------------------# 加载预训练 EfficientNetB3 主干网络(不包含顶层分类器)base_model = tf.keras.applications.EfficientNetB3(include_top=False)base_model.trainable = True # 开启主干网络的可训练开关# 冻结主干网络除最后 5 层以外的所有层参数,实现精准微调for layer in base_model.layers[:-5]:layer.trainable = False# 构建 Keras Functional API 网络结构inputs = layers.Input(shape=(224, 224, 3), name="input_layer") # 输入层定义base_layer = base_model(inputs) # 经过特征提取主干网络dropout_layer_1 = layers.Dropout(0.5)(base_layer) # 第一层随机失活,抑制过拟合flat_layer = layers.Flatten()(dropout_layer_1) # 展平特征图为一维向量dense_1 = layers.Dense(256, activation="relu")(flat_layer) # 全连接层提取高级特征dropout_layer_2 = layers.Dropout(0.5)(dense_1) # 第二层随机失活dense_2 = layers.Dense(128, activation="relu")(dropout_layer_2) # 隐藏全连接层outputs = layers.Dense(1, activation="sigmoid")(dense_2) # 最终二分类输出层# 实例化最终模型对象model = Model(inputs, outputs)
网络结构的整体设计兼顾了特征表达能力与泛化稳定性,将预训练大模型的强特征抽象能力与针对性的全连接映射层紧密结合。微调机制使得模型能够在保持大部分通用语义特征不变的前提下,快速聚焦于猴痘病变区域的差异化表征,为后续高效的模型训练与收敛奠定了良好的网络框架结构。
4.4训练模型
网络架构搭建完毕后,需要对模型进行编译并配置相关的优化参数。这里选择 Adam 优化器控制梯度更新速率,损失函数采用适合二分类任务的交叉熵损失(binary_crossentropy),并以分类准确率(accuracy)作为训练过程中的核心监控指标。完成编译后,传入构建好的训练集与验证集数据流展开 20 个 Epoch 的迭代训练,以实现网络权重的逐步收敛。
# ----------------------------------------------------------------------# 模型编译与迭代训练# ----------------------------------------------------------------------# 编译模型:配置 Adam 优化器、二分类交叉熵损失函数及评估指标model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),loss='binary_crossentropy',metrics=['accuracy'])# 启动模型训练,在训练集与验证集上迭代 20 个轮次history = model.fit(train_data,epochs=20,validation_data=val_data)
训练过程中的各项指标实时反映了模型的学习轨迹与参数调整效果。通过设定合理的迭代轮次与验证集中监视,能够在防止欠拟合的同时动态掌握模型的收敛状态,为下一步分析训练曲线以及评估最终泛化性能提供完整的数据记录。
4.5模型评估
训练完成后,需要从多个维度对模型的泛化能力与分类性能进行综合评估。评估过程分为四大步骤:首先通过绘制损失与准确率演变曲线分析训练收敛轨迹,随后在独立的测试集上计算整体损失与准确率指标,紧接着生成包含精确率、召回率及 F1 分数的分类性能报告,最后通过绘制混淆矩阵直观呈现模型在各类别上的预测与误判细节。
# ----------------------------------------------------------------------# 步骤一:绘制训练与验证指标演变曲线# ----------------------------------------------------------------------def plot_loss_curves(history):"""绘制训练集与验证集的损失与准确率变化曲线参数:history: TensorFlow 模型训练的 History 对象"""loss = history.history['loss']val_loss = history.history['val_loss']accuracy = history.history['accuracy']val_accuracy = history.history['val_accuracy']epochs = range(len(history.history['loss']))# 绘制损失曲线plt.plot(epochs, loss, label='training_loss')plt.plot(epochs, val_loss, label='val_loss')plt.title('Loss')plt.xlabel('Epochs')plt.legend()# 绘制准确率曲线plt.figure()plt.plot(epochs, accuracy, label='training_accuracy')plt.plot(epochs, val_accuracy, label='val_accuracy')plt.title('Accuracy')plt.xlabel('Epochs')plt.legend()plt.show()# 调用函数可视化训练历史曲线plot_loss_curves(history)
损失与准确率曲线反映了模型在各个迭代轮次中的学习轨迹。通过对训练集与验证集两条折线对比分析,可以直观判断模型在训练过程中是否存在过拟合倾向或收敛不充分等性能瓶颈。
# ----------------------------------------------------------------------# 步骤二:独立测试集整体性能评估# ----------------------------------------------------------------------# 在独立的测试集上计算模型的损失值与准确率model.evaluate(test_data)
在测试集上执行整体评估能够在完全未经模型训练的数据上快速检验其综合分类能力,输出的指标构成了该模型客观泛化表现的基础依据。
# ----------------------------------------------------------------------# 步骤三:获取预测概率与详细分类报告# ----------------------------------------------------------------------# 获取模型对测试集的预测结果,并通过四舍五入转为二分类标签(0 或 1)y_pred = tf.math.round(model.predict(test_data))# 解包测试集以提取真实的图像标签列表y_true = []for images, labels in test_data.unbatch():y_true.append(labels.numpy())# 输出包含 Precision、Recall 和 F1-score 的详细分类评估报告print(classification_report(y_true, y_pred, target_names=train_data.class_names))
分类报告量化输出了模型在不同类别上的细粒度指标,特别是针对精确率(Precision)与召回率(Recall)的解析,有助于全面评估模型在应对阳性与阴性病变样本时的判别均衡度。
# ----------------------------------------------------------------------# 步骤四:混淆矩阵可视化分析# ----------------------------------------------------------------------# 计算真实标签与预测标签的混淆矩阵cm = confusion_matrix(y_true, y_pred)# 利用 Seaborn 绘制整型格式的热力图展示混淆矩阵sns.heatmap(cm.astype("int"), annot=True)
混淆矩阵通过热力图的形式清晰展示了真正例、真负例以及误判样本的具体数量分布,为深入分析模型预测失误的具体原因提供了详实的可视化依据。
5.总结
本实验针对猴痘皮肤病变的临床辅助诊断需求,基于包含猴痘与非猴痘(水痘、麻疹等)病变图像的数据集,构建了基于 EfficientNetB3 迁移学习的二分类识别模型。实验通过严格的交叉验证划分配套,并在训练阶段引入多维度图像增强策略,有效解决了小样本皮肤病学数据的特征泛化难题。通过对 EfficientNetB3 主干网络进行高层参数微调以及全连接结构的优化,模型在测试集评估中展现出极优的分类表现,最终测试准确率达到 95.56% 以上,针对猴痘与其他类别的精确率、召回率及 F1 分数均稳定在 0.95 及以上。综合评估与混淆矩阵结果表明,该模型能够精准提取不同皮肤病变特征,具有极强的判别力与泛化稳定性,为医疗影像的自动化筛查与智慧医疗落地提供了可靠的技术参考。
56