文章目录

  • 1、TensorRT 简介
  • 2、一个简单的TensorRT示例
  • 3、简要代码演练
  • 3.1、批量输入
  • 4、配置文件
  • 5、优化您的应用
  • 6、使用混合精度计算
  • 7、设置最大工作区大小
  • 8、重用TensorRT引擎
  • 9、练习题
  • 10、学到更多
  • 11、参考文献

1、TensorRT 简介

这篇新文章,即使用TensorRT加速深度学习推理,已更新为从PyTorch模型而非ONNX模型开始,将示例应用程序升级为使用TensorRT 7,并用UNet替换了ResNet-50分类模型,这是一个细分模型。

欢迎来到TensorRT简介,这是我们的深度学习推理平台。您将学习如何将深度学习应用程序部署到GPU上,如何提高吞吐量并减少推理期间的延迟。TensorRT提供API和解析器以从所有主要的深度学习框架中导入经过训练的模型。然后,它会生成可部署在数据中心以及汽车和嵌入式环境中的优化运行时引擎。使用TensorRT部署在GPU上的应用程序的运行速度比仅CPU平台快40倍。

本教程使用C ++示例引导您完成将ONNX模型导入TensorRT,应用优化并为数据中心环境生成高性能运行时引擎的过程。TensorRT同时支持C ++和Python,使用两者之一的开发人员都会发现此工作流程讨论很有用。如果您喜欢使用Python,请参考TensorRT文档中的API 。

深度学习适用于广泛的应用程序,例如自然语言处理,推荐系统,图像和视频分析。随着越来越多的应用程序在生产中使用深度学习,对准确性和性能的要求导致模型复杂性和尺寸的强劲增长。汽车等安全性至关重要的应用对深度学习模型期望的吞吐量和延迟提出了严格要求。对于某些消费者应用程序(包括推荐程序)也是如此。TensorRT旨在帮助针对这些用例部署深度学习。借助对每个主要框架的支持,TensorRT通过强大的优化,降低的精度使用和有效的内存使用,帮助以低延迟处理大量数据。

接下来需要一台具有支持CUDA的GPU的计算机或具有GPU的云实例,并安装TensorRT。在Linux上,最容易上手的地方是 从Nvidia容器注册表(Nvidia GPU云的一部分)下载TensorRT容器。

2、一个简单的TensorRT示例

该示例包括三个步骤:将经过预训练的图像分类模型导入TensorRT,应用优化并生成引擎,并在GPU上进行推理,如图1所示。
图1.将训练好的模型导入TensorRT并执行推理的三个步骤

第一步是导入模型,其中包括从磁盘上的已保存文件加载模型,并将其从其本机框架或格式转换为TensorRT网络。我们的示例从ONNX模型库以ONNX格式加载模型。ONNX是用于表示深度学习模型的标准,使它们可以在框架之间转移。(许多框架,例如Caffe2,Chainer,CNTK,PaddlePaddle,PyTorch和MXNet,都支持ONNX格式)。接下来,基于输入模型,目标GPU平台和指定的其他配置参数构建优化的TensorRT引擎。最后一步是向TensorRT引擎提供输入数据以执行推理。该样本使用与ONNX模型库中的模型捆绑在一起的输入数据 来进行推断。

该示例在TensorRT中使用以下组件来执行上述步骤:

  • ONNX解析器:以ONNX格式的经过训练的模型作为输入,并在TensorRT中填充网络对象
  • 构建器:在TensorRT中使用网络并生成针对目标平台进行了优化的引擎
  • 引擎:获取输入数据,执行推理并发出推理输出
  • 记录器:与构建器和引擎关联的对象,用于在构建和推断阶段捕获错误,警告和其他信息

让我们将其应用为以ONNX格式导入经过预训练的ResNet50模型并在TensorRT中 执行推理。 从NGC注册表中的TensorRT容器开始,以获取所有预安装的组件并准备就绪。或使用《TensorRT安装指南》中的分步安装说明进行安装。成功安装TensorRT后,请运行以下命令以下载运行此示例所需的所有信息(示例代码,测试输入数据,参考输出),更新依赖项以及使用提供的makefile编译应用程序。

