Cを用いてTensorRT学習(II)++

  この記事ではTensorRTドキュメント「TensorRT・開発・ガイド」第2章「WORKING WITH TENSORRTが使用してC ++ API」の理解を学習から来ています。

A、TensorRTオブジェクトインスタンス

TensorRTAPI
  使用TensorRTオブジェクト・推論の必要性を作成します:

  • IExecutionContext、オブジェクトの推論、ICudaEngineにより得られた物体。
  • ICudaEngine、TensorRTエンジン()はシリアル化ファイルを読み出すことdeserializeCudaEngine、前者シリアライズ()によって後者に基づいて得られ、そして使用することは容易であるている、二つの方法のモデルシリアライズbuildCudaEngine(*ネットワーク)によって生成されます。
  • ILoggerです、グローバル変数は、APIを使用するパラメータとして最もTensorRT。
  • IBuilder createInferBuilder(gLogger)によって作成されました、。
  • iNetworkDefinition、IBuilderオブジェクトのコールcreateNetwork()を取得します。
  • iParserネットワークインタプリタを作成するための入力として、INetwork、その内部parse()メソッドは、モデルファイルを読み込み、ここで留意すべきである特に異なるカフェ、UFF、ONNXで使用される場合TensorRTの関連する実施例を参照することです;
  • IRuntime createInferRuntime(gLogger)によって作成されました、。

  ICudaEngine IBuilder)がbuildCudaEngine()、IRuntime deserializeCudaEngine(せることにより製造することができます。コンテキストが手動で作成されたときにコンテキストを作成するときにIRuntimeとIBuilderが使用されるのでIRuntime、IBuilder、前に作成および構成された推奨のCUDAコンテキストは、デフォルトコンテキストを使用します。

第二には、ネットワークを作成します

  使用TensorRTネットワークを作成するTensorRTの必要性を推論、2つの方法があります。

  • iParserによって主にカフェ、ONNX、UFF(TensorFlow)のために、モデルのシリアル化を既存の。
  • 各層はTensorRTのAPIのネットワーク構造、及びその充填パラメータ訓練で直接定義されます。

  いずれにせよ、あなたは非出力ノードが最適化され、入力と出力のノード名を指定する必要があります。ネットワークモデルはiParserによって作成されたときにネットワークの重みと最適化モデルは、ICudaEngineのIBuilderに保存されます、iParserは、このようにiParserがIBuilderの終了後に実行されなければならない解放、メモリを管理する権利を有します。

2.1 APIは、ネットワークによって定義されました

  各ネットワークは、手動で作成sampleMNISTAPI上の例がありますが、プロセスは次のとおりです。

// 定义IBuilder和iNetworkDefinition
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();

// 添加输入层
auto data = network->addInput(INPUT_BLOB_NAME, dt, Dims3{1, INPUT_H, INPUT_W});

// 添加卷积层(输入节点、strides、权重、偏置)
auto conv1 = network->addConvolution(*data->getOutput(0), 20, DimsHW{5, 5}, weightMap["conv1filter"], weightMap["conv1bias"]);
conv1->setStride(DimsHW{1, 1});

// 添加池化层
auto pool1 = network->addPooling(*conv1->getOutput(0), PoolingType::kMAX, DimsHW{2, 2});
pool1->setStride(DimsHW{2, 2});

// 添加全连接层和激活层
auto ip1 = network->addFullyConnected(*pool1->getOutput(0), 500, weightMap["ip1filter"], weightMap["ip1bias"]);
auto relu1 = network->addActivation(*ip1->getOutput(0), ActivationType::kRELU);

// 添加Softmax层计算最后的概率并设置节点名称
auto prob = network->addSoftMax(*relu1->getOutput(0));
prob->getOutput(0)->setName(OUTPUT_BLOB_NAME);

// 设定输出层
network->markOutput(*prob->getOutput(0));

2.2パーサによって、既存のネットワークモデルを読み込みます

  この方法は、またIBuilder、INetworkDefinitionを作成し、対応するカフェ、UFF、iParserのONNXを作成し、解析モデルを読み込む必要があります。IBuilder INetworkDefinitionファクトリパターンは、異なるネットワークに対応する優先順位、異なる出力機構iParserフレームが作成されます。

  カフェのために:

// 定义IBuilder和iNetworkDefinition
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();

// 创建Caffe的解析器
ICaffeParser* parser = createCaffeParser();

// 解析已有模型,DataType::kFLOAT替换为DataType::kFLOAT能使用半精度
const IBlobNameToTensor* blobNameToTensor = parser->parse("deploy_file" , "modelFile", *network, DataType::kFLOAT);

// 指定网络输出
for (auto& s : outputs)
	network->markOutput(*blobNameToTensor->find(s.c_str()));

  TensorFlowモデルのUFFパーサー(さもなければTensorFlow-TensorRT法)を使用しています。

// 定义IBuilder和iNetworkDefinition
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();

// 创建UFF的解析器
IUFFParser* parser = createUffParser();

// 声明网络输入与输出,对TensorFlow输入非CHW顺序的需要先做转换
parser->registerInput("Input_0", DimsCHW(1, 28, 28), UffInputOrder::kNCHW);
parser->registerOutput("Binary_3");

// 解析已有模型,DataType::kFLOAT替换为DataType::kFLOAT能使用半精度
parser->parse(uffFile, *network, nvinfer1::DataType::kFLOAT);

  ONNXの場合:

// 定义IBuilder和iNetworkDefinition
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();

// 创建ONNX的解析器
nvonnxparser::IONNXParser* parser = nvonnxparser::createONNXParser(*network, gLogger);

// 获取模型
parser->parseFromFile(onnx_filename, ILogger::Severity::kWARNING);

第三に、エンジンを作成

  エンジンはGPUのハードウェア用に最適化されているため、同じGPUを置くためにIBuilderの必要性。IBuilderはまた、最適化性能パラメータを最適化することができ、ネットワーク・オペレーションの精度を設定することができ、その主な属性は、最大のBatchSizeと最大作業領域を設定されています。

  • 最大バッチサイズ、データTensorRTの最適化は、より小さなバッチサイズランタイムを選択し、どのくらいの数の設定。
  • あまりにも小さなセットは、いくつかのTensorRT層を最適化することができない原因となる可能性がある場合、最大ワークスペースのサイズ、最大空間を定義することは、ネットワークストレージ層によって占められて。
// 创建引擎
builder->setMaxBatchSize(maxBatchSize);
builder->setMaxWorkspaceSize(1 << 20);
ICudaEngine* engine = builder->buildCudaEngine(*network);

// 完成处理后释放
parser->destroy();
network->destroy();
builder->destroy();

第四に、シーケンスモデル

  前の確立エンジンを直接使用することができますが、作成エンジンを考慮すると、多くの場合、シリアライゼーション・エンジンを介してバイナリファイルとデシリアライズの読み取りを作成することを選択し、ファイルがプラットフォームやTensorRT間でシリアライズすることができないことに留意すべきで、時間がかかりすぎますバージョン、エンジンが彼らのために最適化されているため。

// 通过引擎创建序列化文件
IHostMemory *serializedModel = engine->serialize();
// store model to disk
// <…>
serializedModel->destroy();

// 通过RunTime对象反序列化
IRuntime* runtime = createInferRuntime(gLogger);
ICudaEngine* engine = runtime->deserializeCudaEngine(modelData, modelSize, nullptr);

第五に、推論

// 创建context来开辟空间存储中间值,一个engine可以有多个context来并行处理
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;

// 使用enqueue方法对CUDA内核在流上排队,进行异步处理
context->enqueue(batchSize, buffers, stream, nullptr);
// 最后的参数是个可选CUDA事件,用于输入缓存区被使用并可安全复用时发出信号

第六に、メモリ管理

  2つのTensorRTデバイスのメモリ管理の仕組みがあります。

  • あなたが直接割り当てを避けたい場合は、直接IExecutionContext作成されたデフォルトの方法では、店舗の活性化データへの固定メモリサイズを割り当てます、あなたはその後、IExecutionContextによってcreateExecutionContextWithoutDeviceMemory()、:: setDeviceMemory()操作のために必要なスペースのネットワークを設定し、ICudaEngineによって:: getDeviceMemorySizeを(使用することができます)メモリ・ブロックのサイズを取得することができます。
  • IGpuAllocatorインターフェース、または割り当ておよび自由空間へIBuilder setGpuAllocatorのIRuntime(&アロケータ)を使用します。

セブン、エンジンをリセット

  TensorRTエンジンは再作成する必要がなく、新たな重みパラメータにより再リセットすることができますが、エンジンは「refittable」として作成されなければならない、とによる最適化されたパラメータへの変更は、他の関連するパラメータを更新する必要があります。パラメータは、更新することができrefitter->getAll(...)鑑賞

// 创建引擎前设置为可重置类型的
...
builder->setRefittable(true);
builder->buildCudaEngine(network);

// 创建重置对象
ICudaEngine* engine = ...;
IRefitter* refitter = createInferRefitter(*engine,gLogger)

// 更新参数,以节点名为“MyLayer”的卷积层为例,新参数需要和原参数属性相同
Weights newWeights = ...;
refitter->setWeights("MyLayer",WeightsRole::kKERNEL, newWeights);

// 查找关联参数,先找到关联参数数量,再查找它们的属性
const int n = refitter->getMissing(0, nullptr, nullptr);
std::vector<const char*> layerNames(n);
std::vector<WeightsRole> weightsRoles(n);
refitter->getMissing(n, layerNames.data(), weightsRoles.data());

// 按属性补充关联参数,不补充额外的参数不会影响到更多的关联参数
for (int i = 0; i < n; ++i)
	refitter->setWeights(layerNames[i], weightsRoles[i], Weights{...});

// 参数补充完成后,更新引擎,如果失败则需查阅日志看是否缺少参数未补充
bool success = refitter->refitCudaEngine();
assert(success);

// 释放重置器
refitter->destroy();

  

  

  

公開された24元の記事 ウォンの賞賛8 ビュー20000 +

おすすめ

転載: blog.csdn.net/yangjf91/article/details/97912773