onnx模型转engine并进行推理全过程解析

这篇具有很好参考价值的文章主要介绍了onnx模型转engine并进行推理全过程解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

深度学习模型在训练好以后,下一步就是部署到不同的设备进行测试,不同设备之间的转换一般可以通过中间件ONNX进行转换,以达到不同平台的通用。本文以模型转为ONNX为起点,分析介绍ONNX转为TensorRT Engine并进行推理的整个流程链路。

1、ONNX序列化为TensorRT Engine

ONNX序列化为TRT模型的整个流程可以用下图表示
onnx模型转engine并进行推理全过程解析
使用C++的API进行开发时,需要引入头文件NvInfer以及NvOnnxParser,C++的接口都是通过I开头的的接口类定义的,如ILogger、IBuilder等。

#include “NvInfer.h”
#include “NvOnnxParser.h”

using namespace nvonnxparser;
using namespace nvinfer1;

1.1 创建builder

创建构建器之前有两种方式实例化ILogger:
1、引用tensorrtx的logging.h,使用其中的Logger

	#include "logging.h"
	
	static Logger gLogger;
	IBuilder* builder = createInferBuilder(gLogger);

2、继承ILogger,实例化接口

	class Logger : public ILogger           
	{
	    void log(Severity severity, const char* msg) noexcept override
	    {
	        if (severity <= Severity::kWARNING)
	            std::cout << msg << std::endl;
	    }
	} logger;
 	IBuilder* builder = createInferBuilder(gLogger);

1.2 创建network

创建构建器后,需要创建网络定义来进行模型优化:

	INetworkDefinition *network = builder->createNetworkV2(0U); //是0U还是1u需视情况而定

1.3 创建parse解析器

创建onnx的解析器来进行网络定义的填充,并读取模型文件并处理是否存在错误。

	IParser* parser = createParser(*network, gLogger);
	parser->parseFromFile(onnx_path, static_cast<int32_t>(ILogger::Severity::kWARNING));
	 for (int32_t i = 0; i < parser->getNbErrors(); ++i) 
    { 
        std::cout << parser->getError(i)->desc() << std::endl;
    }
    std::cout << "successfully parse the onnx model" << std::endl;

1.4 设置必要参数并创建Engine

    IBuilderConfig *config = builder->createBuilderConfig();
	builder->setMaxBatchSize(maxBatchSize);
    config->setMaxWorkspaceSize(1 << 20);
    
    auto profile = builder->createOptimizationProfile();
    auto input_tensor = network->getInput(0);
    auto input_dims = input_tensor->getDimensions();

    input_dims.d[0] = 1;
    profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kMIN, input_dims);
    profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kOPT, input_dims);
    input_dims.d[0] = batchSize;
    profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kMAX, input_dims);
    config->addOptimizationProfile(profile);
#ifdef USE_FP16
    config->setFlag(BuilderFlag::kFP16);
#endif
#ifdef USE_INT8
    config->setFlag(BuilderFlag::kINT8);
#endif

1.5 创建Engine并序列化

	ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
	assert(engine != nullptr);
	(*modelStream) = engine->serialize();
	assert(modelStream != nullptr);
	 std::ofstream p(engine_path, std::ios::binary);
    if (!p)
    {
        std::cerr << "could not open plan output file" << std::endl;
        return -1;
    }
    p.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size());
    modelStream->destroy();

2、读取序列化后TensorRT Engine 并进行推理

onnx转换为engine并序列化后,可以减少构建和优化模型的时间,如下图所示,从序列化的engine读取开始完成整个推理过程。
onnx模型转engine并进行推理全过程解析

2.1 反序列化engine

读取序列化的模型,存放在trtModelstream中。

    size_t size{ 0 };
    std::ifstream file(engine_path, std::ios::binary);
    if (file.good()) {
        file.seekg(0, file.end);
        size = file.tellg();
        file.seekg(0, file.beg);
        trtModelStream = new char[size];
        assert(trtModelStream);
        file.read(trtModelStream, size);
        file.close();

2.2 创建runtime

通过logger创建runtime

 	IRuntime* runtime = createInferRuntime(gLogger);
    assert(runtime != nullptr);

2.3 创建engine

通过runtime解析trtModelstream,创建engine

    ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream, size, nullptr);
    assert(engine != nullptr);