>> git clone https://github.com/parallel-forall/code-samples.git
>> cd code-samples/posts/TensorRT-introduction
>> wget https://s3.amazonaws.com/onnx-model-zoo/resnet/resnet50v2/resnet50v2.tar.gz // Get ONNX model and test data
>> tar xvf resnet50v2.tar.gz # unpack model data into resnet50v2 folder
>> apt-get update
>> apt install libprotobuf-dev protobuf-compiler        # install protobuf to read the input data which is in .pb format
>> git clone --recursive https://github.com/onnx/onnx.git # pull onnx repository from github
>> cd onnx
>> cmake . # compile and install onnx
>> make install -j12
>> cd ..
>> make # compile the TensorRT C++ sample code

让我们从应用程序的简化版本simpleONNX_1.cpp开始,并在其上进行构建。在同一文件夹中提供的后续版本称为simpleONNX_2.cpp和simpleONNX.cpp。

使用训练有素的模型运行样本,并将输入数据作为输入传递。数据以ONNX protobuf文件的形式提供。该示例将TensorRT生成的输出与同一文件夹中的onnx pb文件提供的参考值进行比较,并在提示符下汇总结果。导入ResNet50v2 ONNX模型并生成引擎可能需要几秒钟。我们在Turing T4 GPU上使用TensorRT 5,您的性能可能会因您的设置而异。

>> ./simpleOnnx_1 resnet50v2/resnet50v2.onnx resnet50v2/test_data_set_0/input_0.pb # sample expects output reference values in resnet50v2/test_data_set_0/output_0.pb...INFO: Formats and tactics selection completed in 27.3666 seconds.
INFO: After reformat layers: 75 layers
INFO: Block size 3211264
INFO: Block size 3211264
INFO: Block size 3211264
INFO: Block size 1605632
INFO: Block size 0
INFO: Total Activation Memory: 11239424
INFO: Data initialization and engine generation completed in 0.148307 seconds.
OK

就是这样,您有了一个简单的应用程序,该应用程序已使用TensorRT优化并在您的GPU上运行!

3、简要代码演练

让我们回顾一下上面示例中使用的一些关键代码段,完整的代码也包含在本节的末尾以供参考。

以下代码示例中的主要功能始于声明一个CUDA引擎来保存网络定义和经过训练的参数。引擎是通过createCudaEngine 将ONNX模型的路径作为输入的函数生成的。

// Declare CUDA engine
unique_ptr<ICudaEngine, Destroy<ICudaEngine>> engine{nullptr};
...
// Create CUDA Engine
engine.reset(createCudaEngine(onnxModelPath));

该createCudaEngine 函数解析ONNX模型并将其保存在网络对象中。该制造商的网络转换成TensorRT引擎。下面的代码段演示了这一点。

ICudaEngine* createCudaEngine(string const& onnxModelPath){unique_ptr<IBuilder, Destroy<IBuilder>> builder{createInferBuilder(gLogger)};unique_ptr<INetworkDefinition, Destroy<INetworkDefinition>> network{builder->createNetwork()};unique_ptr<nvonnxparser::IParser, Destroy<nvonnxparser::IParser>> parser{nvonnxparser::createParser(*network, gLogger)};if (!parser->parseFromFile(onnxModelPath.c_str(), static_cast<int>(ILogger::Severity::kINFO))){cout << "ERROR: could not parse input engine." << endl;return nullptr;}return builder->buildCudaEngine(*network); // build and return TensorRT engine
}

创建引擎后,创建一个执行上下文以保存推理期间生成的中间激活值。下面的代码显示了如何创建执行上下文。

// declaring execution context
unique_ptr<IExecutionContext, Destroy<IExecutionContext>> context{nullptr};...// create execution context
context.reset(engine->createExecutionContext());

此应用程序通过launchInference 以下所示的函数异步将推理请求发送到GPU 。输入从中的主机(CPU)复制到设备(GPU)launchInference,进行推断,然后使用该enqueue 函数执行,结果异步复制回。该示例使用CUDA流来管理GPU上的异步工作。异步推理执行通常通过重叠计算来提高性能,因为它可以最大化GPU利用率。该enqueue 函数在CUDA流上放置推理请求,并获取运行时批处理大小,输入,输出的指针以及将用于内核执行的CUDA流作为输入。使用进行从主机到设备的异步数据传输,反之亦然cudaMemcpyAsync。

