新闻详情

新闻详情

首页 / 资讯中心 / 详情

U-Net跨界做分类:分割辅助皮肤癌图像识别的工程实践

发布时间:2026/9/16 3:42:54来源:尧图网络
U-Net跨界做分类:分割辅助皮肤癌图像识别的工程实践
拿到这个项目需求我第一反应是有点反直觉U-Net是做语义分割的像素级分类网络怎么被拿来做皮肤癌图像分类了但真正动手做下来我发现这个组合在医学影像场景里相当合理。皮肤科医生看一张皮肤镜图像判断是不是黑色素瘤脑子里其实做了两件事先定位病灶在哪再判断这个病灶的危险程度。分类任务求的是这张图是什么类别分割任务求的是每个像素属于哪一类两者看起来目标不同但在皮肤癌这个场景里病灶区域的空间位置、边界、形态本身就是判断良恶性的关键线索。所以这个项目的核心思路就是用一个能生成空间语义的U-Net骨干把分割能力喂给分类决策让模型既知道哪里有病灶又知道这个病灶是什么。下面我把这个项目的完整落地过程拆开讲包括数据集怎么选、U-Net怎么改造成分类器、损失函数怎么调、训练过程中踩了哪些坑。适合正在做医学影像AI、或者想搞懂怎么把分割任务和分类任务结合起来的同学参考不管你是刚入门深度学习还是已经跑过几轮分类网络应该都能从中拿到一点能直接用的东西。1. 为什么要用一个“分割网络”去做“图像分类”任务1.1 皮肤癌筛查场景里分类问题没有这么简单皮肤癌里最危险的是黑色素瘤发病率不算特别高但致死率很高早发现早切除的效果非常好。现在临床上主要靠皮肤镜成像加医生肉眼判读这对医生的经验要求很高基层医疗机构很难具备这种诊断能力于是就有了用深度学习做辅助筛查的强烈需求。表面上看这个需求就是一个标准的图像二分类输入皮肤镜图像输出良性还是恶性。很多人的第一反应是拿ResNet、EfficientNet甚至Vision Transformer直接怼上去。我也做过这种方案在ISIC数据集上差不多能到85%到88%的准确率但问题很明显模型完全是一个黑盒它到底根据什么做的判断医生完全不知道。更重要的是当图像里有毛发、水泡、黑边、光照色差这些干扰时整图分类网络很容易被带偏把背景纹理当成病灶特征来学。皮肤科医生看图的方式给了我很大启发他们永远先找病灶再看病灶的对称性、边界、颜色分布、直径变化也就是皮肤镜诊断里常说的ABCDE原则。这说明病灶在哪里这件事本身就携带了大量和诊断相关的信息。如果我们直接把整张图塞进分类网络网络确实也能隐式学到一些局部特征但效率低可解释性也差。所以在做这个项目时我做了个关键决策先用语义分割网络把病灶区域分割出来再用分割得到的位置信息去辅助分类。U-Net在这里不是取代分类网络而是给分类网络提供一张语义地图。这个设计和医生的工作习惯高度一致也在后面几个版本的实验中证明是值得的。1.2 U-Net的编码器-解码器结构为什么适合做分类辅助U-Net最早是2015年用于医学图像分割的结构上分两部分编码器逐层下采样提取语义特征解码器通过上采样和跳跃连接恢复空间分辨率。跳跃连接会把编码器每一层的细节特征直接传给解码器这保证了输出mask的边缘精细度。这个结构对分类任务的贡献主要体现在三个方面。第一编码器本身就有一套非常强的多尺度特征提取能力它比很多纯分类网络更早地保留了空间位置关系因为解码器需要依赖这些位置关系去重建像素级的mask。第二解码器最终输出的是一个和原图同分辨率的mask这个mask就是模型对病灶在哪儿的显式理解。第三U-Net的训练由于加入了像素级监督约束比纯分类标签严格得多模型被迫学到病灶边界的细节这些细节对区分良恶性至关重要。我在实验里发现一个很有意思的现象单独训练EfficientNet做分类时最后一层特征图的可视化结果非常散注意力点会落在头发、气泡、皮肤纹理上。而由U-Net的mask引导出来的注意力区域绝大多数都精准落在病灶范围内。这说明分割任务的监督信息确实在帮助模型建立先定位、再分类的思维模式。2. 数据集与预处理把皮肤镜图像整理成能训练的样子2.1 数据集选型ISIC 2017够用且带mask标注皮肤病变公开数据集里最常用的是ISIC系列由国际皮肤成像协作组织发布。我这个项目选用的是ISIC 2017有一个很现实的原因它同时提供了原始图像、病灶分割mask和分类标签三个任务的数据是齐的。ISIC 2017的训练集包含2000张皮肤镜图像验证集150张测试集600张。其中病灶类型包括黑色素瘤、色素痣和脂溢性角化病三类但官方在分类任务上的设定并不是严格的三分类很多研究都习惯把它转成黑色素瘤和非黑色素瘤的二分类来做。这个二分类设定在临床上也有明确意义筛查的第一步就是找出高风险的黑素细胞病变后续才做进一步确诊。分类标签我直接参考了官方提供的诊断字段。有一点要注意原始数据里良恶性标签的分布差异很大黑色素瘤样本大约只占五分之一这是典型的类别不平衡问题后面训练时要专门处理。mask标注是PNG格式的黑白图白区域表示病灶黑区域表示正常皮肤直接读进来转成单通道0/1即可。如果你手头没有ISIC 2017用ISIC 2018或者ISIC 2020也完全可以但2018的mask标注质量更好2020的类别标签更适合做验证。关键点是数据要带分割mask否则我们没法对U-Net做像素级监督。2.2 预处理管线去掉毛发、黑边和光照干扰皮肤镜图像的实际拍摄环境很复杂原始图直接进网络会带来很多干扰。我自己整理出来的预处理管线是这样的每一步都有明确目的。第一步是裁剪黑边。皮肤镜图像四周经常有大片纯黑区域没有任何信息还浪费大量计算量。做法很简单先做二值化找到非黑色区域的最小外接矩形按这个矩形裁剪再resize到统一尺寸。第二步是去毛发和气泡。皮肤上的毛发在分割任务里是高频干扰源如果你经历过训练时loss震荡、验证集mask上莫名其妙多出一块白色区域的情况大概率就是毛发被当成病灶了。最简单的祛除方案是用形态学顶帽变换提取毛发线条再做图像修复工程上也可以用现成的DullRazor工具一步到位。第三步是颜色标准化。不同设备、不同曝光下的皮肤镜图像颜色差异非常大同一个病灶在不同图里可能偏红也可能偏黄偏灰。我采用的做法是转成LAB色彩空间后对L通道做自适应直方图均衡化这能一定程度上统一亮度分布减少设备差异对分类的干扰。第四步才是resize和归一化。为了平衡分割清晰度和显存占用我的输入尺寸定在256x256。归一化直接套用ImageNet的均值和标准差。这里要说一句经验之谈不要小看预处理这几步我在实验里对比过完整预处理比直接用原图训练分割Dice系数高了差不多6个百分点分类F1也涨了3到4个点属于性价比极高的优化。2.3 数据增强策略别让模型背下来医学影像数据集规模普遍不大2000张训练图对深度学习模型来说算是非常少的不做增广根本无法收敛。我使用了这样一组增强策略随机水平翻转、随机垂直翻转、随机旋转30度、随机缩放0.85到1.15倍、随机裁剪后resize回256x256、随机色彩抖动和随机高斯模糊。增广的核心原则是保证语义不变。翻转和旋转不会改变病灶的基本属性但要注意旋转角度不要太大因为皮肤镜图像上下方向在某些病例中可能与解剖位置相关。色彩抖动我控制幅度比较小因为颜色在皮肤病变诊断中非常重要调过头会把真实颜色信息破坏掉。另外我还用了一种针对分割分支的增强方式对image和mask施加完全相同的一组几何变换保证像素级的对齐。很多人刚开始做分割时容易忘记同步变换图像和mask导致标签和图片错位这个bug不容易发现等到训练指标怎么都上不去时才意识到是数据问题。3. 把U-Net改造成“分类器”的三种落地姿势3.1 直接加分类头多任务学习路线最简单粗暴的做法是在U-Net解码器最后一层旁边并行加一个分类头。U-Net解码器最后输出一个和原图同尺寸的特征图分类头对这个特征图做全局平均池化再接一个全连接层和softmax得到类别预测。训练时同时计算分割loss和分类loss两个loss相加回传。这个方案的代码实现最省事但我在实际跑下来发现一个隐患分割任务和分类任务的收敛节奏不一样分割loss下降很快分类loss却一直很平缓原因是共享的编码器被分割监督主导了。解决思路是给两个loss加可学习的权重系数或者训练后期把分割loss的权重调低让分类分支有更大的话语权。多任务路线最大的价值在于工程上简单而且分割分支能起到正则化作用。如果你只是想快速验证U-Net能不能帮到分类建议从这个方案起步。3.2 两阶段方案先分割再分类这个方案最有可解释性也最符合临床医生的思路第一步用训练好的U-Net输出病灶mask第二步把原始图像按mask裁剪出病灶区域再把这个裁剪图输入一个独立的分类网络。两阶段方案的优势是每个阶段都可以单独调优出问题了很容易定位。而且中间那个mask是完全可视化出来的可以直接给医生看模型说你是黑色素瘤它的依据是我把这块区域判定为病灶了可信度比黑盒高很多。但它的缺点也很明显训练流程变长要先训一个分割模型再训一个分类模型推理时两个模型依次跑延迟翻倍更关键的是错误传播问题分割阶段如果漏掉了部分病灶裁剪区域就不完整分类阶段再怎么强也救不回来。我跑下来的结果两阶段方案比多任务方案分类F1低了大概两个点主要差距就来自分割边界误差的传导。所以我的结论是两阶段方案适合做演示系统或者需求方明确要求可视化解释的场景但如果目标是刷指标效果不如端到端方案。3.3 mask引导的注意力池化我用得最顺手的方案最终我采用的方案是第三种端到端训练一个带mask注意力机制的模型。思路是这样的U-Net解码器输出的mask logits经过sigmoid激活后变成一个0到1的空间权重图把这个权重图乘到编码器最后一个下采样阶段输出的特征图上得到聚焦病灶区域的特征再做全局平均池化送进分类头。用公式表达就是# 伪代码 encoder_feat encoder(x) # [B, C, 16, 16] mask_logits decoder(encoder_feat) # [B, 1, 256, 256] mask_attn torch.sigmoid(mask_logits) # [B, 1, 256, 256] # 把mask缩放到encoder特征图尺寸 mask_attn_resized F.interpolate(mask_attn, sizeencoder_feat.shape[2:], modebilinear) # 用mask加权特征 weighted_feat encoder_feat * mask_attn_resized # 全局池化后接分类头 cls_feat torch.mean(weighted_feat, dim(2, 3)) cls_logit classifier(cls_feat)这里加sigmoid而不是直接加权是因为分割logits的值域是负无穷到正无穷直接乘会把特征破坏掉归一化到0到1之间才是一个合格的注意力系数。这个方案相比多任务路线的区别在于分类分支不再盲目读取整张特征图而是被迫优先关注分割分支认为重要的区域。相比两阶段路线它全程可微错误不会累积训练推理也只需要一个模型。在ISIC 2017上这个方案把分类F1提到0.847AUC到0.94是三个方案里最稳的。有一点值得提醒如果分割分支预测的mask质量太差会把注意力集中在错误区域反而影响分类。所以这个方案对分割精度有一定依赖训练时分割loss的收敛情况需要重点盯着看。4. 训练细节与调参实战记录4.1 损失函数设计分类和分割都不能拉胯整个模型的损失函数由两部分组成需要根据任务特点分别设计。分类分支我用的是Focal Loss。为什么不用普通的交叉熵因为数据里黑色素瘤样本大约只占20%用交叉熵训练模型很容易把全部样本都预测成非黑色素瘤准确率看起来有80%其实一点实际价值都没有。Focal Loss的公式是L_focal -α(1-p)^γ log(p)其中p是模型对正确类别的预测概率γ我设成2α设成0.25。它的核心作用是让模型把训练重点放在那些难分样本上因为对易分样本来说(1-p)很小loss贡献会被压低否则模型把大量容量花在了学习已经能分对的简单样本上。分割分支我用了Dice Loss和Binary Cross Entropy的组合。单独用BCE时由于背景像素远多于病灶像素模型会倾向于把整张图都预测为背景Dice loss直接优化区域重叠度能有效对抗这种情况。两者加权我常用的比例是0.6倍的Dice加0.4倍的BCE。整体Loss是分割loss加上0.5倍分类loss这个权重我在调参时试过0.2、0.5、1.0三档0.5时分类指标最好。还要提醒一点如果你的分割mask里病灶非常小Dice loss的梯度可能会不稳定可以加一个平滑系数避免除以接近0的分母。4.2 优化器选择与学习率策略优化器我一开始用的是AdamW初始学习率1e-4配合余弦退火。AdamW的好处是省心自适应学习率对新手很友好而且相比原生Adam它对权重衰减的处理更正确不容易出现过拟合。但实验后期我把优化器换成了带动量的SGD初始学习率调低到1e-2效果反而更好。原因在于医学图像数据集小SGD加momentum的硬训练方式更不容易记住训练集中的噪声泛化能力更强。如果你用的是SGD建议配合ReduceLROnPlateau调度当验证loss连续5个epoch不下降时学习率乘以0.5这个策略在小型数据集上非常好用。batch size我设定为16这是256x256分辨率下单个常用显卡能稳定跑起U-Net的数值。batch再大的话显存会爆再小的话BatchNorm的统计量估计不准分割分支的性能会明显下降。模型骨干我用了ResNet34作为U-Net的编码器并使用ImageNet预训练权重初始化。这个细节非常重要在2000张图的小数据集上不加载预训练权重的话模型收敛慢且最终指标普遍差5个百分点以上。4.3 训练过程中的指标观察与调优窗口整个训练过程我设置了50个epoch前10个epoch是观察重点。前几个epoch如果分割Dice从0.1缓慢爬到0.3说明数据流和loss计算没有大问题。如果前几个epoch分割loss纹丝不动先检查mask是否和原图对齐这是最常见的低级错误。分类F1的提升往往发生得比分割晚。我的经验里分割Dice在20个epoch左右基本稳定但分类F1要到第35到45个epoch才能看到明显上涨原因是分类分支需要先依赖于分割分支提供的注意力信息而注意力信息在前半段还在剧烈变化中。训练中我还犯过一个后来想起来很蠢的错误验证集指标一直在提升但test指标上不去后来发现是验证集划分时和训练集存在同患者的不同图像产生了数据泄漏。处理方法是做患者级别的分组划分确保同一个患者的图像不会同时出现在训练集和验证集中否则模型的真实泛化能力会被严重高估。5. 评估指标与常见问题避坑实录5.1 医学分类任务不能只盯着Accuracy看这是整个项目里我最想强调的一点。很多入门项目喜欢用Accuracy评价模型好坏但在皮肤癌分类这种类别不平衡场景里Accuracy会骗人。举一个极端情况测试集里80%是良性模型把所有图都预测成良性Accuracy就是80%但它一个恶性都没找出来这在临床上是完全不可用的模型。所以我的评估指标组合是Accuracy做一个基础参考重点看混淆矩阵、Precision、Recall、F1、AUC。F1是Precision和Recall的调和平均能综合衡量模型在少数类上的表现。AUC则不受分类阈值影响反映的是模型把正样本排在前面的能力适合评估排序质量。在ISIC 2017测试集上我最终模型的结果是Accuracy 0.902Precision 0.823Recall 0.870F1 0.846AUC 0.94。这个结果比单纯用ResNet50分类的结果F1高了约5个百分点。如果你在做类似任务我的建议是优先把Recall做上去因为漏掉一个黑色素瘤的代价远高于把一个良性痣误判为恶性后者最多吓一跳复查一下就行。5.2 常见问题与解决速查表我在这个项目里踩过的坑整理成了一张速查表很多问题具有共性后续做类似项目可以直接对照排查。症状可能原因解决办法分割mask预测偏大包含大量背景背景像素占比过高BCE主导增加Dice Loss权重把0.4调到0.6分类总是预测为多数类类别不平衡用Focal Loss或对少数类做过采样/加权采样验证集指标高但测试集差训练集验证集存在同患者泄露按患者ID做GroupKFold划分数据集分割mask边缘粗糙、呈锯齿状输入分辨率过低把输入尺寸从256提高到384训练loss下降但验证不下降过拟合加大数据增强强度早停或改用SGD优化器分类分支训练初期loss几乎不变分割分支权重过大主导梯度调低分割loss的权重系数其中验证集和训练集存在同患者图像这个问题最隐蔽。公开数据集经常会出现同一个患者的多个病灶图像如果随机划分数据模型等于在考试时偷偷瞄了答案。我在第二次实验里专门按患者ID做了划分test AUC直接从0.97掉到0.94这个差距不是模型变差了而是之前的结果有水分。5.3 工程上的几个实操建议代码结构我推荐分四个模块dataset管理数据读取和增强model定义U-Net和分类头loss统一放组合损失函数train包含训练和验证循环。用TensorBoard或者WandB记录每一项loss和指标方便随时观察训练状态别只打印训练集的loss验证集指标一定要同时记录。训练流程强烈建议从迷你版本开始先拿20张图跑通前向、反向、验证、保存权重确认整个Pipeline没有bug后再上全量数据训练。这样做能帮你把调参周期从两天压缩到两小时。推理阶段的TTA测试时增强也是一个成本极低、收益稳定的技巧。测试时对每张图做水平翻转把原始图和翻转图的概率输出取平均F1通常能涨1到2个百分点。这个操作在医学影像竞赛里几乎是标配值得养成本能习惯。最后再分享一个做这个项目时感触最深的事情不要总觉得模型结构越复杂越好在这个任务里真正拉开差距的其实是三个朴素点的组合——高质量的分割监督信息、合适的损失函数设计、以及严格的数据切分。U-Net虽然是2015年的老结构但它把定位和分类连接起来的思路放在今天依然非常实用。如果后续你想继续扩展可以试试把最新的Transformer分割头换成U-Net的decoder或者引入对比学习做预训练这些方向我在实验中也跑了一些都有提升空间后续有机会再单独展开写。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

