MONAI入门介绍

MONAI入门介绍

​ MONAI (Medical Open Network for AI) 是一个专注于医疗图像处理的深度学习框架。下面我们将介绍如何使用 MONAI 进行数据预处理、DataLoader 构建、模型训练以及推理。

文档地址

https://docs.monai.io/en/1.3.1/transforms.html#dictionary-transforms

环境准备

​ 首先,确保安装了 MONAI 和其他必要的库:

pip install monai[all] torch torchvision numpy
  • pip install monai[all]: 这个命令会使用 pip 安装 MONAI 库及其所有依赖项。方括号中的 all 表示安装 MONAI 的全部功能和依赖。MONAI 提供了许多预处理、数据加载、模型构建等用于医疗图像分析的工具和算法。

  • torch torchvision: 这会安装 PyTorch 深度学习框架及其图像处理库 torchvision。PyTorch 是一个广泛使用的深度学习框架,而 torchvision 则包含了一些常用的图像处理功能,如数据集加载、图像转换等。

  • numpy: 这是 Python 中用于科学计算的基础包,用来处理数组和矩阵数据。

导入必要的库

import os
import numpy as np
import torch
from torch.utils.data import DataLoader
from monai.transforms import (
    Compose, LoadImaged, AddChanneld, ScaleIntensityd, ToTensord,
    RandRotate90d, RandFlipd, RandZoomd
)
from monai.data import CacheDataset, Dataset, DataLoader
from monai.networks.nets import UNet
from monai.losses import DiceLoss
from monai.metrics import DiceMetric
from monai.utils import first
from monai.inferers import sliding_window_inference
import matplotlib.pyplot as plt
  1. 导入库和模块:
    • import os: Python 的标准库,用于与操作系统交互,例如文件操作等。
    • import numpy as np: 用于数值计算的库,特别擅长处理数组和矩阵数据。
    • import torch: PyTorch 深度学习框架。
    • from torch.utils.data import DataLoader: PyTorch 中用于批处理和数据加载的工具。
    • from monai.transforms import ...: 导入 MONAI 中的数据转换操作,例如加载图像、添加通道、强度缩放、转换为张量等。
    • from monai.data import CacheDataset, Dataset, DataLoader: 导入 MONAI 中用于处理数据集的类,例如缓存数据集、普通数据集和数据加载器。
    • from monai.networks.nets import UNet: 导入 MONAI 中的 UNet 模型,用于图像分割任务。
    • from monai.losses import DiceLoss: 导入 MONAI 中的 Dice Loss,一种常用于图像分割任务的损失函数。
    • from monai.metrics import DiceMetric: 导入 MONAI 中的 Dice Metric,用于评估分割精度。
    • from monai.utils import first: 导入 MONAI 中的一个实用函数,用于获取迭代器的第一个元素。
    • from monai.inferers import sliding_window_inference: 导入 MONAI 中的滑动窗口推断方法,用于处理大尺寸图像。
  2. 示例中的转换操作(Transforms): 这些转换操作用于预处理和增强图像数据,以准备输入模型进行训练或推断。
    • Compose: 组合多个转换操作。
    • LoadImaged: 加载图像数据。
    • AddChanneld: 添加图像通道维度。
    • ScaleIntensityd: 缩放图像强度。
    • ToTensord: 将图像转换为 PyTorch 张量。
    • RandRotate90d, RandFlipd, RandZoomd: 随机旋转、翻转和缩放图像,用于数据增强。
  3. 其它模块和类:
    • UNet: MONAI 中的 UNet 模型,用于医学图像分割任务。
    • DiceLoss: MONAI 中实现的 Dice Loss 损失函数,用于监督学习中的图像分割损失计算。
    • DiceMetric: MONAI 中的 Dice Metric,用于评估分割精度。
    • sliding_window_inference: MONAI 中的滑动窗口推断方法,用于处理大尺寸图像的推断过程。
    • matplotlib.pyplot as plt: Matplotlib 库中的 pyplot 模块,用于绘制和显示图形。

数据预处理

使用 MONAI 的变换(Transforms)进行数据预处理:

