从零开始 TensorRT(2)Python 篇:原生 API 构建网络

前言

学习资料:
TensorRT 源码示例
官方文档:Working With TensorRT Using The Python API
官方文档:TensorRT Python API
官方文档:CUDA Python
B站视频:TensorRT 教程 | 基于 8.6.1 版本
B站视频配套代码 cookbook

  在 Python 篇中会仿照视频教程中的内容,按以下顺序介绍:

(1)TensorRT 原生 API 构建网络:示例中使用 TensorRT 的 API 搭建网络并进行推理,由于网络过于简单(只有一层且输入与输出相同),会存在如何实际搭建一个网络模型、搭建网络后如何加载参数等疑问。但作为第一个示例,主要的作用是熟悉构建网络和执行推理的流程,这部分代码比较模板化,会经常用到。

(2)解析 ONNX 模型:示例中会把一个 Pytorch 模型导出为 ONNX 格式,然后用 TensorRT 读取并生成引擎进行推理,这也是目前最常用的方法。

(3)PyTorch 框架内 TensorRT 接口:使用 Pytorch 的 API 生成 TensorRT 引擎并推理,此示例最为简单。

PyCharm 环境问题

  初学 TensorRT 时遇到了这样的问题,拿到的示例代码在终端运行时一切正常,到 PyCharm 中明明使用了相同的 conda 环境,却无法正常运行。

Bug1:ImportError: libnvinfer.so.8: cannot open shared object file: No such file or directory
Bug2:TypeError: pybind11::init(): factory function returned nullptr
Bug3:[TRT] [E] 6: [libLoader.cpp::Impl::293] Error Code 6: Internal Error (Unable to load library: libnvinfer_builder_resource.so.8.6.1: libnvinfer_builder_resource.so.8.6.1: cannot open shared object file: No such file or directory)

最终解决方法

PyCharm 顶部菜单栏 → 运行 → 编辑配置 → 环境变量一栏(没有可在修改选项中勾选) → 添加 LD_LIBRARY_PATH=xxx/TensorRT-8.6.1.6/lib

修改后只对运行当前的 Python 文件有效,也可以在编辑配置模板中一同修改,这样新的运行文件也会用同样的配置。

解决过程

  首先碰到 Bug1,查到的解决办法是在 /etc/ld.so.conf 中添加 TensorRT 的 lib 路径,并刷新 sudo ldconfig。于是便碰到了 Bug2 和 Bug3,查到的解决办法是把 libnvinfer_builder_resource.so.8.6.1 复制到 /usr/lib 下。
  虽然程序能正常运行了,但这显然是个不太好的解决方案。

  修改 /etc/ld.so.conf~/.bashrc 都是添加库文件搜索路径,而又有所不同。
  ~/.bashrc 是 Bash shell 的配置文件,对于并非使用 Bash shell 启动的应用程序可能不会生效。而 /etc/ld.so.conf 是系统级别的配置,对终端、应用程序、IDE都有效。

  以下为个人做了各种测试后的一些发现:

(1)由于配置 LD_LIBRARY_PATH 会在终端生效,所以程序能正常运行,但在 PyCharm 环境并不生效,所以会出现找不到 libnvinfer.so.8 的报错,此时整个 TRT 的 lib 目录对于 PyCharm 都不是搜索路径。

(2)在配置 /etc/ld.so.conf 后,对 PyCharm 生效却依然报错,通过 ldconfig -p | grep nvinfer 查看动态库缓存可以发现,里面只有 do_not_link_against_nvinfer_builder_resource,打开 lib 目录可以发现,这个文件是 libnvinfer_builder_resource.so.8.6.1 的链接。经测试,这个链接是在配置 /etc/ld.so.conf 后才新生成的,文件名也直接说了不要链接 nvinfer_builder_resource。虽然没有探究为什么会新生成这样一个链接,但基本可以确定 TRT 并不支持这样配置环境。

(3)在配置 /etc/ld.so.conf 后,报错转变成了 Bug2 和 Bug3 其实就是找不到 libnvinfer_builder_resource.so.8.6.1,所以暴力的把它复制到 /usr/lib 下(系统默认搜索路径),是可以解决问题的。

(4)结合以上所有的发现,可以得知问题的根本是 lib 路径不在 PyCharm 环境中,使用系统级别配置却有个别文件会出现异常,这才导致了各种报错。从而可以想到,只要在 PyCharm 环境变量中加入 lib 路径,即可解决这种问题。

示例:TensorRT 原生 API 构建网络

参考源码:cookbook → 01-SimpleDemo → TensorRT8.5 → main.py

