4.3.tensorRT基础(1)-实现模型的推理过程

news2024/11/28 0:42:51

目录

    • 前言
    • 1. inference案例
    • 总结

前言

杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。

本次课程学习 tensorRT 基础-实现模型的推理过程

课程大纲可看下面的思维导图

在这里插入图片描述

1. inference案例

tensorRT 推理的案例代码如下所示:

void inference(){

    // ------------------------------ 1. 准备模型并加载   ----------------------------
    TRTLogger logger;
    auto engine_data = load_file("engine.trtmodel");
    // 执行推理前,需要创建一个推理的runtime接口实例。与builer一样,runtime需要logger:
    nvinfer1::IRuntime* runtime   = nvinfer1::createInferRuntime(logger);
    // 将模型从读取到engine_data中,则可以对其进行反序列化以获得engine
    nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(engine_data.data(), engine_data.size());
    if(engine == nullptr){
        printf("Deserialize cuda engine failed.\n");
        runtime->destroy();
        return;
    }

    nvinfer1::IExecutionContext* execution_context = engine->createExecutionContext();
    cudaStream_t stream = nullptr;
    // 创建CUDA流,以确定这个batch的推理是独立的
    cudaStreamCreate(&stream);

    /*
        Network definition:

        image
          |
        linear (fully connected)  input = 3, output = 2, bias = True     w=[[1.0, 2.0, 0.5], [0.1, 0.2, 0.5]], b=[0.3, 0.8]
          |
        sigmoid
          |
        prob
    */

    // ------------------------------ 2. 准备好要推理的数据并搬运到GPU   ----------------------------
    float input_data_host[] = {1, 2, 3};
    float* input_data_device = nullptr;

    float output_data_host[2];
    float* output_data_device = nullptr;
    cudaMalloc(&input_data_device, sizeof(input_data_host));
    cudaMalloc(&output_data_device, sizeof(output_data_host));
    cudaMemcpyAsync(input_data_device, input_data_host, sizeof(input_data_host), cudaMemcpyHostToDevice, stream);
    // 用一个指针数组指定input和output在gpu中的指针。
    float* bindings[] = {input_data_device, output_data_device};

    // ------------------------------ 3. 推理并将结果搬运回CPU   ----------------------------
    bool success      = execution_context->enqueueV2((void**)bindings, stream, nullptr);
    cudaMemcpyAsync(output_data_host, output_data_device, sizeof(output_data_host), cudaMemcpyDeviceToHost, stream);
    cudaStreamSynchronize(stream);

    printf("output_data_host = %f, %f\n", output_data_host[0], output_data_host[1]);

    // ------------------------------ 4. 释放内存 ----------------------------
    printf("Clean memory\n");
    cudaStreamDestroy(stream);
    execution_context->destroy();
    engine->destroy();
    runtime->destroy();

    // ------------------------------ 5. 手动推理进行验证 ----------------------------
    const int num_input = 3;
    const int num_output = 2;
    float layer1_weight_values[] = {1.0, 2.0, 0.5, 0.1, 0.2, 0.5};
    float layer1_bias_values[]   = {0.3, 0.8};

    printf("手动验证计算结果:\n");
    for(int io = 0; io < num_output; ++io){
        float output_host = layer1_bias_values[io];
        for(int ii = 0; ii < num_input; ++ii){
            output_host += layer1_weight_values[io * num_input + ii] * input_data_host[ii];
        }

        // sigmoid
        float prob = 1 / (1 + exp(-output_host));
        printf("output_prob[%d] = %f\n", io, prob);
    }
}

我们加载的模型文件是上节课编译好的,整个代码可分为以下几个部分:

1.准备模型并加载

我们首先创建了一个 TensorRT 的 IRuntime 实例,用于运行推理。接着,我们通过 load_file 函数从本地读取一个序列化的 TensorRT 模型,然后使用 IRuntimedeserializeCudaEngine 方法将其反序列化为 ICudaEngine。如果反序列化失败,则释放 IRuntime 实例防止内存泄露

2.创建执行上下文和 CUDA 流

ICudaEnginecreateExecutionContext 方法用于创建一个执行上下文,然后我们创建了一个 CUDA 流用于异步管理

3.准备输入数据并将其移动到 GPU

首先在 host 中创建输入数据,然后分配 GPU 内存并将数据从主机复制到 GPU 上,最后创建一个指向输入和输出数据的指针数组

4.推理并将结果移动回 CPU

IExecutionContextenqueueV2 方法用于启动异步推理,然后将推理结果从 GPU 复制回 主机内存,并同步 CUDA 流以确保复制完成。

5.释放内存

释放 stream、execution、engine、runtime

6.手动推理验证

为了验证 TRT 推理的正确性,又手动计算了一次推理结果,然后将其与 TRT 的结果进行比较