# 定义数据预处理的变换
train_transforms = Compose([
    LoadImaged(keys=['image', 'label']),
    AddChanneld(keys=['image', 'label']),
    ScaleIntensityd(keys=['image', 'label']),
    RandRotate90d(keys=['image', 'label'], prob=0.5),
    RandFlipd(keys=['image', 'label'], prob=0.5),
    RandZoomd(keys=['image', 'label'], prob=0.2, min_zoom=0.9, max_zoom=1.1),
    ToTensord(keys=['image', 'label'])
])

val_transforms = Compose([
    LoadImaged(keys=['image', 'label']),
    AddChanneld(keys=['image', 'label']),
    ScaleIntensityd(keys=['image', 'label']),
    ToTensord(keys=['image', 'label'])
])
1.训练集部分:

LoadImaged(keys=['image', 'label']):

  • 加载图像和标签数据,假设数据中包含 ‘image’ 和 ‘label’ 这两类数据。

AddChanneld(keys=['image', 'label']):

  • 给 ‘image’ 和 ‘label’ 数据添加一个通道维度,通常是将灰度图像转换为 RGB 格式将单通道标签图像处理为多通道

ScaleIntensityd(keys=['image', 'label']):

  • 对 ‘image’ 和 ‘label’ 数据进行强度缩放,通常是将像素值缩放到一个固定范围,如 [0, 1] 或 [-1, 1]。

RandRotate90d(keys=['image', 'label'], prob=0.5):

  • 随机对 ‘image’ 和 ‘label’ 数据进行90度的旋转,概率为0.5,即每次旋转的概率为50%。

RandFlipd(keys=['image', 'label'], prob=0.5):

  • 随机对 ‘image’ 和 ‘label’ 数据进行水平或垂直翻转,概率为0.5,即每次翻转的概率为50%。

RandZoomd(keys=['image', 'label'], prob=0.2, min_zoom=0.9, max_zoom=1.1):

  • 随机对 ‘image’ 和 ‘label’ 数据进行缩放,缩放比例在 [0.9, 1.1] 范围内,概率为0.2,即每次缩放的概率为20%。

ToTensord(keys=['image', 'label']):

  • 将 ‘image’ 和 ‘label’ 数据转换为 PyTorch 张量,以便输入到深度学习模型中。
2.验证集部分:

LoadImaged(keys=['image', 'label']):

  • 同样,加载验证集中的图像和标签数据。

AddChanneld(keys=['image', 'label']):

  • 给图像和标签数据添加通道维度。

ScaleIntensityd(keys=['image', 'label']):

  • 对图像和标签数据进行强度缩放。

ToTensord(keys=['image', 'label']):

  • 将图像和标签数据转换为 PyTorch 张量。

构建 DataLoader

使用 MONAI 构建训练和验证的 DataLoader:

# 定义数据字典
train_files = [{'image': 'path/to/image1.nii', 'label': 'path/to/label1.nii'}, 
               {'image': 'path/to/image2.nii', 'label': 'path/to/label2.nii'}, ...]
val_files = [{'image': 'path/to/image3.nii', 'label': 'path/to/label3.nii'}, ...]

# 构建数据集
train_ds = CacheDataset(data=train_files, transform=train_transforms, cache_rate=1.0)
val_ds = CacheDataset(data=val_files, transform=val_transforms, cache_rate=1.0)

# 构建 DataLoader
train_loader = DataLoader(train_ds, batch_size=2, shuffle=True, num_workers=4)
val_loader = DataLoader(val_ds, batch_size=1, shuffle=False, num_workers=4)
1.定义数据字典
  • train_files: 是一个列表,每个元素是一个字典,包含了训练集中每个样本的图像和对应的标签文件路径。例如,'image': 'path/to/image1.nii' 表示第一个样本的图像文件路径,'label': 'path/to/label1.nii' 表示对应的标签文件路径。

  • val_files: 类似于 train_files,包含了验证集中每个样本的图像和标签文件路径。

2.构建数据集

CacheDataset: 是 MONAI 中的一个数据集类,用于加载和管理数据。参数包括:

  • data: 数据字典列表,即 train_filesval_files
  • transform: 数据预处理变换,分别是 train_transformsval_transforms,用于对数据进行预处理。
  • cache_rate: 缓存率,设置为 1.0 表示缓存所有数据,可以加快训练速度。
