简介:医学图像分类是计算机视觉与临床诊断结合的重要方向,其核心挑战在于高质量数据集的稀缺与标注成本的高昂。甲状腺结节作为体检中的高发异常,其良恶性判别高度依赖超声影像,而公开可用的分类数据集常因规模小、标注不全而难以支撑可靠的模型训练。一个约7,000张、已标注的甲状腺结节图像分类数据集,恰好为图像预处理、迁移学习与模型评估提供了理想的实验基础。从数据清洗、尺寸统一、标签体系设计,到ResNet与DenseNet的选型对比、交叉验证与AUC评估,再到类别不平衡与过拟合的针对性优化,整套流程不仅适用于甲状腺结节任务,也可推广至其他小样本医学影像场景。掌握这些方法,能够帮助研究者和工程师在有限数据下构建稳健、可复现且具备临床参考价值的分类模型,加速医学图像分析从实验走向落地。 甲状腺结节图像分类数据集这种资源,平时在公开渠道里其实不太好找。各家医院的数据出不来,能放出来的又多是小规模、未清洗的样本,真要用来做研究和模型验证,往往得花大量时间在数据整理上。所以当我看到这个“已标注、约7,000张”的甲状腺结节图像分类数据集时,第一反应是:这已经算是一个比较扎实的起步盘了。7000张对自然图像分类来说不算多,但在医学影像尤其是超声图像领域,考虑到标注成本极高——需要专科医生逐张勾选、核对,这个规模完全够做一轮像样的模型训练和算法验证。
这篇文章我想从一个实际做图像分类任务的角度,把这个数据集的构成逻辑、标注方案、预处理细节、模型选型、训练流程和常见坑位都拆开讲一遍。既适合刚入门医学图像分类的研究生,也适合已经跑过几个公开数据集、准备转入医疗影像赛道做工程落地的开发者。重点不只是“怎么训练一个模型”,而是“拿到这种数据集之后,如何把每一步做扎实”,让模型效果可解释、可复现、可落地。
1. 数据集整体设计与内容拆解
1.1 数据规模在医学影像领域的真实定位
先说规模。约7000张图像、已标注,这个数字放进自然图像分类领域确实不起眼,ImageNet动辄百万级,CIFAR-10也有60000张。但在医学影像分类任务里,情况完全不同。超声图像不像自然照片那样可以随便爬取,每一张都涉及患者隐私、设备采集、医生判读等环节。一个三甲医院的超声科,一天能产出几百张甲状腺结节图像,但真正能用于科研和模型训练、且完成规范标注的,可能只有其中一小部分。因为标注过程不是简单打个标签,而是需要超声科医生结合TI-RADS分级、病理结果、随访记录做综合判断。
7000张图像如果按常见分类任务来划分,假设做二分类(良性/恶性),再留出20%做测试集,训练集大概有5600张,这个量级恰好是很多预训练模型微调时的“甜点区”——数据太少容易过拟合,数据太多又需要更强的算力和更长的训练时间。如果做的是TI-RADS多分类(比如2类到5类),每个类别大概能分到1000多张,这时候就需要额外关注类别平衡问题,我在后面第4部分会专门讲。
1.2 数据集的标注粒度决定了任务类型
拿到数据集之后,第一件事不是急着跑模型,而是先搞清楚标注到底标的是什么。这个数据集说的是“图像分类数据集”,那标注大概率是图像级别的标签——即每一张图像对应一个类别标签,比如“良性”或“恶性”,或者更细化的TI-RADS等级。但医学图像数据集的标注有时候还会包含ROI(Region of Interest)信息,比如结节区域的边界框或掩膜。
这两种标注方式对应的任务完全不同:只有图像级标签,那做的是标准的图像分类;如果有边界框或掩膜,那就能进一步做目标检测或语义分割,可以在分类之前先做一个结节区域提取,再用提取出的区域做分类。很多医学图像分类的pipeline里,会先把结节区域裁出来再分类,因为原始超声图像里有大量无关信息,比如甲状腺周围的组织、颈动脉、气管等,这些背景噪声对分类器来说很容易造成干扰。
我在实际使用类似数据集时,习惯先用脚本遍历一遍所有图像的尺寸、通道数、标注文件格式,统计标签分布,画一个柱状图。这个步骤花不了多少时间,但能帮你对数据有一个非常直观的认知:哪些类别占比高、图像尺寸是否统一、标注文件是否有缺失或异常。很多人跳过这一步直接开训,后面遇到loss异常或者准确率上不去,回头排查才发现是数据本身就有问题,白白浪费一整天。
1.3 医学图像分类数据集的“稀缺性溢价”
在做医学图像分类这个方向时,数据集的稀缺性是一个绕不开的现实问题。甲状腺结节在体检中的检出率很高,但并不意味着高质量的公开数据集就很多。很多论文里的数据集来自单一医院、单一设备,样本代表性和泛化能力都有限。这个数据集标明了约7000张、已标注,说明整理方至少在数据清洗和标注一致性上做了工作,这对于后续实验的复现和对比来说非常关键。
从使用者的角度,稀缺性溢价意味着两件事。第一,拿到数据后要倍加珍惜,每一张图都值得认真清洗和利用,不能随便丢弃;第二,在做实验设计时,要尽量把数据集的价值榨干,比如用交叉验证代替单次划分,用模型集成提升稳定性,这些在小数据集上都是非常实用的手段。当然,我也要实事求是地说,一个数据集再优质,也只能覆盖它采集范围内的数据分布,部署到新的医院、新的设备上时,还是要做针对性的finetune和评估,这是医学图像算法的天然属性。
2. 标签体系与图像预处理实操要点
2.1 标签体系:二分类还是多分类
这个数据集的标注内容我现在没法打开确认,但从“图像分类数据集”这个描述来推断,绝大多数医学甲状腺数据集采用的都是二分类或多分类标签。二分类就是良性、恶性二选一,这也是临床上最刚需的判断;多分类则可能引入TI-RADS分级,从2类到5类,甚至包含6类(病理确诊恶性),每一级对应不同的恶性风险概率。
设计标签体系时有个原则值得记住:标签的粒度要和任务需求匹配。如果目标是做辅助筛查,二分类就够了,模型输出一个恶性概率,医生做参考;如果目标是做风险分层,那TI-RADS多分类更有价值,因为不同等级对应不同的随访或穿刺建议。从模型训练的角度,二分类相对容易做,loss收敛稳定,评估指标也好解释;多分类则对数据量和标注质量要求更高,类别之间可能存在模糊边界,比如TI-RADS 3类和4a类在图像上往往差别很细微,医生自己都可能存在判读分歧。
在实操中,我经常会把二分类模型和多分类模型都训练一遍做对比。一方面,二分类模型可以作为baseline,快速验证pipeline是否跑通;另一方面,多分类模型的中间特征可能包含更丰富的信息,如果多分类模型效果足够好,还可以把它的softmax输出或者特征向量拼接进二分类模型,做一个简单的特征融合。这种“多任务”的思路在小数据集上经常能带来惊喜。
2.2 图像尺寸统一与标准化流程
医学图像最让人头疼的一个问题就是尺寸不统一。不同型号的超声设备、不同的采集参数,输出的图像分辨率可能从几百乘几百到两千乘两千不等。直接把原始尺寸扔进模型肯定不行,所以需要一套统一的预处理流程。我一般这样处理:
第一步,统一尺寸。常见做法是resize到224x224或者256x256,这个尺寸是ImageNet预训练模型的标准输入,直接套用可以省去很多麻烦。但直接粗暴resize可能会拉伸图像,让结节形态变形,一个更好的方案是先用短边对齐再做中心裁剪,或者用padding补成正方形再resize。对于甲状腺超声图像,结节通常位于图像中心区域,中心裁剪一般不会丢失关键信息。
第二步,灰度图转三通道。超声图像天生是灰度图,只有一个通道,但大多数预训练模型(如ResNet)的输入是三通道RGB。解决方案有两种:一种是把单通道灰度图直接复制成三通道,保持数值一致;另一种是用伪彩色映射,比如用matplotlib的colormap把灰度图映射成彩色图。我实际测试下来,前者的效果通常更稳定,因为伪彩色映射本质上是非线性变换,可能会丢失或扭曲灰度信息,而复制通道不改变任何信息。当然,如果你从头训练一个只有单通道输入的模型,那就完全不需要这个步骤了。
第三步,归一化。ImageNet预训练模型要求输入按照ImageNet数据集的均值和标准差做归一化,具体数值是mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]。虽然超声图像和自然图像的分布差异很大,但既然用了ImageNet预训练权重,还是按照它的归一化方式来,这是迁移学习的基本操作。如果你选择从头训练,也可以自行计算数据集的均值和标准差,但坦白说,在这种小规模医学数据集上,从头训练的模型很难打过预训练模型。
2.3 数据划分:小心“数据泄漏”
数据划分是一个容易被忽视但后果很严重的问题。对于医学图像数据集,如果同一患者的多个结节图像被同时分到训练集和测试集,模型在训练时其实已经“见过”这个患者的特征了,测试结果会虚高。在真实临床场景中,模型要面对的是从未见过的新患者,所以数据划分必须按患者维度进行,保证同一患者的所有图像只出现在训练集、验证集或测试集中的一个。
如果数据集没有提供患者ID信息,怎么判断哪些图像来自同一患者?一个务实的办法是看文件名。很多医院导出的数据文件名里会包含检查号或患者编号,通过文件名前缀可以反推分组。如果完全没有这类信息,也可以用图像相似度聚类来近似分组,但这个方案比较复杂,而且不一定可靠。实在没办法时,只能用图像级划分,但要在论文或报告中注明这一限制。
另一个经验之谈:测试集一旦确定,就不要反复回到测试集上调参。我在跑实验时习惯把数据集分成三份,训练集用于更新模型参数,验证集用于early stopping和超参选择,测试集只在最终评估时用一次。如果连验证集都被反复调参调到“过拟合”了,最终测试结果也会失真。在医疗AI这种对鲁棒性要求极高的场景下,这种“脏”操作是要尽量避免的。
3. 图像分类模型选型与完整训练流程
3.1 模型选型:从ResNet到EfficientNet
模型选型是训练流程里最让人纠结的一步。我在医学图像分类任务中试过不少网络结构,从ResNet系列、DenseNet系列到EfficientNet系列,简单分享一下实际感受。
ResNet50是最稳妥的baseline,训练速度快、显存占用适中、调试经验丰富,出了任何问题社区里都能找到解决方案。即使你用更先进的模型跑出了更好的效果,论文里通常也需要一个ResNet50作为对照实验。DenseNet121在医学图像上表现一直不错,参数效率高,特征复用机制对细粒度分类任务有天然优势——甲状腺结节的良恶性差异本身就体现在一些局部纹理和边缘特征上,DenseNet密集连接的特性正好契合这种需求。EfficientNet系列则在计算效率上更胜一筹,B3到B5的参数量和数据量级在这个场景下比较匹配,但训练时要注意EMA(指数移动平均)和更强的正则化,否则容易过拟合。
ViT(Vision Transformer)在医学图像分类上也越来越常见,但说实话,在7000张图像这种数据规模下,从零训练的ViT很难胜过CNN,除非用大规模预训练模型做finetune,比如在很多基础模型上预训练过的ViT权重。我的建议是:优先跑通ResNet50和DenseNet121,如果时间允许,再试EfficientNet-B3和ViT做对比实验。不要一上来就在模型结构上花费太多时间,数据清洗和训练细节带来的收益往往更大。
3.2 迁移学习与预训练权重的正确打开方式
医学图像分类任务中,迁移学习不是“可选项”,而是“必选项”。ImageNet预训练模型学到了大量的基础视觉特征——边缘、纹理、形状、颜色分布,这些底层特征在超声图像上同样适用。虽然超声图像和自然图像差异很大,但底层特征迁移的效果依然远好于随机初始化。
实际操作时,有一个关键细节:加载预训练权重后,要不要冻结backbone?我的经验是分阶段训练。第一阶段冻结backbone,只训练最后的全连接分类头,用较小的学习率(比如1e-3)跑几个epoch,让分类头先收敛到合理的状态;第二阶段解冻backbone,用更小的学习率(比如1e-4甚至5e-5)对整个网络做微调。这个策略能避免在训练初期因为分类头随机初始化而回传过大的梯度,破坏预训练权重中已经学好的特征。
另外一个容易被忽略的点是分类头的设计。如果预训练模型最后是1000类输出,替换成2类或5类输出后,新分类头的权重是随机初始化的,这个不匹配会造成第一轮loss特别高。一个不错的技巧是把新分类头的初始化scale调小一点,或者先用一个中间层(比如256维全连接+ReLU)过渡,让特征映射更平滑,实测下来对收敛稳定性有帮助。但这个不是必须的,很多情况下直接替换也能收敛,只是第一轮loss会难看一点。
3.3 训练超参配置与优化器选择
在训练超参这块,以下几个参数是最重要的,也是在类似数据集上反复验证过的经验值。
Batch size:显存允许的情况下,尽量用32或64。医学图像因为预处理后尺寸统一,单个batch的内存消耗没有特别大。小的batch size会导致batch normalization统计量不稳定,训练震荡明显;但batch size过大在正则化效果上可能打折扣。我用得比较多的是32,训练速度和稳定性比较均衡。
优化器:AdamW是当前的最优选择,尤其是在小数据集上,它对权重衰减的处理比传统Adam更合理,不容易把权重衰减和自适应学习率搅在一起。学习率设置方面,我习惯用warmup + cosine annealing策略。先用线性warmup从很小的学习率(比如1e-6)升到峰值学习率(比如1e-4),再通过cosine曲线逐步降到接近0。这个策略在医学图像任务上非常管用,能显著减轻后期loss震荡。
损失函数:二分类用交叉熵即可,但如果类别不平衡,可以给损失函数加上类别权重,或者直接用Focal Loss。Focal Loss是处理医学图像类别不平衡的利器,它通过调节难易样本的权重,让模型更关注那些被错分的困难样本,而不是简单重复学习易分类的多数类样本。如果数据集里良性样本明显多于恶性,Focal Loss的alpha和gamma参数值得认真调一调。
训练轮数:7000张图像的训练集,一般15-25个epoch就足够了,配合early stopping,在验证集loss连续5个epoch不下降时停止训练。我见过有些同学一跑就是50、100个epoch,结果模型早就在第10个epoch过拟合了,后面全靠early stopping兜底。建议在第一次训练时先不加任何trick,让模型跑到过拟合,摸清loss曲线的形态,再逐步加入正则化手段。
3.4 数据增强:医学图像的特异性处理
数据增强在医学图像分类中是一把双刃剑,用好了效果显著,用不好反而会降低性能。常见的基础增强包括随机水平翻转、随机旋转(±10度)、随机缩放、随机裁剪、颜色抖动等。但在超声图像上,有几个细节需要特别注意。
第一,不要做垂直翻转。甲状腺超声图像有严格的解剖方位,上方通常是浅表组织,下方是深层组织,垂直翻转会彻底破坏解剖结构语义,模型学到的东西完全不可用。水平翻转相对安全,因为甲状腺左右两叶在图像上是对称的,但在做增强时还是要谨慎,最好先确认图像中是否有左右标注信息。
第二,弹性形变(elastic deformation)在医学图像上效果很好。这是医学图像增强里一个常见的变换,能模拟超声探头角度变化带来的组织形变。配合网格采样(grid sample)实现,库里有现成接口可以调用。这个增强能让模型对探头角度和压力的微小变化更鲁棒。
第三,模拟超声噪声。超声图像特有的斑噪声(speckle noise)是影响分类性能的重要因素。可以对图像施加适量的高斯噪声或斑点噪声,增强模型对噪声的抵抗能力。但噪声强度不能太大,否则会掩盖真实的组织纹理特征。我的经验是噪声方差控制在原图对比度的1%到3%之间比较合适。
数据增强的具体库,我推荐Albumentations,它的实现效率高,而且提供了丰富的医学图像增强transform。也可以用PyTorch自带的torchvision.transforms,但功能上Albumentations更灵活。需要注意的是,在验证集和测试集上绝对不要做任何数据增强(除了必要的resize和归一化),否则评估结果会虚高且不公平。
4. 数据集的验证与评估细节
4.1 评估指标:只看准确率远远不够
在甲状腺结节分类这类医学图像任务中,准确率是一个很有欺骗性的指标。如果数据集中90%是良性、10%是恶性,一个“全部预测为良性”的傻瓜模型就能达到90%的准确率,但这种模型在临床上毫无价值。医学图像分类任务中,我更关注以下几个指标的组合。
灵敏度(Sensitivity/Recall)反映的是“恶性结节被正确检出的比例”,这个指标在筛查场景中最为关键——漏掉一个恶性肿瘤的代价远高于多做一个不必要的穿刺。特异性(Specificity)反映的是“良性结节被正确识别的比例”,它决定了有多少患者可以避免不必要的进一步检查。AUC(ROC曲线下面积)则不依赖具体阈值,能综合反映模型的排序能力,适合在不同阈值下评估模型性能。
实操中,我会同时计算二分类的准确率、灵敏度、特异性、AUC,并绘制ROC曲线和PR曲线。类别不平衡时,PR曲线比ROC曲线更能揭示模型在少数类上的真实表现。每次实验记录这些指标,方便横向对比不同模型结构、不同训练策略的优劣。
4.2 交叉验证:小数据集的“续命丹”
7000张图像规模不大,如果只用一次train/test split,测试结果会有较大的随机波动——换一个随机种子,AUC可能从0.91变成0.89,这个波动会直接影响你对模型效果的判断。我的建议是使用5折交叉验证。
具体做法:把数据集平均分成5份,每次用4份训练、1份测试,轮流让每一份都当过测试集,最终报告5次测试结果的平均值和标准差。这样做的直接好处是,所有数据都被用于训练和测试,模型的评估更加稳定和可靠;间接好处是,你能看到模型在不同数据子集上的表现差异,对模型稳定性和泛化能力有更深入的理解。
在交叉验证中,每次划分的随机种子需要固定,保证实验可复现。同时每一折的训练过程也要记录最佳epoch的模型权重,最后可以做一个集成推理——5个模型的预测结果取平均或投票,这种简单的集成策略在小数据集上往往能带来一到两个百分点的AUC提升,而且基本不增加推理成本。
4.3 可视化分析:不止于数值指标
数值指标之外,可视化分析能帮你发现很多指标看不出的问题。我每次训练完模型都会做两类可视化。
第一类是混淆矩阵。它能直观显示模型在哪些类别上容易出错,是良性误判为恶性更严重,还是恶性误判为良性更严重。对于甲状腺结节分类,恶性误判为良性的代价更高,如果混淆矩阵显示这类错误较多,就要考虑调整分类阈值,让模型更倾向于输出恶性判断。
第二类是Grad-CAM热力图。通过梯度加权类激活映射,可以查看模型在预测时重点关注图像的哪些区域。对甲状腺结节分类来说,理想的热力图应该集中在结节区域——如果模型关注的是图像边缘的刻度尺、文字注释或者超声设备水印,说明模型学到了与任务无关的伪特征,泛化能力会大打折扣。这类问题在医学图像数据集中相当常见,很多数据集没有很好地对图像进行脱敏处理,刻度尺、设备型号标识、医院水印等信息残留会严重影响模型效果。
4.4 模型泛化能力的外部验证
交叉验证只解决了“同一数据分布下的稳定性”问题,没有解决“换一个数据源还能不能打”的问题。如果条件允许,最好找一批来自不同医院、不同超声设备、不同操作医生采集的甲状腺超声图像作为外部测试集。这种外部验证是医学图像分类模型从论文走向临床应用的关键一步。
我发现很多研究者在公开数据集上跑出漂亮的指标后就认为工作完成了,但真实临床场景中,模型即将面对的图像相对于训练数据一定存在分布偏移。设备型号不同、增益设置不同、探头频率不同、操作手法不同,都会导致图像的亮度、对比度、纹理细节发生明显变化。通过控制数据集的采集条件,可以横向评估模型在不同的设备品牌、图像分辨率、图像质量上的鲁棒性差异。比如将测试结果按设备品牌分组统计分析,就能看到哪些设备上模型表现更好,哪些设备上模型效果明显下降。这种设备维度的性能分层分析,对后续模型的实用化调整非常有帮助。
要缩小这种分布差距,可以在模型训练完成后,用目标设备采集的小批量数据进行快速微调,通常几十到一百张图就足够了。这个过程非常快捷,适合作为一项上线前的常规操作,能显著提升模型在新场景的表现。
5. 常见问题与排查技巧实录
5.1 训练loss不下降或震荡
这是最常遇到的问题。loss一直不降,首先要排除代码bug——检查数据标签是否与图像对应、损失函数是否正确、学习率是否过大或过小。把batch size调小,加载一小批数据过拟合,如果连一个batch都拟合不了,那问题大概率出在代码或数据上。
排除代码问题后,再看几个常见的坑。一个是用ImageNet预训练模型时,学习率设置太高,导致loss震荡不收敛,调整为1e-4以下通常能解决;另一个是batch size太小,比如只有4或8,导致BN层的统计量不稳定,loss曲线像锯齿一样上下跳动。此外,标签错误也会导致loss异常,比如良性标成了恶性,模型怎么学都学不对。这种情况下可以定期检查训练集中被模型高置信度预测错误的样本,往往能发现标注质量问题。
5.2 验证集AUC高但测试集AUC低
这种情况通常是数据泄漏或过拟合。数据泄漏在前面已经说过,最常见的是同一患者的图像同时出现在训练集和测试集。如果你的数据集没有提供患者ID,这是很难完全避免的,但可以通过文件名相关性检查来降低风险。
过拟合则需要加强正则化:增加weight decay、加入dropout、使用更强的数据增强、或者用早停。在医学图像小数据集上,Dropout和权重衰减的效果比在自然图像大模型上更显著。如果把训练集和验证集的loss曲线画在一起,发现训练loss持续下降但验证loss在某个epoch后开始上升,那就是典型的过拟合信号,此时应该采用验证loss最低点的模型权重,而不是最后一个epoch的权重。
5.3 类别不平衡带来的“偏科”问题
医学数据集中良性样本通常远多于恶性样本,类别不平衡是普遍现象。模型会倾向于把不确定的样本预测为多数类,导致灵敏度偏低。解决思路有三个方向。
数据层面:对少数类做过采样,重复使用或通过增强合成新的变体;或者对多数类做欠采样,但这样做会丢失数据,在小数据集上需谨慎使用。损失函数层面:使用加权交叉熵或Focal Loss,让模型更关注少数类的错误。评估层面:不要只看准确率,重点看AUC和灵敏度。这几种方法可以组合使用,我通常先尝试加权交叉熵,因为改动最小且效果直接,如果灵敏度还不够,再引入Focal Loss。
5.4 图像质量参差不齐的处理策略
超声图像的质量受设备、操作者经验、患者体型等许多因素影响。有的图像清晰锐利,结节边界分明;有的图像则模糊、噪声大,结节和背景区分度低。如果模型在低质量图像上表现差,可以考虑训练一个图像质量分类器,先过滤掉质量过低的图像,或者在训练集中加入质量相关的强增强来模拟低质量图像,提升模型的鲁棒性。
另外,很多超声图像上带有刻度尺、注释文字、设备品牌标识等无关信息。这些元素如果被模型当作分类依据,在真实部署时会产生严重问题。在预处理阶段,尽量对图像做中心裁剪,去掉边缘的刻度尺和注释文字区域;如果格式条件允许,也可以考虑用工具检测并去除文字区域。若条件允许,可以像部分团队那样在同一批数据上做对比实验,看看有水印和无水印对性能的影响程度,这个结果能为数据清洗策略提供依据。
6. 从数据集到完整项目的落地建议
6.1 构建最小可行的训练管线
如果不想只用现成代码跑一遍,而是想搭建一个可持续迭代的训练管线,我给你一个相对精简但完整的参考目录结构:
thyroid_project/ ├── config.py # 超参数和路径配置 ├── data/ │ ├── dataset.py # Dataset类,负责读取图像和标签 │ ├── transforms.py # 数据增强与预处理 │ └── split.py # 数据集划分脚本 ├── models/ │ ├── model.py # 模型定义 │ └── losses.py # 损失函数 ├── train.py # 训练入口 ├── evaluate.py # 评估入口 ├── inference.py # 推理脚本 ├── utils/ │ ├── metrics.py # 评估指标计算 │ └── viz.py # 可视化工具 └── results/ # 实验记录和模型权重这套结构的好处是,每个模块职责单一,替换模型结构、增加新评估指标时不需要改动其他模块。我一开始做实验时也是东一榔头西一棒子,代码堆在几个Notebook里,结果后面每次换数据集都要推倒重来。后来花了一天时间重构了这个管线,后续所有实验的迭代效率提升了至少两倍。
6.2 实验记录与可复现性管理
做科研或项目开发,实验记录和可复现性是至关重要的。我自己的习惯是,每次实验前先记录一个实验ID,然后把config文件、数据划分的随机种子、训练日志、模型权重都保存到以实验ID命名的文件夹里。训练完成后,把关键指标(准确率、AUC、灵敏度、特异性)写进一个汇总表格。这样一个月后再回来看,也能清楚知道当时做了哪些尝试、效果如何。
随机种子这个细节容易被忽略。PyTorch框架中需要同时设置Python、NumPy和PyTorch的随机种子,并在某些环境中注意决定论参数和性能参数对结果的影响。不固定随机种子的话,同样的代码和数据集每次跑出来的结果都会有差异,这会让对比实验的可信度大打折扣。
训练日志建议用现成的日志库记录,包括每一个epoch的训练loss、验证loss、学习率、各项评估指标。这些日志不光用于调参分析,写报告时也能直接引用。可视化工具我用的是写作时轻量好上手的方案,比如在本地画loss曲线和混淆矩阵,不额外搭建实验管理平台。如果需要更结构化的管理,可以考虑引入实验管理框架,但对个人项目来说,保持轻量化往往更高效。
6.3 从分类到检测分割的扩展思路
甲状腺结节图像分类数据集虽然只提供图像级标签,但它的价值可以延伸到更多任务中。如果有条件拿到结节区域的ROI标注,可以训练一个结节检测模型自动定位结节位置,再结合分类模型判断良恶性,这种“检测+分类”的级联架构更接近真实临床辅助诊断流程。
退一步讲,即使只有图像级标签,也可以利用弱监督定位方法(如Grad-CAM、CAM)生成结节区域的伪掩膜,辅助医生快速标注,降低人工标注成本。这在实践上是一个省力且有效的思路,适合作为后续扩展方向。
分类模型学到的高层特征还可以迁移到其他甲状腺相关任务中,比如甲状腺弥漫性病变分类、甲状腺结节质地评估等。用这个数据集训练出的模型作为预训练模型,在新任务上用少量标注数据做微调,效果通常优于直接从ImageNet预训练迁移。
我在实际工作中发现一个规律:数据集的价值往往不在于第一次训练出的模型指标有多高,而在于打开了一个可以持续迭代和扩展的方向。7000张图像的分类数据集,训练出一个AUC 0.90+的模型只是第一步,后续的数据积累、模型迭代、临床反馈闭环才是真正产生价值的环节。希望这篇文章能帮你少走一些弯路,把时间和精力花在真正重要的事情上。
本文还有配套的精品资源,点击获取