void launchInference(IExecutionContext* context, cudaStream_t stream, vector<float> const& inputTensor, vector<float>& outputTensor, void** bindings, int batchSize){int inputId = getBindingInputIndex(context);cudaMemcpyAsync(bindings[inputId], inputTensor.data(), inputTensor.size() * sizeof(float), cudaMemcpyHostToDevice, stream);context->enqueue(batchSize, bindings, stream, nullptr);cudaMemcpyAsync(outputTensor.data(), bindings[1 - inputId], outputTensor.size() * sizeof(float), cudaMemcpyDeviceToHost, stream);
}

cudaStreamSynchronize 调用后使用该函数launchInference 可确保在访问结果之前完成GPU计算。可以使用ICudaEngine 类中的函数查询输入和输出的数量,以及每个输入和输出的值和尺寸。该示例最终将参考输出与TensorRT生成的推论进行比较,并将差异打印到提示中。

在TensorRT类参考手册中找到有关所用类的更多信息。完整的代码段如下。

#include "cudaWrapper.h"
#include "ioHelper.h"
#include <NvInfer.h>
#include <NvOnnxParser.h>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <vector>using namespace nvinfer1;
using namespace std;
using namespace cudawrapper;static Logger gLogger;// Maxmimum absolute tolerance for output tensor comparison against reference
// 输出张量与参考值比较的最大绝对公差
constexpr double ABS_EPSILON = 0.005;
// Maxmimum relative tolerance for output tensor comparison against reference
//输出张量与参考值比较的最大相对公差
constexpr double REL_EPSILON = 0.05;ICudaEngine* createCudaEngine(string const& onnxModelPath, int batchSize)
{unique_ptr<IBuilder, Destroy> builder{createInferBuilder(gLogger)};unique_ptr<INetworkDefinition, Destroy> network{builder->createNetwork()};unique_ptr<nvonnxparser::IParser, Destroy> parser{nvonnxparser::createParser(*network, gLogger)};if (!parser->parseFromFile(onnxModelPath.c_str(), static_cast(ILogger::Severity::kINFO))){cout << "ERROR: could not parse input engine." << endl;return nullptr; }return builder->buildCudaEngine(*network); // build and return TensorRT engine
static int getBindingInputIndex(IExecutionContext* context){return !context->getEngine().bindingIsInput(0); // 0 (false) if bindingIsInput(0), 1 (true) otherwise
}void launchInference(IExecutionContext* context, cudaStream_t stream, vector const& inputTensor, vector& outputTensor, void** bindings, int batchSize)
{int inputId = getBindingInputIndex(context);cudaMemcpyAsync(bindings[inputId], inputTensor.data(), inputTensor.size() * sizeof(float), cudaMemcpyHostToDevice, stream);context->enqueue(batchSize, bindings, stream, nullptr);cudaMemcpyAsync(outputTensor.data(), bindings[1 - inputId], outputTensor.size() * sizeof(float), cudaMemcpyDeviceToHost, stream);
}void softmax(vector& tensor, int batchSize)
{size_t batchElements = tensor.size() / batchSize;for (int i = 0; i < batchSize; ++i){float* batchVector = &tensor[i * batchElements];double maxValue = *max_element(batchVector, batchVector + batchElements);double expSum = accumulate(batchVector, batchVector + batchElements, 0.0, [=](double acc, float value) { return acc + exp(value - maxValue); });transform(batchVector, batchVector + batchElements, batchVector, [=](float input) { return static_cast(std::exp(input - maxValue) / expSum); });}
}void verifyOutput(vector const& outputTensor, vector const& referenceTensor)
{for (size_t i = 0; i < referenceTensor.size(); ++i){double reference = static_cast(referenceTensor[i]);// Check absolute and relative tolerance    检查绝对公差和相对公差if (abs(outputTensor[i] - reference) > max(abs(reference) * REL_EPSILON, ABS_EPSILON)){cout << "ERROR: mismatch at position " << i;cout << " expected " << reference << ", but was " << outputTensor[i] << endl;return;}}cout << "OK" << endl;
}int main(int argc, char* argv[])
{// declaring cuda engineunique_ptr<ICudaEngine, Destroy> engine{nullptr};// declaring execution contextunique_ptr<IExecutionContext, Destroy> context{nullptr};vector inputTensor;vector outputTensor;vector referenceTensor;void* bindings[2]{0};vector inputFiles;CudaStream stream;if (argc != 3){cout << "usage: " << argv[0] << "  " << endl; return 1; } string onnxModelPath(argv[1]); inputFiles.push_back(string{argv[2]}); int batchSize = inputFiles.size(); // Create Cuda Engine engine.reset(createCudaEngine(onnxModelPath, batchSize)); if (!engine) return 1; // Assume networks takes exactly 1 input tensor and outputs 1 tensor assert(engine->getNbBindings() == 2);assert(engine->bindingIsInput(0) ^ engine->bindingIsInput(1));for (int i = 0; i < engine->getNbBindings(); ++i){Dims dims{engine->getBindingDimensions(i)};size_t size = accumulate(dims.d, dims.d + dims.nbDims, batchSize, multiplies());// Create CUDA buffer for TensorcudaMalloc(&bindings[i], size * sizeof(float));// Resize CPU buffers to fit Tensorif (engine->bindingIsInput(i))inputTensor.resize(size);elseoutputTensor.resize(size);}// Read input tensor from ONNX fileif (readTensor(inputFiles, inputTensor) != inputTensor.size()){cout << "Couldn't read input Tensor" << endl; return 1; } // Create Execution Context context.reset(engine->createExecutionContext());launchInference(context.get(), stream, inputTensor, outputTensor, bindings, batchSize);// wait until the work is finishedcudaStreamSynchronize(stream);vector referenceFiles;for (string path : inputFiles)referenceFiles.push_back(path.replace(path.rfind("input"), 5, "output"));// try to read and compare against reference tensor from protobuf filereferenceTensor.resize(outputTensor.size());if (readTensor(referenceFiles, referenceTensor) != referenceTensor.size()){cout << "Couldn't read reference Tensor" << endl;return 1;}// Apply a softmax on the CPU to create a normalized distribution suitable for measuring relative error in probabilities.softmax(outputTensor, batchSize);softmax(referenceTensor, batchSize);verifyOutput(outputTensor, referenceTensor);for (void* ptr : bindings)cudaFree(ptr);return 0;
}

3.1、批量输入

该应用示例期望单个输入并在对其进行推断之后返回输出。实际应用程序通常批量输入以实现更高的性能和效率。可以在神经网络的不同层上并行计算一批形状和大小相同的输入。较大的批次通常可以更有效地利用GPU资源。例如,在V100和Tesla T4 GPU上,使用32的倍数进行批量处理可能特别快速高效,因为TensorRT可以将特殊内核用于矩阵乘法和利用Tensor内核的完全连接层。

使用以下代码在命令行中将图像传递给应用程序。在命令行中作为输入参数传递的图像(.pb文件)的数量决定了此样本中的批处理大小。用于test_data_set_*从所有目录中获取所有input_0.pb文件。下面的命令不仅读取一个输入,还读取文件夹中所有可用的输入。当前,下载的数据具有三个输入目录,因此批处理大小将为3。此版本的示例对应用程序进行配置,并将结果打印到提示符下(在下一部分中对此进行详细介绍)。

>> ./simpleOnnx_2 resnet50v2/resnet50v2.onnx resnet50v2/test_data_set_*/input_0.pb # use all available test data sets...INFO: After reformat layers: 75 layers
INFO: Block size 9633792
INFO: Block size 9633792
INFO: Block size 9633792
INFO: Block size 4816896
INFO: Block size 0
INFO: Total Activation Memory: 33718272
INFO: Data initialization and engine generation completed in 0.120244 seconds.
Inference batch size 3 average over 10 runs is 14.5005ms
OK

由于我们要在一次推理中处理多个图像,因此我们对应用程序进行了几处更改。首先,循环收集所有图像(.pb文件)以用作应用程序中的输入:

129c158,160
<     input_files.push_back(string{argv[2]});
---
>     for (int i = 2; i < argc; ++i)
>         input_files.push_back(string{argv[i]});

接下来,使用该setMaxBatchSize 函数指定TensorRT引擎期望的最大批处理大小。然后,构建器将通过选择算法以使其在目标平台上的性能最大化来生成针对该批次大小调整的引擎。尽管引擎将不接受较大的批次大小,但允许在运行时使用较小的批次大小。maxBatchSize 值的选择取决于应用程序以及任何给定时间的预期推理流量(例如,图像数量)。一种常见的做法是构建针对不同批次大小优化的多个引擎(使用不同的maxBatchSize值),然后在运行时选择最优化的引擎。如果未指定,则默认批处理大小为1,这意味着引擎将不会处理大于1的批处理大小。设置此参数,如下面的代码片段所示。

// Build TensorRT engine optimized based on batch size of input data provided
// 根据提供的输入数据的批量大小构建优化的TensorRT引擎
builder->setMaxBatchSize(batchSize);

4、配置文件

现在,您已经看到了一个简单的示例,让我们讨论如何衡量其性能。用于网络推断的最简单的性能度量是输入到网络的输入到输出返回的时间,称为等待时间。 对于许多嵌入式应用程序而言,延迟是一项对安全性至关重要的要求,而消费者应用程序则需要服务质量。较低的延迟使这些应用程序更好。我们的示例使用GPU上的时间戳来衡量应用程序的平均延迟。有很多方法可以在CUDA中对应用程序进行概要分析,并且这篇文章很好地介绍了常用方法及其优点。

CUDA提供了轻量级的事件API,用于创建和销毁事件,记录事件以及计算事件之间的时间。该应用程序可以在CUDA流中记录事件,一个在发起推理之前记录,另一个在推理完成之后记录,如下代码所示。在某些情况下,您可能需要考虑在推理开始之前和推理完成之后在GPU和CPU之间传输数据所花费的时间。存在将数据预取到GPU以及与数据传输进行重叠计算的技术,这些技术可以显着隐藏数据传输开销。该函数cudaEventElapsedTime 测量CUDA流中遇到这两个事件之间的时间。

使用上一节开头的代码来运行此示例并查看分析输出。为了分析应用程序,我们将推理启动包装在simpleONNX_2.cpp中的doInference函数中。请注意以下更新的函数调用:

165,167c196
<         launchInference(context.get(), stream, inputTensor, outputTensor, bindings, batchSize);
<         // wait until the work is finished
<         cudaStreamSynchronize(stream);
---
>         doInference(context.get(), stream, inputTensor, outputTensor, bindings, batchSize);

计算延迟的范围doInference 如下:

// Number of times we run inference to calculate average time
// 我们运行推断计算平均时间的次数
constexpr int ITERATIONS = 10;
...
void doInference(IExecutionContext* context, cudaStream_t stream, vector const& inputTensor, vector& outputTensor, void** bindings, int batchSize)
{CudaEvent start;CudaEvent end;double totalTime = 0.0;for (int i = 0; i < ITERATIONS; ++i){float elapsedTime;// Measure time it takes to copy input to GPU, run inference and move output back to CPU// 测量将输入复制到GPU,运行推理并将输出移回到CPUcudaEventRecord(start, stream);launchInference(context, stream, inputTensor, outputTensor, bindings, batchSize);cudaEventRecord(end, stream);// wait until the work is finished// 等待直到工作完成cudaStreamSynchronize(stream);cudaEventElapsedTime(&elapsedTime, start, end);totalTime += elapsedTime;}cout << "Inference batch size " << batchSize << " average over " << ITERATIONS << " runs is " << totalTime / ITERATIONS << "ms" << endl;
}

许多应用程序离线对大量输入数据执行推理。每秒可能的最大推理数量(称为吞吐量)是这些应用程序的重要指标。您可以通过为更大的特定批次大小生成优化的引擎,运行推断并测量每秒可以处理的批次数量来测量吞吐量。使用每秒的批处理数量和批处理大小来计算每秒的推理数量。我们会将其留给您做进一步练习。

5、优化您的应用

既然您知道如何批量运行推理并分析应用程序,那么让我们对其进行优化。TensorRT的主要优势在于其灵活性和技术的使用,包括混合精度,在所有GPU平台上的高效优化以及能够在多种模型类型之间进行优化的能力。在本节中,我们描述了一些增加吞吐量和减少应用程序延迟的技术。该TensorRT最佳实践指南提供了可用的技术,以及如何利用它们的全面描述。让我们看看下面的一些常用技术。

6、使用混合精度计算

TensorRT使用FP32算法来执行推理以获得尽可能高的推理精度。但是,在许多情况下,您可以使用FP16和INT8精度进行推断,而对结果的准确性影响最小。使用降低的精度表示模型可以使您在内存中容纳更大的模型,并在降低数据传输要求降低精度的情况下实现更高的性能。您还可以将计算与FP32和FP16精度与TensorRT混合,称为混合精度,或者将INT8量化精度用于权重,激活和执行图层。
setFp16Mode 对于支持快速FP16数学的设备,启用FP16内核就像将参数设置为true一样简单。

builder->setFp16Mode(builder->platformHasFastFp16());

该setFp16Mode 参数向构建者表明,较低的精度对于计算是可接受的,并且TensorRT将使用FP16优化的内核(如果它们在所选配置和目标平台上的性能更好)。启用此模式后,可以在FP16或FP32中指定权重,权重将自动转换为适当的精度以进行计算。您还可以灵活地为输入和输出张量指定16位浮点数据类型。我们将其留给用户练习。

7、设置最大工作区大小

TensorRT允许用户使用该setMaxWorkspaceSize 参数在引擎构建阶段增加GPU内存占用。增加限制可能会影响可以同时共享GPU的应用程序数量。将此限制设置得太低可能会滤除几种算法,从而创建次优引擎。即使设置的数量IBuilder::setMaxWorkspaceSize() 高很多,TensorRT也会仅分配所需的内存。因此,应用程序应允许TensorRT构建器提供尽可能多的工作空间。TensorRT的分配不超过此数量,通常更少。

在我们的示例中,我们使用1GB,这使TensorRT可以选择任何可用的算法。

// Allow TensorRT to use up to 1GB of GPU memory for tactic selection
// 允许TensorRT最多使用1GB的GPU内存进行策略选择
constexpr size_t MAX_WORKSPACE_SIZE = 1ULL << 30; // 1 GB worked well for this sample
...
// set builder flag
// 设置构建器标志
builder->setMaxWorkspaceSize(MAX_WORKSPACE_SIZE);

8、重用TensorRT引擎

构建引擎时,构建器对象会为所选平台和配置选择最优化的内核。从网络定义文件构建引擎可能很耗时,并且除非模型,平台或配置发生更改,否则每次需要执行推理时都不应重复进行。您可以在生成引擎后转换引擎的格式,并将其存储在磁盘上以备后用,这称为序列化引擎。当您将引擎从磁盘加载到内存中并继续用于推理时,就会发生反序列化。这些步骤如图2所示。

图2.序列化和存储引擎使重建引擎的需求降至最低
该runtime对象反序列化引擎。

simpleOnnx.cpp包含每次getCudaEngine 加载和使用引擎的功能,而不是每次都创建引擎。如果引擎不可用,它将使用名称创建引擎并将其保存在当前目录中onnx_filename.engine。如果尝试在当前目录中使用此引擎,我们的示例将选择该引擎,然后尝试构建一个新引擎。要强制使用更新的配置和参数构建新引擎,请make clean_engines 在重新运行样本之前,使用命令删除磁盘上存储的所有现有序列化引擎。

164c198
<engine.reset(createCudaEngine(onnxModelPath));
---
> engine.reset(getCudaEngine(onnxModelPath));

请参见getCudaEngine下面的功能。

ICudaEngine* getCudaEngine(string const& onnxModelPath, int batchSize)
{string enginePath{getBasename(onnxModelPath) + "_batch" + to_string(batchSize) + ".engine"};ICudaEngine* engine{nullptr};string buffer = readBuffer(enginePath);if (buffer.size()){// try to deserialize engineunique_ptr<IRuntime, Destroy> runtime{createInferRuntime(gLogger)};engine = runtime->deserializeCudaEngine(buffer.data(), buffer.size(), nullptr);}if (!engine){// Fallback to creating engine from scratchengine = createCudaEngine(onnxModelPath, batchSize);if (engine){unique_ptr<IHostMemory, Destroy> engine_plan{engine->serialize()};// try to save engine for future useswriteBuffer(engine_plan->data(), engine_plan->size(), enginePath);}}return engine;
}

让我们将此保存的引擎用于不同的批处理大小。下面的代码将获取输入数据,将其重复执行与批量大小变量相同的次数,然后将此附加的输入传递给我们的示例。

>> for x in `seq 1 $BATCH_SIZE`; do echo resnet50v2/test_data_set_0/input_0.pb ; done  | xargs ./simpleOnnx resnet50v2/resnet50v2.onnx
...
INFO: Glob Size is 51388144 bytes.
INFO: Added linear block of size 102760448
INFO: Added linear block of size 102760448
INFO: Added linear block of size 102760448
INFO: Added linear block of size 102760448
INFO: Deserialize required 1270729 microseconds.
Inference batch size 4 average over 10 runs is 3.99671112512ms
OK

就是这样!您现在已经了解了如何使用TensorRT优化深度学习应用程序以进行推理的基础知识。存在许多其他优化技术,例如CPU – GPU与计算之间的重叠数据传输以及使用INT8精度,可以帮助您获得更高的推理性能。通过使用TensorRT将介绍性样本的推断从CPU转移到GPU,我们测得的延迟降低了100倍1倍。

9、练习题

希望该示例使您熟悉使用TensorRT获得出色性能所需的关键概念。以下是一些练习,供您应用所学知识,使用其他模型以及通过更改我们在博客中引入的参数来探索设计和性能折衷的影响。

  1. 如果尚未安装TensorRT,请参阅《TensorRT安装指南》以了解安装要求,TensorRT软件包中包含的清单以及安装TensorRT的分步说明。该TensorRT支持矩阵提供了一个外观到支持的功能和软件TensorRT的API,解析器和层。虽然此示例使用C ++,但TensorRT提供了C ++和Python API。请参考API,并参阅TensorRT开发人员指南中的Python和C ++代码示例 以运行本文中包含的示例。
  2. 试用不同的ONNX模型,例如Squeezenet或Alexnet。这些ONNX格式的模型和测试数据可以在GitHub:ONNX Models上找到。
  3. 将setFp16Mode 上述模型的参数的允许精度更改为true / false,并配置应用程序以查看性能差异
  4. 更改运行时用于推理的批处理大小,并查看其如何影响模型和数据集的性能(延迟,吞吐量)

10、学到更多

您可以找到许多资源来帮助您加速图像/视频,语音和推荐器应用程序。这些范围从代码示例,自定进度的深度学习学院实验室和教程,到用于对应用程序进行性能分析和调试的开发人员工具。以下是方便您学习的资源。

本教程未涵盖的一个主题是在TensorRT中以INT8精度精确执行推理。TensorRT自动转换FP32网络以进行部署,同时降低INT8的精度,同时最大程度地降低精度损失。为了实现此目标,TensorRT使用校准过程,以有限的8位整数表示逼近FP32网络时,可将信息丢失降至最低。请参阅此博客以了解有关使用TensorRT 3的自动驾驶汽车的快速INT8推理的更多信息。

有用的资源:

  1. TensorRT简介 (网络研讨会)
  2. TensorRT最佳实践指南
  3. TensorRT 4概述
  4. TensorRT的8位推理
  5. 使用TensorRT优化NMT

如果您在TensorRT方面遇到问题,请查看NVIDIA TensorRT开发者论坛, 以了解TensorRT社区的其他成员是否首先有解决方案。NVIDIA注册开发人员计划也可以在https://developer.nvidia.com/nvidia-developer-program上提交错误。

11、参考文献

CPU: Skylake Gold 6140, 2.3GHz 3.7 GHz Turbo; HT On; 2 sockets enabled, 72 CPU threads enabled. Ubuntu 16.04 (OS Kernel Ver 4.13.0-39-generic); GPU: Tesla T4; CUDA (r410.72, version 10.0.145); TensorRT 5.0.2.1; Batch size: CPU=1; ECC Off.

如何使用TensorRT加速深度学习推理相关推荐

  1. NVIDIA教你用TensorRT加速深度学习推理计算 | 量子位线下沙龙笔记

    主讲人:Ken(何琨)| NVIDIA开发者社区经理 张康 屈鑫 编辑整理 量子位 出品 | 公众号 QbitAI 12月22日,量子位联合NVIDIA英伟达举行了线下交流会,跟现场近百位开发者同学共 ...

  2. [转载]使用 TensorRT 加速深度学习推理 Speeding Up Deep Learning Inference Using TensorRT

    最近在NVIDIA Blog上看到一篇TensorRT教学,挺不错的,收藏了一下.作者是:Josh Park, Sirisha Rella, Siddharth Sharma and Houman A ...

  3. NVIDIA TensorRT高性能深度学习推理

    NVIDIA TensorRT高性能深度学习推理 NVIDIA TensorRT™ 是用于高性能深度学习推理的 SDK.此 SDK 包含深度学习推理优化器和运行时环境,可为深度学习推理应用提供低延迟和 ...

  4. tensorrt轻松部署高性能dnn推理_NVIDIA TensorRT高性能深度学习推理

    NVIDIA TensorRT高性能深度学习推理 NVIDIA TensorRT™ 是用于高性能深度学习推理的 SDK.此 SDK 包含深度学习推理优化器和运行时环境,可为深度学习推理应用提供低延迟和 ...

  5. 英伟达深度学习推理引擎TensorRT,现在开源了

    https://www.toutiao.com/a6703740623364555271/ 2019-06-18 13:37:53 机器之心报道 参与:李亚洲.李泽南.思 英伟达的深度学习推理引擎Te ...

  6. TensorRT是NVIDIA开发的深度学习推理工具,只支持推理,不支持训练 引

    . TensorRT是NVIDIA开发的深度学习推理工具,只支持推理,不支持训练:   目前TensorRT3已经支持Caffe.Caffe2.TensorFlow.MxNet.Pytorch等主流深 ...

  7. 线上报名 | 高性能深度学习推理引擎 TensorRT 实战编程讲解

    NVIDIA TensorRT™ 是一种高性能深度学习推理优化器和运行时提供低延迟和高通量的深度学习推理的应用程序.使用 TensorRT,您可以优化神经网络模型,精确地校准低精度,并最终将模型部署到 ...

  8. 深度学习推理框架调研总结

    深度学习推理框架 作者介绍 1.移动端深度学习推理框架调研 1.1 小米的MACE(2017) 1.2 阿里的MNN 1.3 腾讯的TNN 1.4 ARM的tengine 1.5 百度的paddle- ...

  9. 工程之道,深度学习推理性能业界最佳优化实践

    MegEngine「训练推理一体化」的独特范式,通过静态图优化保证模型精度与训练时一致,无缝导入推理侧,再借助工业验证的高效卷积优化技术,打造深度学习推理侧极致加速方案,实现当前业界最快运行速度.本文 ...

最新文章

  1. 没学数模电可以玩单片机吗
  2. linux 安全 ***检测 杀毒 rootkit
  3. matlab字符衔接,matlab字符串连接(多个字符串)的经验,matlab字符串
  4. The Tower(HDU6559+2018年吉林站+数学)
  5. LACP链路聚合-基础篇
  6. 【 Thread】创建线程的2种方法
  7. 说说Javaweb 服务器与Tomcat源代码解析
  8. why my detail page in SAP UI5 application is failed to be loaded from router
  9. Android studio之提示Failed to resolve: com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46
  10. 机器学习之数据集划分——训练集测试集划分,划分函数,估计器的使用
  11. 初入c++(三)this指针,友元函数,友元类
  12. VB的KeyAscii
  13. Coursera心理学课程考试小抄
  14. 关于embedding的理解,2020-7-30
  15. 蝉联四年VOT冠军、发表数十篇顶会论文,卢湖川与IIAU实验室的成功之路
  16. 前端原生开发解决方案
  17. 小记(1)偷影子的人
  18. 流体力学——漩涡运动
  19. hellow windows
  20. 针织毛衫的概念及设计

热门文章

  1. python窗口编程哪个好_Python界面编程好用的模块推荐
  2. python魔方方法__call__
  3. AnatomyNet: Deep Learning for Fast and Fully Automated Whole-volume Segmentation of Head and Neck An
  4. Launcher3移除Hotseat图标
  5. QlikView 笔记(一) 初次使用时最让我惊喜的函数
  6. windows10无法搜索计算机,win10搜索功能失效用不了如何解决|win10搜索功能搜不了文件的解决方法...
  7. 《区块链技术与应用》北大肖臻老师——课程笔记【4-5】
  8. 双位置继电器ST2-2L/AC220V
  9. 地铁两站之间最短路径查询(python实现)
  10. Matlab算法之优化计算1