NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs

一、引言

tensorRT是一个高性能深度学习推理库。tensorrt包含推理优化器和运行时。TensorRT能够以更高的吞吐量和更低的延迟运行。

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第1张图片

本指南包含tensorrt基本的安装、转换、运行时选择以及最佳运用。

二、安装tensorrt

包含:容器、Debian、pip安装方式。

2.1、容器中安装

公有云上部署参照:NGC Certified Public Clouds Documentation

2.2、Debian安装

1、下载tensorRT

2、安装

os="ubuntuxx04"
tag="cudax.x-trt8.x.x.x-yyyymmdd"
sudo dpkg -i nv-tensorrt-repo-${os}-${tag}_1-1_amd64.deb
sudo apt-key add /var/nv-tensorrt-repo-${os}-${tag}/7fa2af80.pub
sudo apt-get update
sudo apt-get install tensorrt

python3-libnvinfer安装 

python3 -m pip install numpy
sudo apt-get install python3-libnvinfer-dev

TensorFlow中使用tesnorrt,graphsurgeon-tf也会被一起安装

python3 -m pip install protobuf
sudo apt-get install uff-converter-tf

某些例子和python中需要ONNX graphsurgeon

python3 -m pip install numpy onnx
sudo apt-get install onnx-graphsurgeon

3、验证安装

dpkg -l | grep TensorRT

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第2张图片

 2.3. pip安装

虽然pip方式安装没啥问题,但实际上还是需要依赖很多其他的项

 仅支持python3.6到python3.9,以及CUDA11.x。Linux和X86_64 CPU。CentOS 7和Ubuntu 18.04以上。

开始之前

升级一下pip和setuptools

python3 -m pip install --upgrade setuptools pip

安装nvidia-pyindex。

python3 -m pip install nvidia-pyindex

如果使用requirements.txt可以在里面添加命以安装nvidia-pyindex。

--extra-index-url https://pypi.ngc.nvidia.com

步骤

1、安装tensorrt

python3 -m pip install --upgrade nvidia-tensorrt

安装的时候CUDA和CUDNN也会下载下来,因为tensorrt需要这些。

如果出现了一些错误信息,要么是nvidia-pyindex没有安装好,要么就是python版本不对。

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第3张图片

2、验证安装是否成功

导入tensorrt包

确认安装的tensorRT版本是否正确。

创建一个builder对象 

python3
>>> import tensorrt
>>> print(tensorrt.__version__)
>>> assert tensorrt.Builder(tensorrt.Logger())

驱动安装有问题

 三、tensorRT的生态圈

tensorrt会将模型部署成一个engine。

3.1 最基本的tensorrt工作流

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第4张图片

 3.2、 转换和部署选项

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第5张图片

 3.2.1 转换

转换一个tensorrt能够使用的模型主要有三个选择:

  • 使用TF-TRT
  • 使用.onnx文件。
  • 使用c++和python手动构建一个TensorRT API能够使用的网络。

TF-TRT可以转换TensorFlow模型的同时也提供了一个高级runtime API,但是个别特定的算子是不支持的。

ONNX是最常见的选择,它与框架无关,可以支持TensorFlow、pytorch等。ONNX中所有的算子都必须是tensorrt支持的,那些不支持的算子需要自己手动添加。ONNX转换只会生成单一的tensorrt 引擎,比TF-TRT开销要小一些。

某些情况下,比如为了提升性能或者自定义的要求,会通过TensorRT network defintion API手动构建一个TensorRT engines。实际上的手动构建过程也是一一对应的使用TensorRT算子去构建网络,并且载入训练好的模型参数。

3.2.2 部署

有三种部署的方式:

  • 在tensorFlow中直接部署
  • 使用独立的tensorrt runtime API部署
  • 使用NVIDIA Triton Inference Server部署

我们需要根据部署的方式选择对应的模型转换方式。

使用TF-TRT一般都是部署在TensorFlow中的,TF-TRT转换的结果是一个Tensorflow图,只不过其中的操作是TensorRT算子。也就是说TF-TRT模型可以在python中和使用其他TensorFlow模型一样使用。

TensorRT runtime API开销最小,控制最细微,但是如果有一些需要自定义的算子,需要编写成插件形式。一般都是其他AI框架导出到ONNX的。

