TensorRT C++推理代码示例(smoke单目3D检测为例)

3维目标检测算法smoke使用c++ 版TensorRT部署的一些库和基本流程

0. 需要的库

  1. TensorRT 相关

    #include <cuda_runtime_api.h>
    #include <NvInfer.h>
    #include "NvInferPlugin.h"
    
  2. opencv 相关

    #include <opencv2/imgproc.hpp>
    #include <opencv2/highgui.hpp>
    
  3. 其他的标准库

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <cassert>
    #include <cstring>
    #include <sys/stat.h>
    #include <glog/logging.h>
    

1. 流程

  1. 初始化TensorRT

    TRT_Logger gLogger;
    IRuntime* runtime = createInferRuntime(gLogger);
    assert(runtime != nullptr);
    
    
  2. 解析序列化文件

    const std::string enginePath = "/home/user1/cv_project/mmdeploy/smoke2/end2end.trt.engine"; // 替换为您的模型引擎文件路径
    std::ifstream engineFile(enginePath, std::ios::binary);
    assert(engineFile.is_open());
    
    // 从引擎文件中反序列化引擎
    engineFile.seekg(0, engineFile.end);
    int engineSize = engineFile.tellg();
    engineFile.seekg(0, engineFile.beg);
    std::vector<char> engineData(engineSize);
    engineFile.read(engineData.data(), engineSize);
    engineFile.close();
    
  3. 对于有自定义算子的情况

    // 在deserializeCudaEngine()前加上
        bool didInitPlugins = initLibNvInferPlugins(nullptr, "");
    
    
  4. 创建CudaEngine和推理上下文

    ICudaEngine* engine = runtime->deserializeCudaEngine(engineData.data(), engineSize, nullptr);
    assert(engine != nullptr);
    
  5. GPU内存分配

    const int batchSize = 1;
    const int inputChannels = 3; // 三通道图片
    const int inputHeight = 384;
    const int inputWidth = 1280;
    const int inputSize = inputChannels * inputHeight * inputWidth * sizeof(float);
    
    // 输出1的大小
    const int outputSize1 = 1*3*96*320* sizeof(float)/* 第一个输出的大小 */;
    // 输出2的大小
    const int outputSize2 = 1*8*96*320* sizeof(float)/* 第二个输出的大小 */;
    
    void* buffers[3]; // 3个缓冲区(1个输入和2个输出)
    cudaMalloc(&buffers[0], inputSize);
    cudaMalloc(&buffers[1], outputSize1);
    cudaMalloc(&buffers[2], outputSize2);
    
  6. 数据读取和转换

    cv::Mat inputImage = cv::imread("/home/user1/cv_project/mmdeploy/z_log/000008.png"); // 替换为您的图片路径
    cv::Mat resizedImage;
    cv::resize(inputImage, resizedImage, cv::Size(inputWidth, inputHeight));
    resizedImage.convertTo(resizedImage, CV_32FC3); // 
    
    // 将图像从HWC转换为CHW
    // vector<float> a(inputSize);
    float* input_last = new float[inputSize];
    // cv::Mat chwImage(inputChannels, inputHeight, inputWidth, CV_32FC3);
    for (int c = 0; c < inputChannels; ++c)
    {
    for (int h = 0; h < inputHeight; ++h)
    {
    for (int w = 0; w < inputWidth; ++w)
    {   
    // cout<<"helloworld:"<<(c * inputHeight * inputWidth + h * inputWidth + w)<<endl;
    input_last[c * inputHeight * inputWidth + h * inputWidth + w] = static_cast<float>(resizedImage.at<cv::Vec3f>(h, w)[c]) / 255.0f;
    }
    }
    }
    
  7. 复制数据到GPU

// 将输入数据复制到GPU
cout<<"helloworld:2";
float* inputData = new float[inputChannels * inputHeight * inputWidth];
cout<<"helloworld:";
memcpy(inputData, input_last, inputSize);
for (int i=0;i<(inputChannels * inputHeight * inputWidth);i++){
    cout<<"test:"<<inputData[i]<<endl;
}
cudaMemcpy(buffers[0], inputData, inputSize, cudaMemcpyHostToDevice);

  1. 执行推理

    context->execute(batchSize, buffers);
    
  2. 获取输出数据

     // 获取输出数据
        float* outputData1 = new float[outputSize1];
        float* outputData2 = new float[outputSize2];
        cudaMemcpy(outputData1, buffers[1], outputSize1, cudaMemcpyDeviceToHost);
        cudaMemcpy(outputData2, buffers[2], outputSize2, cudaMemcpyDeviceToHost);
    

