TensorRT 5.1.5.0入门 Pytorch & ONNX

TensorRT中的pytorch

Developer Guide中的pytorch

在开发者手册中搜索了一下torch,主要在下面三个部分提到:

  1. 3.2.1 “Hello World” For TensorRT Using PyTorch And Python “中提到了一下,对应的就是示例network_api_pytorch_mnist
  2. 3.2.6 Importing From PyTorch And Other Frameworks 中提到想要在pytorch上使用TensorRT要用TensorRT API复刻网络结构,然后从pytorch中复制权重。
  3. 8. Working With Deep Learning Frameworks中提到 Python API下,使用TensorFlow,Caffe或ONNX兼容框架构建的现有模型可用于使用提供的解析器构建TensorRT引擎(也就是这几个亲儿子有解析器)。 Python API还支持以NumPy兼容格式存储图层权重的框架,例如PyTorch( supports frameworks that store layer weights in a NumPy compatible format的是后儿子,也是儿子,不过只能重构模型)。
  4. 8.2 和 3.2.6介绍的一样
    由此看来,从开发者手册上来看,想要使用pytorch就只能replicate the network architecture。

network_api_pytorch示例demo

demo介绍

这个demo是在线训练了mnist的网络,然后直接用torch的nn.Module.state_dict()方法把weights取出来,填充给builder创建的trt格式的network,然后利用这个被填充完weights的network创建engine,进行推断。
这个demo没有涉及到pytorch从文件中读取weights的问题。

demo流程

    # 只是返回了/mnist目录的绝对路径
    data_path, _ = common.find_sample_data(description="Runs an MNIST network using a PyTorch model", subfolder="mnist")
    # Train the PyTorch model
    mnist_model = model.MnistModel()
    mnist_model.learn()
    # weights调用了nn.Module.state_dict()方法
    weights = mnist_model.get_weights()
    # Do inference with TensorRT.
    with build_engine(weights) as engine:
        # Build an engine, allocate buffers and create a stream.
        # For more information on buffer allocation, refer to the introductory samples.
        inputs, outputs, bindings, stream = common.allocate_buffers(engine)
        with engine.create_execution_context() as context:
            case_num = load_random_test_case(mnist_model, pagelocked_buffer=inputs[0].host)
            # For more information on performing inference, refer to the introductory samples.
            # The common.do_inference function will return a list of outputs - we only have one in this case.
            [output] = common.do_inference(context, bindings=bindings, inputs=inputs, outputs=outputs, stream=stream)
            pred = np.argmax(output)
            print("Test Case: " + str(case_num))
            print("Prediction: " + str(pred))
  1. 如介绍所提,weights是通过在线训练完的mnist_model的参数,利用nn.Module.state_dict()方法创建的。
  2. 同样的流程,build_engine()方法,封装了buildertrt格式的network的创建过程以及利用weights填充networks的过程,最后在build_engine()方法中调用builder.build_cuda_engine(network)来实现engine的创建。
  3. common.allocate_buffers()方法是为host端和device端分配内存的过程。
  4. load_random_test_case()方法是在取用来test的img
  5. do_inference主要将allocate_buffers()分配并填充好的数据放到GPU中,然后执行推理,然后再从GPU中取回output,就是结果。

demo总结

