nnUNetV2 实战:用 MSD 心脏数据集跑通你的第一个医学图像分割模型(附完整代码与结果分析)
nnUNetV2 实战:用 MSD 心脏数据集跑通你的第一个医学图像分割模型
医学图像分割一直是计算机辅助诊断中的核心任务之一。对于刚接触这一领域的研究者或工程师来说,如何快速搭建一个可用的分割模型往往令人头疼。nnUNetV2 作为当前最先进的医学图像分割框架之一,以其"开箱即用"的特性广受好评。本文将手把手带你使用 MSD(Medical Segmentation Decathlon)心脏数据集,从零开始构建一个完整的分割流程。
1. 环境准备与框架搭建
在开始之前,我们需要确保开发环境配置正确。nnUNetV2 对系统环境有一定要求,但相比早期版本已经宽松许多。
1.1 基础环境配置
推荐使用 Ubuntu 20.04 或 22.04 系统,Python 版本需 3.9 以上。以下是具体依赖:
# 创建并激活虚拟环境 python -m venv nnunet_env source nnunet_env/bin/activate # 安装核心依赖 pip install torch==2.0.1 torchvision==0.15.2 -f https://download.pytorch.org/whl/torch_stable.html pip install nnunetv2提示:如果使用 NVIDIA GPU,请确保已安装对应版本的 CUDA 和 cuDNN。可以通过
nvidia-smi命令验证驱动是否正常工作。
1.2 获取 nnUNetV2 源码
虽然可以直接 pip 安装,但为了后续可能的定制化开发,建议从 GitHub 克隆源码:
git clone https://github.com/MIC-DKFZ/nnUNet.git cd nnUNet pip install -e .1.3 目录结构设置
nnUNetV2 需要特定的目录结构来管理数据。在你的工作目录中创建以下结构:
nnUNet_base/ ├── nnUNet_raw ├── nnUNet_preprocessed └── nnUNet_results然后设置环境变量指向这些目录。将以下内容添加到~/.bashrc文件末尾:
export nnUNet_raw="/path/to/nnUNet_raw" export nnUNet_preprocessed="/path/to/nnUNet_preprocessed" export nnUNet_results="/path/to/nnUNet_results"执行source ~/.bashrc使更改生效。
2. 数据集准备与格式转换
MSD 心脏数据集是一个公开的医学影像数据集,包含 30 例心脏 MRI 扫描及对应的专家标注,非常适合快速验证模型效果。
2.1 下载数据集
从官方地址获取数据集:
wget https://msd-for-monai.s3-us-west-2.amazonaws.com/Task02_Heart.tar tar -xvf Task02_Heart.tar解压后会得到一个包含 imagesTr(训练图像)、labelsTr(训练标签)和 imagesTs(测试图像)的目录。
2.2 转换为 nnUNet 格式
nnUNetV2 提供了便捷的转换工具:
nnUNetv2_convert_MSD_dataset -i /path/to/Task02_Heart -o $nnUNet_raw -d 002转换完成后,可以在$nnUNet_raw下看到新生成的Dataset002_Heart目录。检查其结构应如下:
Dataset002_Heart/ ├── dataset.json ├── imagesTr │ ├── case_0000_0000.nii.gz │ └── ... └── labelsTr ├── case_0000.nii.gz └── ...注意:
0000后缀表示模态编号,对于单模态数据(如本数据集)固定为 0000。
3. 数据预处理与实验规划
nnUNetV2 的预处理流程完全自动化,这是其最强大的特性之一。
3.1 运行预处理管道
执行以下命令启动自动预处理:
nnUNetv2_plan_and_preprocess -d 002 --verify_dataset_integrity这个过程会:
- 分析数据集特性(体素间距、图像尺寸等)
- 自动设计合适的网络配置
- 执行归一化、重采样等预处理操作
预处理完成后,可以在$nnUNet_preprocessed下找到处理后的数据。
3.2 理解预处理输出
关键文件包括:
- plans.json:包含自动生成的训练方案
- dataset_properties.pkl:数据集统计信息
- preprocessed目录:存放处理后的图像数据
可以通过以下命令查看数据统计:
import pickle with open('$nnUNet_preprocessed/Dataset002_Heart/dataset_properties.pkl', 'rb') as f: props = pickle.load(f) print(props['spacing_median']) # 打印中位体素间距4. 模型训练与验证
nnUNetV2 支持多种网络配置,对于心脏 MRI 这类中等尺寸数据,2D 和 3D 模型都适用。
4.1 启动训练
使用 5 折交叉验证训练 2D 模型:
nnUNetv2_train 002 2d 0 # 第0折 nnUNetv2_train 002 2d 1 # 第1折 # ... 依次训练全部5折每个训练任务会输出:
- 训练日志(控制台和 tensorboard)
- 模型检查点(.model 和 .pkl 文件)
- 验证集预测结果
4.2 监控训练过程
使用 tensorboard 实时观察训练指标:
tensorboard --logdir $nnUNet_results/Dataset002_Heart/nnUNetTrainer__nnUNetPlans__2d重点关注以下指标:
- train_loss:训练损失
- val_loss:验证损失
- val_Dice:验证集 Dice 系数
典型的训练曲线应该显示损失稳步下降,Dice 系数逐渐上升,最终趋于平稳。
4.3 模型集成与测试
训练完成后,可以集成各折模型提升性能:
nnUNetv2_find_best_configuration -d 002 -c 2d该命令会自动选择最优模型组合,并生成集成预测。
5. 推理与结果可视化
5.1 单样本预测
对新的 MRI 扫描进行预测:
nnUNetv2_predict -i /path/to/input -o /path/to/output -d 002 -c 2d -f 05.2 结果可视化
使用 ITK-SNAP 或 3D Slicer 查看分割结果。以下 Python 代码也可以生成可视化:
import nibabel as nib import matplotlib.pyplot as plt # 加载原始图像和预测 img = nib.load('case_0000_0000.nii.gz').get_fdata() pred = nib.load('prediction.nii.gz').get_fdata() # 选择中间层面可视化 slice_idx = img.shape[2] // 2 plt.figure(figsize=(12,6)) plt.subplot(121) plt.imshow(img[:,:,slice_idx], cmap='gray') plt.title('Original') plt.subplot(122) plt.imshow(img[:,:,slice_idx], cmap='gray') plt.imshow(pred[:,:,slice_idx], alpha=0.5) plt.title('Segmentation') plt.show()5.3 性能评估
nnUNetV2 内置评估工具:
nnUNetv2_evaluate_folder -ref $nnUNet_raw/Dataset002_Heart/labelsTs -pred /path/to/predictions -l 1这会计算 Dice 系数、Hausdorff 距离等指标。对于心脏数据集,2D 模型通常能达到 0.88-0.92 的 Dice 分数。
6. 进阶技巧与问题排查
6.1 常见问题解决
- 预处理失败:检查数据集格式是否正确,特别是
dataset.json中的键值 - 训练不收敛:尝试降低学习率(通过修改
nnUNet/nnunetv2/training/nnUNetTrainer/nnUNetTrainer.py) - 显存不足:使用
3d_lowres配置或减小patch_size(修改plans.json)
6.2 自定义训练配置
要修改默认训练参数,继承默认 Trainer:
from nnunetv2.training.nnUNetTrainer.nnUNetTrainer import nnUNetTrainer class MyTrainer(nnUNetTrainer): def __init__(self, plans, configuration, fold, dataset_json, unpack_dataset, device): super().__init__(plans, configuration, fold, dataset_json, unpack_dataset, device) self.num_epochs = 500 # 延长训练轮次 self.initial_lr = 1e-3 # 调整学习率然后在训练时指定--trainer_class MyTrainer。
6.3 扩展到其他器官
同样的流程适用于其他医学图像分割任务:
- 获取新数据集(如 MSD 肝脏数据)
- 转换格式(注意修改 dataset_id)
- 重新运行预处理和训练
不同器官可能需要调整:
- 2D/3D 模型选择
- 输入图像尺寸
- 训练迭代次数
