tensorrt部署深度学习模型

 GitHub - NVIDIA/TensorRT: TensorRT is a C++ library for high performance inference on NVIDIA GPUs and deep learning accelerators.TensorRT is a C++ library for high performance inference on NVIDIA GPUs and deep learning accelerators. - GitHub - NVIDIA/TensorRT: TensorRT is a C++ library for high performance inference on NVIDIA GPUs and deep learning accelerators.https://github.com/NVIDIA/TensorRT使用 TensorRT 加速深度学习推理 - NVIDIA 技术博客想要更多吗?查看 DLI 实践培训课程: 用 TensorRT 优化和部署 TensorFlow 模型 这是的更新版本 如何用…https://developer.nvidia.com/zh-cn/blog/speeding-up-deep-learning-inference-using-tensorrt/

 tensorflow-tensorrt - Databrickshttps://docs.microsoft.com/zh-cn/azure/databricks/_static/notebooks/deep-learning/tensorflow-tensorrt.html

 7.TensorRT中文版开发教程-----TensorRT中的INT8量化详解_扫地的小何尚的博客-CSDN博客7. 如何使用TensorRT中的INT8点击此处加入NVIDIA开发者计划7.1. Introduction to QuantizationTensorRT 支持使用 8 位整数来表示量化的浮点值。量化方案是对称均匀量化 - 量化值以有符号 INT8 表示,从量化到非量化值的转换只是一个乘法。在相反的方向上,量化使用倒数尺度,然后是舍入和钳位。要启用任何量化操作,必须在构建器配置中设置 INT8 标志。7.1.1. Quantization Workflows创建量化网络有两种工作流程:训https://blog.csdn.net/kunhe0512/article/details/124506907

 基于 TensorRT 实现 Bert 预训练模型推理加速(超详细-附核心代码-避坑指南) - 知乎更新日志: 2022.01.14:八-1,导出ONNX文件,输出设置动态尺寸,增加FP16精度加速数据一、前言本文主要基于 TensorRT 实现 Bert 预训练模型的推理加速,完成这篇笔记的内容,你可以了解以下知识点: 使用 NVIDIA …https://zhuanlan.zhihu.com/p/446477075

【理论知识】实际部署中tensorrt的简单理解_qqsuiying的博客-CSDN博客_tensorrt部署因为各种项目的原因,其实已经用过一段时间tensorrt了,但是一直没仔细梳理过理论知识了,在b站刷到官方教程,写个博客梳理一下tensorrt基础知识和开发流程。(写到一半莫名其妙后半部分被csdn吞了,草稿找不到了,以后还是本地写了)tensorrt简介tensorrt是NV官方的深度学习部署工具➢ 用于高效实现已训练好的深度学习模型的推理过程的 SDK ➢ 内含推理优化器和运行时环境 ➢ 使 DL 模型能以更高吞吐量和更低的延迟运行 ➢ 有 C++ 和 python 的 API,完全等价可以混用tenhttps://blog.csdn.net/qqsuiying/article/details/125272916

 TensorRT8.2最新版入门教程 - 知乎废话不多说,下面进入正题。最近搞了几周TensorRT感知模型部署,查阅了很多资料,发现之前的博客要么是版本太老,不适用新版本,要么是案例代码不全(如老潘),不利于初学者入门。遂花时间重新走了一遍安装流程,并…https://zhuanlan.zhihu.com/p/467401558

 什么是TensorRT - 知乎Tensor是一个有助于在NVIDIA图形处理单元(GPU)上高性能推理c++库。它旨在与TesnsorFlow、Caffe、Pytorch以及MXNet等训练框架以互补的方式进行工作,专门致力于在GPU上快速有效地进行网络推理。 如今现有的一些训…https://zhuanlan.zhihu.com/p/356072366

TensorRT概览_人工智能曾小健的博客-CSDN博客_tensorrt使用cpuTensorRT能加速模型吗?能!根据官方文档,使用TensorRT,在CPU或者GPU模式下其可提供10X乃至100X的加速。本人的实际经验中,TensorRT提供了20X的加速。TensorRT为什么能提升模型的运行速度?TensorRT是英伟达针对自家平台做的加速包,TensorRT主要做了这么两件事情,来提升模型的运行速度。TensorRT支持INT8和FP16的计算。深度学习网络在训练时,通常使用 32 位或 16 位数据。TensorRT则在网络的推理时选用不这么高的精度,达到加https://blog.csdn.net/sinat_37574187/article/details/119801045

 https://www.jianshu.com/p/b7404294041eicon-default.png?t=M85Bhttps://www.jianshu.com/p/b7404294041e

 ========================================================================

因为各种项目的原因,其实已经用过一段时间tensorrt了,但是一直没仔细梳理过理论知识了,在b站刷到官方教程,写个博客梳理一下tensorrt基础知识和开发流程。

(写到一半莫名其妙后半部分被csdn吞了,草稿找不到了,以后还是本地写了)

tensorrt简介

tensorrt是NV官方的深度学习部署工具