源码

  对参考源码进行了一些简化和修改:

  1. 去除从文件读取引擎部分
  2. 省略了错误判断
  3. 网络只有一个输入张量和一个输出张量,内存和显存操作部分去除了循环操作
import numpy as np
import tensorrt as trt
from cuda import cudartlogger = trt.Logger(trt.Logger.ERROR)
builder = trt.Builder(logger)
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
profile = builder.create_optimization_profile()
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)inputTensor = network.add_input("inputT0", trt.float32, [-1, -1, -1])
profile.set_shape(inputTensor.name, [1, 1, 1], [3, 4, 5], [6, 8, 10])
config.add_optimization_profile(profile)
identityLayer = network.add_identity(inputTensor)
network.mark_output(identityLayer.get_output(0))
engineString = builder.build_serialized_network(network, config)
with open("./model.plan", "wb") as f:f.write(engineString)engine = trt.Runtime(logger).deserialize_cuda_engine(engineString)
nIO = engine.num_io_tensors
lTensorName = [engine.get_tensor_name(i) for i in range(nIO)]
context = engine.create_execution_context()
context.set_input_shape(lTensorName[0], [3, 4, 5])data = np.arange(3 * 4 * 5, dtype=np.float32).reshape(3, 4, 5)
inputHost = np.ascontiguousarray(data)
outputHost = np.empty(context.get_tensor_shape(lTensorName[1]),dtype=trt.nptype(engine.get_tensor_dtype(lTensorName[1]))
)
_, inputDevice = cudart.cudaMalloc(inputHost.nbytes)
_, outputDevice = cudart.cudaMalloc(outputHost.nbytes)
context.set_tensor_address(lTensorName[0], inputDevice)
context.set_tensor_address(lTensorName[1], outputDevice)cudart.cudaMemcpy(inputDevice, inputHost.ctypes.data, inputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice)
context.execute_async_v3(0)
cudart.cudaMemcpy(outputHost.ctypes.data, outputDevice, outputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost)print(lTensorName[0])
print(inputHost)
print(lTensorName[1])
print(outputHost)cudart.cudaFree(inputDevice)
cudart.cudaFree(outputDevice)

逐句分析

(1)构建期

"日志记录器 Logger"
"多个 Builder 可共享同个 Logger, 日志等级: VERBOSE, INFO, WARNING, ERROR, INTERNAL_ERROR"
"通常使用 VERBOSE, INFO 可查看优化信息"
logger = trt.Logger(trt.Logger.ERROR)
"计算图构建器 Builder"
"模型搭建的入口, 网络的内部表示和可执行程序引擎有它的成员方法生成"
builder = trt.Builder(logger)
"计算网络(计算图) Network"
"网络的主体, 搭建网络时往里添加层并标记输入输出节点"
"EXPLICIT_BATCH 模式: 显示batch维度, 可支持 Batch Normalization, Reshape, Transpose, Reduce 等 batch 维度参与的各种变换"
"IMPLICIT_BATCH 模式: 隐藏batch维度, 老版本默认模式, 新版本逐渐弃用"
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
"动态模式(Dynamic Shape Mode)下的配置器 Optimization Profile, 帮助网络优化"
"动态模式下, 输入张量形状可以在推理时决定"
profile = builder.create_optimization_profile()"构建器的配置器 Config"
"用于设置模型参数, 例如是否开启 FP16, INT8 模式等"
config = builder.create_builder_config()
"设置可用显存(单位: Byte)"
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)"网络输入张量, 有3个维度且每个维度的尺寸都可变"
inputTensor = network.add_input("inputT0", trt.float32, [-1, -1, -1])
"给定输入张量的最小、最常见、最大尺寸"
"profile.set_shape(tensorName, minShape, commonShape, maxShape)"
profile.set_shape(inputTensor.name, [1, 1, 1], [3, 4, 5], [6, 8, 10])
config.add_optimization_profile(profile)"添加 identity 层(恒等函数)"
identityLayer = network.add_identity(inputTensor)
"网络输出"
network.mark_output(identityLayer.get_output(0))
"生成序列化网络"
engineString = builder.build_serialized_network(network, config)

(2)运行期