2. 整体代码

#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
#include <cstring>
#include <cuda_runtime_api.h>
#include <NvInfer.h>
#include <sys/stat.h>
#include <glog/logging.h>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include "NvInferPlugin.h"

using namespace nvinfer1;
using namespace std;
using namespace cv;


// Logger for TRT info/warning/errors, https://github.com/onnx/onnx-tensorrt/blob/main/onnx_trt_backend.cpp
class TRT_Logger : public nvinfer1::ILogger
{
    nvinfer1::ILogger::Severity _verbosity;
    std::ostream* _ostream;

public:
    TRT_Logger(Severity verbosity = Severity::kWARNING, std::ostream& ostream = std::cout)
        : _verbosity(verbosity)
        , _ostream(&ostream)
    {
    }
    void log(Severity severity, const char* msg) noexcept override
    {
        if (severity <= _verbosity)
        {
            time_t rawtime = std::time(0);
            char buf[256];
            strftime(&buf[0], 256, "%Y-%m-%d %H:%M:%S", std::gmtime(&rawtime));
            const char* sevstr = (severity == Severity::kINTERNAL_ERROR ? "    BUG" : severity == Severity::kERROR
                        ? "  ERROR"
                        : severity == Severity::kWARNING ? "WARNING" : severity == Severity::kINFO ? "   INFO"
                                                                                                   : "UNKNOWN");
            (*_ostream) << "[" << buf << " " << sevstr << "] " << msg << std::endl;
        }
    }
};


