pytorch.onnx.export方法参数详解,以及onnxruntime-gpu推理性能测试

Torch.onnx.export执行流程:

1、如果输入到torch.onnx.export的模型是nn.Module类型,则默认会将模型使用torch.jit.trace转换为ScriptModule

2、使用args参数和torch.jit.trace将模型转换为ScriptModule,torch.jit.trace不能处理模型中的循环和if语句

3、如果模型中存在循环或者if语句,在执行torch.onnx.export之前先使用torch.jit.script将nn.Module转换为ScriptModule

4、模型转换成onnx之后,预测结果与之前会有稍微的差别,这些差别往往不会改变模型的预测结果,比如预测的概率在小数点之后五六位有差别。

Onnx模型导出,并能够处理动态的batch_size:

Torch.onnx.export导出模型:

检查导出的模型:

onnxruntime执行导出的onnx模型:

onnxruntime-gpu推理性能测试:

备注:安装onnxruntime-gpu版本时,要与CUDA以及cudnn版本匹配

网络结构:修改Resnet18输入层和输出层,输入层接收[N, 1, 64, 1001]大小的数据,输出256维

测试数据(重复执行10000次,去掉前两次的模型warmup):

输入数据batch_size = 1:[1, 1, 64, 1001]
        pytorch:            2.59 ms
        onnxruntime-gpu:    2.28 ms
        性能提升:           12%
        GPU峰值使用率:       95% vs 50% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

输入数据batch_size = 2:[2, 1, 64, 1001]
        pytorch:            2.92 ms
        onnxruntime-gpu:    2.73 ms
        性能提升:           6.5%
        GPU峰值使用率:       100% vs 41% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

输入数据batch_size = 4:[4, 1, 64, 1001]
        pytorch:            3.93 ms
        onnxruntime-gpu:    3.94 ms
        性能提升:           0%
        GPU峰值使用率:       100% vs 33% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

输入数据batch_size = 8:[8, 1, 64, 1001]
        pytorch:            6.84 ms
        onnxruntime-gpu:    21 ms
        性能提升:           -207%
        GPU峰值使用率:       100% vs 61% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

输入数据batch_size = 16:[16, 1, 64, 1001]
        pytorch:            13.85 ms
        onnxruntime-gpu:    11.41 ms
        性能提升:           17.6%
        GPU峰值使用率:       100% vs 29% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

输入数据batch_size = 32:[32, 1, 64, 1001]
        pytorch:            22.64 ms
        onnxruntime-gpu:    23.56 ms
        性能提升:           0%
        GPU峰值使用率:       100% vs 28% (Tesla P40, pytorch在前)
        CPU使用率:           单核100%

结论:onnxruntime可以提升模型推理速度,但是不擅长处理批量数据,不知道能不能这样理解?还是说只对于我这个网络模型是这个情况,没找到规律,也没找到参考文档,暂时还没搞清楚。关于这个问题,github上找到了这几个问题可以参考:

Gap in inference time between onnxruntime and torch vanishes when increasing the batch size · Issue #9660 · microsoft/onnxruntime · GitHub

https://github.com/microsoft/onnxruntime/issues/2796

https://towardsdatascience.com/an-empirical-approach-to-speedup-your-bert-inference-with-onnx-torchscript-91da336b3a41

 

onnx模型导出及onnxruntime推理完整代码:

import torch
import torchvision
import onnx
import onnxruntime
import numpy as np
import os

# 设置pytorch下载的预训练模型保存位置
os.environ["TORCH_HOME"] = "./pretrained_models"


