使用 MONAI Deploy 在 AMD GPU 上进行全身分割

Total body segmentation using MONAI Deploy on an AMD GPU — ROCm Blogs

2024 年 4 月 4 日 作者: Vara Lakshmi Bayanagari.

医疗开放网络人工智能(MONAI)是一个开源组织,提供最先进的医疗成像模型的 PyTorch 实现,涵盖从分类和分割到图像生成的各个方面。MONAI 的生命周期为研究人员、临床医生和同领域的贡献者提供了三种不同的端到端工作流工具:MONAI Core、MONAI Label 和 MONAI Deploy。

MONAI Core 提供可用于端到端训练和推理的模型。MONAI Label 是一个智能工具,可基于用户交互自动标记数据集。MONAI Deploy 是一个打包工具,提供命令行接口(CLI)命令(如 monai-deploy exec、`monai-deploy package`)来部署可以投入生产的 AI 应用程序。此外,它允许将您的应用程序打包成 MAP/Docker 镜像,可以使用 monai-deploy run 命令运行。MONAI Deploy 提供了打包的示例应用程序(例如脾脏分割和乳腺密度分类)。

正如MONAI 的教程所解释的那样,创建一个应用程序/SDK 需要我们定义一组运算符,这些运算符将按顺序执行。运算符是应用程序中的一个工作单元,可以有多个虚拟输入/输出端口。每个端口通过将前一个运算符的输出端口的输出传递给当前运算符的输入端口,从而促进应用程序的进展。例如,脾脏分割应用程序的官方教程使用了五个预定义的运算符:

  • DICOMDataLoaderOperator: 从输入文件夹中的 .dcm 文件加载 DICOM(标准医疗体积存储格式)研究。

  • DICOMSeriesSelectorOperator: L根据规则集从每个 DICOM 研究中加载特定数据系列。该示例中使用的规则集使用正则表达式过滤每个研究中的 CT 文件。或者,我们还可以添加多个条件,例如:`Spleen & CT 1` 为第一个条件,`Abdomen & CT 2` 为第二个条件,如此处所示:

    {
    "selections": [{"name": "CT Series","conditions": {"StudyDescription": "(.*?)","Modality": "(?i)CT","SeriesDescription": "(.*?)"}}
    ]
    }
    
  • DICOMSeriesToVolumeOperator: 将 DICOM 实例转换为 NumPy 数组进行进一步处理。

  • MonaiBundleInferenceOperator:  AI 运算符加载通用的 TorchScript 模型,选择设备,执行输入预处理和输出后处理。用于加载感兴趣模型的 model.ts 捆绑包位于数据文件夹中,并在命令 model-deploy exec -m model.ts -i dcm -o output 中传递。此运算符通常适用于任何 MONAI 捆绑包,并适应不同的配置参数,例如输入转换、数据类型、输入参数和模型推理(如 `bundle('model/extra/metadata.json' 中定义。警告 - 不要将捆绑包名称更改为 model.ts 以外的任何名称。这样做可能会在读取元数据配置文件时导致错误)。

  • DICOMSegmentationWriterOperator: AI 模型的每像素二进制输出由此运算符处理以生成预测的分割脾脏。然后将其转换为 DICOM 实例并保存到磁盘。

在这篇博客中,我们将讲解使用 NIfTI 体积进行全身分割的 MONAI Deploy 示例。现有示例使用运算符探索 DICOM 数据和元数据,并不容易与 NIfTI 数据集成。本博客作为编写自定义 NIfTI 数据运算符的入门。

您可以在这个GitHub 文件夹中找到与本博客相关的文件。

实现

要跟随本博客,你需要:

  • 安装基于 ROCm 的 torch 和 torchvision。这个实验是在 ROCm 5.7.0 上进行的。参阅系统要求 了解硬件和操作系统的支持。

    pip install torch==2.0.1 torchvision==0.15.2 -f https://repo.radeon.com/rocm/manylinux/rocm-rel-5.7/
    
  • 安装 MONAI Deploy 应用程序 SDK 0.5.1 版本。这将帮助你使用 monai-deploy run 和 monai-deploy package 等命令来启动应用程序。

    pip install monai-deploy-app-sdk==0.5.1
    
  • 从 zenodo.org 下载一个用于推理的单一测试对象到输入文件夹,即 ts_data

     curl https://zenodo.org/records/10047263/files/Totalsegmentator_dataset_small_v201.zip --output ts.zipunzip ts.zip s0011/ct.nii.gzmv s0011/ct.nii.gz ts_data// Remove downloadsrm -r s0011rm ts.zip
    
  •  安装其他所需的库。

    pip install monai pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh
    

代码

TotalSegmentator 是一个开源项目,它使用与 ResNet 等效的网络从整个人体 CT 扫描图像中分割出 105 个部位,包括颅骨、胃、心脏、肺和消化道。所有类别的列表存储在 这里。

我们使用 MONAI 预训练模型结合 MONAI Deploy App SDK 来构建 TotalSegmentator 应用程序。您可以在 Project-MONAI GitHub 仓库 中找到用于预训练该模型的训练配置。我们将使用此配置文件构建模型的预处理和后处理管道,并加载 预训练的检查点。确保下载检查点并将其放在输入文件夹中,即 ts_data,否则脚本将引发如下代码块所示的错误。

curl https://drive.google.com/file/d/1c3osYscnr6710ObqZZS8GkZJQlWlc7rt/view?usp=share_link -o ./ts_data/model.pt

构建 TotalSegmentator 应用程序的第一个操作符 - PreprocessNiftiOperator,它从输入路径加载 NIfTI 文件和预训练模型。

@md.output('image', np.ndarray, IOType.IN_MEMORY)
@md.output('model', str, IOType.IN_MEMORY)
class PreprocessNiftiOperator(Operator):def __init__(self):super().__init__()def compute(self, op_input, op_output, context):input_path = op_input.get().pathlogging.info(input_path)files = os.listdir(input_path)if model not in files:logging.error('Cannot find model.pt file in the input path')returninput_file = files[0] # ct.nii.gz filenifti_input = nib.load(os.path.join(input_path,input_file)).get_fdata()op_output.set(nifti_input, 'image')op_output.set(os.path.join(input_path, 'model.pt'), 'model')

接下来,定义 TotalSegmentator 应用程序的核心操作符 SegInferenceOperator,该操作符预处理数据,加载 SegResNet 模型,并对输出进行推理和后处理。该操作符的装饰器定义了临时数据存储中 InputContext 和 OutputContext 端口的数据类型和存储类型。此数据存储是在应用程序启动期间在 MONAI 工作目录 <current_dir>/.monai_workdir/ 内创建的,用于存储中间结果。`SegInferenceOperator` 期望两个输入端口分别保存 NumPy 数据和预训练 ckpt 的路径。它输出一个‘输出已保存’消息,以成功结束操作符。

@md.input('image', np.ndarray, IOType.IN_MEMORY)
@md.input('model', str, IOType.IN_MEMORY)
@md.output('output_msg', str, IOType.IN_MEMORY)
class SegInferenceOperator(Operator):def __init__(self, roi_size=96,pre_transforms = True,post_transforms = True,model_name = 'SegResNet'):super().__init__()def compute(self, op_input, op_output, context):input_image = op_input.get("image") #ndarrayinput_image = np.expand_dims(input_image, axis=-1)# input_image = torch.tensor(input_image).float()# 没有使用标准的 MonaiSegInferenceOperator 因为它深度集成了 DICOM 样式元数据渲染,对 NIfTI 数据不够灵活。此外,它从应用上下文中加载 monai.core.model.Model 而不是 torch.nn.Modulenet = SegResNet(spatial_dims= 3,in_channels= 1,out_channels= 105,init_filters= 32,blocks_down= [1,2,2,4],blocks_up= [1,1,1],dropout_prob= 0.2)#加载从 InputContext 中提取的预训练检查点net.load_state_dict(torch.load(op_input.get('model')))device = torch.device("cuda" if torch.cuda.is_available() else "cpu")net.to(device)# 定义要应用的变换列表pixdim = [3.0, 3.0, 3.0]self.pre_transforms = Compose([EnsureChannelFirstd(keys='image', channel_dim=-1),Orientationd(keys='image', axcodes='RAS'),# Resized(keys="image", spatial_size=(208,208,208), mode="trilinear", align_corners=True),Spacingd(keys='image', pixdim=pixdim, mode='bilinear'),NormalizeIntensityd(keys='image', nonzero=True),ScaleIntensityd(keys='image', minv=-1.0, maxv=1.0)])self.post_transforms = Compose([Activationsd(keys='pred', sigmoid=True),AsDiscreted(keys='pred', argmax=True),Invertd(keys='pred', transform=self.pre_transforms, orig_keys='image'),SaveImaged(keys='pred', output_dir='/home/aac/monai-2/output', meta_keys='pred_meta_dict')])dataset = Dataset(data=[{'image':input_image}], transform=self.pre_transforms)dataloader = DataLoader(dataset, batch_size=1)for i in dataloader:logging.info(f'Preprocessed input size is {i["image"].shape}')o = net(i['image'].to(device))logging.info(f'Output size is {o.shape}')i['pred'] = o.detach()out = [self.post_transforms(x) for x in decollate_batch(i)]op_output.set("Output saved",'output_msg')

您现在可以使用这两个操作符来构建这个应用程序:

import logging# 需要设置 SegmentDescription 属性。从 pydicom.sr.codedict 导入,因为它不是应用程序 SDK 包的一部分。
from pydicom.sr.codedict import codes
from operators import PreprocessNiftiOperator, SegInferenceOperator
from monai.deploy.core import Application, resource@resource(cpu=1, gpu=1, memory="7Gi")
class TotalBodySegmentation(Application):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)def run(self, *args, **kwargs):# 此方法调用基类来运行。可以省略,如果只是简单地调用它。logging.info(f"Begin {self.run.__name__}")super().run(*args, **kwargs)logging.info(f"End {self.run.__name__}")def compose(self):logging.info(self._context.model_path)"""创建应用程序特定的操作符并将它们连接到处理 DAG 中。"""logging.info(f"Begin {self.compose.__name__}")preprocess_op = PreprocessNiftiOperator()inference_op = SegInferenceOperator()self.add_flow(preprocess_op, inference_op, {'image': 'image', 'model': 'model'})logging.info(f"End {self.compose.__name__}")if __name__ == "__main__":logging.basicConfig(level=logging.DEBUG)app_instance = TotalBodySegmentation(do_run=True)

通过以下命令对测试示例进行分割;结果作为 NIfTI 对象保存在输出文件夹中。

monai-deploy exec total_body_segmentation.py -i ts_data/ -o output/ -l DEBUG

结果

使用MONAI的`matshow3d`库进行可视化:

from monai.visualize import blend_images, matshow3d
import matplotlib.pyplot as plt
import nibabel as nib
import osoutput_image = nib.load(os.path.join('./output/0/0_trans.nii.gz')).get_fdata()
print(output_image.shape)
matshow3d(volume=output_image[:,:,200:300],fig=None,title="output image",figsize=(100, 100),every_n=5,frame_dim=-1,show=True,# cmap="gray",
)

注意,每个输入体积的切片上都有多个部分被分割出来。你可以使用MONAI Label来进行每个分割部分的3D可视化。

output.JPG

你可以使用monai-deploy命令将应用程序打包并上传为Docker镜像。使用打包应用程序时使用的Docker标签来检索并运行它

实际案例

开发了TotalSegmentator的团队还使用MONAI Deploy创建了另一个基于他们自定义模型和训练参数的应用程序,您可以在此查看: application 。他们最近在生产环境中发布了一个原型,以促进医学研究与最新AI工作流程的结合,从而提高其采用率。这是MONAI Deploy的一个实际生产用例。该应用程序不仅生成分割结果,还生成PDF报告,这对医生和研究人员非常有用。

鸣谢

我们要感谢Project MONAI在AI医学影像应用中的开源贡献。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/464221.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决 ClickHouse 高可用集群中 VRID 冲突问题:基于 chproxy 和 keepalived 的实践分析

Part1背景描述 近期&#xff0c;我们部署了两套 ClickHouse 生产集群&#xff0c;分别位于同城的两个数据中心。这两套集群的数据保持一致&#xff0c;以便在一个数据中心发生故障时&#xff0c;能够迅速切换应用至另一个数据中心的 ClickHouse 实例&#xff0c;确保服务连续性…

推荐FileLink数据跨网摆渡系统 — 安全、高效的数据传输解决方案

在数字化转型的浪潮中&#xff0c;企业对于数据传输的需求日益增加&#xff0c;特别是在不同网络环境之间的文件共享和传输。为了满足这一需求&#xff0c;FileLink数据跨网摆渡系统应运而生&#xff0c;为企业提供了一种安全、高效的数据传输解决方案。 安全第一&#xff0c;保…

力扣排序350题 两个元组的交集2

题目&#xff1a; 给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两 数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个 数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取 较小值&#xff09;。可以不考虑输出…

Python酷库之旅-第三方库Pandas(193)

目录 一、用法精讲 896、pandas.Index.isna方法 896-1、语法 896-2、参数 896-3、功能 896-4、返回值 896-5、说明 896-6、用法 896-6-1、数据准备 896-6-2、代码示例 896-6-3、结果输出 897、pandas.Index.notna方法 897-1、语法 897-2、参数 897-3、功能 897…

使用Mac如何才能提高OCR与翻译的效率

OCR与截图大家都不陌生&#xff0c;或许有的朋友对于这两项功能用到的不多&#xff0c;但是如果经常会用到的话&#xff0c;那你就该看看了 iOCR&#xff0c;快捷键唤出翻译窗口&#xff0c;不论是截图翻译、划词翻译、输入翻译、剪切板翻译&#xff0c;统统快捷键完成&#x…

《欢乐饭米粒儿9》第五期:用笑声诠释生活,让爱成为日常

在忙碌的生活节奏中&#xff0c;我们总是在寻找那份能够触动心灵深处的温暖与欢笑。由鲜博士独家冠名播出的独创小品剧《欢乐饭米粒儿》第九季作为一档家庭喜剧节目&#xff0c;正是这样一股清流&#xff0c;它以轻松幽默的方式&#xff0c;将家的温暖、爱的传递和生活的真谛娓…

基于人脸识别PCA算法matlab实现及详细步骤讲解

人脸识别 % FaceRec.m % PCA 人脸识别修订版&#xff0c;识别率88&#xff05; % calc xmean,sigma and its eigen decomposition allsamples[];%所有训练图像 for i1:40 for j1:5 aimread(strcat(e:\ORL\s,num2str(i),\,num2str(j),.jpg)); % imshow(a); ba(1:112*92…

C#的Event事件示例小白级剖析

1、委托Delegate 首先说一下delegate委托&#xff0c;委托是将方法作为参数进行传递。 // 定义了一个委托类型public delegate void MyDelegate(int num);// 定义了一个啥也不干的委托实例public MyDelegate m_delegate _ > {};// 定义了一个和委托相同格式的方法public …

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭&#xff0c;makefile体系逐渐增多&#xff0c;导致make单编模块的时间越来越长&#xff0c;每次都需要半个小时甚至更长时间&#xff0c;其原因为每次make都会重新加载所有mk文件&#xff0c;再生成ninja编译&#xff0c;此完整过程十分耗时…

VSCode 1.82之后的vscode server离线安装

概述 因为今天在公司开发项目的时候&#xff0c;需要离线配置vscode远程开发环境&#xff0c; 根据参考链接1配置了一遍&#xff0c;不管怎么重启&#xff0c;VSCODE都还是提示下载vscode server&#xff0c;后面在官方issue上找到了解决方案 解决方案 修改Remote SSH的配置…

什么是 OpenTelemetry?

OpenTelemetry 定义 OpenTelemetry (OTel) 是一个开源可观测性框架&#xff0c;允许开发团队以单一、统一的格式生成、处理和传输遥测数据&#xff08;telemetry data&#xff09;。它由云原生计算基金会 (CNCF) 开发&#xff0c;旨在提供标准化协议和工具&#xff0c;用于收集…

缓存、注解、分页

一.缓存 作用&#xff1a;应用查询上&#xff0c;内存中的块区域。 缓存查询结果&#xff0c;减少与数据库的交互&#xff0c;从而提高运行效率。 1.SqlSession 缓存 1. 又称为一级缓存&#xff0c;mybatis自动开启。 2. 作用范围&#xff1a;同一…

AI打造超写实虚拟人物:是科技奇迹还是伦理挑战?

内容概要 在这个科技飞速发展的时代&#xff0c;超写实虚拟人物仿佛从科幻小说中走进了我们的日常生活。它们以生动的形象和细腻的动作&#xff0c;不仅在影视、广告和游戏中吸引了无数目光&#xff0c;更让我们对AI技术的未来充满了期待和疑惑。这些数字化身在逼真的外貌下&a…

CODESYS可视化星三角降压启动程序控制电气动画图

#一个用CODESYS可视化做的星三角降压启动程序控制电气动画图# 前言: 关于星三角降压启动控制,作为电气行业入门的必备知识点,涉及到电机本身特性导致的电压,电流(转矩),功率和转速等一系列的关系和变化,以及星型和三角形的绕组方式。本篇我们使用CODESYS结合程序和可视…

物联网赋能的人工智能图像检测系统

一、引言 在数字化时代&#xff0c;物联网&#xff08;IoT&#xff09;技术已经成为我们生活中不可或缺的一部分&#xff0c;极大地优化了我们的交通出行和医疗服务。物联网的核心优势在于其卓越的连接能力&#xff0c;它能够构建和连接庞大的资源数据库&#xff0c;为智能化图…

软件架构演变:从单体架构到LLM链式调用

0 前言 软件架构——我们数字世界的蓝图——自20世纪中叶计算机时代诞生以来&#xff0c;已经发生了巨大演变。 20世纪60年代和70年代早期&#xff0c;以大型主机和单体软件为主导。而今天&#xff0c;数字领域已完全不同&#xff0c;运行在由云计算、API连接、AI算法、微服务…

Claude 3.5 Sonnet模型新增了PDF支持功能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【每日一题】LeetCode - 三数之和

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 示…

基于 Canal + Elasticsearch 的业务操作日志解决方案

一、问题来源 在日常的业务系统中&#xff0c;操作日志是不可或缺的一部分。它能帮助我们追踪用户的操作行为&#xff0c;记录关键数据的变更&#xff0c;甚至在必要时支持操作回滚。最近&#xff0c;我们接到客户的需求&#xff0c;希望在系统中实现一个业务操作日志管理的功能…

Python并发编程库:Asyncio的异步编程实战

Python并发编程库&#xff1a;Asyncio的异步编程实战 在现代应用中&#xff0c;并发和高效的I/O处理是影响系统性能的关键因素之一。Python的asyncio库是专为异步编程设计的模块&#xff0c;提供了一种更加高效、易读的并发编程方式&#xff0c;适用于处理大量的I/O密集型任务…