如下內容根據我的理解整理而成,若有錯誤,歡迎指出,不勝感激。html
更新:看了一個NVIDIA關於TensorRT 6的分享視頻,官方建議使用TensorRT的Python接口進行開發,且TensorRT提供的Parser不太好用,建議本身實現API來構建網絡。git
本文首先根據TensorRT開發者指南梳理TensorRT的C++接口使用流程,而後基於TensorRT的官方例程「Hello World」 For TensorRT來了解其具體使用方式。github
由上一篇Blog中的內容可知,模型從導入TensorRT到執行Inference大體通過下面三個階段:算法
ILogger
編程
首先說明一個必須但不是很重要的類ILogger
,它用於記錄一些日誌信息。 在編程時,咱們須要聲明一個全局的ILogger
對象gLogger,TensorRT中不少方法都須要它做爲參數 (貌似須要繼承ILogger
類來編寫本身的Logger類)網絡
IBuilder
異步
IBuilder
類應該算是最重要的一個類,在使用時,首先要使用TensorRT的全局方法createInferBuilder()
來建立一個IBuilder
類指針,而後由該指針調用IBuilder
類方法建立Network和Engine類的指針。ide
INetworkDefinition
ui
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,其中比較重要的參數有兩個:
疑問二:runtime vs context 在讀開發者指南時,這兩個概念有點亂,這裏區分一下:
注意一:CUDA context 從開發者指南中可知,儘管可使用默認的CUDA context而不顯式建立它,但官方不建議這麼作,推薦在建立一個runtime或builder對象時,建立並配置本身的CUDA context。
理清上述流程後,該例子的cpp源碼不難理解,具體細節這裏再也不闡述。