Kaggle RSNA 乳腺癌检测比赛复盘(一)—— 赛题介绍和自我总结
比赛描述
赛题非常简单:给定某个乳房的一组乳腺 X 影像图片,通过图片鉴别该乳房是否患有乳腺癌,一个常见的图像而分类比赛。
复杂点:某一个乳房会给出至少 2 张图片,分别为两个视角拍摄(CC 和 MLO),而一个病人有两个乳房,因此对一个病人来说,至少有 4 张图片。而标注的标签,都是在乳房级别而不是图像级别。因此,如果当作单图像分类的问题来处理,最后需要做聚合(比如某个乳房的 N 个图像推断出了 N 个结果,那么需要对这 N 个结果做聚合来得到最终的结果)。
评价指标是 pF1,类似于一种概率的 F-Score。实际用下来,还是需要设置合理的 threshold 来涨点,所以感觉还不如就直接用 F-Score。比赛的数据量很大,训练数据有 314G,但类别极不平衡,仅有 %1 左右的正样本。另外,本地验证得分和公榜得分差异也巨大,最后会有一定的 shakeup。
很容易想到这个比赛拉开分差的几个点:
- 如何处理不均衡的样本
- 如何处理多张图片单个标签的问题
- 如何应对最后的 shakeup
个人总结
从公榜 12(🏅️),到私榜被 shake 到了 26 名(🥈),我属于被 shake 得最惨的几号人之一。
先戳痛处:说说金牌怎么就歪成银牌了
那天我很郁闷,梦寐以求的 SOLO 金就这么没了,甚至前一天晚上觉都没睡好。
其实被 shake-down 基本在预料之中,但又完全是有机会避免的。我有几处明知 overfit LB 还一意孤行的点:
-
选择了使用百分位数作为 threshold 的提交。
用百分位数动态选择 threshold 来做判断,是一定会 overfit 的做法。但因为是我最高的公榜提交,因此我还是选择了它。结果当然很糟,公榜 0.63 而私榜只有 0.44。
但这种做法也不是完全没用,我发现用百分位数 threshold 来测试不同模型在 LB 上的表现效率很高,因为不同模型的 threshold 有可能不同,如果想测试模型的 LB 则可以使用百分位数的 threshold 来避免手动调整 threshold。当然在大多数情况,直接使用 CV 的最佳 threshold 可能是更好。
-
没有选择差异性更强的 ensemble 方式。
我有两个 ensemble 模型完全一致的提交,其唯一不同之处是是否对不同模型的输入做了不同的变化,其中一个做了一个没有,而没有做变化的 LB 得分高出了两个点,因此我也根据 LB 的得分选择了没有变化的提交,最后 PB 的得分正好相反:输入有做变化的高出了 2 个点。
总结下来,几乎就是没有把 Trust CV 贯彻到底,特别是在模型选择的时候。
比赛很难,SOLO 更难,如何保持热情
这次比赛过程中,我在公榜的金牌区呆了很长时间,甚至一度到达第二名。结果我发现好的名次并不能让我更有拼劲,甚至一度想放弃比赛。
最能让我产生动力的因素,是分享。我是抱着学习的初衷参加这次比赛的,在比赛的前一个月,我的名次大概在铜牌银牌之间徘徊,但那时的我并不着急于上分,而是以搜集信息和思考为主,甚至花了大部分时间学习了一下 CUDA 编程,解决了解析 dicom 文件速度过慢的问题,我开源了两个 lib:ExhaustiveWeightedRandomSampler 和 nvjpeg2k-python,分享到 Kaggle 社区后得到的回应也非常不错。
那时的我很快乐,不像是一个孤独的竞争者,要跟其他的参赛者拼个你死我活,而更多的是扮演一个合作者,为了解决一个难题,贡献自己微弱的力量。但那天,一切都变了…
我随意提交的一个单折单模型的分数挺进了公榜的前 20 名,我知道,只要我加上多折的聚合,就一定能到金牌,甚至进入奖金区都不无可能。之后的几天我开始聚合模型提交,而且开始 probing 公榜的 threshold,果不其然,我顺利的到达了第二名,这应该追平了历史的最高名次,但这没有任何意义,只能满足一时的虚荣心。
接下来我开始变得胜负欲非常强,可能是对金牌太过于执着,比赛的目的不再是学习和分享,而是拿到金牌。最后与金牌失之交臂,也算是点醒了我。我知道很多人可能跟我一样,都非常希望获得奖牌。但在 Kaggle 这个社区,分享和学习一定是更有意义的事。
最后再说说我的方案
我用了最简单的方案,即将任务作为单张图片的分类问题,最后提交的时候在单个乳房维度上做一个 max 结果聚合即可。基本就是最常见的方法,而这点也给了我信心,只要处理好各种细节,做好实验管理,即便是最基础的方案也能斩获不错的名次。
因为直接使用了单张图片训练,而标签是跟着单个乳房的,所以势必会训练到很多 False Positive 样本,这也是为什么在结果聚合的时候取了 max 而不是 mean 的原因。
对于 False Positive 这一点,还做了一点改进就是训练 Out of Folds 并获得样本的置信度,然后根据置信度来丢弃一些「高度疑似」FP 的样本。这个操作非常有效,CV 得分提高了 0.03 ~ 0.04 分。
在模型上,Convnext V2 在 CV 上全面碾压了其他模型。
另外在 CV / LB 相关性较小的情况下,以下一些操作可能可以减小 shakeup 的影响:
- 使用更重的数据增强,比如 cutout,mixup,mosaic,可能更能防止 shake。
- 使用外部数据和更多的训练流程(fine-tune、蒸馏 等)。
- 融合不同的方案,尽管某些方案的 CV 提升可能没有甚至降低。