【nnunetv2.pth模型转onnx】

部署运行你感兴趣的模型镜像
import torch
from torch import nn
from nnunetv2.training.nnUNetTrainer.nnUNetTrainer import nnUNetTrainer
from nnunetv2.utilities.get_network_from_plans import get_network_from_plans
from nnunetv2.utilities.plans_handling.plans_handler import PlansManager, ConfigurationManager
from nnunetv2.utilities.dataset_name_id_conversion import convert_id_to_dataset_name
from nnunetv2.paths import nnUNet_results
from nnunetv2.utilities.label_handling.label_handling import determine_num_input_channels
from nnunetv2.experiment_planning.plan_and_preprocess_api import plan_experiments
import json
def load_json(file: str):
    with open(file, 'r') as f:
        a = json.load(f)
    return a
from nnunetv2.run.run_training import run_training
import os

def build_network_architecture(plans_manager: PlansManager,
                                   dataset_json,
                                   configuration_manager: ConfigurationManager,
                                   num_input_channels,
                                   enable_deep_supervision: bool = True) -> nn.Module:
       
        return get_network_from_plans(plans_manager, dataset_json, configuration_manager,
                                      num_input_channels, deep_supervision=enable_deep_supervision)

if __name__ == "__main__":
 
    dataset_id =511
    task_name = "roi"
    checkpoint_name = 'checkpoint_final.pth'
    configuration = '3d_fullres'
    fold = '0'
    patch_size=[96, 128, 192]
 
    dataset_name = convert_id_to_dataset_name(dataset_id)
    model_training_output_dir = os.path.join(nnUNet_results, dataset_name)
    checkpoint_file = os.path.join(nnUNet_results, dataset_name,f'fold_{fold}', checkpoint_name)
    checkpoint = torch.load(checkpoint_file,map_location=torch.device('cpu'))
    
    dataset_json_file = os.path.join(model_training_output_dir, 'dataset.json')
    dataset_fingerprint_file = os.path.join(model_training_output_dir, 'dataset_fingerprint.json')
    plan_file = os.path.join(model_training_output_dir, 'plans.json')
     
    dataset_json = load_json(dataset_json_file)
    dataset_fingerprint = load_json(dataset_fingerprint_file)
    plan = load_json(plan_file)

                         
    f = int(fold) if fold != 'all' else fold

    plans_manager = PlansManager(plan)

    configuration_manager = plans_manager.get_configuration(configuration)
    num_input_channels = determine_num_input_channels(plans_manager, configuration_manager,
                                                                   dataset_json)
    network =build_network_architecture(
                plans_manager,
                dataset_json,
                configuration_manager,
                num_input_channels
            )

 
    net=network
    net.load_state_dict(checkpoint["network_weights"])
    net.eval()
 
    dummy_input = torch.randn(1, 1, *patch_size)#.to("cuda")
 
    torch.onnx.export(
        net,
        dummy_input,
        os.path.join(nnUNet_results, dataset_name,f'fold_{fold}', f'{task_name}.onnx'),
        input_names=['input'],
        output_names=['output']
        # dynamic_axes = {'input': {0: 'batch_size'},'output': {0: 'batch_size'}}
        )



参考博客:https://blog.youkuaiyun.com/qq_35007834/article/details/134707439?spm=1001.2014.3001.5501
按照大佬的模版改的,能生成会有警告,欢迎评论交流!

补充:如果运行不成功,可直接修改predict_from_raw_data.py文件,推理一下即可。