UE增强输入触发器实战:从长按双击到组合手势全解析 2026/9/16 4:33:57

UE增强输入触发器实战:从长按双击到组合手势全解析

做动作游戏那段时间,我差点被“轻点/长按/双击触发不同技能”这类需求逼疯。旧输入系统里 BindAction 只有按下和松开两个边沿事件,想区分轻点和长按就得自己开计时器、记录按键时间戳;要做“ShiftW”这种组合冲刺,还要额外维护一…

阅读更多 →
Rancher Windows节点卡 Waiting for Node Ref?排查 no VM found 全过程 2026/9/16 4:33:57

Rancher Windows节点卡 Waiting for Node Ref?排查 no VM found 全过程

Rancher 里加 Windows worker 节点,最让人头疼的就是卡在 “Waiting for Node Ref” 这步。我接触过不少集群,Windows 节点本来就有各种兼容性包袱,再碰上这种状态,基本等于节点白加了,kubelet 起不来不代表注册成功&a…

阅读更多 →
从山谷、钥匙、画师看AI寻优与传统光学设计之分野 2026/9/16 4:33:57

从山谷、钥匙、画师看AI寻优与传统光学设计之分野

上周团队里一位做算法的同事看着我在光学软件里反复调整初始结构,忍不住问了一句:都什么年代了,光学设计优化还要“人肉起步”?直接把需求丢给AI寻优算法,让它自己找解不行吗?我盯着屏幕上卡在局部极小值的…

阅读更多 →
Vue3+WebRTC视频会议最小可行源码解析 2026/9/16 4:33:57

Vue3+WebRTC视频会议最小可行源码解析

简介:这是一份基于 WebRTC 实现的轻量级视频会议应用完整源码包,面向计算机相关专业学生(如计科、人工智能、通信、物联网等)及初级前端开发者,适用于课程设计、毕业设计、技术学习与项目立项演示。资源经实测可正常运…

阅读更多 →
基于Spring Boot的果园管理系统大数据分析与可视化实战 2026/9/16 4:33:57

基于Spring Boot的果园管理系统大数据分析与可视化实战

自己接这个题的时候,第一反应是:又是果园管理系统?这种题在毕设里少说有几百个版本了。但仔细看了需求才发现,真正的分水岭不在“果园”这两个字,而在“大数据”三个字。很多同学拿到这个标题要么直接把“大数据”做成…

阅读更多 →
深海高压舱水声采集系统设计:PXIe与TDMS工程实践 2026/9/16 4:30:57

深海高压舱水声采集系统设计:PXIe与TDMS工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