如何调用一个具有动态维度的tensorrt engine

本文详细阐述了如何在C++中使用TensorRT处理具有动态维度的模型,涉及如何通过`IExecutionContext`的`setBindingDimensions`方法设置输入维度,并提供了从引擎文件加载、维度检查到推理执行的完整流程示例。

调用具体动态维度的模型engine时如果没有指定维度,会导致报类似这样的错误:

[TRT] Parameter check failed at: engine.cpp::resolveslots::1227, condition: allInputDimensionsSpecified(routine)

在python代码里,在调用engine推理前做这样的设置即可:

context.set_binding_shape(0, (BATCH, 3, INPUT_H, INPUT_W))

在C++代码里改如何设置,很少有文章提及,关于如何调用有动态维度的模型,一般都是举的python代码的例子,我查了一下TensorRT的头文件NvInferRuntime.h里的代码才知道,C++代码里应该调用IExecutionContext类型的实例的setBindingDimensions(int bindingIndex, Dims dimensions)方法。

总体思路是:拿到一个对维度未知的模型engine文件后,首先读入文件内容并做deserialize获得engine:

ARNet::ARNet(std::string engine_file,
                         std::string shape_file, std::string input_name,
                         std::string output_name)
    : mEngine(nullptr) {
  samplesCommon::OnnxSampleParams params;
  params.inputTensorNames.push_back(input_name.c_str());
  params.outputTensorNames.push_back(output_name.c_str());
  params.int8 = false;
  params.fp16 = true;
  mParams = params;
  std::string se_path = engine_file;  //"arnet_b1_fp16.engine";
  if (access(se_path.c_str(), 4) != -1) {
    nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(gLogger);
    std::ifstream fin(se_path);
    std::string cached_engine = "";
    while (fin.peek() != EOF) {
      std::stringstream buffer;
      buffer << fin.rdbuf();
      cached_engine.append(buffer.str());
    }
    fin.close();
    mEngine = std::shared_ptr<nvinfer1::ICudaEngine>(
        runtime->deserializeCudaEngine(cached_engine.data(),
                                       cached_engine.size(), nullptr),
        samplesCommon::InferDeleter());
    if(!mEngine){
      std::cout <<"Deserialize from "<< se_path <<" failed!!! rebuild enigne ..." << std::endl;
      build();
      return;
    }
...

然后调用getBindingDimensions()查看engine的输入输出维度(如果知道维度就不用):

for (int i = 0; i < mEngine->getNbBindings(); i++)
{
     nvinfer1::Dims dims = mEngine->getBindingDimensions(i);
     printf("index %d, dims: (");
     for (int d = 0; d < dims.nbDims; d ++)
     {
         if (d < dims.nbDims -1) 
             printf("%d,", dims.d[d]);
         else
             printf("%d", dims.d[d]);
     }
     printf(")\n");
}

在调用context->executeV2()做推理前把维度值为-1的动态维度值替换成具体的维度并调用context->setBindingDimensions()设置具体维度,然后在数据填入input buffer准备好后调用contex

### TensorRT Engine 文件反序列化教程 TensorRT 提供了一种高效的机制用于加载和运行已经生成的序列化模型(即 `.engine` 文件)。以下是关于如何对 TensorRTEngine 文件进行反序列化的详细说明以及示例代码。 #### 1. 反序列化的核心概念 在 TensorRT 中,序列化后的引擎文件可以通过 `nvinfer1::IRuntime` 类中的方法重新加载到内存中。此过程涉及创建一个运行时实例并调用其 `deserializeCudaEngine` 方法[^1]。 #### 2. 示例代码实现 以下是一个完整的 Python 实现示例,展示如何从磁盘读取已保存的 `.engine` 文件并将其反序列化为可执行的推理引擎: ```python import tensorrt as trt def load_engine(engine_file_path): # 初始化 TensorRT 运行时对象 runtime = trt.Runtime(trt.Logger(trt.Logger.WARNING)) with open(engine_file_path, "rb") as f: engine_data = f.read() # 将 .engine 文件内容读入内存 # 调用 deserialize_cuda_engine 函数完成反序列化 engine = runtime.deserialize_cuda_engine(engine_data) return engine if __name__ == "__main__": engine_file_path = "./model.engine" engine = load_engine(engine_file_path) if engine is not None: print("Engine loaded successfully!") else: print("Failed to load the engine.") ``` 上述代码展示了通过 `Runtime` 对象加载 `.engine` 文件的过程,并返回了一个可以用来执行推理任务的引擎实例。 #### 3. 动态维度支持下的反序列化处理 当涉及到动态输入尺寸的情况时,在反序列化之后还需要额外配置上下文 (Context),以便指定实际使用的批量大小或其他参数。具体做法如下所示: ```cpp #include <NvInfer.h> #include <fstream> using namespace nvinfer1; ICudaEngine* loadEngine(const char* filePath){ std::ifstream file(filePath,std::ios::binary); if(!file.good()){ throw std::runtime_error("Could not find engine file!"); } file.seekg(0,std::ios::end); size_t size=file.tellg(); file.seekg(0); char *trtModelStream=new char[size]; file.read(trtModelStream,size); IRuntime* runtime= createInferRuntime(gLogger); ICudaEngine* engine=runtime->deserializeCudaEngine(trtModelStream,size,nullptr); delete[] trtModelStream; return engine; } void createContextWithDynamicShapes(ICudaEngine& engine,int batchSize){ IExecutionContext* context=engine.createExecutionContext(); bool success=context->setBindingDimensions( 0,//假设第一个绑定项是输入数据 Dims4(batchSize,-1,-1,-1)//根据实际情况调整形状定义 ); } ``` 以上 C++ 版本同样实现了类似的逻辑,但增加了针对动态批次的支持功能[^2]。 #### 注意事项 - 序列化与反序列化过程中需确保版本兼容性。 - 如果存在多个输入/输出节点,则应逐一为其分配缓冲区地址。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arnold-FY-Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值