def predict_logits_from_preprocessed_data(self, data: torch.Tensor) -> torch.Tensor:
        """
        IMPORTANT! IF YOU ARE RUNNING THE CASCADE, THE SEGMENTATION FROM THE PREVIOUS STAGE MUST ALREADY BE STACKED ON
        TOP OF THE IMAGE AS ONE-HOT REPRESENTATION! SEE PreprocessAdapter ON HOW THIS SHOULD BE DONE!

        RETURNED LOGITS HAVE THE SHAPE OF THE INPUT. THEY MUST BE CONVERTED BACK TO THE ORIGINAL IMAGE SIZE.
        SEE convert_predicted_logits_to_segmentation_with_correct_shape
        """
        n_threads = torch.get_num_threads()
        torch.set_num_threads(default_num_processes if default_num_processes < n_threads else n_threads)
        with torch.no_grad():
            prediction = None

            for params in self.list_of_parameters:

                # messing with state dict names...
                if not isinstance(self.network, OptimizedModule):
                    self.network.load_state_dict(params)
                else:
                    self.network._orig_mod.load_state_dict(params)

                # ##################
                # # # 转onnx
                # print("---------------转onnx-------------------------")
                # self.network=self.network.cpu()
                # self.network.eval()
                # x1 = torch.randn(1,1,96,96,128, requires_grad=True).cpu()
                # torch.onnx.export(
                #     self.network,
                #     x1,
                #     r'C:/nnUNet/nnUNetFrame/DATASET/nnUNet_results/test/test.onnx',
                #     export_params=True,
                #     verbose=True,
                #     do_constant_folding=True,
                #     opset_version=11,
                #     input_names=['modelInput'],
                #     output_names=['modelOutput']#,
                #     #dynamic_axes={'modelinput': {0:'batchsize',2: 'height',3: 'width'}, 'modeloutput': {0:'batchsize',2: 'height',3: 'width'}}
                # )
                # print("Model has been converted to onnx!")


                # why not leave prediction on device if perform_everything_on_device? Because this may cause the
                # second iteration to crash due to OOM. Grabbing tha twith try except cause way more bloated code than
                # this actually saves computation time
                if prediction is None:
                    prediction = self.predict_sliding_window_return_logits(data).to('cpu')
                else:
                    prediction += self.predict_sliding_window_return_logits(data).to('cpu')

            if len(self.list_of_parameters) > 1:
                prediction /= len(self.list_of_parameters)

            if self.verbose: print('Prediction done')
            prediction = prediction.to('cpu')
        torch.set_num_threads(n_threads)
        return prediction

您可能感兴趣的与本文相关的镜像

PyTorch 2.9

PyTorch 2.9

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

