1. 课程导入与nnU-Net定位

医学影像分割与自然图像分割看似同源,实际工程差异极大。自然图像通常是二维、通道固定、目标语义宽泛;而医学影像常见三维体数据,如CT的HU值、MRI的多序列(T1、T2、FLAIR、DWI)、PET的SUV值,不同模态的体素间距、方向矩阵、灰度动态范围完全不同。更棘手的是,同一器官在不同中心、不同扫描协议下,层厚可能从0.5 mm到5 mm不等,视野和重建核也各不相同。这意味着一个在A数据集上表现良好的网络,直接迁移到B数据集时,往往因为各向异性间距和强度分布偏移而性能骤降。

nnU-Net的核心价值,正是把这种“每次换数据集都要重新调参”的重复劳动,转化为一套可复用的自配置范式。它不追求网络结构的创新,而是让预处理、网络拓扑、训练策略和推理方式全部由数据集本身的指纹自动推导。理解这一点,是后续所有工程操作的前提。

医学影像分割任务的三个工程特点

第一是各向异性与间距差异。CT腹部数据常见层厚3 mm、层内间距0.7 mm,而脑部MRI可能是1 mm各向同性。nnU-Net会统计所有训练案例的体素间距中位数,据此决定是否重采样到目标间距,以及是否在低分辨率分支中进一步下采样。第二是类别不平衡与目标尺寸差异。肝脏可能占数万体素,而胰腺肿瘤可能只有几百体素,nnU-Net通过基于区域的目标采样和深度监督来缓解。第三是标注成本高、数据量小。一个分割数据集往往只有几十到几百例,因此五折交叉验证、数据增强和集成推理成为默认配置,而不是可选项。

nnU-Net自配置范式的四个决策层

nnU-Net的“自配置”并非黑箱,而是四个可解释的决策层:数据指纹分析(间距、尺寸、强度、类别比例)、预处理策略(重采样、归一化、裁剪)、网络拓扑生成(patch大小、batch大小、池化次数、卷积核数量)、训练与推理策略(损失函数、优化器、增强、滑动窗口重叠率、集成方式)。这四个层次共同决定了最终模型的行为。

nnU-Net 自配置范式:从数据指纹到推理输出 ① 数据指纹分析 体素间距中位数 图像尺寸 / patch候选 强度范围 / 类别比例 ② 预处理策略 重采样到目标间距 Z-score / CT裁剪归一化 非零区域裁剪 ③ 网络拓扑生成 patch / batch 大小 池化次数与卷积核数 3D U-Net / 2D / 级联 ④ 训练与推理 Dice+CE 损失 五折交叉验证 滑动窗口 + 集成 输入数据流: 原始影像 (NIfTI) + 标注 → 指纹提取 → 预处理 → patch采样 → 网络前向 → 损失计算 → 反向传播 → 权重更新 推理数据流: 测试影像 → 同一预处理 → 滑动窗口切块 → 五折模型分别预测 → 概率平均 → argmax → 分割结果 关键自配置参数(示例) • 目标间距:由训练集中位数决定,如 [1.0, 1.0, 1.0] mm • patch大小:如 128×128×128,需满足显存约束 • batch大小:如 2,由patch大小和显存反推 • 池化次数:如 5,保证最深特征图不小于4体素 • 初始卷积核数:如 32,每下采样一层翻倍 • 滑动窗口重叠:如 0.5,平衡精度与推理速度 课程项目与数据准备总览 • 项目目标:完成一个医学影像分割任务的完整工程链路 • 数据格式:NIfTI (.nii.gz),图像与标注分离存放 • 目录结构:imagesTr / labelsTr / imagesTs • 数据集划分:五折交叉验证,每折独立训练与验证 • 评估指标:Dice系数、HD95、类别平均Dice • 交付物:训练好的五折模型 + 推理脚本 + 评估报告

课程项目与数据准备总览

本课程围绕一个完整的医学影像分割项目展开。项目数据采用NIfTI格式,图像与标注分别存放在imagesTr和labelsTr目录下,测试图像放在imagesTs。每个病例的文件名遵循CaseID_0000.nii.gz的命名规则,其中0000表示第一个模态通道。如果使用多模态数据,则依次为0001、0002等。标注文件只保留一个通道,体素值对应类别索引,背景为0。

数据准备阶段需要完成三件事:一是确认所有图像的几何信息(间距、方向、原点)可被正确读取;二是检查标注与图像的空间对齐,避免因重采样或方向矩阵不一致导致标签错位;三是统计类别分布,判断是否存在极端不平衡。这些检查不需要复杂工具,用SimpleITK或nibabel读取后打印关键属性即可。

import nibabel as nib
img = nib.load("imagesTr/Case001_0000.nii.gz")
print("shape:", img.shape)
print("spacing:", img.header.get_zooms())
print("affine:\n", img.affine)

lab = nib.load("labelsTr/Case001.nii.gz")
print("label unique:", np.unique(lab.get_fdata()))

运行后应确认:图像与标注的shape一致,spacing符合预期,affine矩阵没有异常旋转或翻转,标签值只包含0和1(或0到K-1)。如果发现标签值出现0.5、1.2等非整数,说明标注在保存时被插值过,需要重新导出为最近邻插值。

数据准备阶段最常见的错误是图像与标注的affine不一致。即使shape相同,affine不同也会导致空间位置错位。建议在训练前用nibabel或SimpleITK逐例检查,并统一重采样到同一参考空间。

从数据指纹到训练配置的推导逻辑

nnU-Net的自配置不是随机搜索,而是基于规则的推导。以体素间距为例:如果训练集中位间距为[0.7, 0.7, 3.0] mm,nnU-Net会将其重采样到[0.7, 0.7, 3.0]附近的目标间距,而不是强行各向同性。这是因为强行各向同性会引入大量插值伪影,反而降低分割质量。再如patch大小,它由目标间距下的图像尺寸和显存预算共同决定:先计算所有训练图像在目标间距下的尺寸中位数,再从中选择能被16整除、且满足显存约束的最大patch。

网络拓扑的生成同样有明确规则:池化次数由patch大小决定,保证最深特征图在每个维度上不小于4体素;初始卷积核数通常为32,每下采样一层翻倍,直到达到512或显存上限。这些规则使得nnU-Net在不同数据集上都能生成“合理”的配置,而不需要人工反复试错。

本课程的学习路径