def pytorch_2_onnx():
    """
    将pytorch模型导出为onnx,导出时pytorch内部使用的是trace或者script先执行一次模型推理,然后记录下网络图结构
    所以,要导出的模型要能够被trace或者script进行转换
    :return:
    """
    # 加载预训练模型
    model = torchvision.models.alexnet(pretrained=True)
    print(model)

    model_path = "alexnet.onnx"

    # pytorch转换为onnx内部使用trace或者script,需要提供一组输入数据执行一次模型推理过程,然后进行trace记录
    dummy_input = torch.randn(4, 3, 224, 224, device="cpu")
    input_names = ["input_data"] + ["learned_%d" % i for i in range(16)]
    output_names = ["output_data"]

    torch.onnx.export(
        model,  # pytorch网络模型
        dummy_input,    # 随机的模拟输入
        model_path,     # 导出的onnx文件位置
        export_params=True,     # 导出训练好的模型参数
        verbose=10,             # debug message
        training=torch.onnx.TrainingMode.EVAL,  # 导出模型调整到推理状态,将dropout,BatchNorm等涉及的超参数固定
        input_names=input_names,    # 为静态网络图中的输入节点设置别名,在进行onnx推理时,将input_names字段与输入数据绑定
        output_names=output_names,  # 为输出节点设置别名
        # 如果不设置dynamic_axes,那么对于输入形状为[4, 3, 224, 224],在以后使用onnx进行推理时也必须输入[4, 3, 224, 224]
        # 下面设置了输入的第0维是动态的,以后推理时batch_size的大小可以是其他动态值
        dynamic_axes={
            # a dictionary to specify dynamic axes of input/output
            # each key must also be provided in input_names or output_names
            "input_data": {0: "batch_size"},
            "output_data": {0: "batch_size"}
        })
    return model_path


def onnx_check(model_path):
    """
    验证导出的模型格式时候正确
    :param model_path:
    :return:
    """
    onnx_model = onnx.load(model_path)
    onnx.checker.check_model(onnx_model)
    print(onnx.helper.printable_graph(onnx_model.graph))


def onnx_inference(model_path):
    """
    模型推理
    :param model_path: 
    :return: 
    """
    # 使用onnxruntime-gpu在GPU上进行推理
    session = onnxruntime.InferenceSession(model_path,
                                           providers=[
                                               ("CUDAExecutionProvider", {  # 使用GPU推理
                                                   "device_id": 0,
                                                   "arena_extend_strategy": "kNextPowerOfTwo",
                                                   "gpu_mem_limit": 4 * 1024 * 1024 * 1024,
                                                   "cudnn_conv_algo_search": "EXHAUSTIVE",
                                                   "do_copy_in_default_stream": True,
                                                   # "cudnn_conv_use_max_workspace": "1"    # 在初始化阶段需要占用好几G的显存
                                               }),
                                               "CPUExecutionProvider"       # 使用CPU推理
                                           ])
    # session = onnxruntime.InferenceSession(model_path)
    data = np.random.randn(2, 3, 224, 224).astype(np.float32)

    # 获取模型原始输入的字段名称
    input_name = session.get_inputs()[0].name
    output_name = session.get_outputs()[0].name
    print("input name: {}".format(input_name))

    # 以字典方式将数据输入到模型中
    outputs = session.run([output_name], {input_name: data})
    print(outputs)


