本章說明 C++ API 的基本用法,假設(shè)您從 ONNX 模型開始。sampleOnnxMNIST更詳細(xì)地說明了這個用例。
C++ API 可以通過頭文件NvInfer.h
訪問,并且位于nvinfer1
命名空間中。例如,一個簡單的應(yīng)用程序可能以:
#include “NvInfer.h” using namespace nvinfer1;
TensorRT C++ API 中的接口類以前綴I
開頭,例如ILogger
、IBuilder
等。
CUDA 上下文會在 TensorRT 第一次調(diào)用 CUDA 時自動創(chuàng)建,如果在該點(diǎn)之前不存在。通常最好在第一次調(diào)用 TensoRT 之前自己創(chuàng)建和配置 CUDA 上下文。 為了說明對象的生命周期,本章中的代碼不使用智能指針;但是,建議將它們與 TensorRT 接口一起使用。
3.1. The Build Phase
要創(chuàng)建構(gòu)建器,首先需要實(shí)例化ILogger接口。此示例捕獲所有警告消息,但忽略信息性消息:
class Logger : public ILogger { void log(Severity severity, const char* msg) noexcept override { // suppress info-level messages if (severity <= Severity::kWARNING) std::cout << msg << std::endl; } } logger;
然后,您可以創(chuàng)建構(gòu)建器的實(shí)例:
IBuilder* builder = createInferBuilder(logger);
3.1.1. Creating a Network Definition
創(chuàng)建構(gòu)建器后,優(yōu)化模型的第一步是創(chuàng)建網(wǎng)絡(luò)定義:
uint32_t flag = 1U <(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); INetworkDefinition* network = builder->createNetworkV2(flag);
為了使用 ONNX 解析器導(dǎo)入模型,需要kEXPLICIT_BATCH
標(biāo)志。有關(guān)詳細(xì)信息,請參閱顯式與隱式批處理部分。
3.1.2. Importing a Model using the ONNX Parser
現(xiàn)在,需要從 ONNX 表示中填充網(wǎng)絡(luò)定義。 ONNX 解析器 API 位于文件NvOnnxParser.h中,解析器位于nvonnxparser
C++ 命名空間中。
#include “NvOnnxParser.h” using namespace nvonnxparser;
您可以創(chuàng)建一個 ONNX 解析器來填充網(wǎng)絡(luò),如下所示:
IParser* parser = createParser(*network, logger);
然后,讀取模型文件并處理任何錯誤。
parser->parseFromFile(modelFile, static_cast(ILogger::Severity::kWARNING)); for (int32_t i = 0; i < parser.getNbErrors(); ++i) { std::cout << parser->getError(i)->desc() << std::endl; }
TensorRT 網(wǎng)絡(luò)定義的一個重要方面是它包含指向模型權(quán)重的指針,這些指針由構(gòu)建器復(fù)制到優(yōu)化的引擎中。由于網(wǎng)絡(luò)是通過解析器創(chuàng)建的,解析器擁有權(quán)重占用的內(nèi)存,因此在構(gòu)建器運(yùn)行之前不應(yīng)刪除解析器對象。
3.1.3. Building an Engine
下一步是創(chuàng)建一個構(gòu)建配置,指定 TensorRT 應(yīng)該如何優(yōu)化模型。
IBuilderConfig* config = builder->createBuilderConfig();
這個接口有很多屬性,你可以設(shè)置這些屬性來控制 TensorRT 如何優(yōu)化網(wǎng)絡(luò)。一個重要的屬性是最大工作空間大小。層實(shí)現(xiàn)通常需要一個臨時工作空間,并且此參數(shù)限制了網(wǎng)絡(luò)中任何層可以使用的最大大小。如果提供的工作空間不足,TensorRT 可能無法找到層的實(shí)現(xiàn)。默認(rèn)情況下,工作區(qū)設(shè)置為給定設(shè)備的總?cè)謨?nèi)存大??;必要時限制它,例如,在單個設(shè)備上構(gòu)建多個引擎時。
config->setMemoryPoolLimit(MemoryPoolType::kWORKSPACE, 1U << 20);
一旦指定了配置,就可以構(gòu)建引擎。
IHostMemory* serializedModel = builder->buildSerializedNetwork(*network, *config);
由于序列化引擎包含權(quán)重的必要拷貝,因此不再需要解析器、網(wǎng)絡(luò)定義、構(gòu)建器配置和構(gòu)建器,可以安全地刪除:
delete parser; delete network; delete config; delete builder;
然后可以將引擎保存到磁盤,并且可以刪除它被序列化到的緩沖區(qū)。
delete serializedModel
注意:序列化引擎不能跨平臺或 TensorRT 版本移植。引擎特定于它們構(gòu)建的確切 GPU 模型(除了平臺和 TensorRT 版本)。
3.2. Deserializing a Plan
假設(shè)您之前已經(jīng)序列化了一個優(yōu)化模型并希望執(zhí)行推理,您將需要創(chuàng)建一個運(yùn)行時接口的實(shí)例。與構(gòu)建器一樣,運(yùn)行時需要一個記錄器實(shí)例:
IRuntime* runtime = createInferRuntime(logger);
假設(shè)您已將模型從緩沖區(qū)中讀取,然后可以對其進(jìn)行反序列化以獲得引擎:
ICudaEngine* engine = runtime->deserializeCudaEngine(modelData, modelSize);
3.3. Performing Inference
引擎擁有優(yōu)化的模型,但要執(zhí)行推理,我們需要管理中間激活的額外狀態(tài)。這是通過ExecutionContext
接口完成的:
IExecutionContext *context = engine->createExecutionContext();
一個引擎可以有多個執(zhí)行上下文,允許一組權(quán)重用于多個重疊的推理任務(wù)。 (當(dāng)前的一個例外是使用動態(tài)形狀時,每個優(yōu)化配置文件只能有一個執(zhí)行上下文。)
要執(zhí)行推理,您必須為輸入和輸出傳遞 TensorRT 緩沖區(qū),TensorRT 要求您在指針數(shù)組中指定。您可以使用為輸入和輸出張量提供的名稱查詢引擎,以在數(shù)組中找到正確的位置:
int32_t inputIndex = engine->getBindingIndex(INPUT_NAME); int32_t outputIndex = engine->getBindingIndex(OUTPUT_NAME);
使用這些索引,設(shè)置一個緩沖區(qū)數(shù)組,指向 GPU 上的輸入和輸出緩沖區(qū):
void* buffers[2]; buffers[inputIndex] = inputBuffer; buffers[outputIndex] = outputBuffer;
然后,您可以調(diào)用 TensorRT 的 enqueue 方法以使用CUDA 流異步啟動推理:
context->enqueueV2(buffers, stream, nullptr);
通常在內(nèi)核之前和之后將cudaMemcpyAsync()
排入隊(duì)列以從 GPU 中移動數(shù)據(jù)(如果數(shù)據(jù)尚不存在)。enqueueV2()
的最后一個參數(shù)是一個可選的 CUDA 事件,當(dāng)輸入緩沖區(qū)被消耗時發(fā)出信號,并且可以安全地重用它們的內(nèi)存。
要確定內(nèi)核(可能還有memcpy()
)何時完成,請使用標(biāo)準(zhǔn) CUDA 同步機(jī)制,例如事件或等待流。
關(guān)于作者
Ken He 是 NVIDIA 企業(yè)級開發(fā)者社區(qū)經(jīng)理 & 高級講師,擁有多年的 GPU 和人工智能開發(fā)經(jīng)驗(yàn)。自 2017 年加入 NVIDIA 開發(fā)者社區(qū)以來,完成過上百場培訓(xùn),幫助上萬個開發(fā)者了解人工智能和 GPU 編程開發(fā)。在計(jì)算機(jī)視覺,高性能計(jì)算領(lǐng)域完成過多個獨(dú)立項(xiàng)目。并且,在機(jī)器人和無人機(jī)領(lǐng)域,有過豐富的研發(fā)經(jīng)驗(yàn)。對于圖像識別,目標(biāo)的檢測與跟蹤完成過多種解決方案。曾經(jīng)參與 GPU 版氣象模式GRAPES,是其主要研發(fā)者。
審核編輯:郭婷
-
機(jī)器人
+關(guān)注
關(guān)注
211文章
28687瀏覽量
208630 -
NVIDIA
+關(guān)注
關(guān)注
14文章
5079瀏覽量
103805 -
gpu
+關(guān)注
關(guān)注
28文章
4785瀏覽量
129404
發(fā)布評論請先 登錄
相關(guān)推薦
Spire.XLS for C++組件說明
![Spire.XLS for <b class='flag-5'>C++</b>組件說明](https://file1.elecfans.com/web3/M00/05/E7/wKgZO2eFwUuAbuoQAAAbn_khf8A091.png)
AKI跨語言調(diào)用庫神助攻C/C++代碼遷移至HarmonyOS NEXT
C7000 C/C++優(yōu)化指南用戶手冊
![<b class='flag-5'>C</b>7000 <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>優(yōu)化指南用戶手冊](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
TMS320C6000優(yōu)化C/C++編譯器v8.3.x
![TMS320<b class='flag-5'>C</b>6000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器v8.3.x](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
C7000優(yōu)化C/C++編譯器
![<b class='flag-5'>C</b>7000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
ostream在c++中的用法
基于OpenHarmony標(biāo)準(zhǔn)系統(tǒng)的C++公共基礎(chǔ)類庫案例:SafeBlockQueue
![基于OpenHarmony標(biāo)準(zhǔn)系統(tǒng)的<b class='flag-5'>C++</b>公共基礎(chǔ)類庫案例:SafeBlockQueue](https://file.elecfans.com/web2/M00/26/21/pYYBAGG5jjSALfrEAAAwAa9Oig8799.png)
OpenHarmony標(biāo)準(zhǔn)系統(tǒng)C++公共基礎(chǔ)類庫案例:HelloWorld
![OpenHarmony標(biāo)準(zhǔn)系統(tǒng)<b class='flag-5'>C++</b>公共基礎(chǔ)類庫案例:HelloWorld](https://file.elecfans.com/web2/M00/26/21/pYYBAGG5jjSALfrEAAAwAa9Oig8799.png)
OpenVINO2024 C++推理使用技巧
C++中實(shí)現(xiàn)類似instanceof的方法
![<b class='flag-5'>C++</b>中實(shí)現(xiàn)類似instanceof的方法](https://file1.elecfans.com/web2/M00/FE/0C/wKgaomaYe1CAQ31QAAAnf0IkoSU605.png)
鴻蒙OS開發(fā)實(shí)例:【Native C++】
![鴻蒙OS開發(fā)實(shí)例:【Native <b class='flag-5'>C++</b>】](https://file1.elecfans.com/web2/M00/C8/31/wKgZomYZMTCAaDv3AAY5x13C324319.jpg)
使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯誤
![使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯誤](https://file1.elecfans.com/web2/M00/A9/66/wKgZomUl7m-AHJX6AABuJjgxs14678.png)
評論