看demo的代码发现,确实如开发者手册3.2.6所说的,pytorch在这个demo上的实现,就是用”tensorRT语法“重新把网络结构写了一遍,也就是方法populate_network()的实现。

    input_tensor = network.add_input(name=ModelData.INPUT_NAME, dtype=ModelData.DTYPE, shape=ModelData.INPUT_SHAPE)

    conv1_w = weights['conv1.weight'].numpy()
    conv1_b = weights['conv1.bias'].numpy()
    conv1 = network.add_convolution(input=input_tensor, num_output_maps=20, kernel_shape=(5, 5), kernel=conv1_w, bias=conv1_b)
    conv1.stride = (1, 1)

    pool1 = network.add_pooling(input=conv1.get_output(0), type=trt.PoolingType.MAX, window_size=(2, 2))
    pool1.stride = (2, 2)

    conv2_w = weights['conv2.weight'].numpy()
    conv2_b = weights['conv2.bias'].numpy()
    conv2 = network.add_convolution(pool1.get_output(0), 50, (5, 5), conv2_w, conv2_b)
    conv2.stride = (1, 1)

    pool2 = network.add_pooling(conv2.get_output(0), trt.PoolingType.MAX, (2, 2))
    pool2.stride = (2, 2)

    fc1_w = weights['fc1.weight'].numpy()
    fc1_b = weights['fc1.bias'].numpy()
    fc1 = network.add_fully_connected(input=pool2.get_output(0), num_outputs=500, kernel=fc1_w, bias=fc1_b)

    relu1 = network.add_activation(input=fc1.get_output(0), type=trt.ActivationType.RELU)

    fc2_w = weights['fc2.weight'].numpy()
    fc2_b = weights['fc2.bias'].numpy()
    fc2 = network.add_fully_connected(relu1.get_output(0), ModelData.OUTPUT_SIZE, fc2_w, fc2_b)

    # ModelData是上面自定义的一个数据结构
    fc2.get_output(0).name = ModelData.OUTPUT_NAME
    network.mark_output(tensor=fc2.get_output(0))

传入的network是TensorRT由builder创建的network,add_xxx()方法都是network的内置函数,看c++版本的别的demo,看到network是INetworkDefinition类型的指针。

INetworkDefinition* network = builder->createNetwork();

然后去Nvinfer.h中去找INetworkDefinition,发现这类下面果然有很多add_xxx()方法:

class INetworkDefinition
{
public:
	virtual ITensor* addInput(const char* name, DataType type, Dims dimensions) = 0;
	virtual void markOutput(ITensor& tensor) = 0;
	virtual IConvolutionLayer* addConvolution(ITensor& input, int nbOutputMaps, DimsHW kernelSize, Weights kernelWeights, Weights biasWeights) = 0;
	virtual IFullyConnectedLayer* addFullyConnected(ITensor& input, int nbOutputs, Weights kernelWeights, Weights biasWeights) = 0;
	...

所以,其实这个demo就是利用tensorRT自带的构建网络的功能重建了torch构建的网络,没有读任何网络结构。所以还是想要用pytorch转onnx,再使用tensorRT。

TensorRT中的ONNX

Developer Guide中的onnx

由上面的结论,想用onnx格式进行尝试。
同样在Developer Guide中搜索一下onnx,发现有75处提到了,这里简略记录:

  1. 1.4 中提出ONNX parser在c++和python都有接口,但是要注意版本

The ONNX Parser shipped with TensorRT 5.1.x supports ONNX IR (Intermediate Representation) version 0.0.3, opset version 9.

  1. 2.2 介绍了demo实例,“Hello World” For TensorRT From ONNX" ->对应2.25节(C++)
  2. 2.2.5 中 Importing An ONNX Model Using The C++ Parser API实例 ->对应2.25节 (C++)
  3. 3.2 中Importing From ONNX Using Python->对应3.2.5节(Python)
  4. 3.2.2 中最后介绍了ONNXParserAPI也是->对应3.2.5节(还给了一个ONNX Parser API的链接)(Python)
  5. 3.2.5 中介绍的Python+TensorRT+ONNX的sample,主要是介绍了“ Introduction To Importing Caffe, TensorFlow And ONNX Models Into TensorRT Using Python”的sample和“ Object Detection With The ONNX TensorRT Backend In Python”的sample(Python)
  6. 7.2. Deploying To An Embedded System

Export the trained network to a format such as UFF or ONNX which can be imported into TensorRT (see Working With Deep Learning Frameworks for more details).

