本章说明 c++ api 的基本用法,假设您从 onnx 模型开始。 sampleonnxmnist更详细地说明了这个用例。
c++ api 可以通过头文件nvinfer.h访问,并且位于nvinfer1命名空间中。例如,一个简单的应用程序可能以:
#include “nvinfer.h”using namespace nvinfer1; tensorrt c++ api 中的接口类以前缀i开头,例如ilogger 、 ibuilder等。
cuda 上下文会在 tensorrt 第一次调用 cuda 时自动创建,如果在该点之前不存在。通常最好在第一次调用 tensort 之前自己创建和配置 cuda 上下文。 为了说明对象的生命周期,本章中的代码不使用智能指针;但是,建议将它们与 tensorrt 接口一起使用。
3.1. the build phase 要创建构建器,首先需要实例化ilogger接口。此示例捕获所有警告消息,但忽略信息性消息:
class logger : public ilogger { void log(severity severity, const char* msg) noexcept override { // suppress info-level messages if (severity <= severity::kwarning) std::cout << msg << std::endl; }} logger; 然后,您可以创建构建器的实例:
ibuilder* builder = createinferbuilder(logger); 3.1.1. creating a network definition 创建构建器后,优化模型的第一步是创建网络定义:
uint32_t flag = 1u
3.1.2. importing a model using the onnx parser 现在,需要从 onnx 表示中填充网络定义。 onnx 解析器 api 位于文件nvonnxparser.h中,解析器位于nvonnxparser c++ 命名空间中。
#include “nvonnxparser.h”using namespace nvonnxparser; 您可以创建一个 onnx 解析器来填充网络,如下所示:
iparser* parser = createparser(*network, logger); 然后,读取模型文件并处理任何错误。
parser->parsefromfile(modelfile, static_cast(ilogger::severity::kwarning));for (int32_t i = 0; i < parser.getnberrors(); ++i){std::cout desc() config->setmemorypoollimit(memorypooltype::kworkspace, 1u delete parser;delete network;delete config;delete builder; 然后可以将引擎保存到磁盘,并且可以删除它被序列化到的缓冲区。
delete serializedmodel 注意:序列化引擎不能跨平台或 tensorrt 版本移植。引擎特定于它们构建的确切 gpu 模型(除了平台和 tensorrt 版本)。 3.2. deserializing a plan 假设您之前已经序列化了一个优化模型并希望执行推理,您将需要创建一个运行时接口的实例。与构建器一样,运行时需要一个记录器实例:
iruntime* runtime = createinferruntime(logger); 假设您已将模型从缓冲区中读取,然后可以对其进行反序列化以获得引擎:
icudaengine* engine = runtime->deserializecudaengine(modeldata, modelsize); 3.3. performing inference 引擎拥有优化的模型,但要执行推理,我们需要管理中间激活的额外状态。这是通过executioncontext接口完成的:
iexecutioncontext *context = engine->createexecutioncontext(); 一个引擎可以有多个执行上下文,允许一组权重用于多个重叠的推理任务。 (当前的一个例外是使用动态形状时,每个优化配置文件只能有一个执行上下文。)
要执行推理,您必须为输入和输出传递 tensorrt 缓冲区,tensorrt 要求您在指针数组中指定。您可以使用为输入和输出张量提供的名称查询引擎,以在数组中找到正确的位置:
int32_t inputindex = engine->getbindingindex(input_name);int32_t outputindex = engine->getbindingindex(output_name); 使用这些索引,设置一个缓冲区数组,指向 gpu 上的输入和输出缓冲区:
void* buffers[2];buffers[inputindex] = inputbuffer;buffers[outputindex] = outputbuffer; 然后,您可以调用 tensorrt 的 enqueue 方法以使用cuda 流异步启动推理:
context->enqueuev2(buffers, stream, nullptr); 通常在内核之前和之后将cudamemcpyasync() 排入队列以从 gpu 中移动数据(如果数据尚不存在)。 enqueuev2()的最后一个参数是一个可选的 cuda 事件,当输入缓冲区被消耗时发出信号,并且可以安全地重用它们的内存。
要确定内核(可能还有memcpy() )何时完成,请使用标准 cuda 同步机制,例如事件或等待流。
关于作者
ken he 是 nvidia 企业级开发者社区经理 & 高级讲师,拥有多年的 gpu 和人工智能开发经验。自 2017 年加入 nvidia 开发者社区以来,完成过上百场培训,帮助上万个开发者了解人工智能和 gpu 编程开发。在计算机视觉,高性能计算领域完成过多个独立项目。并且,在机器人和无人机领域,有过丰富的研发经验。对于图像识别,目标的检测与跟踪完成过多种解决方案。曾经参与 gpu 版气象模式grapes,是其主要研发者。
电机控制系统故障原因有哪些
石油化工自动化控制仪表的主要功能分析
高通洽购TD厂商苏州傲世通 欲通吃3G芯片市场
此前比特币大涨是一个人为操纵的结果?
NIPS会议又出现了抱怨声,这届NIPS真不好办
TensorRT的C++接口解析
全球智能手机活跃用户数仍持续成长
东芝闪存业务如果无法以180亿美元卖出,就只剩涨价或上市两条路
光纤带光缆套管的设计原理分析
DS2152, DS2154, DS2151, DS2153
斯洛伐克不会再将中国电信供应商华为视为安全威胁
从产业链到生态圈,电气化和数字化将重塑未来十年的世界
PROC SQL介绍
华为Mate 9和小米MIX,你选谁?
西门子S7-200 SMART通信端口连接技术分析
测量无线系统中的驻波比和增益
vivo Z5曝光将标配22.5W快充搭载骁龙712平台和4500mAh的大电池
数字串扰在数据转换器中的影响:串扰对时钟的影响
彭博称美国服务器发现中国侵入的痕迹
深度学习经典的自动标注软件介绍