NVIDIA Triton Inference Server是一个开源的推理服务软件,可以支持部署任意框架的模型(TensorFlow、tensorrt、pytorch、ONNX runtime),可以直接部署在本地或者其他云服务平台。可以并发执行多个推理,自带负载均衡。假如这是一个云服务,例如http形式的NVIDIA Triton Inference Server是你很好的选择。

3.3 选择一个正确的工作流

选择转换和部署模型的两个重要因素:

  • 选择的深度学习框架
  • 部署TensorRT的目的

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第6张图片

 四、部署ONNX的示例

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第7张图片

 4.1 导出模型

两个主要的方式

  • TF-TRT使用TensorFlow savedmodels
  • 保存成ONNX

下载ONNX形式的ResNet-50模型,并解压

wget https://s3.amazonaws.com/download.onnx/models/opset_8/resnet50.tar.gz
tar xzf resnet50.tar.gz

4.2 选择batch size

小的batch size延时会比较小,大的batch size吞吐量比较大。batch size越大,处理时间越长,但是减少了每个样本的推理时间。

TensorRT可以动态的设置batchsize的大小,也可以设置一个固定的值。比如BATCH_SIZE=64

4.3 选择精度

推理的精度明显可以比训练的时候要小,精度越低,计算越快、显存消耗越低,并且不会损失太多重要的精度信息。TensorRT支持TF32、FP32、FP16和INT8。

FP32是大多数框架在训练的时候默认的训练精度

import numpy as np
PRECISION = np.float32

4.4 转换模型

trtexec --onnx=resnet50/model.onnx --saveEngine=resnet_engine.trt

resnet_engine.trt就是TensorRT engine

4.5 部署模型
独立部署在python、C++中

部署在TensorFlow中。

1、创建ONNXClassifierWrapper

from onnx_helper import ONNXClassifierWrapper
N_CLASSES = 1000 # Our ResNet-50 is trained on a 1000 class ImageNet task
trt_model = ONNXClassifierWrapper("resnet_engine.trt", [BATCH_SIZE, N_CLASSES],
target_dtype = PRECISION)

2、生成模拟批量

BATCH_SIZE=32
dummy_input_batch = np.zeros((BATCH_SIZE, 224, 224, 3))

3、将batch数据喂入engine,得到预期的预测

predictions = trt_model.predict(dummy_input_batch)

直到运行的时候才开始导入和初始化engine,因此需要一些时间。

五、TF-TRT集成

TF-TRT是一个python接口,可以直接TensorFlow中使用,可以使用TensorFlow SavedModels直接保存NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第8张图片

 六、ONNX转换和部署

6.1导出ONNX

TensorFlow可以使用keras2onnx和tf2onnx。

也可以使用trtexec

6.1.1 从TensorFlow中到处ONNX

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第9张图片

步骤

1、从keras.applications导入ResNet-50模型,这里面也包含了预训练的权重

from tensorflow.keras.applications import ResNet50
model = ResNet50(weights='imagenet')

2、转换ResNet-50模型到ONNX形式

import tf2onnx
model.save('my_model')
!python -m tf2onnx.convert --saved-model my_model --output temp.onnx
onnx_model = onnx.load_model('temp.onnx')

3、设置batch size

import onnx
BATCH_SIZE = 64
inputs = onnx_model.graph.input
for input in inputs:
dim1 = input.type.tensor_type.shape.dim[0]
dim1.dim_value = BATCH_SIZE

4、保存ONNX文件

model_name = "resnet50_onnx_model.onnx"
onnx.save_model(onnx_model, model_name)

6.1.2 从pytorch中导出ONNX

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第10张图片

步骤

1、 从torchvision中导出ResNet-50模型,并且包含预训练权重

import torchvision.models as models
resnext50_32x4d = models.resnext50_32x4d(pretrained=True)

2、保存ONNX

import torch
BATCH_SIZE = 64
dummy_input=torch.randn(BATCH_SIZE, 3, 224, 224)

这里会创建一个假的batch。

3、保存ONNX文件

import torch.onnx
torch.onnx.export(resnext50_32x4d, dummy_input, "resnet50_onnx_model.onnx",
verbose=False)

6.2 将ONNX转换成TensorRT Engine

  • 使用trtexect
  • 使用TensorRT API
trtexec --onnx=resnet50_onnx_model.onnx --saveEngine=resnet_engine.trt

6.3 部署TensorRT Engine到python runtime API中

七、使用TensorRT Runtime API

TensorRT直接运行比TensorFlow的TF-TRT的性能要好很多。C++ API的开销是最低的,但是python的API很多,比如Numpy、Scipy,比较容易做一些原型设计、debugging和测试。