➢ 用于高效实现已训练好的深度学习模型的推理过程的 SDK ➢ 内含推理优化器和运行时环境 ➢ 使 DL 模型能以更高吞吐量和更低的延迟运行 ➢ 有 C++ 和 python 的 API,完全等价可以混用

tensorrt主要进行以下工作

➢ 构建期(推理优化器) ➢ 模型解析 / 建立 加载 Onnx 等其他格式的模型 / 使用原生 API 搭建模型 ➢ 计算图优化 横向层融合(Conv),纵向层融合(Conv+add+ReLU), …… ➢ 节点消除 去除无用层,节点变换(Pad, Slice, Concat, Shuffle), …… ➢ 多精度支持 FP32 / FP16 / INT8 / TF32(可能插入 reformat 节点) ➢ 优选 kernel / format 硬件有关优化 ➢ 导入 plugin 实现自定义操作 ➢ 显存优化 显存池复用 ➢ 运行期(运行时环境) ➢ 运行时环境 对象生命期管理,内存显存管理,异常处理 ➢ 序列化反序列化 推理引擎保存为文件或从文件中加载

2.tensorrt的部署简要流程

搭建tensorrt的基本流程

➢ 基本流程 ➢ 构建期 ➢ 建立 Builder(引擎构建器) ➢ 创建 Network(计算图内容) ➢ 生成 SerializedNetwork(网络的 TRT 内部表示) ➢ 运行期 ➢ 建立 Engine 和 Context ➢ Buffer 相关准备(Host 端 + Device 端 + 拷贝操作) ➢ 执行推理(Execute)

示例代码在官方github的01-SimpleDemo/TensorRT8中的 TRT8-cudart.py 或 TRT8.cpp(python 和 C++ 等价版本)

官方github上的代码更新过,和教程不完全相同,但思路完全一样。

构建期:

logger = trt.Logger(trt.Logger.ERROR)                                       # 指定 Logger,可用等级:VERBOSE,INFO,WARNING,ERRROR,INTERNAL_ERROR
if os.path.isfile(trtFile):                                                 # 如果有 .plan 文件则直接读取
    with open(trtFile, 'rb') as f:
        engineString = f.read()
    if engineString == None:
        print("Failed getting serialized engine!")
        return
    print("Succeeded getting serialized engine!")
else:                                                                       # 没有 .plan 文件,从头开始创建
    builder = trt.Builder(logger)                                           # 网络元信息,Builder/Network/BuilderConfig/Profile 相关
    network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
    profile = builder.create_optimization_profile()
    config = builder.create_builder_config()
    config.max_workspace_size = 1 << 30

    inputTensor = network.add_input('inputT0', trt.DataType.FLOAT, [-1, -1, -1])  # 指定输入张量
    profile.set_shape(inputTensor.name, [1, 1, 1], [3, 4, 5], [6, 8, 10])   # 指定输入张量 Dynamic Shape 范围
    config.add_optimization_profile(profile)

    identityLayer = network.add_identity(inputTensor)                       # 恒等变换
    network.mark_output(identityLayer.get_output(0))                        # 标记输出张量

    engineString = builder.build_serialized_network(network, config)        # 生成序列化网络
    if engineString == None:
        print("Failed getting serialized engine!")
        return
    print("Succeeded getting serialized engine!")
    with open(trtFile, 'wb') as f:                                          # 将序列化网络保存为 .plan 文件
        f.write(engineString)
        print("Succeeded saving .plan file!")

运行期:

