肺癌项目(上):为什么不能一把梭,以及数据怎么变成样本
这一章讲三件事: 这本书后半段的大项目——从胸部 CT 找肺结节——是怎么设计的;CT 数据这种「野数据」有多少要先懂的规矩;以及原始文件怎么一步步变成第 07 章那种
__getitem__能吐出来的样本。 位置:Part 2 的转折点。从这里开始,「理解数据」比「设计模型」更占篇幅——这是作者们刻意让你体味的真实项目结构。
1. 任务与它的难度来源
任务一句话:输入一个病人胸部的 CT 扫描,输出疑似恶性肿瘤的位置。1
早期发现肺癌极大地提高存活率,但人工筛片是「在 100 个草垛里找针」:每一张片都要受过多年训练的专家盯着看,而绝大多数片子里什么都没有——人脑不擅长这种单调的警觉1。
那为什么不让神经网络直接读整张 CT?书里给了一个数量级答案2:
即使是恶性肿瘤病人,一张 CT 里也有高达 99.9999% 的体素不是癌。 书里给了两个生活化类比:相当于高清电视屏幕上两个像素的色差;相当于一书架小说里一个拼错的词。
端到端(不给模型定中间步骤、输入直接到答案)的做法在通用视觉上很成功,但那是在几十万张图、类别不稀缺的条件下;这里两个条件都没有2。
解法:三步流水线
① 数据加载(本章) 原始文件 → 能按候选点取出小方块数据
② 分割(第 15 章) 整张 CT → 标出「可能是结节」的体素(热图)
③ 分类(第 13–14 章) 每个候选点的小方块 → 结节/非结节
图说:像工厂的装配线,每站只干一件事。
注意顺序:书先做 ③ 再做 ②——因为标注数据直接支持 ③,而 ② 最难。
分步的代价书里写明了:两个模型不联合训练,梯度不能从最终答案一路回传到最前——上限会低一些,但每一步可教、可调、可换人接手2。临床上也更想要「标出可疑点供医生复核」,而不是一个黑盒二元诊断。
还有一句必须听进去的作者声明:这个项目跑出来的结果不能用于临床——它是教学载体,不是医疗设备3。
2. 先懂数据:CT 的规矩
CT 扫描可以粗理解为「三维 X 光」:X 光是三维身体投影到二维平面,CT 保住了第三维——机器绕身体一圈圈扫,计算机反推出每个小体积的密度,得到一整块三维数组。这个三维数组里的每个单元叫体素(voxel,三维版像素)4。
四条规矩,条条后面都要用4:
- 数值是 Hounsfield 单位(HU):空气 ≈ −1000,水 = 0,骨 ≥ +1000。肿瘤大约在水附近。
- 体素通常不是立方体:行列方向(横断面)间距小,头脚方向间距大(比如 1.125×1.125×2.5 毫米)——因为病人是躺在床上沿头脚方向移动的,这条轴的采样方式不同。书里有句方法论:这个事实是作者从机器照片里病人移动的方向推出来的——懂你的数据,连物理来源都要懂4。
- 原生格式是 DICOM,1984 年的医学影像标准,复杂;好在 LUNA 数据集已经转成了好读得多的 MetaIO 格式(
.mhd头 +.raw体)。 - 每张 CT 约 512×512×(100~250) 体素,约 3200 万个数——而最小的结节只有几毫米,约「比整张 CT 小一百万倍」4。
3. 标注数据:脏才是常态
数据源是 LUNA16 大挑战:888 张 CT 扫描,带人工标注,外加一个公开排行榜(比方法成绩的公开榜单)5。
两个 CSV 文件,第一次见 识真实数据的脏6:
candidates.csv:551066 行,「看着像结节的候选点」——每行是 seriesuid(那张 CT 的唯一编号)+ 三维坐标 + class(1=真是结节,0=不是)。其中真是结节的只有 1351 个。annotations.csv:1187 行,给其中一部分结节标了直径(毫米)。
两个文件的坐标对不齐:同一个结节,一边写 (−128.70, −175.32, −298.39),另一边写 (−128.94, −175.04, −297.87)——都是「中心附近」,谁也不精确等于谁6。书里选择做模糊匹配:两点各轴差值都不超过「直径÷4」就算同一个(这是对「直径/2 是半径、容差再砍半」的朴素实现)。「真实数据集常常就是这样,你得自己做这种缝合」6。
把两份数据缝成一张干净表之后,按结节直径从大到小排序——后面每隔 10 个取一个做验证集时,大小分布才有代表性,否则验证集可能全是极端尺寸,模型看着像不行6。