7.1 创建测试容器并构建tensorrt engine

步骤

1、下载源码

$ git clone https://github.com/NVIDIA/TensorRT.git
$ cd TensorRT/quickstart

2、将模型转换成ONNX

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第11张图片

 

        运行一个NVIDIA PyTorch容器

$ docker run --rm -it --gpus all -p 8888:8888 -v `pwd`:/workspace -w /workspace/
SemanticSegmentation nvcr.io/nvidia/pytorch:20.12-py3 bash

     导出模型到ONNX

$ python export.py

3、使用trtexec将ONNX构建成一个tensorRT engine

trtexec利用tensorrt onnx解析器载入onnx模型到TensorRT网络图中,然后TensorRT Builder API生成一个被优化的engine。这个构建过程比较耗时,但是可以离线操作。

trtexec --onnx=fcn-resnet101.onnx --fp16 --workspace=64 --minShapes=input:1x3x256x256
--optShapes=input:1x3x1026x1282 --maxShapes=input:1x3x1440x2560 --buildOnly --
saveEngine=fcn-resnet101.engine

--fp16 使用FP16精度,还有一个选项是FP32

--int8 使用INT8精度,还有一个选项是FP32

--best 为每一层使用所有支持的精度,以达到最佳性能

--workspace为算法设置持久显存的大小MB。基于特定平台,这个值应该尽可能的高,TensorRT会分配所需要的量,但是不会超过最大值。

--minShapes 和 --maxShapes指定网络输入的每个维度上的范围。--optShape指定auto-tuner应该处理的尺寸。
--buildOnly 不需要度量推理性能

--saveEngine 保存的序列化引擎的路径

--safe 就是tensorRT安全模式下运行。

--minTiming 和 --avgTiming在tactic selection时的最小和平均迭代次数。

--noBuilderCache 在tensorRT中禁用层定时缓存,通过缓存层概要信息,计时缓存有助于减少构建阶段花费的时间,并且对大多数模型都适用。在遇到问题的时候才打开这个开关。

--timingCacheFile可以保存和载入全局的timing cache。

4、可选项目。使用trtexect验证随机生成的伪数据输入情况。

trtexec --shapes=input:1x3x1026x1282 --loadEngine=fcn-resnet101.engine

--shapes就是输入的形状,假设成功了。

7.2 c++中调用Engine

1、构建并运行c++分割教程。

$ make
$ ./bin/segmentation_tutorial

步骤

1、从文件中反序列化TensorRT engine。该文件内容将被读取到缓冲并反序列化到内存。

td::vector engineData(fsize);
engineFile.read(engineData.data(), fsize);
util::UniquePtr
runtime{nvinfer1::createInferRuntime(sample::gLogger.getTRTLogger())};
util::UniquePtr mEngine(runtime-
>deserializeCudaEngine(engineData.data(), fsize, nullptr));

TensorRT对象通过destory()方法销毁,本示例中使用自定义删除方法的智能指针来管理生存周期。

struct InferDeleter
{
template 
void operator()(T* obj) const
{
if (obj) obj->destroy();
}
};
template 
using UniquePtr = std::unique_ptr

2、TensorRT执行上下文封装了执行状态,比如推理过程中产生的临时变量保存在持久化显存中。

因为分割模型的输入是动态变化的,但是推理的时候必须设置固定的形状。输出的形状可以查询网络输出形状。

auto input_idx = mEngine->getBindingIndex("input");
assert(mEngine->getBindingDataType(input_idx) == nvinfer1::DataType::kFLOAT);
auto input_dims = nvinfer1::Dims4{1, 3 /* channels */, height, width};
context->setBindingDimensions(input_idx, input_dims);
auto input_size = util::getMemorySize(input_dims, sizeof(float));
auto output_idx = mEngine->getBindingIndex("output");
assert(mEngine->getBindingDataType(output_idx) == nvinfer1::DataType::kINT32);
auto output_dims = context->getBindingDimensions(output_idx);
auto output_size = util::getMemorySize(output_dims, sizeof(int32_t));

网络输入输出索引可以通过名称查询

3、在准备推理的时,为输入输出分配CUDA显存,处理完数据后,就将数据复制到分配的显存当中,并生成引擎绑定列表。

语义分割中,输入数据会被归一化到[0,1],RGB归一化使用的均值是[0.485, 0.456, 0.406],标准差[0.229, 0.224,0.225]。此处操作有utility 类 RGBImageReader抽象。

