MONAI 0.9 版本技术解读:Bundle 模型打包、医学图像目标检测、Swin Transformer 与 MetaTensor 预览
【免费下载链接】MONAIAI Toolkit for Healthcare Imaging项目地址: https://gitcode.com/GitHub_Trending/mo/MONAI
本指南基于 MONAI 0.9 版本发布说明(docs/source/whatsnew_0_9.md),系统梳理该版本引入的五大核心能力:MONAI Bundle 标准化模型打包格式、医学图像中的目标检测组件(RetinaNet 2D/3D)、用于三维医学图像分析的 Swin UNETR、DeepEdit/NuClick 交互式分割组件,以及作为数据表示重构第一步的 MetaTensor/MetaObj API 预览。读完本文,你将掌握 0.9 版本的关键 API 用法、各模块在仓库中的代码位置与调用方式,并能直接基于这些组件搭建可复用的深度学习工作流。
版本总览:0.9 的五个关键主题
MONAI 0.9 是一次面向"可复用性"与"新范式"的里程碑式发布,发布说明开篇即列出五个主题:
- MONAI Bundle:定义可移植的深度学习模型描述格式,贯穿模型开发生命周期;
- Object detection in medical images:面向医学图像的定位与分类工作流,包含 RetinaNet 网络与 2D/3D 边界框处理;
- Swin Transformers for 3D medical image analysis:将 Swin UNETR 引入 MONAI,支持三维多器官分割;
- New interactive segmentation components:集成 DeepEdit 与 NuClick 等交互式分割工作流组件;
- MetaTensor API preview:数据表示层面的重大重构,新增
MetaTensor与MetaObj核心数据结构。
下文按这五个主题逐一展开,每个部分都会给出仓库内的源码佐证与实操入口。
MONAI Bundle:标准化的模型打包与配置驱动工作流
设计目标与核心收益
MONAI Bundle 定义了一种可移植的深度学习模型描述格式,一个 bundle 中包含模型开发生命周期中的关键信息,让用户和程序都能理解模型的用途与用法。发布说明总结的monai.bundleAPI 收益包括:
- 标准化打包格式:统一的模型存储与分享方式;
- 结构化配置文件:用于深度学习工作流的快速原型设计;
- 易用的编程 API:将超参数设置与 Python 代码分离;
- 灵活的配置组件:允许接入不同的底层 Python 实现;
- 解耦组件细节:让联邦学习(federated learning)与 AutoML 等高层学习范式不再关心组件内部实现。
从仓库结构看,monai/bundle/目录(monai/bundle)是 0.9 引入的独立子包,包含config_item.py(ConfigItem/ConfigComponent/ConfigExpression三类配置项的定位与实例化)、config_parser.py(ConfigParser主解析器)、reference_resolver.py($@ref引用解析器)、properties.py、scripts.py、workflows.py与__main__.py(提供命令行入口)。
ConfigParser:配置即代码的解析核心
ConfigParser是 Bundle 体系中最核心的入口类,位于 monai/bundle/config_parser.py。它遍历结构化的配置源(嵌套 dict 或 list),为每个配置项创建带唯一 ID 的ConfigItem,并支持通过 ID 便捷访问。其典型工作流为:
- 用配置源初始化
ConfigParser; - 调用
get_parsed_content()按 ID 获取目标组件(可选实例化)。
配置语法由三类符号驱动:
$前缀表示表达式(ConfigExpression),如"$@my_dims + 1",可使用globals中预置的模块(默认注入monai、torch、np/numpy作为全局变量);@前缀表示引用(ReferenceResolver),如"@my_net"指向同配置中的另一个节点,支持::(或#)层级分隔与相对 ID(@#同级、@##上一级);%前缀表示宏(macro),可从其他配置文件引入片段,如"%/data/config.json#net";_target_键声明组件目标(ConfigComponent),ComponentLocator会依据该字符串从monai命名空间或用户传入模块中定位类并实例化。
官方 docstring 中的最小示例展示了完整用法(config_parser.py):
from monai.bundle import ConfigParser config = { "my_dims": 2, "dims_1": "$@my_dims + 1", "my_xform": {"_target_": "LoadImage"}, "my_net": {"_target_": "BasicUNet", "spatial_dims": "@dims_1", "in_channels": 1, "out_channels": 4}, "trainer": {"_target_": "SupervisedTrainer", "network": "@my_net", "preprocessing": "@my_xform"} } parser = ConfigParser(config) # 实例化前可读写配置(set 需发生在 parse 之前) parser["my_net"]["in_channels"] = 4 # 解析并实例化网络组件 parser.parse(True) net = parser.get_parsed_content("my_net", instantiate=True)从当前仓库源码可以看到,ConfigParser已支持点号链式访问(parser.training.trainer.max_epochs等价于parser.get_parsed_content("training::trainer::max_epochs"))、JSON/YAML 配置文件的加载合并(load_config_files)、以及配置导出(export_config_file)。
真实 Bundle 配置示例
仓库测试数据 tests/testing_data/config_fl_train.json 提供了可直接阅读的完整 Bundle 配置骨架,它演示了如何用 JSON 描述一套完整的监督训练工作流:
{ "bundle_root": "tests/testing_data", "dataset_dir": "@bundle_root", "val_interval": 1, "imports": ["$import os"], "device": "$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')", "network_def": { "_target_": "DenseNet121", "spatial_dims": 2, "in_channels": 1, "out_channels": 6 }, "network": "$@network_def.to(@device)", "loss": {"_target_": "torch.nn.CrossEntropyLoss"}, "optimizer": { "_target_": "torch.optim.Adam", "params": "$@network.parameters()", "lr": 0.0001 } }该配置体现了 Bundle 的几个关键设计点:
"dataset_dir": "@bundle_root"是引用:@bundle_root引用了同配置中的根路径;"device": "$torch.device(...)"是表达式:利用预置全局变量torch动态计算设备;"network_def"是组件定义:_target_为DenseNet121,而"network": "$@network_def.to(@device)"又通过表达式对组件实例做.to(device)调用;train/validate两节分别组织 transforms(LoadImaged、EnsureChannelFirstD、ScaleIntensityd、RandRotated、RandFlipd、RandZoomd等)、Dataset/DataLoader、inferer、handlers、trainer/evaluator 与 metric;- 顶层还有
initialize/run/finalize三个表达式列表,如"$monai.utils.set_determinism(seed=123)"与"$@train#trainer.run()",分别对应生命周期的初始化、执行与收尾动作。
这种"配置驱动"模式正是 Bundle 解耦超参数与 Python 代码的核心体现:训练逻辑(SupervisedTrainer、DataLoader)完全由配置描述,修改网络结构、学习率、数据增强策略都无需改动代码。相关测试可参考 tests/bundle/test_config_parser.py 与 tests/bundle/test_reference_resolver.py。更多教程式内容在仓库文档 docs/source/bundle_intro.rst 中有系统介绍。
医学图像中的目标检测:RetinaNet 2D/3D 组件
模块组成
0.9 发布说明指出,该版本提供了目标定位与分类工作流的基础组件:2D/3D 边界框处理、RetinaNet 网络块与架构、以及基于坐标的预处理、难负样本采样等通用工具。这些应用级模块位于 monai/apps/detection,按功能划分为:
| 子目录 | 职责 | 关键文件 |
|---|---|---|
networks/ | RetinaNet 检测器与骨干网络 | retinanet_detector.py、retinanet_network.py |
transforms/ | 坐标/边界框相关预处理与后处理 | array.py、dictionary.py、box_ops.py |
utils/ | 锚框、匹配、编码、采样等工具 | anchor_utils.py、ATSS_matcher.py、box_coder.py、box_selector.py、hard_negative_sampler.py、predict_utils.py、detector_utils.py |
metrics/ | COCO 指标与匹配 | coco.py、matching.py |
RetinaNetDetector 的输入输出契约
RetinaNetDetector(monai/apps/detection/networks/retinanet_detector.py)是一个单阶段、基于锚框(anchor)的目标检测器,支持 2D(C,H,W)与 3D(C,H,W,D)输入。其接口契约如下:
- 输入:一个 tensor 列表(每个元素
(C,H,W)或(C,H,W,D),像素值在 0-1 范围,各图尺寸可不同),或一个(B,C,H,W[,D])的批量 tensor; - 训练模式:额外接收 targets(dict 列表),包含
boxes(FloatTensor[N,4]或FloatTensor[N,6],StandardMode即[xmin,ymin,xmax,ymax]或[xmin,ymin,zmin,xmax,ymax,zmax]格式)与labels;返回包含分类损失与回归损失的Dict[str, Tensor]; - 推理模式:仅需输入,返回后处理后的
List[Dict[Tensor]],每个元素含boxes与对应分数等字段。
从源码 import 关系可以看出完整的检测流水线:AnchorGenerator生成多尺度锚框,ATSSMatcher(Adaptive Training Sample Selection)完成正负样本匹配,BoxCoder负责边界框编解码,HardNegativeSampler处理难负样本挖掘,BoxSelector做预测框筛选(NMS 等),resnet_fpn_feature_extractor提供 ResNet+FPN 骨干。这与 torchvision 的 RetinaNet 有渊源(源码注释标注其改编自 pytorch/vision 的 retinanet.py 并保留 BSD-3-Clause 许可),但针对医学图像扩展了 3D 支持。
围绕该模块,仓库还配套了完整的单元测试(tests/apps/detection,共 14 个测试文件)与边界框工具库 monai/data/box_utils.py(提供box_iou、模式转换等函数),可直接用于评估检测结果的 IoU 计算。
Swin Transformers 用于三维医学图像分析
Swin UNETR 在 MONAI 中的实现
0.9 版本在核心库中实现了Swin UNETR模型,其论文出处为 "Hatamizadeh et al., Swin UNETR: Swin Transformers for Semantic Segmentation of Brain Tumors in MRI Images"(monai/networks/nets/swin_unetr.py 的类注释)。该模型将 3D Swin Transformer 作为编码器,与 U 形解码器结构结合,支持多器官分割等任务,发布说明提到其编码器权重可来自在公开数据集 5050 例 CT 扫描上进行的自监督预训练。
Swin UNETR 的关键构造参数(swin_unetr.py)包括:
in_channels/out_channels:输入与输出通道数;patch_size(默认 2):patch token 尺寸,输入各空间维度必须能被patch_size ** 5整除(默认即被 32 整除),这一约束源于 patch embedding 之后接 4 个 PatchMerging 下采样阶段、每阶段空间分辨率减半的结构;合法输入例如(32,32,32)、(96,96,96)、(128,128,128)、(64,32,192),否则forward()会抛出ValueError;depths(默认(2,2,2,2))与num_heads(默认(3,6,12,24)):每个 stage 的 Transformer 层数与注意力头数;window_size(默认 7):局部窗口大小;feature_size(默认 24):网络特征维度;mlp_ratio(默认 4.0):MLP 隐藏维度与嵌入维度之比;norm_name(默认"instance"):特征归一化类型;drop_rate/attn_drop_rate/dropout_path_rate:dropout 与 drop path 比率;use_checkpoint(默认 False):启用梯度检查点以降低显存占用;spatial_dims(默认 3):支持 2D/3D;downsample:下采样模块,可选"mergingv2"、"merging"(0.9.0 原始版本,默认)或自定义nn.Module;use_v2:使用 swinunetr_v2 变体(每个 Swin stage 起始处增加残差卷积块)。
典型用法示例(来自源码 docstring):
# 3D 单通道输入 (96,96,96),4 类输出,feature_size=48 net = SwinUNETR(in_channels=1, out_channels=4, feature_size=48) # 3D 4 通道输入 (128,128,128),3 类输出,各 stage 层数 (2,4,2,2) net = SwinUNETR(in_channels=4, out_channels=3, depths=(2, 4, 2, 2)) # 2D 输入 (96,96),启用梯度检查点 net = SwinUNETR(in_channels=3, out_channels=2, use_checkpoint=True, spatial_dims=2)从源码结构看,Swin UNETR 由PatchEmbed、SwinTransformerBlock(基于window_partition/window_reverse与WindowAttention)、PatchMerging、UnetrBasicBlock、UnetrUpBlock、UnetOutBlock等 monai/networks/blocks 中的基础块组装而成,其中MLPBlock、PatchEmbed等在 blocks 子包中均有独立实现。仓库还提供了配套测试 tests/networks/nets/test_swin_unetr.py,可用于验证前向传播与形状约束。由于 Swin Transformer 为视觉任务通用结构,该实现也可在 2D 设置下使用(spatial_dims=2)。
新的交互式分割组件:DeepEdit 与 NuClick
0.9 将深度学习交互式分割工作流中的新组件整合进核心代码库,作为 MONAILabel 最新功能的构建基础,主要包括DeepEdit与NuClick两条工作流,分别位于:
- monai/apps/deepedit:核心为
Interaction类(interaction.py)与一整套变换(transforms.py); - monai/apps/deepgrow:核心为
Interaction类(interaction.py)与对应变换(transforms.py)。
DeepEdit 的 transforms 模块(monai/apps/deepedit/transforms.py)包含一整套"交互信号 → 训练样本"的变换链,例如:
AddInitialSeedPointDeepEditd:随机初始化首个种子点(模拟用户首次点击);AddGuidanceSignalDeepEditd:将点击/涂鸦(scribble)编码为高斯引导信号,叠加到输入上;AddRandomGuidanceDeepEditd:在训练中随机追加新引导点,模拟迭代式交互;AddGuidanceFromPointsDeepEditd/ResizeGuidanceMultipleLabelDeepEditd:从点生成引导并处理多标签缩放;FindDiscrepancyRegionsDeepEditd:找到预测与标签不一致区域,用于主动式交互采样;DiscardAddGuidanced、SplitPredsLabeld、RemapLabelsToSequentiald(标签重映射为连续整数,NormalizeLabelsInDatasetd为其向后兼容别名)等辅助变换。
DeepGrow 的 transforms 模块(monai/apps/deepgrow/transforms.py)提供AddInitialSeedPointd、AddGuidanceSignald、AddRandomGuidanced、FindDiscrepancyRegionsd、SpatialCropForegroundd、SpatialCropGuidanced、ResizeGuidanced、RestoreLabeld、Fetch2DSliced等,其中RestoreLabeld用于在推理后将裁剪区域的分割结果恢复到原始空间。
这些组件与Interaction类共同构成"点击驱动"的训练/推理闭环:模型根据初始种子点或迭代新增的引导信号产出分割,再通过 discrepancy 区域发现来挑选下一次交互位置。配套测试位于 tests/apps/deepedit 与 tests/apps/deepgrow。
MetaTensor API 预览:数据表示重构的第一步
背景:为什么需要元数据感知的张量
发布说明指出,主要医学影像模态(CT/MRI 等)关联的元数据在许多生物医学应用中至关重要,尤其是 MONAI 一直聚焦的数据驱动方法。因此 0.9 开始了数据表示层面的重大重构,第一步即实现核心数据结构MetaTensor与MetaObj,作为feature preview(功能预览),后续里程碑版本将在此基础上继续演进。
源码实现与核心特性
MetaObj(monai/data/meta_obj.py)是抽象基类,通过多重继承让子类(如torch.Tensor与np.ndarray)附加元数据存储能力。其内部状态包括:
_meta(dict):元数据字典,默认{},其中嵌套存放 affine 矩阵等;_applied_operations(list):已应用的变换操作记录;_pending_operations(list):待应用的变换操作(服务于懒执行);_is_batch(bool):是否为批量数据;_spatial_ndim(int):空间维度数,默认 3。
MetaTensor(monai/data/meta_tensor.py)同时继承MetaObj与torch.Tensor,行为与torch.Tensor一致但扩展了元数据功能。其构造签名支持affine、meta、applied_operations、spatial_ndim等参数,官方示例:
import torch from monai.data import MetaTensor t = torch.tensor([1, 2, 3]) affine = torch.as_tensor([[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 1]], dtype=torch.float64) m = MetaTensor(t, affine=affine, meta={"some": "info"}) m2 = m + m assert isinstance(m2, MetaTensor) assert m2.meta["some"] == "info" assert torch.all(m2.affine == affine)使用要点与限制(来自源码注释):
- 运算结果自动保留元数据:
c = a + b时,若a.is_batch为 False,则从第一个MetaObj实例复制辅助数据;批量数据为效率考虑做浅拷贝; - 构建批量数据时应使用
monai.data.DataLoader(而非torch.utils.data.DataLoader),以便正确 collate 元数据; - 批量语义:
batch[0]返回第 0 张图及其元数据;batch[:, 0]、batch[..., -1]、batch[1:3]等非单元素切片会返回(部分)元数据并将is_batch置为 True; - 需要 PyTorch 1.9 或更新版本以获得完整兼容性;更早版本在
torch.jit.trace、跨进程共享等方面有已知限制(可用as_tensor()规避 trace 问题); - 若构造函数中
affine非 None 且meta已含affine键,会触发警告。
applied_operations/pending_operations的存在为后续"变换可逆性"(invertible transforms)与懒加载采样(lazy resampling)等高级特性预留了数据基础,这也是 0.9 之后 MONAI 数据管线演进的基石。相关测试位于 tests/data/meta_tensor。
总结与升级建议
MONAI 0.9 通过五大主题确立了后续版本的技术方向:
- Bundle提供了"配置即代码"的模型打包与复用范式,
ConfigParser以$/@/%/_target_四种语法统一了表达式、引用、宏与组件实例化,使模型可以在不同项目与联邦学习、AutoML 等上层框架间流转; - 检测组件补齐了医学图像目标定位能力,
RetinaNetDetector同时支持 2D/3D 边界框,配套的锚框生成、ATSS 匹配、BoxCoder、难负样本采样与 COCO 指标形成完整闭环; - Swin UNETR将 Transformer 架构带入 3D 医学图像分割,需注意输入尺寸须能被
patch_size ** 5整除的约束; - DeepEdit/NuClick交互式组件让标注与分割形成人机协同工作流,也是 MONAILabel 的底层构建块;
- MetaTensor/MetaObj预览标志着数据表示从"纯张量 + 外部元数据"向"元数据感知张量"的迁移开始,是后续可逆变换与懒执行特性的地基。
升级到 0.9 及以后版本时,建议优先体验 Bundle 的配置驱动开发流程(可参考 tests/testing_data/config_fl_train.json 等仓库内置配置),并关注 MetaTensor 相关 API 的演进——它虽为预览特性,但会影响后续所有数据管线代码的写法。
【免费下载链接】MONAIAI Toolkit for Healthcare Imaging项目地址: https://gitcode.com/GitHub_Trending/mo/MONAI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考