tag

U-Net

从 patch 热力图到 U-Net:肝脏识别进度记录

从 patch 热力图到 U-Net:肝脏识别进度记录 0. 背景 好久没更新博客了。 上一次还在看 nnU-Net 的论文,想着先把数据空间、预处理和输入格式这些基础问题弄明白。后来真正开始做肝脏识别,路线也从一开始的 patch 分类和粗 ROI,慢慢走到了现在的 U-Net 像素级分割。 这篇不打算写成很完整的教程,主要想记一下: 为什么换模型、换完以后做了什么,以及现在到底做到哪一步了。 先说明一下,目前实际训练的是自己写的轻量 2D U-Net baseline,并不是直接运行官方 nnU-Net。完整代码放在公开仓库里:liver-segmentation code。 1. 换模型前,旧方案卡在哪里 换 U-Net 之前,做的是一个监督式对比学习的 patch 分类器。 它会判断一个 96 × 96 的 CT patch 是 liver 还是 non-liver,然后在完整 CT 上滑窗,把每个 patch 的概率重新叠回三维空间,最后得到一张肝脏热力图。 这条路线不是完全没用。它确实能大致找到肝脏,也很适合验证“模型到底有没有学到肝脏区域”。但越往后做,问题越明显: 它学的是“这个 patch 里像不像有肝脏”,不是“每一个像素是不是肝脏”; 滑窗概率回填以后,边缘容易变厚、变糊; 模型只看局部,容易把附近灰度相似的器官和软组织一起圈进来; 阈值一改,Recall 和 Precision 就会明显拉扯; 最大连通域、闭运算、矢状面过滤都能清掉一些小块,但更像是在补救结果。 旧方案最后选中的是 epoch 40、阈值 0.80。在 4 个完整验证 CT 上,平均 Recall 是 0.9504,Precision 是 0.7266,Dice 是 0.8220。 召回率已经不算低,但误检还是很多。这个时候继续给后处理叠规则,收益越来越有限。后来想明白,问题不只是模型容量不够,而是任务本身没有对齐: 想要的是一张像素级 mask,却一直在训练一个 patch 级分类器。 所以决定换成 U-Net。 2. 先把 U-Net 的最小闭环跑通 这次没有一上来就堆很复杂的结构,而是先写了一个比较小的 2D U-Net: 单通道轴向 CT 输入; 4 层 encoder 和 decoder; skip connection; GroupNorm; base channels 为 16; 总参数量约 194 万。 输出也从“这个 patch 是不是肝脏”,变成了“这一张切片上每个像素属于肝脏的概率”。

阅读全文 »

nnU-Net 模型学习笔记

nnU-Net 模型学习笔记 0. 背景 这篇主要是对论文 nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation 的学习记录。 一开始看到 nnU-Net 的时候,其实很容易把它理解成“一个更厉害的 U-Net 变体”。但是读完论文之后发现,它真正重要的地方好像并不是提出了什么特别炫的新网络结构,而是把医学图像分割里一堆容易被忽略的工程细节系统化了。 论文里也直接把 nnU-Net 解释成 no-new-Net,这个名字还挺有意思的。它大概想表达的是: 不一定非要发明一个新的网络结构,先把 U-Net 该做好的事情全部做好。 这点对我还挺有提醒意义的。因为之前做 DICOM 预处理、期相配准、nnU-Net 输入格式的时候,我也经常会下意识觉得“模型才是核心”,但实际上数据怎么裁剪、怎么重采样、spacing 怎么统一、标签怎么插值、patch 怎么取,这些东西如果没处理好,后面的模型可能只是看起来很努力。 1. nnU-Net 想解决什么问题 医学图像分割里面,U-Net 本身已经是一个很经典的结构了。 但是问题在于,不同数据集之间差异非常大: 有的是 CT,有的是 MRI; 有的是 2D 图像,有的是 3D 体数据; 有的 spacing 比较均匀,有的 z 轴很厚; 有的图像范围很大,比如肝脏、肺; 有的目标很小,比如海马体、胰腺病灶; 有的数据集病例很多,有的数据集病例很少。 所以同样是 U-Net,直接拿来用并不一定能跑出好结果。 如果每来一个新任务,都靠人工去调网络深度、patch size、batch size、归一化方式、数据增强方式、推理策略,那整个流程就会非常依赖经验,也很难保证可复现。 nnU-Net 的思路就是: 给定一个新的医学图像分割任务,尽量自动分析数据集特征,然后自动生成一套适合这个任务的 U-Net 训练和推理方案。 所以它不是单纯的一个模型,而更像是一个完整的自动化分割框架。 2. 核心理解:它不追求“新”,而追求“配好” 论文里有一个观点我觉得挺关键: 很多所谓的新结构,在没有把 baseline 充分调好的情况下,看起来确实能提升性能。但如果基础 U-Net 已经被认真配置过,很多花哨结构带来的提升可能就没有那么明显了。 所以 nnU-Net 没有采用 residual connection、dense connection、attention mechanism 这些当时常见的改造,而是只在原始 U-Net 上做了很小的改动: 使用 leaky ReLU; 使用 instance normalization;

阅读全文 »