void* input_mem{nullptr};
cudaMalloc(&input_mem, input_size);
void* output_mem{nullptr};
cudaMalloc(&output_mem, output_size);
const std::vector mean{0.485f, 0.456f, 0.406f};
const std::vector stddev{0.229f, 0.224f, 0.225f};
auto input_image{util::RGBImageReader(input_filename, input_dims, mean, stddev)};
input_image.read();
auto input_buffer = input_image.process();
cudaMemcpyAsync(input_mem, input_buffer.get(), input_size, cudaMemcpyHostToDevice, stream);

4、推理执行使用上下文executionV2或enqueueV2。在执行完成后,将预测结果复制到主机内存,并释放所有显存。
 

void* bindings[] = {input_mem, output_mem};
bool status = context->enqueueV2(bindings, stream, nullptr);
auto output_buffer = std::unique_ptr{new int[output_size]};
cudaMemcpyAsync(output_buffer.get(), output_mem, output_size, cudaMemcpyDeviceToHost, stream);
cudaStreamSynchronize(stream);
cudaFree(input_mem);
cudaFree(output_mem);

5、为了可视化结果,将预测结果用伪彩色显示,输出到output.ppm。有utility类ArgmaxImageWriter抽象。

const int num_classes{21};
const std::vector palette{ (0x1 << 25) - 1, (0x1 << 15) - 1, (0x1 << 21) - 1};
auto output_image{util::ArgmaxImageWriter(output_filename, output_dims, palette, num_classes)};
output_image.process(output_buffer.get());
output_image.write();

NVIDIA TensorRT----Quick Start Guide | NVIDIA Docs_第12张图片

7.3 在python中运行engine

1、安装pycuda

$ pip install pycuda

 2、运行jupyter,并且复制对应token到浏览器中http://:8888

$ jupyter notebook --port=8888 --no-browser --ip=0.0.0.0 --allow-root

3、打来tutorial-runtime.ipynb作参考

八、其他资源

表1.

资源 描述
layer构建的API文档

layer层手动构建是很有必要的,这样我们可以自定义的构建网络模型。

ONNX解析插件示例文档 如果模型中有TensorRT不支持的层,我们就可以自己写一个解析ONNX的插件。
ONNX-TensorRT 的GitHub 在python中使用ONNX-TensorRT做早期的原型设计非常有效。
TF-TRT产品文档 TF-TRT产品文档
分析工具 分析工具
TensorRT的产品文档 TensorRT的产品文档
TensorRT OSS的GitHub 有OSS TensorRT的组件、运用、插件示例等
TensorRT开发者页 包含下载、博客、代码示例

8.1 术语

Batch

batch是统一处理的输入集合,batch中每个实例具有相同的形状,并且经过网络的处理流程也是一样的,在推理过程中是并行处理的。

Builder

TensorRT的模型优化器,Builder接受一个网络的定义作为输入、执行一个与设备无关和指定设备的优化,并创建一个engine。

D

Dynamic batch

一种推理部署模式,batch size只有在运行的时候才知道。batch是推理时唯一可以配置的维度。

E

Engine

由TensorRT Builder优化的网络模型表达。

Explicit batch

指定Batch大小,ONNX解析中不支持。

Framework integration

一些如TensorFlow框架中集成了tensorRT.

N

Network definition

网络模型在TensorRT中的表示,包含tensor和operators的graph

O

ONNX

Open Neural Network eXchange,用于表示机器学习模型的独立框架标准。

ONNX parser

从ONNX模型中解析并创建一个tensorRT的网络定义。

P

Plan

序列化形式的优化后的推理引擎,为了初始化推理引擎,应用程序首先会从一个plan文件中反序列化出一个模型。典型的应用程序之构建一次引擎,并将其序列化为plan文件以供后续使用。

Precision

表示数值的精度,这个是在构建tensorRT的时候就会被指定,tensorRT支持FP32、FP16、INT8。之前大多数设备默认是FP32,现在默认为TF32,这是一种使用FP32存储用于低精度快速计算的形式。

R

Runtime

在engine推理时执行TensorRT的组件。runtime API支持引擎输入输出的同步异步执行、分析、枚举和查询。

T

TF-TRT

TensorFlow中集成的TensorRT,优化并执行兼容的子图,并允许tensorFlow执行剩余的子图。

你可能感兴趣的:(pytorch,深度学习)