int main()
{
    // 指定模型引擎文件的路径
    TRT_Logger gLogger;
    const std::string enginePath = "/home/user1/cv_project/mmdeploy/smoke2/end2end.trt.engine"; // 替换为您的模型引擎文件路径

    // 初始化TensorRT
    IRuntime* runtime = createInferRuntime(gLogger);
    assert(runtime != nullptr);

    std::ifstream engineFile(enginePath, std::ios::binary);
    assert(engineFile.is_open());

    // 从引擎文件中反序列化引擎
    engineFile.seekg(0, engineFile.end);
    int engineSize = engineFile.tellg();
    engineFile.seekg(0, engineFile.beg);
    std::vector<char> engineData(engineSize);
    engineFile.read(engineData.data(), engineSize);
    engineFile.close();

    // 创建CudaEngine
    
    // 在deserializeCudaEngine()前加上
    bool didInitPlugins = initLibNvInferPlugins(nullptr, "");

    ICudaEngine* engine = runtime->deserializeCudaEngine(engineData.data(), engineSize, nullptr);
    assert(engine != nullptr);

    // 创建推理上下文
    IExecutionContext* context = engine->createExecutionContext();
    assert(context != nullptr);

    // 分配GPU内存
    // 分配GPU内存
    const int batchSize = 1;
    const int inputChannels = 3; // 三通道图片
    const int inputHeight = 384;
    const int inputWidth = 1280;
    const int inputSize = inputChannels * inputHeight * inputWidth * sizeof(float);

    // 输出1的大小
    const int outputSize1 = 1*3*96*320* sizeof(float)/* 第一个输出的大小 */;
    // 输出2的大小
    const int outputSize2 = 1*8*96*320* sizeof(float)/* 第二个输出的大小 */;

    void* buffers[3]; // 3个缓冲区(1个输入和2个输出)
    cudaMalloc(&buffers[0], inputSize);
    cudaMalloc(&buffers[1], outputSize1);
    cudaMalloc(&buffers[2], outputSize2);

    // 准备输入数据(假设您有一张RGB图片)
    cv::Mat inputImage = cv::imread("/home/user1/cv_project/mmdeploy/z_log/000008.png"); // 替换为您的图片路径
    cv::Mat resizedImage;
    cv::resize(inputImage, resizedImage, cv::Size(inputWidth, inputHeight));
    resizedImage.convertTo(resizedImage, CV_32FC3); // 

    // 将图像从HWC转换为CHW
    // vector<float> a(inputSize);
    float* input_last = new float[inputSize];
    // cv::Mat chwImage(inputChannels, inputHeight, inputWidth, CV_32FC3);
    for (int c = 0; c < inputChannels; ++c)
    {
        for (int h = 0; h < inputHeight; ++h)
        {
            for (int w = 0; w < inputWidth; ++w)
            {   
                // cout<<"helloworld:"<<(c * inputHeight * inputWidth + h * inputWidth + w)<<endl;
                input_last[c * inputHeight * inputWidth + h * inputWidth + w] = static_cast<float>(resizedImage.at<cv::Vec3f>(h, w)[c]) / 255.0f;
            }
        }
    }

    
    // 将输入数据复制到GPU
    cout<<"helloworld:2";
    float* inputData = new float[inputChannels * inputHeight * inputWidth];
    cout<<"helloworld:";
    memcpy(inputData, input_last, inputSize);
    for (int i=0;i<(inputChannels * inputHeight * inputWidth);i++){
        cout<<"test:"<<inputData[i]<<endl;
    }
    cudaMemcpy(buffers[0], inputData, inputSize, cudaMemcpyHostToDevice);

    // 执行推理
    context->execute(batchSize, buffers);

    // 获取输出数据
    float* outputData1 = new float[outputSize1];
    float* outputData2 = new float[outputSize2];
    // ...
    cudaMemcpy(outputData1, buffers[1], outputSize1, cudaMemcpyDeviceToHost);
    cudaMemcpy(outputData2, buffers[2], outputSize2, cudaMemcpyDeviceToHost);
    // ...

    // 处理输出数据
    // 在这里进行后处理或使用输出数据进行其他操作

    std::ofstream outputFile1("output1.txt");
    if (outputFile1.is_open())
    {
        for (int i = 0; i < outputSize1/(sizeof(float)); i++)
        {
            outputFile1 << outputData1[i] << " ";
        }
        outputFile1.close();
    }

    std::ofstream outputFile2("output2.txt");
    if (outputFile2.is_open())
    {
        for (int i = 0; i < outputSize2/(sizeof(float)); i++)
        {
            outputFile2 << outputData2[i] << " ";
        }
        outputFile2.close();
    }

    // 释放资源
    delete[] inputData;
    delete[] outputData1;
    delete[] outputData2;
    delete[] input_last;
    // ...
    context->destroy();
    engine->destroy();
    runtime->destroy();

    return 0;
}

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 YOLOv5 在 C++ 中进行 TensorRT 推理并返回边界框坐标的代码示例: ```cpp // 加载 TensorRT 模型并创建推理引擎 nvinfer1::ICudaEngine* engine = loadEngine(); // 创建 TensorRT 推理上下文 nvinfer1::IExecutionContext* context = engine->createExecutionContext(); // 输入数据缓冲区 void* inputDataBuffer = get_input_data(); // 获取输入数据 // 分配 GPU 内存并将输入数据复制到 GPU 上 cudaMalloc(&gpuInputDataBuffer, inputSize); cudaMemcpy(gpuInputDataBuffer, inputDataBuffer, inputSize, cudaMemcpyHostToDevice); // 输出数据缓冲区 void* outputDataBuffer = get_output_data(); // 获取输出数据 // 分配 GPU 内存并将输出数据清零 cudaMalloc(&gpuOutputDataBuffer, outputSize); cudaMemset(gpuOutputDataBuffer, 0, outputSize); // 执行 TensorRT 推理 void* bindings[] = {gpuInputDataBuffer, gpuOutputDataBuffer}; context->execute(1, bindings); // 将输出数据从 GPU 复制回 CPU cudaMemcpy(outputDataBuffer, gpuOutputDataBuffer, outputSize, cudaMemcpyDeviceToHost); // 解析输出数据并返回边界框坐标 float* outputData = (float*) outputDataBuffer; std::vector<std::tuple<float, float, float, float>> boxes; for (int i = 0; i < outputSize / sizeof(float); i += 6) { if (outputData[i + 4] > confidenceThreshold) { // 计算边界框坐标 float x = outputData[i + 0] * imageWidth; float y = outputData[i + 1] * imageHeight; float w = outputData[i + 2] * imageWidth; float h = outputData[i + 3] * imageHeight; float left = x - w / 2; float top = y - h / 2; float right = x + w / 2; float bottom = y + h / 2; boxes.push_back(std::make_tuple(left, top, right, bottom)); } } // 释放 GPU 内存 cudaFree(gpuInputDataBuffer); cudaFree(gpuOutputDataBuffer); // 释放 TensorRT 对象 context->destroy(); engine->destroy(); ``` 其中,`loadEngine()` 函数用于加载 TensorRT 模型并创建推理引擎,`get_input_data()` 和 `get_output_data()` 函数用于获取输入和输出数据的指针,`inputSize` 和 `outputSize` 分别表示输入和输出数据的大小,`confidenceThreshold` 是一个置信度阈值,用于筛选边界框。返回的 `boxes` 是一个 `tuple` 数组,每个 `tuple` 表示一个边界框的左上角和右下角坐标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值