分割与微调:让模型自己找出候选,不再靠人工清单
这一章讲三件事: 分割和分类有什么本质不同;SAM 这种「基础模型」是什么、能直接拿来干什么;以及本章的核心手法——用大模型的输出当标签,微调一个小模型替它干活。 位置:三步流水线的第 ② 步。做完这章,candidates.csv 这份人工清单就被自己的模型取代了。本章相对独立:新模型、新数据集、新训练循环。
1. 分类回答「有没有」,分割回答「在哪」
第 13–14 章的分类器有一个隐藏前提:候选点由 candidates.csv 给好。可那份清单是 LUNA 比赛方请人标出来的——换一批 CT、换一家医院,清单就没了。流水线还差一环:从整张 CT 里把「值得分类的位置」自己找出来1。
这就是分割(segmentation):不再给整张图一个标签,而是给每个像素一个标签——这块像结节、那块不是,输出是一张和输入一样大的「热图」。书里的对比很形象:分类模型像漏斗或放大镜,一大把像素进去、一个标签出来;分割要的是图像进、图像出2。
邻近的三个任务别混1。给每个像素分类的做法,这叫语义分割——「语义」就是「按内容是什么」:
| 任务 | 输出 | 例 |
|---|---|---|
| 语义分割 | 每个像素属于哪一类 | 「这些像素是结节」 |
| 实例分割 | 每个像素属于哪个对象 | 「这是结节 1、那是结节 2」 |
| 目标检测 | 对象外接框 | 「结节在这个框里」 |
本章选语义分割(给每个像素标上「属于哪一类」):医学上要的是「精确到体素的范围」,不是框,而同类结节之间不必区分个体1。
2. SAM:点一下就出掩码的通用分割模型
自己从零训一个分割模型,标签从哪来?给每个体素标「是不是结节」,是放射科医生级别的活——贵到不现实。书里的答案是站在一个现成巨人的肩膀上:SAM(Segment Anything Model,Meta 2023 年发布)3。
SAM 的用法和普通模型不一样:你给它图,再给提示——点一个点、框一个框,或给一张粗略掩码——它就吐出这个提示所指物体的分割掩码。点一下照片里狗的鼻子,得到三张嵌套的掩码:整条狗、鼻子、鼻子的局部,各带一个置信度4。它是零样本(zero-shot)的:从没见过你的数据类别,不用训练直接能用——靠的是 1100 万张图、11 亿张掩码训出来的通用「什么东西算一个物体」的直觉3。
结构上它是三个 ViT 系组件(第 10 章讲的 Transformer 在图像上的用法)的接力:图像编码器把整图压成特征;提示编码器把你的点/框/掩码也变成特征;掩码解码器把两者合并,生成最终掩码5。
试用一把(走查的第一步):随便拿一张普通照片(书里用的是一张宇航员照)喂给自动掩码生成器,不点任何提示,它自己扫全图,返回 79 张掩码——头盔、背包、手臂,各自独立成片。每张附带的 predicted_iou 是模型自报的置信度(「我觉得这掩码有多完整」),不是真和答案比出来的分数——书里特地标了这一点,它的值甚至可以超过 16。
两句冷静的提醒:
- SAM 的训练数据是自然照片。书里的专栏直说:自然图像和医学影像之间有「领域差距」(domain gap),它在 CT 上表现如何要试了才知道,不能默认行7。
- 用别人的模型先看许可证:SAM 用 Apache 2.0(宽松、可商用),但**「网上能下载」不等于公有领域**,而且代码的许可证和权重的许可证可以是两份8。
3. 主走查:从一张 CT 切片到一个微调好的分割模型
SAM 有个硬限制:它只吃 2D 图,而我们的 CT 是 3D 体。书里正面接受了这个妥协:沿轴抽出 2D 切片来用。代价有两个,都记着账:切片厚度不一被忽略(让模型学着扛);3D 上下文(上下切片里的连续性)整条丢掉9。
限制变成了机会,本章的核心手法登场——既然 SAM 要提示才干活,那就让它当「标注工」10:
① 取切片:getSingleSlice 从 3D CT 沿轴切出 2D 灰度图
② 给提示:标注文件里有结节中心点——正好当 SAM 的点提示
③ 收掩码:SAM 输出该点的结节掩码,存成二值图
④ 造数据集:几千组「CT 切片 + SAM 掩码」,配 metadata.jsonl 记录出处
⑤ 微调小模型:拿 ④ 当标准答案,训练 SegFormer 不看提示直接出掩码
图说:大模型出一次力,小模型从此自立。SAM 只在造数据时登场,部署时没有它。
第 ⑤ 步是本章第二个核心概念:微调(fine-tuning,第 03 章讲嵌入表时露过一次名,这里正式定义)——拿一个已经在别的大数据集上训好的模型,在自己的数据上继续训练。它不从头学「什么是边缘、什么是纹理」,只学「在这个新任务上该怎么输出」,所以小数据、单张 GPU 就够11。
被微调的模型是 SegFormer(轻量版 nvidia/mit-b0,一个专为语义分割设计的 Transformer):预训练权重全保留,只把解码头(最后把特征变成掩码的那几层)换掉重训。加载时 Hugging Face 会警告「decode_head 的权重是 newly initialized(新初始化的)」——这正是预期的,不用慌12。
走查的最后两步,细节各有一句讲究:
- 优化器用 AdamW(Adam 的变体,把权重衰减从梯度里拆出来单独施加;Adam 本身是第 05 章见过的自适应学习率优化器),学习率 6×10⁻⁵,和 SegFormer 原论文保持一致13。
- 训练循环能短得意外:Hugging Face 的
SegformerImageProcessor管预处理,model(pixel_values=…, labels=…)直接返回损失——把掩码当 labels 传进去,框架内部自己算好损失,20 个 epoch 训练和验证损失一起降14。
保存模型时,书里重申第 08 章的规矩:存 state_dict(参数字典),别用 pickle 存整个模型对象——后者把类的路径也腌进了文件,代码一重构就加载不回来;而 load_state_dict 要求参数名一一对应,所以加载前要把模型结构原样建好15。
推理端走一遍:新 CT → 切片 → 处理器 → SegFormer → 每张切片一张「疑似结节」热图 → 热图里连成片的高分区取中心,就是 candidates.csv 的替代品——流水线闭环了16。
4. 作者的判断与证据
| 说法 | 性质 |
|---|---|
| 选语义分割而非实例/检测 | 论证选择,理由是医学上要体素级范围1 |
| SAM 零样本能力、11M 图/1.1B 掩码 | 论文事实(arXiv:2304.02643),书里转述3 |
| 自然图像到医学影像有领域差距 | 作者警告 + 引外部研究(arXiv:2304.14660),方向可靠7 |
| 「SAM 掩码当标签训小模型」是合理工程 | 本章的赌注:SAM 掩码不是医生标的,标签噪声进了训练集;书里靠最后那张分割结果图论证「够用」,未做系统的噪声分析10 |
| 只微调解码头、单卡可训 | 有据,mit-b0 轻量版 + 训练损失实测12 |
| AdamW lr=6×10⁻⁵ | 沿用原论文设置,未在本任务上调过13 |
5. 边界与局限
- 切片法丢了 3D 上下文:一个横跨三张切片的小结节,每张上都只剩淡影——书里承认这是拿精度换简单9。
- SAM 的掩码里混着它自己的错误,这些错误会被 SegFormer 当成真理学进去;更稳的做法是加一道筛(比如只保留和标注直径相符的掩码),书里没做。
- predicted_iou 是自报置信度,别当质量分用6。
- 切片厚度不一致被「让模型学着扛」一句带过——换了扫描规程要重查。