【转载】TensorRT系列之⼊门篇
TensorRT 系列之⼊门篇
原创 2018-01-28 ⼦棐 ⼦棐之GPGPU
这个世界没有免费的午餐,如果有---那就是TensorRT……
——⼦棐
Why TensorRT
训练对于深度学习来说是为了获得⼀个性能优异的模型,其主要的关注点在于模型的准确度等指标。推理则不⼀样,其没有了训练中的反向迭代过程,是针对新的数据进⾏预测,⽽我们⽇常⽣活中使⽤的AI服务都是推理服务。相较于训练,推理的关注点不⼀样,从⽽也给现在有技术带来了新的挑战:
影响
现有框架的局限性影响
需求现有框架的局限性
需求
⾼吞吐率⽆法处理⼤量和⾼速的数据增加了单次推理的开销
低响应时间应⽤⽆法提供实时的结果损害了⽤户体验(语⾳识别、个性化推荐和实时⽬标检测)
⾼效的功耗以及显存消耗控制⾮最优效能增加了推理的开销甚⾄⽆法进⾏推理部署
部署级别的解决⽅案⾮专⽤于部署使⽤框架复杂度和配置增加了部署难度以及⽣产率
根据上图可知,推理更关注的是⾼吞吐率、低响应时间、低资源消耗以及简便的部署流程,⽽TensorRT就是⽤来解决推理所带来的挑战以及影响的部署级的解决⽅案。
部署流程
TensorRT
TensorRT部署流程
TensorRT的部署分为两个部分:
[if !supportLists]1. [endif]优化训练好的模型并⽣成计算流图
[if !supportLists]2. [endif]使⽤TensorRT Runtime部署计算流图
关于这个流程很⾃然我们会想到以下⼏个问题:
[if !supportLists]1. [endif]TensorRT⽀持什么框架训练出来的⽹络模型呢?
[if !supportLists]2. [endif]TensorRT⽀持什么⽹络结构呢?
[if !supportLists]3. [endif]TensorRT优化器做了哪些优化呢?
[if !supportLists]4. [endif]TensorRT优化好的计算流图可以运⾏在什么设备上呢?
个中因果,诸位看官,稍安勿躁,待本⽂娓娓道来。
TensorRT
之⼤胃王
TensorRT之⼤胃王
输⼊篇之⽹络框架:TensorRT3⽀持所有常见的深度学习框架包括Caffe、Chainer、CNTK、MXnet、PaddlePaddle、Pytorch、TensorFlow以及Theano。
输⼊篇之⽹络层:TensorRT3⽀持的⽹络层包括
Convolution
LSTM and GRU
Activation: ReLU, tanh, sigmoid
Pooling: max and average
Scaling
ElementWise
LRN
Fully-connected
SoftMax
Deconvolution
Concatenation
Flatten
Padding
Plugin
RNN: RNN, GRU, LSTM
Scale
Shuffle
Softmax
Squeeze
Unary
输⼊篇之接⼝⽅式:TensorRT3⽀持模型导⼊⽅式包括C++ API、Python API、NvCaffeParser和NvUffParser
输出篇之⽀持系统平台:TensorRT3⽀持的平台包括Linux x86、Linux aarch64、Android aarch64和QNX aarch64。
输出篇之⽀持硬件平台:TensorRT3可以运⾏在每⼀个GPU平台,从数据中⼼的Tesla P4/V100到⾃动驾驶和嵌⼊式平台的DrivePX及TX1/TX2。
TensorRT 模型导⼊流程
如上图所⽰,模型的导⼊⽅法可以根据框架种类分成三种:Caffe、TensorFlow和其他。
Caffe
[if !supportLists]1. [endif]使⽤C++/Python API导⼊模型:通过代码定义⽹络结构,并载⼊模型weights的⽅式导⼊;
[if !supportLists]2. [endif]使⽤NvCaffeParser导⼊模型:导⼊时输⼊⽹络结构prototxt⽂件及caffemodel⽂件即可。
TensorFlow
[if !supportLists]1. [endif]训练完成后,使⽤uff python接⼝将模型转成uff格式,之后使⽤NvUffParaser导⼊;
[if !supportLists]2. [endif]对于TensorFlow或者keras(TensorFlow后端)的,利⽤Freeze graph来⽣成.pb(protobuf)⽂件,之后使⽤convert-to-uff⼯具将.pb⽂件转化成uff格式,然后利⽤NvUffParaser导⼊。
其他框架
使⽤C++/Python API导⼊模型:通过代码定义⽹络结构,载⼊模型weights的⽅式导⼊。以Pytorch为例,在完成训练后,通过stat_dict()函数获取模型的weights,从⽽在定义⽹络结构时将weights载⼊。
[if !supportLineBreakNewLine]
[endif]
[if !supportLineBreakNewLine]
[endif]
注:weights⽂件是保存的C++ Map对象,该对象定义为:
std::map
其中Weights类型是在NvInfer.h中定义,为存储weights的array。
TensorRT 优化细节
⽹络模型在导⼊⾄TensorRT后会进⾏⼀系列的优化,主要优化内容如下图所⽰。
Layer & Tensor Fusion
TensorRT在获得⽹络计算流图后会针对计算流图进⾏优化,这部分优化不会改变图中最底层计算内容,⽽是会去重构计算图来获得更快更⾼效的执⾏⽅式,即计算不变优化计算⽅法。
以下图为例:
深度学习框架在做推理时,会对每⼀层调⽤多个/次功能函数。⽽由于这样的操作都是在GPU上运⾏的,从⽽会带来多次的CUDA Kernel
launch过程。相较于Kernel launch以及每层tensor data读取来说,kernel的计算是更快更轻量的,从⽽使得这个程序受限于显存带宽并损害了GPU利⽤率。
TensorRT通过以下三种⽅式来解决这个问题:
[if !supportLists]1. [endif]Kernel纵向融合:通过融合相同顺序的操作来减少Kernel Launch的消耗以及避免层之间的显存读写操作。如上
图所⽰,卷积、Bias和Relu层可以融合成⼀个Kernel,这⾥称之为CBR。
[if !supportLists]2. [endif]Kernel横向融合:TensorRT会去挖掘输⼊数据且filter⼤⼩相同但weights不同的层,对于这些层不是使⽤三个不同的Kernel⽽是使⽤⼀个Kernel来提⾼效率,如上图中超宽的1x1 CBR所⽰。
[if !supportLists]3. [endif]消除concatenation层,通过预分配输出缓存以及跳跃式的写⼊⽅式来避免这次转换。
通过这样的优化,TensorRT可以获得更⼩、更快、更⾼效的计算流图,其拥有更少层⽹络结构以及更少Kernel Launch次数。下表列出了常见⼏个⽹络在TensorRT优化后的⽹络层数量,很明显的看到TensorRT可以有效的优化⽹络结构、减少⽹络层数从⽽带来性能的提升。
Layers Layers after fusion
NetworkLayers
Network
VGG194327
Inception V3309113
ResNet-152670159
FP16 & INT8 精度校准
⼤多数的⽹络都是使⽤FP32进⾏模型训练,因此模型最后的weights也是FP32格式。但是⼀旦完成训练,所有的⽹络参数就已经是最优,在推理过程中是⽆需进⾏反向迭代的,因此可以在推理中使⽤FP16或者INT8精度计算从⽽获得更⼩的模型,低的显存占⽤率和延迟以及更⾼的吞吐率。TensorRT可以采⽤FP32、FP16和INT8精度部署模型,只需要在uff_to_trt_engine函数中指定相应数据类型即可:
[if !supportLists]o [endif]对于FP32, 使⽤ trt.infer.DataType.FLOAT.
[if !supportLists]o [endif]对于FP16 指令 以及 Volta GPU内的Tensor Cores, 使⽤trt.infer.DataType.HALF
[if !supportLists]o [endif]对于INT8, 使⽤ trt.infer.DataType.INT8.
更多详细的信息会在未来⼏期解释,如有兴趣请保持关注。
Kernel Auto-Tuning
TensorRT会针对⼤量的Kernel进⾏参数优化和调整。例如说,对于卷积计算有若⼲种算法,TensorRT会根据输⼊数据⼤⼩、filter⼤⼩、tensor分布、batch⼤⼩等等参数针对⽬标平台GPU进⾏选择和优化。
Dynamic Tensor Memory
TensorRT通过为每⼀个tensor在其使⽤期间设计分配显存来减少显存的占⽤增加显存的复⽤率,从⽽避免了显存的过度开销以获得更快和⾼效的推理性能。
优化结果
上图为基于Resnet50⽹络,分别在CPU、V100+TensorFlow、V100+TensorRT上进⾏推理时的性能⽐较,纵轴为每秒处理的图⽚数量。相较于CPU和TensorFlow,TensorRT可以带来40倍和18倍的吞吐率的提升,⽽这部分的提升只需要在拥有GPU的前提下使⽤TensorRT即可免费获得。
TensorRT 部署⽅法
完成TensorRT优化后可以得到⼀个Runtime
inference engine,这个⽂件可以被系列化保存⾄硬盘中,⽽这个保存的序列化⽂件我们称之为“Plan”(流图),之所以称之为流图,因此其不仅保存了计算时所需的⽹络weights也保存了Kernel执⾏的调度流程。TensorRT提供了write_engine_to_file()函数以来保存流图。
在获得了流图之后就可以使⽤TensorRT部署应⽤。为了进⼀步的简化部署流程,TensorRT提供了TensorRT Lite API,它是⾼度抽象的接⼝会⾃动处理⼤量的重复的通⽤任务例如创建⼀个Logger,反序列化流图并⽣成Runtime inference engine,处理输⼊的数据。以下代码提供了⼀个使⽤TensorRT Lite
API的范例教程,只需使⽤API创建⼀个Runtime Engine即可完成前⽂提到的通⽤任务,之后将需要推理的数据载⼊并送⼊Engine即可进⾏推理。
from tensorrt.lite import Engine
from tensorrt.infer import LogSeverity
import tensorrt
tensorflow入门教程# Create a runtime engine from plan file using TensorRT Lite API
engine_single = Engine(PLAN="keras_vgg19_ine",
postprocessors={"dense_2/Softmax":analyze})
images_trt, images_tf = load_and_preprocess_images()
results = []
for image in images_trt:
result = engine_single.infer(image) # Single function for
inference
results.append(result)
敲⿊板TensorRT3Highlight
TensorRT3Highlight
敲⿊板
TensorRT3带来的三个重⼤更新为:
[if !supportLists]1. [endif]TensorFlow Model
Importer - 便捷的API⽤于导⼊TensorFLow训练的模型,优化并⽣成推理Engine。
[if !supportLists]2. [endif]Python API -
Python API⽤于进⼀步提⾼开发效率。
[if !supportLists]3. [endif]Volta Tensor
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论