《二》TensorRT之C++接口使用

如下內容根據我的理解整理而成,若有錯誤,歡迎指出,不勝感激。html

更新:看了一個NVIDIA關於TensorRT 6的分享視頻,官方建議使用TensorRT的Python接口進行開發,且TensorRT提供的Parser不太好用,建議本身實現API來構建網絡。git

0. 寫在前面

本文首先根據TensorRT開發者指南梳理TensorRT的C++接口使用流程,而後基於TensorRT的官方例程「Hello World」 For TensorRT來了解其具體使用方式。github

1. C++接口使用

上一篇Blog中的內容可知,模型從導入TensorRT到執行Inference大體通過下面三個階段:算法

  • Network Definition
  • Builder
  • Engine 這三個階段分別對應着TensorRT中一些重要的類和方法,下面分別來敘述。

ILogger編程

首先說明一個必須但不是很重要的類ILogger,它用於記錄一些日誌信息。 在編程時,咱們須要聲明一個全局的ILogger對象gLogger,TensorRT中不少方法都須要它做爲參數 (貌似須要繼承ILogger類來編寫本身的Logger類)網絡

IBuilder異步

IBuilder類應該算是最重要的一個類,在使用時,首先要使用TensorRT的全局方法createInferBuilder()來建立一個IBuilder類指針,而後由該指針調用IBuilder類方法建立Network和Engine類的指針。ide

INetworkDefinitionui

INetworkDefinition類即爲網絡定義,可經過IBuilder類方法createNetwork()返回其指針。spa

ICudaEngine

ICudaEngine類即爲Engine,可經過IBuilder類方法buildCudaEngine()/buildEngineWithConfig()返回其指針。 注意,可經過導入模型生成Engine和經過反序列化來加載Engine兩種Engine生成方式。

IParser

IParser類對應着前文所述的三種不一樣的解釋器,可根據須要來使用。 IParser類方法parse()用於解析並加載模型及參數到TensorRT網絡中(INetworkDefinition類)

IExecutionContext

Engine的運行須要一個運行時環境,createExecutionContext()方法爲相應的ICudaEngine生成一個IExecutionContext類型的運行環境context。

一個簡單的代碼示例以下:

# builder
IBuilder* builder = createInferBuilder(gLogger);

# network
INetworkDefinition* network = builder->createNetwork();

# parser -> load params to network
CaffeParser* parser = createCaffeParser();
const IBlobNameToTensor* blobNameToTensor = parser->parse(args);

# engine
builder->setMaxBatchSize(maxBatchSize);
IBuilderConfig * config = builder->createBuilderConfig();
config->setMaxWorkspaceSize(1 << 20);
ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);

# serialize engine if necessary
IHostMemory *serializedModel = engine->serialize();

//# 若是是直接反序列化來獲取engine,上述不少步驟都不須要
//IRuntime* runtime = createInferRuntime(gLogger);
//ICudaEngine* engine = runtime->deserializeCudaEngine(modelData, modelSize, nullptr);

# inference
IExecutionContext *context = engine->createExecutionContext();

# 獲取輸入輸出層的索引
int inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
int outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);

# 指針指向輸入輸出層在GPU中的存儲位置
void* buffers[2];
buffers[inputIndex] = inputbuffer;
buffers[outputIndex] = outputBuffer;

# 異步執行inference
context->enqueue(batchSize, buffers, stream, nullptr);

# clear
serializedModel->destroy();
parser->destroy();
network->destroy();
config->destroy();
builder->destroy();
...

疑問一:IBuilder配置參數 可根據須要來配置builder,其中比較重要的參數有兩個:

  • maxBatchSize: TensorRT的輸入是NHWC格式,maxBatchSize代表了N最大可爲多少,如當N=8時,模型一次可處理8張圖片,速度要大於調用8次、每次處理一張圖片的總時間;
  • maxWorkspaceSize:每一層算法的運行都須要臨時的存儲空間,該參數限制了每一層可以使用的最大臨時存儲空間。

疑問二:runtime vs context 在讀開發者指南時,這兩個概念有點亂,這裏區分一下:

  • runtime: 直接反序列化獲取engine時,須要定義該類,此時不須要前面builder等相關的操做
  • context:每個engine的運行都須要context,一個engine可有多個context

注意一:CUDA context 從開發者指南中可知,儘管可使用默認的CUDA context而不顯式建立它,但官方不建議這麼作,推薦在建立一個runtime或builder對象時,建立並配置本身的CUDA context。

2. 「Hello World」 For TensorRT

理清上述流程後,該例子的cpp源碼不難理解,具體細節這裏再也不闡述。

相關文章
相關標籤/搜索