每年到毕设选题季,总有人问我“想做个深度学习相关的项目,数据最好是现成的,又不要太卷,有什么推荐”。这一题我几乎都会回同一个方向:基于ISIC数据集的皮肤病黑色素瘤分类。原因很简单——数据集公开、任务边界清晰、训练成本可控,而且医学影像加深度学习的组合天然适合写论文、画可视化、做答辩展示。它不像人脸识别那样被做烂了,也不像语义分割那样要折腾一堆标注工具,属于那种“认真做能出彩,偷懒抄也死不了”的稳妥型选题。下面我把从选题、数据准备、模型训练到答辩避坑的完整思路都捋一遍,打算拿这个当毕设的同学可以直接照着走。
1. 为什么我推荐把ISIC黑色素瘤分类做成毕设
1.1 医学影像与深度学习的天然契合点
皮肤镜图像从数据结构上看是张普通RGB图片,不需要像CT那样做三维体素重建,直接用现成的卷积神经网络就能处理,这是它比很多医学影像任务门槛低的关键。但它的临床含义又足够深刻:黑色素瘤是恶性程度很高的皮肤肿瘤,早期五年生存率能到95%以上,晚期却骤降到不到20%,所以“AI辅助识别黑色素瘤”天然自带社会价值。拿这个做毕设,无论论文引言还是最终答辩,你都有充足的动机可以讲,不愁没话说。再加上ISIC数据集本身是公开的皮肤镜病灶图像集合,图像已经做过匿名脱敏,不需要自己跑医院收集数据,完全绕开了医疗隐私和伦理审批的大坑,对在校生尤其友好。
1.2 数据集公开、工作量可控,适合毕设节奏
毕设最怕两个问题:一是数据收集到崩溃,二是模型怎么调都不收敛。ISIC避开了第一点,下载解压就能用,标注基本清晰;第二点也不用太担心,因为这是标准的图像分类任务,各大预训练模型都能直接迁移。以我平时建议的时间分配为例:前两到三周做数据清洗、划分和预处理,中间五到六周做模型搭建、训练和调参,再花三周做错误分析、可视化图表和论文插图,最后留四周写论文和做PPT。整个节奏很线性,中途就算卡住,最多是AUC差一两个点,不会出现连数据都拿不到这种死局。对于第一次完整做人工智能项目的同学来说,这种“可回退”的感觉非常重要。
1.3 可延展的创新方向,不止“套个ResNet跑一遍”
很多同学担心这个题目被人做烂了,其实恰恰相反,公开数据意味着你能跟大量基线对比,但公开数据也意味着人人都能看到同样的问题。比如类别不平衡——ISIC里良性痣的数量明显多于黑色素瘤,怎么设计损失函数让少数类召回率提上去;再比如模型可解释性——用Grad-CAM画出模型关注区域,分析它到底是在看病灶边缘还是背景纹理;还有改进点可以是数据增强策略、模型集成、伪标签半监督等等。这些方向都不需要去额外找数据,只需要换一种训练策略或分析视角,就能形成论文里的“增量创新”,对本科毕设来说是够用的。
2. ISIC数据集到底能不能直接用:数据构成与任务边界
2.1 先认清ISIC官方数据的常见版本
ISIC是一个系列数据集,常被用的是2016、2017、2018这几届挑战赛数据,其中2017版训练集大概有2000张皮肤镜图像,类别包括黑色素瘤、良性痣和脂溢性角化病三类。很多毕设会进一步把它简化成二分类:只保留黑色素瘤和良性痣两类,把脂溢性角化病舍弃。这样处理的好处是任务更纯粹,临床中最关键的鉴别就是“这个黑痣是良性还是恶性”,二分类的指标解释也直观。如果你想增加一点难度,也可以保留三分类,跟官方挑战赛的任务设定保持一致,但那样就要处理多分类不平衡和类别相似度的复杂问题,工作量会明显增加。
2.2 二分类和三分类该怎么选
我个人的倾向是优先做二分类,尤其对本科毕设而言。理论上,二分类的混淆矩阵、ROC曲线、AUC这些指标都非常好讲,答辩时随便问都能接得住;而三分类一旦被追问“为什么第三类样本这么少”“你想没想过多标签关系”,就容易卡壳。从实验角度说,二分类只用两类数据也减少了训练时间,方便快速跑通全流程。等到二分类模型稳定后,若还有余力,可以再做一个额外实验,把三分类情况作为对比或扩展分析放进去,这样论文里就有了“主实验 + 扩展实验”的结构,层次更丰富。
2.3 数据划分是最容易翻车的环节
很多新手一上来就把所有图像随机打乱,按比例划出训练集和验证集,表面看没问题,实际上可能严重“数据泄露”。ISIC数据集的元数据里包含患者编号信息,同一个患者的病灶有可能拍了多张不同角度或不同时期的图像。如果这些图像被随机分进训练集和验证集,模型在验证时就会“记住”同一个人的背景和纹理特征,导致验证指标虚高到离谱。正确做法是必须按患者ID划分:先根据元数据把同一个患者的所有图片归入同一子集,再去切训练验证测试。我之前帮同学排查过一个AUC高达0.97但换成患者级划分后只剩0.91的案例,这个0.06的差距不是模型退步,而是之前的结果里混了太多“作弊成分”,后面那个数字才是真实水平。
3. 落手之前先定好“度量标准”:准确率骗人,AUC才靠谱
3.1 为什么准确率在皮肤癌数据上会失真
黑色素瘤分类天生是类别不平衡问题。比如数据集中黑色素瘤可能只占10%,如果模型把所有图像都判为良性,准确率也会是90%,看起来不错,但完全没有临床价值。如果只盯着准确率调参,你很容易选中一个“全猜良性”的坏模型。所以在医学图像领域,通用的评估指标是AUC、F1、敏感性和特异性。简单解释一下:敏感性,也叫召回率,是指所有真正的黑色素瘤样本中有多少被模型识别了出来;特异性是指所有良性样本中有多少被正确判断为良性。临床上“漏诊”比“误诊”更危险,所以我们通常优先看敏感性,再同时关注特异性,防止模型为了抓阳性而把所有图片都标成恶性。
3.2 建议记录的多维指标组合
我建议每个实验结束后至少记录四样东西:AUC、F1、敏感性、特异性。AUC反映模型整体排序能力,不依赖具体阈值;F1是精确率和召回率的调和平均,适合不平衡评估;敏感性和特异性则对应不同临床场景。画ROC曲线时把AUC标在图上,论文里非常直观。对于少数类特别少的场景,还可以补充Precision-Recall曲线,因为正例极少时PR曲线比ROC曲线更能暴露模型性能差异。报告时不要只写“准确率96%”这种话,最好写成“模型在ISIC验证集上取得AUC 0.93,敏感性0.86,特异性0.89,在阈值为0.4时F1为0.68”,老师一看就知道你有评估常识。
3.3 训练过程中不要只看loss
有个高频困惑是:训练loss明明降得很低,验证集AUC却上不去。这是因为交叉熵loss的最小化方向不完全等价于分类阈值的优化,尤其在小数据集上,loss在后期容易过拟合到训练集的噪声上。正确做法是每个epoch同时打印训练loss、验证loss、验证AUC三项指标,并且优先把验证AUC作为早停依据。如果连续10个epoch验证AUC没有创新高,就保存当前最优权重并降低学习率继续训练,或者直接停止。调参时也别强迫训练loss降到接近0,那样大概率是过拟合,真正要看的是验证集指标怎么走。
4. 模型选型与迁移学习:主干网络对比与踩坑记录
4.1 从ResNet起步还是直接上EfficientNet
皮肤镜图像分类的主流做法是使用在ImageNet上预训练过的CNN。VGG16太老且参数量大,ResNet50是稳妥起点,EfficientNet系列则性价比更高。第一次跑通流程我建议用ResNet50,因为结构经典、代码实现随处能找到、调试资料多,训练速度也适中。等全套流程稳定后再换成EfficientNet-B3或B4,通常能在相近训练成本下把AUC提升一到两个点。要注意EfficientNet的输入尺寸和缩放方式,B4默认输入可能是224或240,显存占用也会变大。如果显存不够,优先降低batch size,不要直接把图像分辨率改成128,否则预训练权重的感受野会被打乱,迁移效果反而变差。
4.2 迁移学习的具体打开方式
不建议从零随机初始化训练。常规做法是加载预训练权重,先冻结大部分网络层,只训练最后面的全连接分类层,这样能快速得到一个勉强可用的基线。但这个基线并不是终点,因为皮肤镜图像和ImageNet自然图像的特征分布差异比较大,只训练分类头学不到病灶特有的颜色纹理组合。更稳妥的分阶段策略是:第一阶段冻结主干5个epoch,只训练分类头,把学习率设为1e-3级别;第二阶段解冻主干最后一小部分,大约四分之一规模,用1e-5级别的学习率微调整个网络。如果数据只有一两千张,不建议解冻过多层,否则很容易过拟合,验证集AUC先升后降。
4.3 输入尺寸、全局池化与分类层设计
不同预训练模型对输入尺寸要求不同,但多数情况224×224够用。这里有个操作细节:很多人直接把原始图像resize成227×227或224×224,结果病灶被拉变形,比例失真。更推荐的预处理是先将图像短边缩放到目标尺寸,再做中心裁剪或随机裁剪,保留病灶的相对形状。分类头方面,建议把预训练模型的最后一层换成“全局平均池化(GAP)+ Dropout + 全连接层”的组合。GAP能大幅减少参数数量,也能保留空间特征;Dropout率可以设0.5,数据量小的时候提到0.7。输出层做二分类就输出两个节点,接softmax即可。
5. 让训练曲线真正收敛的调参细节:损失权重、学习率与数据增强
5.1 类别不均衡的损失函数写法
处理类别不平衡最直接的方式是给交叉熵损失加类别权重。例如统计得到黑色素瘤样本500张,良性样本1500张,那权重可以设为其他类样本数除以该类的样本数:
class_counts = torch.tensor([1500.0, 500.0]) # [良性, 黑色素瘤] weights = class_counts.sum() / (2 * class_counts) weights = weights.to(device) criterion = nn.CrossEntropyLoss(weight=weights)这样少数类的损失贡献会被放大,模型就不会一味把样本往多数类推。除了加权交叉熵,也可以尝试Focal Loss,它对容易分类的样本施加较低权重,让模型更关注难分的黑色素瘤。不过Focal Loss有gamma和alpha两个超参数要调,初期不必急于引入。对于ISIC这种10%~20%阳性比例的数据集,加权交叉熵通常已经足够,Focal Loss的收益有限。如果最终还需要提升敏感性,可以把分类阈值从0.5降低到0.3,这样更多“存疑”图像会被判为黑色素瘤,代价是特异性下降,这是可以接受的取舍。
5.2 学习率调度与优化器选择
优化器首选AdamW,初始学习率建议为5e-5到1e-4。如果整个网络都从头训练,可以用1e-3;但迁移学习场景下,主干网络用的是预训练权重,学习率太大会把已经学好的特征破坏掉。我推荐分不同模块设置不同学习率:分类头用1e-4,主干解冻部分用1e-5,这样既让新学习器快速拟合,也避免破坏旧知识。调度器上,余弦退火简单好用,也可以配合ReduceLROnPlateau在验证指标停滞后把学习率降到原来的十分之一。在小数据集上,batch size也很关键。ISIC这种量级,16或32都可以,如果显存允许尽量选32,梯度更稳定。
5.3 数据增强要像“皮肤科医生”而不是“图像滤镜”
很多同学直接套用CIFAR/ImageNet的增强习惯:随机旋转90度、上下翻转、随机裁剪、颜色抖动全都上。这对于皮肤镜图像是危险的。皮肤镜图像里的病灶有特定的方向性特征?其实旋转方向本身不该成为分类依据,但旋转过大确实会让病灶形态失真;更关键的是,图像里常有的毛发、反光、血管、标尺、油滴等伪影容易成为模型“捷径特征”。正确思路是模拟临床中可能遇到的变化:小角度旋转(±10度)、水平翻转、轻微缩放裁剪、亮度对比度小幅度扰动。Random Erasing这种随机遮挡对皮肤镜图像尤其有效,它强迫模型关注全局病灶结构而不是某一个小亮斑。我见过不少项目去掉Random Erasing后AUC下降2-3个点的例子,强烈建议把它加进训练流。
6. 模型检视:混淆矩阵和Grad-CAM能告诉你的三件事
6.1 混淆矩阵:漏诊是第一禁忌
训练好后不要只汇报AUC,还要画出验证集或测试集的混淆矩阵。以二分类为例,四个格子分别是真良性、假恶性、真恶性、假良性。临床上最怕的是假良性,也就是真黑色素瘤被模型漏掉了,这在混淆矩阵里是左下角或右下角,必须重点盯。如果混淆矩阵出现敏感性偏低,说明模型过于保守,需要降低判断阈值或加强少数类训练。如果特异性偏低,说明模型把大量良性误判为恶性,虽然后果不如漏诊严重,但也会造成不必要的活检负担。建议输出百分比格式,并标注每个类别的样本数,答辩时直接放大展示。
6.2 Grad-CAM可视化:模型关注的是病灶本身还是背景伪影
Grad-CAM是检验模型“到底在看什么”的利器。它把最后一层特征图的梯度加权求和,叠回到原图上形成热力图,回答“模型的决策依据是哪块区域”。实际操作时,选择几个典型的真阳性和假阳性样本,分别生成热力图。一个经常出现的问题:模型预测黑色素瘤时,热力图高亮区域却落在图片角落的标尺、背景皮肤纹理甚至污渍上,说明模型学到了数据集的伪影,而不是临床特征。遇到这种情况,回到数据预处理环节,把标尺区域裁剪掉,或对这类伪影做随机擦除,再重新训练。Grad-CAM不只是论文里的插图,更是诊断模型偏见的手段,这个认知能让你的答辩分析部分很有深度。
6.3 和公开基线横向对比的技巧
ISIC官方挑战赛每年都有排行榜,很多论文公开了在ISIC测试集上的AUC和敏感性结果。对比时需要注意两个陷阱:一是保证数据集划分一致,二是保证评估指标口径一致。如果你用自己划分的验证集跟官方测试集对比,数字没有可比性。更稳妥的做法是:下载官方训练集和验证集,先跑一个最朴素的ResNet作为自建baseline,记录其AUC、F1、敏感性、特异性;然后在此基础上加迁移学习、数据增强、损失函数改进,形成“baseline vs 改进方案”的纵向对比;最后引用公开SOTA结果作为外部参照。这样论文的曲线既有“自己的上升弧线”,又有“和顶会的差距参考”,逻辑非常完整。
7. 从“跑通”到“答辩”:毕设最容易扣分的坑和补救清单
7.1 实验记录习惯决定答辩底气
我见过不少同学跑完模型只留下一张训练曲线截图,老师问“优化器是什么”“学习率多少”“训练了几个epoch”时支支吾吾。最好的办法是从第一天就建一个实验记录表,至少包括:数据集划分方式、预训练权重来源、输入分辨率、batch size、优化器、初始学习率、学习率调度、数据增强配置、最终AUC、F1、敏感性、特异性。每次实验追加一行,最后整理成论文附录。这个表不仅是你的工作量证明,还能帮你快速复盘哪些修改真正起了作用。答辩时拿出这个表,告诉老师“我总共做了27组实验,最终的方案是在第18组基础上……”,说服力非常强。
7.2 数据集划分泄露:最隐蔽的扣分点
按患者ID划分这个点我前面已经说过,但这里要再强调一次,因为它是所有新手最容易踩的坑。如果你不小心用了随机划分,验证集AUC可能虚高,答辩时一旦老师追问“你的训练集和验证集里面有没有同一个患者的图像”,你可能答不上来。所以在实验设置部分一定要写清楚:基于患者ID去重划分,保证同患者所有图像处于同一子集。哪怕重新划分后AUC降低了,这个“降低”反而是可信的,技术上绝对是加分项。也不要试图用随机划分跑出高AUC来糊弄答辩,这类数据泄露问题在提问环节几乎是必考题。
7.3 别忽略可复现性:固定种子、保存配置、写README
可复现性是深度学习项目的生命线。代码里要固定随机种子:Python、NumPy、PyTorch分别固定,数据加载的shuffle随机种子也固定。保存配置文件(config.py或yaml),每次实验都记录下当前配置,并在保存模型权重时同步保存一份配置快照。最好把每个epoch的权重都存一份,至少保留最优权重和最后一个epoch权重,方便中途断点恢复。最后写一个详细的README,注明数据集版本、预训练权重下载地址、运行顺序、依赖环境版本、GPU型号和显存大小。具备这些,答辩时如果老师现场要求“把你的代码跑一遍”,你不会手忙脚乱。
最后再说一点实在的:用ISIC做毕设,最大的收获往往不是AUC涨了几个点,而是你完整走了一遍“数据清洗—实验设计—模型训练—错误分析—结论主张”的闭环。表面上看这是个分类任务,实际上你练的是如何把抽象问题拆成可验证的实验,再用证据说服别人。这个题目给了一个非常合适的起点,剩下的高度取决于你愿意把每个环节琢磨得多细。祝你顺利把这个项目做扎实,答辩的时候底气十足。