"计算图可执行程序 Engine"
engine = trt.Runtime(logger).deserialize_cuda_engine(engineString)
nIO = engine.num_io_tensors
lTensorName = [engine.get_tensor_name(i) for i in range(nIO)]
"GPU进程"
context = engine.create_execution_context()
"推理时实际输入的形状"
context.set_input_shape(lTensorName[0], [3, 4, 5])data = np.arange(3 * 4 * 5, dtype=np.float32).reshape(3, 4, 5)
"CPU 内存申请"
inputHost = np.ascontiguousarray(data)
outputHost = np.empty(context.get_tensor_shape(lTensorName[1]),dtype=trt.nptype(engine.get_tensor_dtype(lTensorName[1]))
)
"GPU 显存申请"
_, inputDevice = cudart.cudaMalloc(inputHost.nbytes)
_, outputDevice = cudart.cudaMalloc(outputHost.nbytes)
"设置张量显存地址"
context.set_tensor_address(lTensorName[0], inputDevice)
context.set_tensor_address(lTensorName[1], outputDevice)
"输入数据从内存拷贝到显存"
cudart.cudaMemcpy(inputDevice, inputHost.ctypes.data, inputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice)
"模型推理"
context.execute_async_v3(0)
"输出数据从显存拷贝到内存"
cudart.cudaMemcpy(outputHost.ctypes.data, outputDevice, outputHost.nbytes, cudart.cudaMemcpyKind.cudaMemcpyDeviceToHost)
"释放显存"
cudart.cudaFree(inputDevice)
cudart.cudaFree(outputDevice)

(3)从文件读取
  省略构建期直接读取文件,可以节省大量时间,但是只能在当前的软硬件环境下使用

with open("./model.plan", "rb") as f:engineString = f.read()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/666492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OSG帧渲染,如何实现自定义动画效果

看到这个标题,老司机可能会想到OSG动画相关的内容,比如osg::AnimationPath类和osg::AnimationPathCallback类,这些动画类,可以实现按照一定的插值方式,生成路径,物体对象按照生成的路径或者预先指定的路径来完成相应的动作的动画。 路径动画有三种动画模式,分别为单摆环…

幻兽帕鲁服务器游戏版本怎么升级更新?

哈喽大家好&#xff0c;我是咕噜美乐蒂&#xff0c;很高兴又见面啦&#xff01; 幻兽帕鲁&#xff08;Monster Hunter: World&#xff09;是一款热门的多人在线游戏&#xff0c;玩家可以在服务器上与其他玩家一起探险、狩猎怪物。为了保持游戏的平衡性和提供更好的游戏体验&am…

【百度Apollo】探索创新之路:深入了解Apollo开放平台

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

docker部署RedisCluster集群简单介绍

本文介绍自己建立一个redis-cluster集群的实践&#xff0c;三主三从&#xff0c;使用docker搭建。 其实搭建很简单&#xff0c;就是建立6个容器&#xff0c;每个容器配置不同的端口号&#xff0c;其他的都是一样的。 假设建立6个端口号分别为 5555到5560。 配置文件 port 5…

redis相关问题

面试官&#xff1a;什么是缓存穿透 ? 怎么解决 ? 候选人&#xff1a; 嗯~~&#xff0c;我想一下 缓存穿透是指查询一个一定不存在的数据&#xff0c;如果从存储层查不到数据则不写入缓存&#xff0c;这将导致这个不存在的数据每次请求都要到 DB 去查询&#xff0c;可能导致 D…

树莓派突然不能ssh远程连接的踩坑记录及解决方案

在家研究树莓派&#xff0c;远程连接树莓派吃了不少苦&#xff0c;总是一些意想不到的问题出现&#xff0c;明明昨天还能远程连接&#xff0c;今天又不能了。经过一系列排查&#xff0c;终于锁定&#xff1a; 因为我之前设置的树莓派的静态ip地址&#xff0c;但是可能因为是家…

ai创作软件有哪些?这5个软件了解一下

ai创作软件有哪些&#xff1f;随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域都展现出了惊人的实力。特别是在内容创作领域&#xff0c;AI技术已经成为了助力创作者们提高效率、释放创意的得力助手。今天&#xff0c;我们将为大家介绍五款AI创作…

开源模型应用落地-业务优化篇(四)

一、前言 经过线程池优化、请求排队和服务实例水平扩容等措施,整个AI服务链路的性能得到了显著地提升。但是,作为追求卓越的大家,绝不会止步于此。我们的目标是在降低成本和提高效率方面不断努力,追求最佳结果。如果你们在实施AI项目方面有经验,那一定会对GPU服务器的高昂…

软件工程(最简式总结)

目录 第一章:概述 1.软件危机的表现原因 2.常见的软件开发方法包括&#xff1a; 3.软件工程基本原则 4.软件工程三要素 5.设计模式的分类 6.针对变换型数据流设计步骤 7.针对事务型数据流设计步骤 第二章&#xff1a;软件过程 1.软件生命周期 2.软件过程模型 &…

