MONAI(Medical Open Network for AI)是专为医学影像分析设计的开源深度学习框架,基于 PyTorch 构建,提供医疗影像专用的数据预处理、网络模块、损失函数和评估工具。以下是快速掌握 MONAI 的完整教程。


目录

  1. 安装与环境配置
  2. 核心设计理念
  3. 数据加载与预处理
  4. 网络模型构建
  5. 训练与验证流程
  6. 医学影像专用功能
  7. 实战案例
  8. 注意事项
  9. 扩展与优化

安装与环境配置

# 使用 pip 安装
pip install monai

# 安装最新开发版
pip install git+https://github.com/Project-MONAI/MONAI

# 安装 CUDA 支持
pip install monai[cuda]

推荐环境

Python >= 3.7
PyTorch >= 1.8
CUDA 11.x (用于GPU加速)
NVIDIA驱动 >= 450.xx

核心设计理念

特性说明
医疗影像专用3D/4D影像支持、医学坐标系统
模块化架构可组合的 transforms 和网络模块
分布式训练支持多GPU/TPU 训练
与 ITK/ANTs 兼容支持医学影像标准格式
可解释性工具Grad-CAM、可视化等

数据加载与预处理

1. 数据集定义(NIfTI 文件示例)

from monai.data import Dataset, DataLoader
from monai.transforms import LoadImaged, EnsureChannelFirstd, ScaleIntensityRanged

data = [
    {"image": "path/to/image.nii.gz", "label": "path/to/label.nii.gz"}
    for _ in range(10)
]

transforms = Compose([
    LoadImaged(keys=["image", "label"]),
    EnsureChannelFirstd(keys=["image", "label"]),
    ScaleIntensityRanged(
        keys=["image"],
        a_min=-500,
        a_max=1000,
        b_min=0.0,
        b_max=1.0,
        clip=True
    )
])

dataset = Dataset(data=data, transform=transforms)
loader = DataLoader(dataset, batch_size=2, num_workers=4)

2. 医学影像专用变换

from monai.transforms import (
    Spacingd, 
    Orientationd, 
    CropForegroundd,
    RandCropByPosNegLabeld
)

transforms = Compose([
    LoadImaged(keys=["image", "label"]),
    EnsureChannelFirstd(keys=["image", "label"]),
    Spacingd(  # 重采样
        keys=["image", "label"],
        pixdim=(1.5, 1.5, 2.0),
        mode=("bilinear", "nearest")
    ),
    Orientationd(  # 标准化方向
        keys=["image", "label"],
        axcodes="RAS"
    ),
    CropForegroundd(  # 裁剪背景
        keys=["image", "label"],
        source_key="image"
    )
])

网络模型构建

1. 使用内置模型

from monai.networks.nets import UNet, DenseNet121

# 3D U-Net
model = UNet(
    spatial_dims=3,
    in_channels=1,
    out_channels=2,
    channels=(16, 32, 64, 128, 256),
    strides=(2, 2, 2, 2)
).to(device)

# 分类网络
model = DenseNet121(
    spatial_dims=3,
    in_channels=1,
    out_channels=2
)

2. 自定义网络

import torch.nn as nn
from monai.networks.blocks import Convolution

class CustomModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.block = Convolution(
            spatial_dims=3,
            in_channels=1,
            out_channels=16,
            kernel_size=3,
            act="RELU"
        )
        
    def forward(self, x):
        return self.block(x)

训练与验证流程

1. 标准训练循环

from monai.losses import DiceLoss
from monai.metrics import DiceMetric
from monai.engines import SupervisedTrainer

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

loss_function = DiceLoss(to_onehot_y=True, softmax=True)
optimizer = torch.optim.Adam(model.parameters(), 1e-4)
metric = DiceMetric(include_background=False, reduction="mean")

trainer = SupervisedTrainer(
    device=device,
    max_epochs=10,
    train_data_loader=loader,
    network=model,
    optimizer=optimizer,
    loss_function=loss_function
)

2. 可视化监控(TensorBoard)

from monai.handlers import TensorBoardStatsHandler

stats_handler = TensorBoardStatsHandler(
    log_dir="./runs",
    writer=None,
    flush_freq=10
)

trainer.handlers.append(stats_handler)

医学影像专用功能

1. 医学坐标系统

from monai.data.meta_tensor import MetaTensor
from monai.transforms.utils import create_grid

# 保留空间元数据
image_tensor = MetaTensor(image_array, affine=affine_matrix)

# 坐标转换
from monai.transforms import Orientation

transform = Orientation(axcodes="RAS")
transformed_image = transform(image_tensor)

2. 3D 可视化

from monai.visualize import plot_2d_or_3d_image

plot_2d_or_3d_image(
    data=sample["image"],
    step=0,
    writer=None,
    frame_dim=-1,
    tag="input_image"
)

实战案例

1. 3D 医学图像分割

# 数据加载
from monai.data import DecathlonDataset

dataset = DecathlonDataset(
    root_dir="/path/to/BraTS2021",
    task="Task01_BrainTumour"
)

# 模型定义
from monai.networks.nets import UNet

model = UNet(
    spatial_dims=3,
    in_channels=4,
    out_channels=3,
    channels=(16, 32, 64, 128, 256),
    strides=(2, 2, 2, 2)
)

# 损失函数
loss_function = DiceLoss(to_onehot_y=True, softmax=True)

2. 多模态分类

from monai.networks.nets import TwoStreamFusionNet

model = TwoStreamFusionNet(
    modality1="MRI",
    modality2="PET",
    backbone="resnet18",
    num_classes=2
)

注意事项

  1. 医学影像格式:
    • 优先使用 NIfTI (.nii.gz) 或 ITK 格式
    • 使用 nibabel 或 SimpleITK 验证数据
  1. 内存优化:
   from monai.data import CacheDataset
   dataset = CacheDataset(data, transforms, cache_num=20)  # 预加载缓存
   
  1. 切片方向问题:
   from monai.transforms import Flip
   transform = Flip(spatial_axis=2)  # 根据医学坐标轴调整
   
  1. 类别不平衡处理:
   loss_function = DiceLoss(
       to_onehot_y=True,
       softmax=True,
       include_background=False
   )
   
  1. 调试技巧:
    • 使用 monai.utils.print_debug_info() 检查环境
    • 使用 torchvision.utils.make_grid() 可视化中间特征

扩展与优化

1. 分布式训练

# 启动多进程训练
torchrun --nproc_per_node=4 train.py
from monai.engines import SupervisedTrainer
from torch.nn.parallel import DistributedDataParallel

model = DistributedDataParallel(model)

2. 模型导出

from monai.export import export_onnx

export_onnx(
    model=model,
    inputs=[torch.randn(1, 1, 128, 128, 128)],
    filename="model.onnx",
    dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}
)

总结

MONAI 的核心优势在于:

  • 医学影像专用:原生支持 3D/4D 数据、医学坐标系统
  • 模块化设计:可灵活组合 transforms、模型、损失函数
  • 生产就绪:支持分布式训练、ONNX 导出、TensorRT 加速
  • 社区支持:活跃的开源社区,持续更新医学影像最新算法

进一步学习: