十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于EfficientNet的猴痘皮肤病变图像分类:从数据工程到模型部署的医疗AI实战

基于EfficientNet的猴痘皮肤病变图像分类:从数据工程到模型部署的医疗AI实战 1. 项目概述从“猴痘”到“识别”一个AI医疗影像项目的诞生最近在整理过往项目资料时翻到了一个挺有意思的实战项目代号“第P4周猴痘病识别”。这名字听起来有点神秘其实就是我们团队当时为了验证一个快速原型开发流程用深度学习技术做的一个皮肤病变图像分类器核心目标是区分猴痘Monkeypox与其他几种常见的、外观相似的皮肤病症。当时市面上公开的、标注好的猴痘图像数据集还非常稀缺这个项目从数据搜集、清洗、模型选型到部署测试完整走了一遍踩了不少坑也积累了一些在资源受限条件下做医疗AI项目的实用经验。今天就跟大家详细拆解一下这个项目的来龙去脉、技术选型的思考以及那些教科书里不会写的实操细节。猴痘作为一种病毒性人畜共患病其皮肤表现如皮疹、水疱、脓疱与天花、水痘、甚至某些细菌感染或过敏反应有相似之处。对于非皮肤科专科医生尤其在基层医疗单位或疫情初期快速、准确的初步识别存在挑战。我们这个项目的初衷并非要替代专业医生而是探索能否利用计算机视觉技术构建一个辅助筛查工具帮助医护人员在大量疑似病例中快速进行初筛和分流提升工作效率并为后续的实验室确诊争取时间。项目适合对深度学习、计算机视觉特别是医疗AI应用感兴趣的开发者、研究人员以及希望了解一个完整AI项目从0到1落地过程的朋友。下面我就从项目设计思路开始一步步还原我们当时是怎么做的。2. 项目整体设计与核心思路拆解2.1 核心需求与问题定义接到这个任务时首要任务是明确我们要解决的具体问题。泛泛而谈“识别猴痘”是不行的。经过与医学顾问的初步沟通我们将问题精确定义为一个多类皮肤病变图像分类任务。具体来说我们计划区分以下四类猴痘 (Monkeypox): 目标类别。水痘 (Chickenpox): 同样表现为水疱是重要的鉴别诊断对象。麻疹 (Measles): 斑丘疹有时可能与猴痘早期皮疹混淆。正常皮肤或其他 (Normal/Others): 作为一个“兜底”类别包含健康皮肤或其他不相关的皮肤状况以提高模型的鲁棒性。选择这四类是基于医学上的鉴别诊断需求和数据可获得性的平衡。天花虽然最相似但已绝迹数据极少而水痘和麻疹是常见病有相对丰富的公开图像数据。定义“其他”类别至关重要可以防止模型对任何输入都强行归入前三类减少误报。注意在医疗AI项目中问题定义的准确性直接决定了项目的价值和天花板。必须与领域专家Domain Expert紧密合作确保技术目标与临床实际需求对齐。我们最初曾考虑加入“疥疮”、“脓疱疮”等但因图像特征差异较大且数据混杂为避免任务过于复杂而暂缓。2.2 技术路线选型与考量确定了分类任务后接下来是选择技术路线。对于图像分类卷积神经网络CNN是毋庸置疑的首选。但具体用哪种架构是从头训练Training from Scratch还是使用迁移学习Transfer Learning迁移学习 vs. 从头训练医疗影像数据尤其是针对特定病种如猴痘的数据通常量少且标注成本极高。我们的项目初期预计只能收集到几百到几千张有效图像这对于动辄需要数百万ImageNet图像训练的大型CNN来说是远远不够的。因此迁移学习是唯一可行的方案。我们利用在大型通用图像数据集如ImageNet上预训练好的模型将其知识迁移到我们的特定医疗图像任务上。模型架构选型我们评估了当时几种主流的高效CNN架构ResNet50: 经典且强大在ImageNet上表现优异结构相对规整是可靠的基线选择。EfficientNet-B3/B4: 通过复合缩放Compound Scaling在精度和效率之间取得了更好平衡在计算资源有限的情况下尤其有吸引力。DenseNet121: 特征复用率高参数相对较少可能在小数据集上表现更好。Vision Transformer (ViT): 当时Transformer在视觉领域刚兴起虽然潜力巨大但在小规模医疗数据集上容易过拟合且训练成本高。经过初步调研和简单的原型测试我们最终选择了EfficientNet-B4作为主干网络。主要理由是在相近的精度下EfficientNet通常比ResNet更小、更快相较于更复杂的模型它在我们的数据规模上过拟合的风险相对可控并且有丰富的开源预训练权重和易于使用的框架支持如TensorFlow/Keras, PyTorch。整体流程设计我们规划了标准的深度学习流水线数据收集与清洗 - 数据预处理与增强 - 模型构建与迁移学习 - 模型训练与验证 - 模型评估与测试 - 简易部署与测试。 这个流程看似标准但在医疗数据的每一个环节都有特殊的“坑”需要特别注意。3. 数据工程医疗AI项目的基石与最大挑战3.1 数据搜集与面临的困境数据是AI模型的燃料但对于“猴痘”这个相对新兴且敏感的课题获取高质量、标注准确的图像数据集是第一个巨大挑战。我们主要通过以下途径公开医学数据集搜索如Kaggle、GitHub上的相关竞赛数据集。幸运的是当时已有一个名为“Monkeypox Skin Lesion Dataset (MSLD)”的公开数据集开始流传它包含了猴痘、水痘、麻疹和正常的图像但数量有限总计约2000张左右且图像质量参差不齐。医学文献与机构网站从已发表的医学论文的附图、世界卫生组织WHO、疾病控制与预防中心CDC等权威机构的公开教育材料中手动收集并截图。这里必须严格遵守版权和伦理规定仅用于研究验证并计划在最终产品中替换为合规授权数据。网络爬虫谨慎使用在严格遵守robots协议和版权法的前提下从少数专业的医学图像库网站进行定向采集。这是一个灰色地带必须极度谨慎。我们严格限定了来源网站仅限明确允许研究使用的并进行了严格的去标识化处理移除所有患者个人信息和元数据。即使这样我们最初收集到的原始图像也不足3000张且存在严重问题类别不平衡猴痘图像最少水痘和麻疹较多。质量差异大分辨率不一、光照不均、拍摄角度多样、背景杂乱有些图片甚至包含文字标注或测量尺。标注噪声来自网络的图片标注可能不准确例如将“带状疱疹”误标为“水痘”。3.2 数据清洗与标注标准化面对“脏数据”我们花了近一半的项目时间进行清洗和标准化这是确保模型可信度的关键。自动过滤去除低质图像使用OpenCV检测并删除分辨率过低如小于224x224、严重模糊通过拉普拉斯方差计算或几乎全黑/全白的图像。去重计算图像的感知哈希pHash移除高度相似的重复图像。手动审核与标注这是最耗时但无法替代的步骤。我们邀请了一位医学专业的同学作为顾问对每一张自动过滤后的图像进行复核。制定标注规范明确各类别的视觉特征。例如猴痘皮疹通常更离心分布面向手掌、脚底、面部水疱形态更一致水痘皮疹呈“向心性”分布躯干多且可见不同期的皮疹丘疹、水疱、结痂共存。我们将这些特征写成文档供标注参考。使用标注工具采用LabelImg或更简单的分类文件夹方式进行整理。对于不确定的图像直接剔除绝不保留存疑样本。数据扩增策略 为了应对数据量小和类别不平衡我们采用了强化的数据增强Data Augmentation。除了常见的旋转、翻转、缩放、裁剪外针对医疗图像特点我们增加了颜色扰动轻微调整亮度、对比度、饱和度模拟不同拍摄设备的光照条件。弹性形变模拟皮肤表面的细微纹理变化。添加噪声模拟图像传输或采集过程中的高斯噪声、椒盐噪声。混合增强如MixUp将两张图像按比例混合同时混合其标签有助于模型学习更平滑的决策边界减轻过拟合。我们使用TensorFlow的ImageDataGenerator或Albumentations库功能更强大来实现这些增强。关键点增强操作必须在训练阶段实时进行而不是预先增强保存以最大化数据多样性。4. 模型构建、训练与调优实战4.1 迁移学习的实现细节我们使用PyTorch框架以EfficientNet-B4的ImageNet预训练权重为基础。import torch import torch.nn as nn from torchvision import models, transforms import torch.optim as optim # 1. 加载预训练模型并冻结所有底层参数 model models.efficientnet_b4(pretrainedTrue) for param in model.parameters(): param.requires_grad False # 冻结特征提取层 # 2. 替换分类头Classifier Head # EfficientNet的最后一层是 classifier其结构为 Sequential( Dropout, Linear(1792, num_classes) ) num_ftrs model.classifier[1].in_features # 获取原全连接层输入特征数 model.classifier[1] nn.Linear(num_ftrs, 4) # 替换为我们的4分类全连接层 # 将新的分类头参数设置为可训练 for param in model.classifier.parameters(): param.requires_grad True model model.to(device) # 移至GPU为什么先冻结再微调预训练模型底层学习的是通用边缘、纹理、形状特征这些对医学图像同样有用。直接在小数据上训练所有层会导致这些宝贵知识被“洗掉”并极易过拟合。冻结底层只训练新换上的分类头相当于让模型快速适应新任务。4.2 训练策略与超参数设置训练分为两个阶段第一阶段分类头训练只训练我们新添加的classifier层。使用较大的学习率如1e-3让模型快速适应新的分类任务。这个阶段通常很快5-10个epoch即可。第二阶段整体微调解冻模型的部分或全部底层卷积层用较小的学习率如1e-4, 1e-5进行精细微调。我们采用分层解冻策略从靠近分类头的后几层开始解冻逐步解冻更前面的层这样更稳定。# 优化器与损失函数 criterion nn.CrossEntropyLoss() # 第一阶段优化器只优化分类头参数 optimizer_stage1 optim.Adam(model.classifier.parameters(), lr1e-3) # 第二阶段优化器优化所有参数但使用更小的学习率 optimizer_stage2 optim.Adam(model.parameters(), lr1e-4) # 学习率调度器在验证集性能停滞时降低学习率 scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer_stage2, modemin, factor0.5, patience3)关键超参数经验批次大小 (Batch Size)受GPU内存限制我们设为16或32。较小的批次大小可能带来正则化效果但训练噪声更大。图像尺寸EfficientNet-B4的默认输入是380x380但我们初始尝试了224x224以加快训练速度后期再尝试提升分辨率。正则化除了数据增强我们在全连接层使用了较高的Dropout率0.5并使用了权重衰减Weight Decay, 1e-4来防止过拟合。早停 (Early Stopping)监控验证集损失如果连续5-10个epoch没有下降则停止训练并回滚到验证集性能最好的模型权重。4.3 评估指标的选择与解读对于医疗分类模型不能只看准确率Accuracy特别是当数据不平衡时。我们主要关注以下指标混淆矩阵直观展示每个类别的分类情况看模型主要混淆了哪两类。精确率Precision、召回率Recall和F1-Score针对每一个类别计算。对于“猴痘”这个目标类别我们更关注召回率即“尽可能找出所有真正的猴痘病例”宁可误报不可漏报。但同时要用精确率来平衡避免误报过多。宏平均Macro-average和加权平均Weighted-averageF1综合评估模型在所有类别上的表现。我们使用sklearn.metrics来全面计算这些指标。在测试集上的结果大致如下模拟数据类别精确率召回率F1-Score支持数猴痘0.860.820.84112水痘0.910.880.89150麻疹0.890.930.91135正常0.950.940.95203准确率0.90600宏平均0.900.890.90600加权平均0.910.900.90600从混淆矩阵发现模型最主要的错误是将少数猴痘病例预测为水痘反之亦然。这符合医学常识也指明了模型改进的方向——需要更多这两种病的对比学习数据。5. 部署尝试与性能优化思考项目后期我们尝试了简单的本地部署以验证模型的可用性。模型导出将训练好的PyTorch模型转换为TorchScript格式或使用ONNX Runtime进行转换以获得更好的跨平台推理性能。# 示例转换为TorchScript model.eval() example_input torch.rand(1, 3, 380, 380).to(device) traced_script_module torch.jit.trace(model, example_input) traced_script_module.save(monkeypox_classifier.pt)构建简易Web接口使用Flask或FastAPI快速搭建一个本地服务。from fastapi import FastAPI, File, UploadFile import torch from PIL import Image import io app FastAPI() model torch.jit.load(monkeypox_classifier.pt) model.eval() app.post(/predict/) async def predict(file: UploadFile File(...)): image_data await file.read() image Image.open(io.BytesIO(image_data)) # 进行与训练时相同的数据预处理 processed_image preprocess(image).unsqueeze(0) with torch.no_grad(): outputs model(processed_image) _, predicted torch.max(outputs, 1) class_names [Monkeypox, Chickenpox, Measles, Normal] return {prediction: class_names[predicted.item()]}性能优化考量模型轻量化考虑到未来可能在移动设备或边缘设备上使用我们探索了模型剪枝Pruning和量化Quantization。使用PyTorch的torch.quantization将FP32模型转换为INT8模型模型大小减少约75%推理速度提升2-3倍精度损失在可接受的1%以内。推理加速对于服务器端可以考虑使用TensorRT或OpenVINO等推理引擎进一步优化。实操心得部署时最大的坑是前后端数据预处理的一致性。训练时我们用了一套复杂的Compose包括Resize、ToTensor、Normalize在部署的API中必须完全复现包括归一化所用的均值和标准差。任何细微差别都会导致模型性能急剧下降。最佳实践是将预处理函数与模型一起打包或严格文档化。6. 遇到的典型问题、排查过程与解决方案实录在项目开发过程中我们遇到了几乎所有做小规模医疗AI项目都会遇到的典型问题。6.1 问题一模型过拟合严重验证集准确率远低于训练集现象训练集准确率很快达到95%以上但验证集准确率卡在70%左右且波动大。排查首先检查数据划分确认训练集和验证集是随机划分的且类别分布大致相同使用sklearn的StratifiedKFold思想进行分层划分。检查数据增强确认增强只应用于训练集验证集应使用确定性的预处理仅Resize和Normalize。观察损失曲线训练损失持续下降验证损失在几个epoch后开始上升这是过拟合的典型标志。解决方案增强数据多样性增加了更激进的数据增强如CutMix、RandomErasing。加强正则化提高了Dropout率从0.3到0.5增加了权重衰减系数。简化模型从EfficientNet-B4降级到B3甚至尝试了更轻量的MobileNetV3发现B3在验证集上表现更稳定。采用更保守的训练策略缩短第二阶段微调的解冻层数使用更小的学习率并更早地触发早停。标签平滑Label Smoothing在损失函数中引入标签平滑防止模型对训练标签过于自信提升了约1.5%的验证集准确率。6.2 问题二模型对“猴痘”和“水痘”的混淆率最高现象混淆矩阵显示这两类之间的相互误判占到了总错误的一半以上。排查这是医学图像本身的难点。我们和医学顾问一起重新审视了被错误分类的样本图像。发现一些猴痘早期或不典型的皮疹确实与水痘非常相似甚至资深医生也可能需要结合病史和其他检查。解决方案针对性数据收集重点寻找那些能清晰展示两者区别的病例图像例如展示猴痘皮疹离心分布手掌、脚底的图片以及水痘向心分布和“四世同堂”不同期皮疹共存特点的图片。集成学习训练了多个不同架构ResNet50, DenseNet121或不同数据增强策略下的模型让它们对“猴痘 vs. 水痘”这个二分类子任务进行投票集成模型的混淆率有所降低。后处理规则作为一种临时方案我们设计了一个简单的后处理逻辑如果模型预测为“猴痘”但置信度低于某个阈值如0.7且次高预测是“水痘”则输出“需进一步鉴别猴痘或水痘”并将置信度一并返回给用户。这明确了模型的不确定性比强行给出一个可能错误的单一结果更负责任。6.3 问题三推理速度在CPU上较慢现象本地Flask API在CPU上处理一张图片需要1-2秒无法满足实时性要求。排查使用torch.utils.bottleneck或PyTorch Profiler进行分析发现时间主要消耗在模型前向传播和图像预处理上。解决方案模型量化如前所述INT8量化是提升CPU推理速度最有效的手段之一。批处理在API设计上支持批量图片预测能更好地利用计算资源。使用更快的图像处理库将PIL替换为opencv-python进行基本的图像读取和缩放有轻微提升。考虑边缘部署如果场景允许可以将模型部署在带有NPU的边缘设备如某些型号的手机、开发板上专门为推理优化。7. 项目反思、伦理考量与未来方向回顾整个“第P4周”项目它更像一个技术验证原型Proof of Concept而非一个成熟的产品。但它完整地走完了从问题定义到简易部署的闭环价值巨大。核心收获与反思数据质量远大于模型复杂度在医疗领域一个用1000张高质量、标注精准的图像训练的简单模型其可信度可能远超用1万张噪声数据训练的复杂模型。数据清洗和标注的时间投入回报率最高。领域知识不可或缺没有医学顾问的指导我们连该区分哪些病、该关注图像的哪些特征都无从下手。AI工程师必须与领域专家深度协作。理解模型的局限性我们的模型只是在有限的图像数据上学习到了统计规律。它不能理解病因、病理也无法结合患者病史、实验室检查。它永远只是一个辅助工具最终的诊断决策权必须在医生手中。伦理与责任开发医疗AI模型必须怀有敬畏之心。我们需要考虑模型偏差如果数据主要来自某一人种对其他人群的识别率可能下降、可解释性为什么模型做出这个判断、数据隐私和安全等一系列问题。在项目早期我们就应制定相应的伦理审查清单。未来可探索的方向多模态学习结合皮肤镜图像、患者病史文本去标识化后等多源信息进行综合判断。异常检测与不确定性估计当输入图像不属于任何已知类别时模型应能给出“未知”或“低置信度”的提示而不是强行分类。持续学习设计机制让模型能在获得新的、经过严格审核的标注数据后安全地进行增量学习而不会遗忘旧知识。真正的临床验证与医疗机构合作进行前瞻性的临床试验在真实世界环境中评估其敏感性、特异性、对临床工作流程的影响以及最终对患者结局的改善。这个项目让我深刻体会到将AI技术应用于像医疗这样的严肃领域技术实现只是冰山一角。对问题的深刻理解、对数据的敬畏、对伦理的考量以及对模型局限性的清醒认识共同构成了冰山下那更庞大、更关键的部分。希望这次分享不仅能提供一些技术上的参考更能引发大家对AI应用边界和责任的思考。
返回列表