运行效果如下:

在这里插入图片描述

图1-1 inference案例运行效果

从结果来看 tensorRT 推理的结果和验证的结果一致,可知整个推理过程没问题

关于代码的重点提炼

1. bindings 是 tensorRT 对输入输出张量的描述,bindings = input_tensor + output_tensor。比如 input 有 a,output 有 b,c,d,那么 bindings = [a,b,c,d],binding[0] = a,binding[2] = c。此时看到 engine->getBindingDimensions(0) 你得知道获取的是什么

2. enqueueV2 是异步推理,加入到 stream 队列等待执行。输入的 bindings 则是 tensors 的指针(注意是 device pointer),其 shape 对应于编译时指定的输入输出的 shape

3. createExecutionContext 可以执行多次,允许一个引擎创建多个执行上下文,不过看看就好,别当真😂

关于推理的知识点有:(from 杜老师)

执行推理的步骤:

1. 准备模型并加载

2. 创建 runtime:createInferRuntime(logger)

3. 使用运行时时,以下步骤:

  • 3.1. 反序列化创建 engine,得为 engine 提供数据:runtime->deserializeCudaEngine(modelData, modelSize),其中 modelData 包含的是 input 和 output 的名字,形状,大小和数据类型
class ModelData(object):
INPUT_NAME = "data"
INPUT_SHAPE = (1, 1, 28, 28) // [B, C, H, W]
OUTPUT_NAME = "prob"
OUTPUT_SIZE = 10
DTYPE = trt.float32
  • 3.2. 从 engine 创建执行上下文:engine->createExecutionContext()

4. 创建 CUDA 流 cudaStreamCreate(&stream)

  • 4.1. CUDA 编程中流是组织异步工作的一种方式,创建流来确定 batch 推理的独立
  • 4.2. 为每个独立 batch 使用 IExecutionContext(3.2中已经创建),并为每个独立批次使用 cudaStreamCreate 创建 CUDA 流

5. 数据准备:

  • 5.1. 在 host 上声明 input 和 output 数组大小,搬运到 gpu 上
  • 5.2. 要执行 inference,必须用一个指针数组指定 input 和 output 在 gpu 中的指针
  • 5.3. 推理并将 output 搬运回 cpu

6. 启动所有工作后,与所有流同步以等待结果 cudaStreamSynchronize

7. 按照与创建相反的顺序释放内存

总结

本节课程主要学习了利用 TRT-CPP 的 API 来进行模型推理,主要步骤包括:准备模型并加载、创建执行上下文和 CUDA 流、准备输入数据并将其移动到 GPU、推理并将结果移动回 CPU、释放内存。目前是通过调用 API 接口来推理模型,后面将会学习利用 onnxparser 解析 onnx 创建并推理模型。

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

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

相关文章

深度学习——LSTM解决分类问题

RNN基本介绍 概述 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种深度学习模型&#xff0c;主要用于处理序列数据&#xff0c;如文本、语音、时间序列等具有时序关系的数据。 核心思想 RNN的关键思想是引入了循环结构&#xff0c;允许…

JavaBeans

Code eamples ① Product.java (JavaBean Class) ② Bean.java (Servlet) ③ complie javac -encoding utf-8 -d ..\classes -sourcepath . chapter15\Bean.java ④ Tomcat ⑤ http://localhost:8080/book/chapter15/bean

flink水位线传播及任务事件时间

背景 本文来讲解一下flink的水位线传播及对其对任务事件时间的影响 水位线 首先flink是通过从源头生成水位线记录的方式来实现水位线传播的&#xff0c;也就是说水位线是嵌入在正常的记录流中的特殊记录&#xff0c;携带者水位线的时间戳&#xff0c;以下我们就通过图片的方…

Docker常用命令(三)

1、镜像命令 1、列出本地主机上的镜像 docker images [options]optiins说明&#xff1a; -a&#xff1a;列出本地所有的镜像&#xff08;包含历史映像层&#xff09; -q&#xff1a;只显示镜像ID2、搜索某个镜像信息 docker search [options] 镜像名字3、下载镜像 docker …

Kafka第二课-代码实战、参数配置详解、设计原理详解

一、代码实战 一、普通java程序实战 引入依赖 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>2.4.1</version></dependency><dependency>&l…

windows环境hadoop报错‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Hadoop版本为2.7.3&#xff0c;在环境配置好后&#xff0c;检查hadoop安装版本&#xff0c;报如标题所示错误&#xff0c;尝试网上主流的几种方法均无效。 错误&#xff1a;windows环境hadoop报错’D:\Program’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误方…

Jackson使用

导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

静态输出调节