<think>首先,用户的问题是:“我想查找将.pth模型换为.onnx模型并进行推理的方法 请问将.pth模型换为.onnx模型并进行推理的方法”。这是在询问如何将PyTorch的.pth模型换为ONNX格式,并进行推理。 系统指令要求: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 用户提供的引用内容: - 引用[1]:描述将PointNet的.pth模型换为ONNX,并用C++的onnxruntime推理部署。 - 引用[2]:给出Python代码将.pthONNX,并提到ONNXTensorRT。 - 引用[3]:简要说明.pth.pt,然后.ptONNX。 - 引用[4]:示例代码将ResNet34的.pth模型ONNX,包括模型加载和导出。 - 引用[5]:注意事项和常见问题,如确保模型在eval模式、加载状态后立即导出等。 用户的问题是基于这些引用,询问换和推理方法。我需要基于这些引用构建一个清晰的回答。 回答结构: 由于系统要求结构清晰,帮助用户逐步解决问题,我应该分步解释过程: 1. 准备模型:加载.pth模型2. 换到ONNX:使用torch.onnx.export函数。 3. 验证ONNX模型:使用ONNX的检查工具。 4. 推理ONNX模型:可以选择Python或C++进行推理。 5. 常见问题和注意事项。 最后,生成相关问题。 确保使用中文回答。 关键点: - 引用中的代码示例,我可以总结和提炼。 - 添加引用标识,例如[^1]。 - 换为ONNX时,模型必须在eval模式,避免动态轴问题等。 分步计划: 1. **加载.pth模型**:先加载训练好的PyTorch模型。 - 例如,使用torch.load加载权重,设置模型为eval模式。 - 引用[4]和[5]强调model.eval()的重要性。 2. **导出为ONNX模型**:使用torch.onnx.export函数。 - 需要提供输入张量示例。 - 指定输入和输出名称。 - 可选参数如opset_version。 - 引用[2]、[3]、[4]有代码示例。 3. **验证ONNX模型**:使用onnx.load和onnx.checker.check_model确保模型有效。 - 引用[4]提到这一点。 4. **推理ONNX模型**: - 在Python中,可以使用onnxruntime库加载ONNX模型并进行推理。 - 在C++中,使用onnxruntime的C++ API,如引用[1]描述。 - 引用[1]提到C++推理部署。 5. **常见问题**: - 确保加载权重后立即导出,避免修改模型状态(引用[5])。 - 输入形状和动态轴设置。 - 输出与原始模型的比较。 生成相关问题: - 类似示例中的格式:快速排序相关问题。 - 例如: 1. 如何验证换后的ONNX模型与原始PyTorch模型输出一致? 2. 在C++中使用onnxruntime推理的具体步骤是什么? 3. 换过程中常见错误及其解决方案? 回答大纲: - 介绍换和推理的重要性。 - 分步讲解: - 步骤1:加载PyTorch模型 - 步骤2:导出为ONNX格式 - 步骤3:验证ONNX模型 - 步骤4:进行推理(Python示例) - 注意事项 - 相关问题 在回答中,自然地添加引用标识,例如在描述某个点时提到引用来源。 </think>### 将.pth模型换为.onnx模型并进行推理的方法 基于您提供的引用内容,我将逐步解释如何将PyTorch的.pth模型换为ONNX格式并进行推理。整个过程主要包括四个步骤:加载Pyth模型、导出为ONNX模型、验证ONNX模型和在推理框架中使用ONNX模型。以下方法基于引用中的最佳实践,确保换和推理的高可靠性[^1][^2][^3][^4][^5]。 --- #### **步骤1: 加载PyTorch模型.pth文件)** 在换前,必须先正确加载训练好的PyTorch模型,并设置模型为评估模式(eval mode)。 - **关键操作**: - 使用`torch.load()`加载模型权重。 - 调用`model.eval()`禁用dropout和batchnorm等训练层,确保推理一致性。 - 确保模型结构匹配权重文件(例如,调整全连接层输出类别数)。 - 提供一个示例输入张量(形状需与实际推理一致)。 **示例代码(参考引用[4][^4])**: ```python import torch import torch.nn as nn # 定义模型结构(以ResNet34为例,替换为您自己的模型) class YourModel(nn.Module): def __init__(self, num_classes=14): super(YourModel, self).__init__() # 假设为ResNet34结构 self.model = nn.Sequential( # 您的模型层定义 ) self.fc = nn.Linear(512, num_classes) # 替换为您的输出类别数 def forward(self, x): return self.fc(self.model(x)) # 加载.pth模型 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = YourModel(num_classes=14) # 设置类别数 pth_path = './your_model.pth' # .pth文件路径 model.load_state_dict(torch.load(pth_path, map_location=device)) # 加载权重 model = model.to(device) model.eval() # 强制设置为评估模式,避免动态行为导致换错误[^5] # 创建示例输入张量(形状需匹配实际输入) example = torch.randn(1, 3, 224, 224).to(device) # 输入示例:batch_size=1, channels=3, height=224, width=224 ``` **注意事项**: - 如果.pth文件包含`module.`前缀(如在多GPU训练后),需先移除前缀以兼容单GPU加载(参考引用[5][^5])。 - 示例输入张量需与推理时的真实数据一致,避免形状不匹配错误。 --- #### **步骤2: 导出为ONNX模型.onnx文件)** 使用PyTorch的`torch.onnx.export()`函数将模型换为ONNX格式。关键是通过动态轴设置处理可变输入(如批次大小)。 - **核心参数**: - `input_names`和`output_names`:指定输入和输出节点名称。 - `dynamic_axes`:允许输入/输出维度可变(例如动态批次大小)。 - `opset_version`:指定ONNX算子集版本(推荐使用9或11以稳定支持)。 **示例代码(参考引用[2][^4][^5])**: ```python import onnx onnx_path = './your_model.onnx' # ONNX输出路径 torch.onnx.export( model, # PyTorch模型实例 example, # 示例输入张量 onnx_path, # 输出ONNX文件路径 export_params=True, # 包含模型参数 opset_version=11, # 算子集版本,兼容性强 do_constant_folding=True, # 启用常量折叠优化 input_names=["input"], # 输入节点名称 output_names=["output"], # 输出节点名称 dynamic_axes={ "input": {0: "batch_size"}, # 批次大小动态 "output": {0: "batch_size"} } ) print(f"ONNX模型已导出到: {onnx_path}") ``` **常见错误与解决**: - **输出不一致问题**:确保在加载权重后立即导出,且未修改模型结构(引用[5][^5])。 - **算子不支持**:如果报错如`Unsupported operator`,降低`opset_version`或检查模型层兼容性。 --- #### **步骤3: 验证ONNX模型** 换后,必须验证ONNX模型的正确性,避免换过程中的错误。 - **使用ONNX工具检查**: - 加载ONNX模型并运行`onnx.checker.check_model()`。 - 打印模型结构以确认输入/输出节点。 **示例代码(参考引用[4][^4])**: ```python onnx_model = onnx.load(onnx_path) # 加载ONNX模型 onnx.checker.check_model(onnx_model) # 检查模型有效性(无输出表示正常) print(onnx.helper.printable_graph(onnx_model.graph)) # 打印模型结构,验证节点 ``` **验证要点**: - 比较ONNX模型输出与原始PyTorch模型输出(使用相同输入),确保误差在可接受范围内(例如$|\Delta y| < 10^{-5}$)。 --- #### **步骤4: 使用ONNX模型进行推理** ONNX模型可以在多种框架中推理,包括Python和C++。以下提供两种常见方法。 ##### **方法1: Python推理(使用onnxruntime)** 适用于快速测试和部署。 - **安装onnxruntime**: ```bash pip install onnxruntime # CPU版本 pip install onnxruntime-gpu # GPU加速版本 ``` - **推理代码**(参考引用[1][^2]): ```python import numpy as np import onnxruntime as ort # 加载ONNX模型 ort_session = ort.InferenceSession(onnx_path) # 准备输入数据(需换为numpy数组) input_data = np.random.randn(1, 3, 224, 224).astype(np.float32) # 示例输入 ort_inputs = {ort_session.get_inputs()[0].name: input_data} # 运行推理 ort_outputs = ort_session.run(None, ort_inputs) print("推理结果:", ort_outputs[0]) # 输出为numpy数组 ``` ##### **方法2: C++推理(使用onnxruntime)** 适用于高性能嵌入式部署(参考引用[1][^1])。 1. **下载onnxruntime**: - 从[ONNX Runtime GitHub](https://github.com/microsoft/onnxruntime/releases)下载预编译库。 2. **示例C++代码**(简化版): - 文件`loadonnx.cpp`: ```cpp #include <onnxruntime_cxx_api.h> #include <vector> Ort::Session load_model(const char* model_path) { Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); Ort::SessionOptions session_options; return Ort::Session(env, model_path, session_options); } std::vector<float> inference(Ort::Session& session, std::vector<float>& input_data) { Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); std::vector<int64_t> input_shape = {1, 3, 224, 224}; # 输入形状 Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_data.data(), input_data.size(), input_shape.data(), input_shape.size()); const char* input_names[] = {"input"}; const char* output_names[] = {"output"}; auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); float* output_data = output_tensors[0].GetTensorMutableData<float>(); return std::vector<float>(output_data, output_data + output_tensors[0].GetTensorTypeAndShapeInfo().GetElementCount()); } ``` - 编译运行(使用CMake链接onnxruntime库)。 **推理注意事项**: - **性能优化**:在GPU上使用CUDA或TensorRT加速(引用[2][^2])。 - **框架选择**:也可用LibTorch或OpenVINO(引用[1][^1]),但ONNXRuntime跨平台性更强。 --- #### **关键注意事项** 1. **模式一致性**:换前必须调用`model.eval()`,否则模型行为不一致可能导致输出错误(引用[5][^5])。 2. **动态轴设置**:如果推理时批次大小变化,使用`dynamic_axes`确保灵活性。 3. **算子兼容性**:复杂模型(如PointNet)需检查ONNX算子支持;若失败,可尝试简化模型或更新PyTorch版本。 4. **输出验证**:换后对比PyTorch和ONNX输出,误差应小于$10^{-5}$(使用均方误差计算:$\text{MSE} = \frac{1}{n}\sum (y_{\text{pth}} - y_{\text{onnx}})^2$)。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值