  1. 10.3中提示onnx的问题,如果常量输入用于不支持常量输入的层,就会message error,考虑用tensor Input代替。
  2. A.3. Command Line Program中在calib和int8参数后面提到,如今版本的tensorRT是不支持onnx的int8的。

“Hello World” For TensorRT From ONNX”

.
这个sample将在mnixt数据集上训练好的model转化成onnx(Open Neural Network Exchange)格式。
C++代码除了多了个报错机制,基本和读取caffe模型一样

if (!onnxToTRTModel("mnist.onnx", 1, trtModelStream))
        gLogger.reportFail(sampleTest);

gLogger.reportFail的作用是查看有关网络的其他信息(包括图层信息和单个图层维度)。

Importing An ONNX Model Using The C++ Parser API实例

.
  这个部分提到ONNX是有严格的版本限制的,TensorRT5.1.x支持的是ONNX IR 0.03,opset 9。
  一般来说,ONNX解析器是具备向后兼容性的,因此之前版本的ONNXmodel一般不会遇到问题,但是不后兼容的功能可能会有例外,这时就需要把ONNX的模型文件转到支持的版本。
  可能,有些人的model是通过更高版本的opsets生成的,这时可以看一下Github上TensorRT的ONNX模块是不是更新了,查看适合的版本。具体的位置是onnx_trt_backend.cpp的BACK+OPSET_VERSION变量的值。如果需要的话要下载最新版本的解析器,README写了build的过程
  之后就又链接到了“Hello World” For TensorRT From ONNX”这个sample。

Importing From ONNX Using Python

Python接口的onnx使用,这里涉及两个sample。

Introduction To Importing Caffe, TensorFlow And ONNX Models Into TensorRT Using Python

第一个sample只是介绍python中创建engine和执行inference的过程。[Introduction To Importing ONNX Models Into TensorRT Using Python](Introduction To Importing Caffe, TensorFlow And ONNX Models Into TensorRT Using Python).

Object Detection With The ONNX TensorRT Backend In Python

基于yolov3-608的目标检测sample,不支持Ubuntu14.04及以下,不支持Python3.
第二个sample包含了yolov3转onnx,onnx转TensorRT的过程。Object Detection With The ONNX TensorRT Backend In Python.

ONNX Parser API的研究

问题

  1. pycharm运行缺少.so文件问题
    示例:

ImportError: libnvinfer.so.5: cannot open shared object file: Nosuch file or directory

缺少什么文件就去/TensorRT5.x.x.x/targets/x86_64-linux-gnu/lib/目录下找对应的文件,复制到usr/lib

sudo cp /TensorRT5.x.x.x/targets/x86_64-linux-gnu/lib/libnvinfer.so.5 /usr/lib/

如果发现这个目录下没有报错的.so文件,就是误删了或者安装的不是TensorRT5.x,TensorRT4.x就会出现这个问题缺少libnvonnxparser.so.
问题出现原因是python加载动态库方面是默认从系统lib库上查找库文件,所以把需要的.so复制上去就行了。

  1. onnx出现的message error
    研发者手册里提示,出现这个问题可能是因为在不支持常量输入的层以常量作为了输入,考虑用tensor Input代替即可。
  2. 在自己复写pytorch代码的时候,出了个小python问题。
    引用Variable()方法的时候,报错
File "/media/boyun/6a2d0d8c-27e4-4ad2-975c-b24087659438/pycharm/self_pytoch_tensorRT/test.py", line 54, in <module>
    batch_x, batch_y = Variable(batch_x.cuda(), volatile=True), Variable(batch_y.cuda(), volatile=True)
TypeError: 'module' object is not callable

查了之后告诉我,采用import...方式导入模块后,调用模块中的方法应该是模块名.方法(),如果忘记写模块名就会这样报错,后来检查了,确实Variable方法应该是用from导入
From torch.autograd import Variable
我的导入方法出了错误。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值