2.4 创建context

    IExecutionContext* context = engine->createExecutionContext();
    assert(context != nullptr);
    runtime->destroy();

2.5 前处理+前向推理+后处理

前处理

float* input_data = (float*)malloc(3 * input_h * input_w * sizeof(float));
int ImgCount = InputImage.size();
    for (int b = 0; b < ImgCount; b++) {
        cv::Mat img = InputImage.at(b);
        int w = img.cols;
        int h = img.rows;
        int i = 0;
        for (int row = 0; row < h; ++row) {
            uchar* uc_pixel = img.data + row * img.step;
            for (int col = 0; col < input_w; ++col) {
                input_data[b * 3 * input_h * input_w + i] = (float)uc_pixel[2] / 255.0;
                input_data[b * 3 * input_h * input_w + i + input_h * input_w] = (float)uc_pixel[1] / 255.0;
                input_data[b * 3 * input_h * input_w + i + 2 * input_h * input_w] = (float)uc_pixel[0] / 255.0;
                uc_pixel += 3;
                ++i;
            }
        }

    }

前向推理

void doInference()
{
    const ICudaEngine& engine = context.getEngine();
    // Pointers to input and output device buffers to pass to engine.
    // Engine requires exactly IEngine::getNbBindings() number of buffers.
    //assert(engine.getNbBindings() == 2);
    void* buffers[2];
    // In order to bind the buffers, we need to know the names of the input and output tensors.
    // Note that indices are guaranteed to be less than IEngine::getNbBindings()
    const int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME);
    const int outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);
    //const int inputIndex = 0;
    //const int outputIndex = 1;
    // Create GPU buffers on device
    cudaMalloc(&buffers[inputIndex], batchSize * 3 * input_h * input_w * sizeof(float));
    cudaMalloc(&buffers[outputIndex], batchSize * output_size * sizeof(float));
    // Create stream
    cudaStream_t stream;
    CHECK(cudaStreamCreate(&stream));
    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
    CHECK(cudaMemcpyAsync(buffers[inputIndex], input, batchSize * 3 *input_h * input_w * sizeof(float), cudaMemcpyHostToDevice, stream));
    context.enqueue(batchSize, buffers, stream, nullptr);
    CHECK(cudaMemcpyAsync(output, buffers[outputIndex], batchSize * output_size * sizeof(float), cudaMemcpyDeviceToHost, stream));
    cudaStreamSynchronize(stream);
    // Release stream and buffers
    cudaStreamDestroy(stream);
    CHECK(cudaFree(buffers[inputIndex]));
    CHECK(cudaFree(buffers[outputIndex]));

后处理
以LPRNet为例

    std::vector<int> preds;
    std::cout << std::endl;
    for (int i = 0; i < 18; i++) {
        int maxj = 0;
        for (int j = 0; j < 68; j++) {
            if (prob[i + 18 * j] > prob[i + 18 * maxj]) maxj = j;
        }
        preds.push_back(maxj);
    }
    int pre_c = preds[0];
    std::vector<int> no_repeat_blank_label;
    for (auto c: preds) {
        if (c == pre_c || c == 68 - 1) {
            if (c == 68 - 1) pre_c = c;
            continue;
        }
        no_repeat_blank_label.push_back(c);
        pre_c = c;
    }
    std::string str;
    for (auto v: no_repeat_blank_label) {
        str += alphabet[v];
    }

以上是利用TensorRT C++ API进行ONNX构建trt engine,并进行推理的全过程解析,基本所有的onnx转化为TRT模型进行推理都包含在以上方式中,仅此记录。

–END–文章来源地址https://www.toymoban.com/news/detail-461964.html