视觉惯性SLAM系列——ORB-SLAM3的重定位线程(Relocalization Thread)(九)

ORB-SLAM3的重定位线程&#xff08;Relocalization Thread&#xff09;&#xff08;九&#xff09; 重定位线程&#xff08;Relocalization Thread&#xff09;在ORB-SLAM3系统中扮演着关键的角色&#xff0c;尤其是在跟踪丢失的情况下。这个线程的主要任务是在相机失去当前轨迹…

flask_django_python五金电商网络营销的可视化分析研究

前面部分完成了系统需求分析&#xff0c;了解到新闻数据业务方面的需求&#xff0c;系统主要分为用户管理、五金信息管理、在线留言、系统管理等功能。销的可视化研究&#xff0c;并对这些数据进行处理&#xff0c; 然后对这些数据进行可视化分析和统计。 Python 爬虫技术目前来…

Element-plus之el-upload上传图片后回显,以及将回显的图片再次上传

在实际的业务中往往需要把提交但尚未上传的图片显示回前端&#xff0c;等待上传&#xff0c;以下方法是将提交后的图片回显的方法 <template><el-uploadaction"/api/imageContainer/saveOrUpdate"accept"image/bmp,image/jpeg,image/jpg,image/png,ima…

优雅的从HuggingFace下载模型

1. 下载全部文件 以下都以下载bloom模型为例 git lfs install git lfs clone https://huggingface.co/bigscience/bloom-7b1这种方式下载会显示下载的进度及网速&#xff0c;因此一般推荐使用这种方式下载。如果直接使用git clone https://huggingface.co/bigscience/bloom-7…

【云计算】opentack的高级服务部署与调优

opentack的高级服务部署与调优 swift 对象存储 安装 Swift 服务。安装完成后&#xff0c;使用命令创建一个名叫 examcontainer 的容器&#xff0c;将 cirros-0.3.4-x86_64-disk.img 镜像上传到 examcontainer 容器中&#xff0c;并 设置分段存放&#xff0c;每一段大小为 10…

js数组和字符串之间的转换方式以及数组的一些方法

一、数组和字符串之间的转换方式 1&#xff09;将字符串切割成字符串数组—stringObject.split(separator, howmany) seperator-----字符串、正则表达式&#xff0c;必需 howmany------指定返回的数组的最大长度&#xff0c;可省略&#xff0c;省略后全量返回 源代码 var str&q…

Linux内核与驱动面试经典“小”问题集锦(1)

笔者混迹职场这么多年来换了不少工作。头些年做的是单片机工程师&#xff0c;后来转入了Linux。转入Linux后&#xff0c;一开始做BSP和驱动工程师&#xff08;当然后来应用工程师的事也没少干&#xff09;&#xff0c;近几年来专做了Linux内核与系统工程师。由打转入Linux后&am…

c++阶梯之类与对象(一)

目录 1.面向过程与面向对象 c语言的视角&#xff1a; c的视角 2. 类的引入 3. 类的定义 3.1 类的两种定义方式 3.2 成员变量如何命名 4. 类的访问限定符与封装 4.1 访问限定符 4.2 封装 5. 类的作用域 6. 类的实例化 7. 类对象模型 7.1 怎么计算一个类对象的…

redis布隆过滤器(Bloom)详细使用教程

文章目录 布隆过滤器1. 原理2. 结构和操作3. 特点和应用场景4. 缺点和注意事项 应用-redis插件布隆过滤器使用详细过程安装以及配置springboot项目使用redis布隆过滤器下面是布隆过滤器的一些基础命令 扩展 布隆过滤器 Bloom 过滤器是一种概率型数据结构&#xff0c;用于快速判…

解决方案必备PPT网站

解决方案工作过程中&#xff0c;必备的技能: 1.word排版&#xff08;投标文件的编写等...&#xff09; 2.PPT汇报&#xff08;如何快速找到你需要的模版&#xff0c;并且输入汇报资料&#xff09; 免费&#xff08;免费使用&#xff0c;同时也不需要注册&#xff09; 1.优…

【ETOJ P1013】小e的书架 题解(二分查找)

题目描述 小e要把 n n n 本规格相同的书放进书架里&#xff0c;对于每一本书&#xff0c;他可以横着放也可以竖着放&#xff08;不能斜着放&#xff09;。 书的宽度为 1 1 1&#xff0c;高度为 h h h&#xff0c;书架的高度为 t t t&#xff0c;意味着如果你横着放&#…