3.构建DataLoader

DataLoader: 是 PyTorch 中的数据加载器,用于批量加载数据并提供数据的迭代器。参数包括:

  • train_dsval_ds: 分别是之前构建的训练集和验证集数据集对象。
  • batch_size: 每个批次的样本数,这里训练集设为 2,验证集设为 1
  • shuffle: 是否在每个 epoch 开始前打乱数据,训练集设为 True,验证集设为 False
  • num_workers: 加载数据时使用的子进程数,可以加速数据加载过程。

构建模型、损失函数和优化器

# 构建 UNet 模型
model = UNet(
    dimensions=3,
    in_channels=1,
    out_channels=2,
    channels=(16, 32, 64, 128, 256),
    strides=(2, 2, 2, 2),
    num_res_units=2
).cuda()

# 定义损失函数和优化器
loss_function = DiceLoss(to_onehot_y=True, softmax=True)
optimizer = torch.optim.Adam(model.parameters(), 1e-4)
1.构建 UNet 模型

UNet: 是 MONAI 中提供的 UNet 模型类,用于图像分割任务。

  • dimensions=3: 指定模型处理的数据维度数,这里是三维的医学图像数据。
  • in_channels=1: 输入图像的通道数,这里假设输入是单通道的灰度图像。
  • out_channels=2: 输出的通道数,通常用于分割任务,表示预测两类(如前景和背景)。
  • channels=(16, 32, 64, 128, 256): UNet 模型中各个层级的通道数设置,从浅层到深层依次增加。
  • strides=(2, 2, 2, 2): UNet 模型中各个层级的步长设置,决定了每个池化操作的缩减程度。
  • num_res_units=2: UNet 模型中每个层级的残差单元数,用于增强模型学习能力和稳定性。

.cuda(): 将模型移动到 GPU 上进行加速计算,如果没有 GPU,则不需要这一步。

2.定义损失函数和优化器

DiceLoss: 是 MONAI 中实现的 Dice Loss 损失函数,常用于图像分割任务。

  • to_onehot_y=True: 表示将输入的标签转换为 one-hot 编码形式,用于计算 Dice Loss。
  • softmax=True: 表示在计算 Dice Loss 之前对模型的输出进行 softmax 操作。

torch.optim.Adam(model.parameters(), 1e-4): 使用 Adam 优化器来优化模型参数。

  • model.parameters(): 获取模型中所有需要训练的参数。
  • 1e-4: Adam 优化器的学习率,这里设置为 0.0001。

训练模型

定义训练和验证过程:

# 训练和验证过程
max_epochs = 100
val_interval = 2
dice_metric = DiceMetric(include_background=True, reduction="mean", get_not_nans=False)

best_metric = -1
best_metric_epoch = -1
epoch_loss_values = []
metric_values = []

for epoch in range(max_epochs):
    print("-" * 10)
    print(f"epoch {epoch + 1}/{max_epochs}")
    model.train()
    epoch_loss = 0
    step = 0
    for batch_data in train_loader:
        step += 1
        inputs, labels = batch_data["image"].cuda(), batch_data["label"].cuda()
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = loss_function(outputs, labels)
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
    epoch_loss /= step
    epoch_loss_values.append(epoch_loss)
    print(f"epoch {epoch + 1} average loss: {epoch_loss:.4f}")

    if (epoch + 1) % val_interval == 0:
        model.eval()
        with torch.no_grad():
            metric = 0
            metric_count = 0
            for val_data in val_loader:
                val_inputs, val_labels = val_data["image"].cuda(), val_data["label"].cuda()
                val_outputs = sliding_window_inference(val_inputs, (96, 96, 96), 4, model)
                value = dice_metric(y_pred=val_outputs, y=val_labels)
                metric += value.item()
                metric_count += 1
            metric /= metric_count
            metric_values.append(metric)
            if metric > best_metric:
                best_metric = metric
                best_metric_epoch = epoch + 1
                torch.save(model.state_dict(), "best_metric_model.pth")
            print(f"current epoch: {epoch + 1} current mean dice: {metric:.4f}")
            print(f"best mean dice: {best_metric:.4f} at epoch: {best_metric_epoch}")