到了这里,关于onnx模型转engine并进行推理全过程解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MATLAB导入Solidworks机器人模型全过程

    版本:MATLAB2019a、Solidworks2022(Win11系统必须要下2022版(含)之后的) 机器人模型:埃斯顿机器人(ER20-1780-F) 步骤1:打开模型。将机器人模型 (可在官网下载)(ER20-1780-F)在Solidworks打开,打开文件的类型是.SLDASM为文件后缀。(如图1所示) 图1 步骤2:建立关节坐标系。在

    2024年02月07日
    浏览(63)
  • 位置环速度环串级位置式PID实现全过程解析(详细)

    电机型号:MD36N行星减速电机_AB两相光电编码器霍尔编码器 电机参数: 单片机型号:STM32F429IG,keil 程序最终功能:串级位置式PID反复调节电机,使得电机可以在一定范围内精准任意停靠在某个位置,比如电机控制目标在圆形轨道转动,就可以实现在固定角度的位置停靠,四

    2023年04月08日
    浏览(41)
  • opencv-python学习笔记(十一):HOG+SVM进行行人检测全过程

    本次是接着python-opencv学习笔记(七):滑动窗口与图像金字塔 一起在实验楼所做实验,为啥中间隔了四篇才接着发出来,主因是我发文比较随意(懒),当时这部分并没有总结完,至少我感觉我看的相关资料还不够多,整体理解不深,另外就是项目需求,在做很多其它的东

    2024年02月05日
    浏览(58)
  • python使用onnx模型进行推理

    我们可以看到基于YoloV7训练的cfg有两种yaml文件,一个是training文件夹,一个是deploy文件夹,这两种文件夹有啥不一样呢??? 大家可以看下下面别人的issuse,,记住这个很关键,就是你选择哪个yaml训练对你后面导出的onnx是很关键的,后面我们会说到。 1、training中的yaml文件

    2024年02月12日
    浏览(52)
  • 使用Pyecharts进行全国水质TDS地图可视化全过程2:使用Power Query 进行百万行级别数据匹配

    简介:本文介绍使用Excel  Power Query进行数据匹配。利用这种方式,可以在几分钟内完成百万级别数据量的匹配。 在TDS可视化地图项目中,我们的原始数据没有TDS和具体安装地址的对应,我们需要通过机器条码去匹配安装台账的地址。 这个数据量很大,有多大?我们截取的时

    2024年02月05日
    浏览(57)
  • TensorRT 推理 (onnx->engine)

    测试使用:【Win10+cuda11.0+cudnn8.2.1+TensorRT8.2.5.1】 关于安装 一、模型转换 onnx2trt 方法1:使用wang-xinyu/tensorrtx部署yolov5方法:https://wangsp.blog.csdn.net/article/details/121718501 方法2:使用tensorRT转成engine 方法3:使用C++ onnx_tensorrt将onnx转为trt 的推理engine 参考 【python 方法参考】 方法4:

    2023年04月08日
    浏览(35)
  • 2020年数维杯数学建模C题 垃圾转运优化模型设计求解全过程文档及程序

    原题再现:    随着我国人口的不断增加及城镇化进程的快速推进,城市面临了众多公共管理方面的难题。如生活垃圾、废气废水及排泄物等等的处理问题。截止2019年底我国拥有十多个千万规模以上的大型城市,城镇人口数量达到了8.48亿人。    数据统计结果表明我国的

    2024年02月07日
    浏览(44)
  • yolov5训练pt模型并转换为rknn模型,部署在RK3588开发板上——从训练到部署全过程

    目录 一、任务介绍 二、实验过程 2.1 使用正确版本的yolov5进行训练(平台:x86机器windows系统) 2.2 best.pt转换为best.onnx(平台:x86机器window系统) 2.3 best.onnx转换为best.rknn(平台:x86机器Linux系统) 2.3.1 环境准备和工具包安装 2.3.2 onnx转换为rknn 2.4 RK3588部署rknn实现NPU加速(平台:

    2024年02月03日
    浏览(49)
  • C++使用onnxruntime/opencv对onnx模型进行推理(附代码)

    结果: current image classification : French bulldog, possible : 16.17 对两张图片同时进行推理 current image classification : French bulldog, possible : 16.17 current image class ification : hare, possible : 8.47 https://download.csdn.net/download/qq_44747572/87810859 https://blog.csdn.net/qq_44747572/article/details/131631153

    2024年02月05日
    浏览(51)
  • 2015年亚太杯APMCM数学建模大赛B题城市公共交通服务水平动态评价模型求解全过程文档及程序

    原题再现    城市公共交通服务评价是城市公共交通系统建设和提高公共交通运营效率的重要组成部分。对于公交企业,管理和规划部门,传统公交车站、线路和换乘枢纽的规划数据只是基于主管部门收集的统计数据和人工盘点。    在自动采集技术日益发展的今天,如果

    2024年02月07日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包