```engine = trt.Runtime(logger).deserialize_cuda_engine(engineString)          # 使用 Runtime 来创建 engine
if engine == None:
    print("Failed building engine!")
    return
print("Succeeded building engine!")

context = engine.create_execution_context()                                 # 创建 context(相当于 GPU 进程)
context.set_binding_shape(0, [3, 4, 5])                                     # Dynamic Shape 模式需要绑定真实数据形状
nInput = np.sum([engine.binding_is_input(i) for i in range(engine.num_bindings)])  # 获取 engine 绑定信息
nOutput = engine.num_bindings - nInput
for i in range(nInput):
    print("Bind[%2d]:i[%2d]->" % (i, i), engine.get_binding_dtype(i), engine.get_binding_shape(i), context.get_binding_shape(i), engine.get_binding_name(i))
for i in range(nInput,nInput+nOutput):    
    print("Bind[%2d]:o[%2d]->" % (i, i - nInput), engine.get_binding_dtype(i), engine.get_binding_shape(i), context.get_binding_shape(i), engine.get_binding_name(i))

data = np.arange(3 * 4 * 5, dtype=np.float32).reshape(3, 4, 5)              # 准备数据和 Host/Device 端内存
bufferH = []
bufferH.append(np.ascontiguousarray(data.reshape(-1)))
for i in range(nInput, nInput + nOutput):
    bufferH.append(np.empty(context.get_binding_shape(i), dtype=trt.nptype(engine.get_binding_dtype(i))))
bufferD = []
for i in range(nInput + nOutput):
    bufferD.append(cudart.cudaMalloc(bufferH[i].nbytes)[1])

for i in range(nInput):                                                     # 首先将 Host 数据拷贝到 Device 端
    cudart.cudaMemcpy(bufferD[i], bufferH[i].ctypes.data, bufferH[i].nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice)

context.execute_v2(bufferD)                                                 # 运行推理计算

for i in range(nInput, nInput + nOutput):                                   # 将结果从 Device 端拷回 Host 端
    cudart.cudaMemcpy(bufferH[i].ctypes.data, bufferD[i], bufferH[i].nbytes, cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost)

for i in range(nInput + nOutput):
    print(engine.get_binding_name(i))
    print(bufferH[i].reshape(context.get_binding_shape(i)))

for b in bufferD:                                                           # 释放 Device 端内存
    cudart.cudaFree(b)

tensorrt搭建与开发方式 官方列出了三种方案

➢ 使用框架自带 TRT 接口(TF-TRT, Torch-TensorRT) ➢ 简单灵活,部署仍在原框架中,无需书写 Plugin

➢ 使用 Parser(TF/Torch/… → ONNX[1] → TensorRT) ➢ 流程成熟, ONNX 通用性好,方便网络调整,兼顾效率性能

➢ 使用 Parser(TF/Torch/… → ONNX[1] → TensorRT) ➢ 流程成熟, ONNX 通用性好,方便网络调整,兼顾效率性能

三种方案各有优劣


 

我自己做过的以及网上开源的项目中,更过是采用第二种方式,第一种方案也有,第三种则见得少一些(毕竟我也是刚开始接触tensorrt)

github中也给出了使用API搭建MNIST手写识别模型的示例

不过pytorch和paddle的demo都是TODO待更新,目前只有TensorFlow的

代码基本流程如下: ➢ TensorFlow 中创建并训练一个网络 ➢ 提取网络权重,保存为 para.npz ➢ TensorRT 中重建该网络并加载 para.npz 中的权重 ➢ 生成推理引擎 ➢ 用引擎做实际推理

tensorrt运行期

engine是trt中的计算引擎,有点类似于cpu计算中的线程,算是基本计算单元。

➢生成 TRT 内部表示 ➢ serializedNetwork = builder. build_serialized_network(network, config) ➢生成 Engine ➢ engine = trt.Runtime(logger).deserialize_cuda_engine( serializedNetwork ) ➢创建 Context ➢ context = engine.create_execution_context() ➢绑定输入输出(Dynamic Shape 模式必须) ➢ context.set_binding_shape(0,[1,1,28,28]) ➢准备 Buffer ➢ inputHost = np.ascontiguousarray(inputData.reshape(-1)) ➢ outputHost = np.empty(context.get_binding_shape(1), trt.nptype(engine.get_binding_dtype(1))) ➢ inputDevice = cudart.cudaMalloc(inputHost.nbytes)[1] ➢ outputDevice = cudart.cudaMalloc(outputHost.nbytes)[1] ➢执行计算 ➢ cudart.cudaMemcpy(inputDevice, inputHost.ctypes.data, inputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice) ➢ context.execute_v2([int(inputDevice), int(outputDevice)]) ➢ cudart.cudaMemcpy(outputHost.ctypes.data, outputDevice, outputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost)

这里补了一点 CUDA异构计算的知识

➢CUDA 异构计算 ➢ 同时准备 CPU 端内存和 GPU端显存 ➢ 开始计算前把数据从内存拷贝到显存中 ➢ 计算过程的输入输出数据均在 GPU端读写 ➢ 计算完成后要把结果拷贝会内存才能使用

在运行过程中就需要涉及到内存和显存的数据拷贝

➢Buffer ➢ 内存和显存的申请 ➢ inputHost = np.ascontiguousarray(inputData.reshape(-1)) ➢ outputHost = np.empty(context.get_binding_shape(1), trt.nptype(engine.get_binding_dtype(1))) ➢ inputDevice = cudart.cudaMalloc(inputHost.nbytes)[1] ➢ outputDevice = cudart.cudaMalloc(outputHost.nbytes)[1]

➢ 内存和显存之间的拷贝 ➢ cudart.cudaMemcpy(inputDevice, inputHost.ctypes.data, inputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice) ➢ cudart.cudaMemcpy(outputHost.ctypes.data, outputDevice, outputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost)

➢ 推理完成后释放显存 ➢ cudart.cudaFree(inputDevice) ➢ cudart.cudaFree(outputDevice)

1

1

开发者辅助工具

➢trtexec TensorRT 命令行工具,主要的 End2End 性能测试工具 ➢Netron 网络可视化 ➢onnx-graphsurgeon onnx 计算图编辑 ➢polygraphy 结果验证与定位,图优化 ➢Nsight Systems 性能分析

等用熟了之后看看能不能单独写个博客

主要参考自nvidia官方给出的教程,教程是基于8.2.3版本的TensorRT。

trt-samples-for-hackathon-cn/cookbook at master · NVIDIA/trt-samples-for-hackathon-cn · GitHub

在b站官方还有个简单的讲解视频,不过个人觉得ppt比讲解本身重要一点。

以及

(7条消息) TensorRT 之入门篇点PY的博客-CSDN博客tensorrt教程

你可能感兴趣的:(算法工程,python,人工智能,机器学习)