​ 这段代码实现了一个简单的 UNet 模型的训练和验证过程。通过循环迭代每个 epoch,在每个 epoch 中进行训练和验证操作。训练阶段通过计算损失函数并优化模型参数,验证阶段通过评估指标(这里是 Dice 系数)来评估模型的性能,并记录最佳指标及其对应的模型状态。这种训练和验证的循环过程可以帮助优化模型,并监控模型在验证集上的表现。

1.设置训练参数和评估指标
  • max_epochs: 总的训练轮数,这里设置为 100。

  • val_interval: 每隔多少个 epoch 进行一次验证集的评估,这里设置为 2。

  • dice_metric: DiceMetric 是 MONAI 中用于计算 Dice 系数的类。

    • include_background=True: 包括背景类在内的所有类别。

    • reduction="mean": 计算 Dice 系数的方式为取平均值。

    • get_not_nans=False: 在计算 Dice 系数时不考虑 NaN 值。

2.初始化训练过程的变量和数据结构
  • best_metric: 记录最佳的评估指标(这里是 Dice 系数),初始化为 -1。
  • best_metric_epoch: 记录达到最佳指标时的 epoch 数,初始化为 -1。
  • epoch_loss_values: 记录每个 epoch 的平均损失值。
  • metric_values: 记录每个验证阶段的评估指标(这里是 Dice 系数)。
3.主训练循环
  • for epoch in range(max_epochs): 开始迭代每个 epoch。
4.训练阶段
  • model.train(): 将模型设置为训练模式,启用 Batch Normalization 和 Dropout 等。

  • train_loader: 是之前定义的训练集 DataLoader,用于批量加载训练数据。

  • 循环遍历每个 batch 的数据,将数据和标签移动到 GPU 上,通过前向传播计算输出并计算损失,然后反向传播更新模型参数。

  • epoch_loss /= step: 计算当前 epoch 的平均损失,并将其添加到 epoch_loss_values 列表中。

5.验证阶段
  • (epoch + 1) % val_interval == 0: 每隔 val_interval 个 epoch 执行一次验证阶段。

  • model.eval(): 将模型设置为评估模式,此时不会启用 Batch Normalization 和 Dropout 等。

  • torch.no_grad(): 在评估阶段,不需要计算梯度,因此使用 torch.no_grad() 块以减少内存消耗和加速计算。

  • sliding_window_inference(val_inputs, (96, 96, 96), 4, model): 使用滑动窗口推断方法对验证集数据进行预测。

  • dice_metric(y_pred=val_outputs, y=val_labels): 计算预测输出和真实标签之间的 Dice 系数。

  • 计算并记录当前 epoch 的 Dice 系数,并更新 metric_values 列表。

  • 如果当前 epoch 的 Dice 系数优于历史最佳指标 best_metric,则更新 best_metricbest_metric_epoch,并保存模型的状态字典到文件 “best_metric_model.pth”。

  • 打印当前 epoch 的评估结果和历史最佳指标。

推理

使用训练好的模型进行推理:

# 加载最佳模型
model.load_state_dict(torch.load("best_metric_model.pth"))

# 进行推理
model.eval()
with torch.no_grad():
    for i, test_data in enumerate(val_loader):
        test_images, test_labels = test_data["image"].cuda(), test_data["label"].cuda()
        test_outputs = sliding_window_inference(test_images, (96, 96, 96), 4, model)
        test_outputs = torch.argmax(test_outputs, dim=1).detach().cpu().numpy()
        
        # 可视化推理结果
        plt.figure("check", (18, 6))
        plt.subplot(1, 3, 1)
        plt.title("image")
        plt.imshow(test_images[0, 0, :, :, 50].cpu(), cmap="gray")
        plt.subplot(1, 3, 2)
        plt.title("label")
        plt.imshow(test_labels[0, 0, :, :, 50].cpu())
        plt.subplot(1, 3, 3)
        plt.title("output")
        plt.imshow(test_outputs[0, :, :, 50])
        plt.show()

​ 这段代码加载了经过训练和验证的最佳模型,并使用该模型对验证集或测试集的数据进行推理。推理过程中,首先将模型设置为评估模式,然后通过滑动窗口推断方法对每个数据样本进行预测,最后将预测结果和真实标签进行可视化展示。这种推理和可视化过程有助于直观地理解模型在图像分割任务中的表现和效果。