if __name__ == '__main__':
    model_path = pytorch_2_onnx()

    onnx_check(model_path)

    onnx_inference(model_path)

  • 26
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: torch.onnx.export函数是PyTorch中用于将模型导出为ONNX格式的函数。ONNX是一种开放式的深度学习框架,可以用于在不同的平台和框架之间共享模型。torch.onnx.export函数接受以下参数: 1. model:要导出的PyTorch模型。 2. args:模型的输入参数,可以是一个张量或一个元组。 3. f:导出的ONNX文件的名称。 4. export_params:如果为True,则导出模型的参数。 5. opset_version:导出的ONNX版本。 6. do_constant_folding:如果为True,则将模型中的常量折叠。 7. input_names:模型的输入名称。 8. output_names:模型的输出名称。 9. dynamic_axes:动态轴的字典,用于指定输入和输出的变化轴。 使用torch.onnx.export函数可以将PyTorch模型导出为ONNX格式,以便在其他平台和框架中使用。 ### 回答2: torch.onnx.exportPyTorch中的一个API,用于将定义好的模型导出为ONNX格式,从而可以在其他平台或框架中使用。 在使用torch.onnx.export时,需要提供以下参数: - model:待导出的模型 - args:模型输入的张量 - f:导出的ONNX文件的路径或文件句柄 - input_names:输入张量的名称列表 - output_names:输出张量的名称列表 - dynamic_axes:为输入和输出张量指定动态轴的名称和长度。例如:{‘input’: {0: ‘batch_size’}, ‘output’: {0: ‘batch_size’}}表示对于输入和输出的第0维设置为变化的动态轴,而它们的名称为“batch_size”。 - opset_version:ONNX模型所使用的运算符版本,例如opset_version=11表示使用ONNX版本11的运算符。 下面是一个简单的示例,展示了如何使用torch.onnx.export将模型导出为ONNX格式。 ``` import torch import torchvision dummy_input = torch.randn(10, 3, 224, 224) model = torchvision.models.alexnet(pretrained=True) torch.onnx.export(model, dummy_input, "alexnet.onnx", verbose=True) ``` 在上述示例中,我们首先载入预训练的AlexNet模型,并随机生成一个形状为[10,3,224,224]的张量作为输入数据。然后,我们使用torch.onnx.export将AlexNet模型导出为ONNX模型,并将其保存为"alexnet.onnx"文件。 这个API实际上还挺好用的,特别是在多次部署部署时可以避免重复工作。笔者在使用过程中也遇到了一些坑,比如导出的onnx模型放到tensorflow里跑的时候需要默认转置,如果涉及到模型的输入形状动态改变的话还需要设置对于维度名称的设置和onnx模型opset_version设置。阅读文档是件严肃的事情,用好了一定可以起到事半功倍的效果。 ### 回答3: PyTorch是一种非常流行的深度学习框架,其提供了ONNX(开放式神经网络交换)作为模型导出的标准。通过使用ONNXPyTorch可以将训练好的模型导出为不同的平台所需的不同格式。这就使得模型可以在不同平台和环境中进行部署和运行。在PyTorch中,我们可以使用torch.onnx.export函数从PyTorch模型导出一个ONNX模型。 torch.onnx.export函数可以将PyTorch模型保存为ONNX模型,其原型如下: torch.onnx.export(model, args, f, export_params=True, verbose=False, input_names=None, output_names=None, operator_export_type=None, opset_version=None, input_shapes=None, dynamic_axes=None, do_constant_folding=True, example_outputs=None, strip_doc_string=True, keep_initializers_as_inputs=None) 其中,参数model是我们要导出为ONNX模型的PyTorch模型,args是PyTorch模型输入的张量,f是导出ONNX模型的文件名。 export_params确定是否将训练参数导出到ONNX模型中,verbose指定是否输出详细信息。input_names和output_names是模型输入和输出张量的名称。operator_export_type指定导出模型时要使用的运算符类型,opset_version指定使用的ONNX版本。 input_shapes和dynamic_axes在导出多个批次数据时非常有用。input_shapes可以指定张量的完整形状,dynamic_axes可以指定哪个维度应该是变量维度(批次维度)。 do_constant_folding可以控制是否执行常量折叠优化,例如可以删除不再需要的常量。example_outputs是生成器,提供模型的输出示例。strip_doc_string确定是否删除ONNX模型中的注释字符串。keep_initializers_as_inputs决定是否在导出的ONNX模型的输入中保留初始化器。 使用torch.onnx.export函数时,要注意输入和输出张量的数量和顺序。如果我们的PyTorch模型有多个输入或输出,我们需要在input_names和output_names中提供所有输入和输出名称,并在args中按顺序提供所有输入张量。 除了torch.onnx.export函数之外,我们还可以使用PyTorch提供的其他API来进行模型导出。例如,我们可以使用torch.jit.trace函数来动态跟踪模型操作,并生成Torch脚本模型。我们还可以使用torch.jit.script函数将整个PyTorch模型转换为Torch脚本模型。但是,对于某些平台或工具,ONNX格式是最好的选择。 在总体上,通过使用torch.onnx.export函数,我们可以轻松地将训练好的PyTorch模型导出为ONNX模型,以便在不同的平台和环境中进行部署和运行。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值