用NVIDIA-TensorRT构造深度神经网络
Deploying Deep Neural Networks with NVIDIA TensorRT
NVIDIA TensorRT是一个用于生产环境的高性能深度学习推理库。电源效率和响应速度是部署的深度学习应用程序的两个关键指标,因为直接影响用户体验和所提供服务的成本。Tensor RT为运行时性能自动优化训练的神经网络,在Tesla P100 GPU上提供高达16倍的能效(性能/瓦),而普通的CPU专用深度学习推理系统(见图1)。图2显示了NVIDIA Tesla P100和K80使用TensorRT和相对复杂的GoogLenet神经网络架构运行推理的性能。
在本文中,将向展示如何在基于GPU的部署平台上使用Tensor RT从经过训练的深层神经网络中获得最佳的效率和性能。
深度学习训练和部署
用深层神经网络求解有监督机器学习问题涉及两步过程。
第一步是利用gpu对海量标记数据进行深层神经网络训练。在这一步中,神经网络学习数以百万计的权值或参数,使其能够将输入数据示例映射到正确的响应。由于目标函数相对于网络权值最小,训练需要在网络中反复向前和向后传递。为了估计真实世界的性能,通常需要训练几个模型,并根据训练期间没有看到的数据验证模型的准确性。
下一步——推理——使用经过训练的模型根据新数据进行预测。在此步骤中,在生产环境(如数据中心、汽车或嵌入式平台)中运行的应用程序中使用经过最佳训练的模型。对于一些应用,如自动驾驶,推理是实时进行的,因此高吞吐量是至关重要的。
Figure 3: Deep learning training to deployment workflow with NVIDIA DIGITS and Tensor RT.
要了解更多关于训练和推理之间的区别,请参阅Michael Andersch关于GPUs推理的文章。
目标部署环境引入了训练环境中通常不存在的各种挑战。例如,如果目标是使用经过训练的神经网络感知其周围环境的嵌入式设备,则通过该模型的正向推理将直接影响设备的总体响应时间和功耗。优化的关键指标是功率效率:每瓦特的推理性能。
每瓦特性能也是最大化数据中心运营效率的关键指标。在这种情况下,需要最小化在地理上和时间上完全不同的大量请求上使用的延迟和能量,这限制了形成大批量的能力。
NVIDIA TensorRT
Tensor RT是一个高性能的推理引擎,旨在为常见的深度学习应用(如图像分类、分割和目标检测)提供最大的推理吞吐量和效率。Tensor RT优化训练的神经网络以获得运行时性能,并为web/移动、嵌入式和汽车应用程序提供GPU加速推理。
Figure 4: The TensorRT workflow, showing the two key functionalities of TensorRT: the TensorRT neural network optimizer (middle) and the TensorRT target runtime (right).
TensorRT的使用分为两个阶段:构建和部署。在构建阶段,TensorRT对网络结构进行优化,并生成一个用于计算深神经网络前向传递的优化计划。该计划是一个优化的目标代码,可以序列化并存储在内存或磁盘上。
部署阶段通常采用长时间运行的服务或用户应用程序的形式,该服务或用户应用程序接受成批输入数据,通过对输入数据执行计划来执行推理,并返回成批输出数据(分类、对象检测等)。使用TensorRT,不需要在部署硬件上安装和运行深入学习框架。关于推理服务的批处理和管道的讨论是另一篇文章的主题;相反,将重点讨论如何使用TensorRT进行推理。
TensorRT构建阶段
Tensor RT运行时需要三个文件来部署分类神经网络:
网络体系结构文件(deploy.prototxt文件),
训练重量(net.caffemodel网站),和
为每个输出类提供名称的标签文件。
此外,还必须定义批大小和输出层。代码清单1演示了如何将Caffe模型转换为TensorRT对象。构建者(第4-7行)负责读取网络信息。或者,如果不提供网络体系结构文件,则可以使用生成器定义网络信息(deploy.prototxt文件)。
Tensor RT支持以下层类型。
- Convolution: 2D
- Activation: ReLU, tanh and sigmoid
- Pooling: max and average
- ElementWise: sum, product or max of two tensors
- LRN: cross-channel only
- Fully-connected: with or without bias
- SoftMax: cross-channel only
- Deconvolution
卷积:二维
激活:ReLU,tanh和sigmoid
池化:最大值和平均值
元素:两个张量的和、积或最大值
LRN:仅跨信道
全连接:有无偏倚
SoftMax: 仅跨通道
反卷积
1. IBuilder* builder = createInferBuilder(gLogger);
2.
3. // parse the caffe model to populate the network, then set the outputs
4. INetworkDefinition* network = builder->createNetwork();
5.
6. CaffeParser parser;
7. auto blob_name_to_tensor = parser.parse(“deploy.prototxt”,
8. trained_file.c_str(),
9. *network,
10. DataType::kFLOAT);
11.
12. // specify which tensors are outputs
13. network->markOutput(*blob_name_to_tensor->find("prob"));
14.
15. // Build the engine
16. builder->setMaxBatchSize(1);
17. builder->setMaxWorkspaceSize(1 << 30);
18. ICudaEngine* engine = builder->buildCudaEngine(*network);
还可以使用张量RT C++ API来定义没有CAFE解析器的网络,如清单2所示。可以使用API定义任何受支持的层及其参数。可以定义在网络之间变化的任何参数,包括卷积层权重维度和输出,以及池化层的窗口大小和步长。
ITensor* in = network->addInput(“input”, DataType::kFloat, Dims3{…});
IPoolingLayer* pool = network->addPooling(in, PoolingType::kMAX, …);
在定义或加载网络之后,必须如清单1的第13行所示指定输出张量;在示例中,输出是“prob”(表示概率)。接下来,定义批大小(第16行),根据部署场景的不同,批大小可能有所不同。清单1使用的批处理大小为1,但可以选择更大的批处理大小来满足应用程序需要和系统配置。下面,TensorRT执行层优化以减少推理时间。虽然这对API用户是透明的,但是分析网络层需要内存,因此必须指定最大工作空间大小(第17行)。
最后一步是调用buildCudaEngine执行层优化,并根据提供的输入和参数使用优化的网络构建引擎。一旦模型转换为TensorRT对象,就可以部署,可以在主机设备上使用,也可以保存并在其地方使用。
TensorRT对神经网络图进行了一些重要的转换和优化。首先,消除未使用输出的层,以避免不必要的计算。接下来,在可能的情况下,卷积层、偏压层和ReLU层被融合形成一个单层。图6显示了图5中原始网络上垂直层融合的结果(融合层在图6中标记为CBR)。层融合提高了在GPU上运行张量RT优化网络的效率。
Figure 5: An example convolutional neural network with multiple convolutional and activation layers.
另一个转换是水平层融合或层聚合,以及聚合层到各自输出所需的划分,如图7所示。水平层融合通过合并具有相同源张量的层并应用具有相似参数的相同操作来提高性能,从而产生一个更大的层以获得更高的计算效率。图7中的示例显示了图5中3个1×1 CBR层的组合,这些层将相同的输入合并到一个更大的1×1 CBR层中。请注意,必须分解此层的输出,以便从原始输入图馈入不同的后续层。
在TensorRT解析器读取经过训练的网络和配置文件之后,TensorRT在构建阶段对API用户透明地执行转换,如清单1所示。
TensorRT Deploy Phase
推理生成器(IBuilder)buildCudaEngine方法返回指向新的推理引擎运行时对象(ICudaEngine)的指针。此运行时对象已准备好立即使用;或者,可以将其状态序列化并保存到磁盘或对象存储以供分发。序列化的目标代码称为计划。
如前所述,与运行时推断引擎之间的批处理和流式处理数据的整个范围超出了本文的范围。清单3演示了使用推理机处理一批输入数据以生成结果所需的步骤。
/ The execution context is responsible for launching the
// compute kernels
IExecutionContext *context = engine->createExecutionContext();
// In order to bind the buffers, we need to know the names of the
// input and output tensors.
int inputIndex = engine->getBindingIndex(INPUT_LAYER_NAME),
int outputIndex = engine->getBindingIndex(OUTPUT_LAYER_NAME);
// Allocate GPU memory for Input / Output data
void* buffers = malloc(engine->getNbBindings() * sizeof(void*));
cudaMalloc(&buffers[inputIndex], batchSize * size_of_single_input);
cudaMalloc(&buffers[outputIndex], batchSize * size_of_single_output);
// Use CUDA streams to manage the concurrency of copying and executing
cudaStream_t stream;
cudaStreamCreate(&stream);
// Copy Input Data to the GPU
cudaMemcpyAsync(buffers[inputIndex], input,
batchSize * size_of_single_input,
cudaMemcpyHostToDevice, stream);
// Launch an instance of the GIE compute kernel
context.enqueue(batchSize, buffers, stream, nullptr);
// Copy Output Data to the Host
cudaMemcpyAsync(output, buffers[outputIndex],
batchSize * size_of_single_output,
cudaMemcpyDeviceToHost, stream));
// It is possible to have multiple instances of the code above
// in flight on the GPU in different streams.
// The host can then sync on a given stream and use the results
cudaStreamSynchronize(stream);
使用TensorRT最大化性能和效率
TensorRT 1.0现在可以免费下载给NVIDIA开发者程序的成员。
NVIDIA TensorRT使能够轻松地部署神经网络,以最高的性能和效率为产品添加深度学习功能。在构建阶段,TensorRT识别优化网络的机会,在部署阶段,TensorRT以最小化延迟和最大吞吐量的方式运行优化的网络。
如果运行的是由数据中心服务器支持的web或移动应用程序,TensorRT的低开销意味着可以部署更多样、更复杂的模型,为产品添加智能,让用户感到高兴。如果正在使用深入学习来创建下一代智能设备,TensorRT将帮助部署具有高性能、高精度和高能效的网络。
此外,TensorRT使能够利用gpu的能力,使用混合精度FP16数据执行神经网络推理。在Tesla P100和jetsontx2gpu上使用FP16进行神经网络推理可以减少一半的内存使用,并提供更高的性能。