1.加载最佳模型
  • torch.load("best_metric_model.pth"): 使用 PyTorch 的 torch.load 函数加载之前保存的最佳模型的状态字典。这个文件路径 "best_metric_model.pth" 需要根据你实际保存的模型文件名来指定。

  • model.load_state_dict(): 将加载的模型状态字典加载到预先定义的模型 model 中,以恢复训练时的模型参数和状态。

2.进行推理
  • model.eval(): 将模型设置为评估模式,确保在推理过程中不启用 Dropout 和 Batch Normalization。

  • torch.no_grad(): 在推理过程中不需要计算梯度,使用 torch.no_grad() 上下文管理器以减少内存消耗和加速计算。

  • val_loader: 是之前定义的验证集 DataLoader,用于批量加载验证集数据。

  • sliding_window_inference(test_images, (96, 96, 96), 4, model): 使用滑动窗口推断方法对验证集或测试集数据进行预测。这里的参数 (96, 96, 96) 表示滑动窗口的大小,4 表示滑动窗口的步长。

  • torch.argmax(test_outputs, dim=1): 对模型输出的概率分布取最大值的索引,得到预测的类别标签。

  • .detach().cpu().numpy(): 将张量从 GPU 转移到 CPU,并转换为 NumPy 数组,以便后续的可视化处理。

3.可视化推理结果
  • plt.figure("check", (18, 6)): 创建一个名为 “check” 的图形窗口,大小为 (18, 6) 英寸。

  • plt.subplot(1, 3, 1): 将窗口分成一行三列,当前操作在第一列中。

  • plt.title("image"): 设置第一列的标题为 “image”。

  • plt.imshow(test_images[0, 0, :, :, 50].cpu(), cmap="gray"): 显示测试图像的切片(在这里是第 50 层),使用灰度颜色映射显示。

  • plt.subplot(1, 3, 2): 切换到第二列,用于显示真实标签。

  • plt.title("label"): 设置第二列的标题为 “label”。

  • plt.imshow(test_labels[0, 0, :, :, 50].cpu()): 显示真实标签的切片图像。

  • plt.subplot(1, 3, 3): 切换到第三列,用于显示模型预测结果。

  • plt.title("output"): 设置第三列的标题为 “output”。

  • plt.imshow(test_outputs[0, :, :, 50]): 显示模型预测输出的切片图像。

  • plt.show(): 显示所有子图。

​ 以上代码展示了如何使用 MONAI 进行数据预处理、DataLoader 构建、模型训练以及推理。根据具体任务和数据集,可以调整变换、模型参数以及训练过程中的细节。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
阿里的DataV和京东的莫奈都是优秀的大数据可视化平台,但是在以下几个方面存在一些差异: 1. 技术架构:DataV采用了基于Kubernetes的容器化架构,可以快速扩展、自动化部署和管理,同时支持多云部署;莫奈则采用了基于Spark的分布式计算架构,支持GPU加速,能够快速处理大规模数据。 2. 用户群体:DataV更注重企业级用户,提供了丰富的企业级功能和服务,支持多种数据源接入,适用于金融、电商、物流等行业的大屏展示和实时监控;而莫奈则更注重学术机构、政府部门等研究型用户,提供了多种数据挖掘和预测分析算法和模型。 3. 功能模块:DataV提供了多种实时数据接入和展示方式,支持多种数据可视化图表和报表,同时提供了数据分析和预测分析算法和模型;而莫奈则更注重数据挖掘和预测分析功能,提供了更加多样化的算法和模型库,同时支持地图可视化和物联网数据接入。 4. 扩展性:DataV提供了插件式开发和二次开发的方式,可以灵活地进行定制和扩展,支持多种开发语言和框架;而莫奈则更注重算法和模型的扩展和优化,提供了多种扩展方式和可配置参数。 综上所述,阿里的DataV和京东的莫奈都是优秀的大数据可视化平台,但是在技术架构、用户群体、功能模块和扩展性方面存在一些差异。用户可以根据自身需求选择不同的平台,或者结合两个平台的优势进行定制开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li小李同学Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值