1.理论部分 15. SISO反馈控制器设计 (6)&#xff1a;输出调节-静态反馈 Output Regulation - 知乎 (zhihu.com) 上述博客已经写的很好了&#xff0c;过多描述 2.仿真实验 3.参考理论 首先通过18式求解出X和U&#xff0c;然后设计一个让原系统初始稳定的控制律Kx&#xff0c;…

第二周习题

2.创建类MyDate,year属性和month属性,编写一个方法totalDays,该方法通过年份和月份判断该月一共有多少天,在主函数中接受用户输入年和月&#xff0c;调用该方法测试它. 这里考虑平年和闰年 “平年2月有28天。闰年的2月有29天 那么就有区别了 只要判断这一点就行了&#xff01;&…

框架开发使用注解处理器APT优雅提效

目录 概述1.什么是注解处理器APT2.应用场景3.如何使用3.1 创建注解API模块3.2 创建注解处理器模块3.3 使用注解 概述 在现在的很多开源框架中&#xff0c;我们经常能在源码中看到注解处理器的影子&#xff0c;比如我们熟悉的阿里的ARouter,Android开发中的替代findViewById神器…

【git】git以及可视化界面下载安装

git 以及可视化界面下载安装 git下载安装测试功能 sourceTree下载安装 git 下载安装 下载地址 git官网上有多个版本&#xff0c;点击“Click here to download” &#xff0c;下载下来之后&#xff0c;一直下一步安装即可 测试功能 在任意文件夹中右击&#xff0c;看到图中…

Linux三剑客

前言 关于bash&#xff1a; bash&#xff1a;命令处理器&#xff0c;运行在文本窗口&#xff0c;能够执行用户输入的命令。 脚本&#xff1a;从linux文件中读取命令&#xff0c;被称为脚本。 1 命令&#xff1a;alias&#xff1a;起别名 2 快捷键操作&#xff1a; ctrla&#…

浅谈如何提高自动化测试的稳定性和可维护性

目录 前言&#xff1a; 装饰器与出错重试机制 什么是装饰器&#xff1f; 编写一个出错重试装饰器 pytest 里的出错重试机制实现 Allure 里的测试用例分层 为什么要采用分层机制&#xff1f; allure 的装饰器step 前言&#xff1a; 自动化测试在软件开发中扮演着重要的…

Fortran lapack求数组的特征值,特征向量

call zgeev(V, V, n, arr, lda, w, vl, ldvl, vr, ldvr, work, lwork, rwork, info) 这个函数是求矩阵的特征值&#xff0c;且结果是双精度复数的情况&#xff0c;具体可以查MKL的官方文档。 如果是单精度复数就要用cgeev&#xff0c;其中的参数也是将双精度改为单精度即可。…

Hive,FineBI-30W聊天数据分析及可视化-B站黑马学习记录

2023B站黑马Hadoop、Hive、云平台实战项目 目录 1. 清洗数据 2. 计算各指标&#xff0c;并创建表存储结果 3.FineBI连接Hive数据库&#xff0c;将指标结果可视化 1. 清洗数据 1&#xff09;部分数据缺失地理位置信息&#xff08;sender_gps&#xff09;&#xff0c;需要剔…

Linux下的调试器——gdb使用指南

文章目录 一.序二.安装gdb调试器三.进入调试四.调试相关指令 前言&#xff1b; 在VS环境下&#xff0c;我们不仅可以写代码、编译、运行可执行程序&#xff0c;还可以对生成的可执行程序进行调试。本章我们就来学习如何在Linux环境下进行调试。 一.序 要进行调试&#xff0c;首…

EPICS一个示例数据库实例详解

以下是一个示例数据库图表&#xff1a; 以上记录的数据库文件如下&#xff1a; record(ao, "$(P):SET") {field(FLNK, "$(P):ACTIVATE")field(VAL, "2")field(OUT, "$(P):RUN")field(DRVH, "40")field(DRVL, "5"…

摩尔投票算法(Moore‘s Voting Algorithm)及例题

摩尔投票算法&#xff08;Moores Voting Algorithm&#xff09;及例题 摩尔投票算法简介摩尔投票算法算法思想摩尔投票算法经典题目169. 多数元素229. 多数元素 II6927. 合法分割的最小下标 上午打力扣第 354 场周赛最后十五分钟用摩尔投票算法顺利 AC 第三题&#xff0c;以前没…

ViewRootImpl简析

ViewRootImpl简析 如何实现视图和wms沟通桥梁的作用Session的创建获取画布如何实现事件分发的桥梁作用 The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of…

快速搭建Python(Django)+Vue环境并实现页面登录注册功能

文章目录 一. 创建vue项目及环境搭建1. 创建vue项目2. 配置axios3. 创建vue组件login和register4. 设置并引用路由vue-router5. 完成login&#xff0c;register组件代码6. 完成App.vue的代码 二. 创建django项目及环境搭建1. 创建django项目2.配置mysql数据库3. 创建应用app4.创…