TensorRT相关知识总结如下 目前自己理解还不够透彻 有问题望指出~
这张图是一个完整的现代深度学习应用,在硬件的应用方面,三个比较大的常用的领域是:视觉相关,包含医疗、自动驾驶、摄像头的处理等等;另外是语音和自然语言处理相关,包含语义理解和语音识别。为了实现这些功能,会使用各种各样的框架,包括Caffe、TensorFlow、PyTorch等等。框架不同,每个人的使用习惯也不同,但最终都是完成一件事情:深度学习模型的训练,以及深度模型的推理。这样一个工具。完成这两个任务最核心的内容还是计算。今天主要核心介绍的就是TensorRT以及相关的DeepStream SDK,他们如何来加速深度学习推理计算。
Tensor,深度学习中的张量。一个一维Tensor的叫Vector,二维的叫Matrix,三维四维的Tensor都有。 Tensor RT的Tensor指的就是这个概念,而整个TensorRT的工具是指一个GPU Inference Engine,也就是一个GPU推理引擎。GPU推理引擎是干什么的呢?我们在做推理的时候,比如拿Caffe框架训练出来一个模型,那么推理的时候就直接拿Caffe框架Test。但是上述场景只适用于做研究或者做课题,部署到产品端会更复杂。举个例子,比如部署到自动驾驶汽车上,框架都很常见,但这么大的框架塞到一个嵌入式的移动设备中非常不合适,里边的空间、计算的内存、CPU的一些计算资源,不可能还有其余的空间给这些框架。自动驾驶汽车上要求提高反应速度,在实验室里的话,一秒反应1帧、5帧甚至10帧都没问题,但是在实际的应用中,需要反应很快,这时候就面临一个计算资源有限的问题,在计算资源有限的情况下,还要得到一个更好的加速效果。硬件设备是没法调整的,那么就要从调整算法入手。TensorRT就会在前端的Inference平台上,包括在服务器的一些显卡上,专门针对性地帮助推理。
使用Jetson Nano部署烟火检测模型时,网络模型较大,参数较多,会导致推理速度慢,延迟高等问题,对于实时视频检测来说是比较致命的缺点,TensorRT推理优化器可以对训练好的模型进行优化以改善上述问题。TensorRT即为高性能深度学习支持引擎,TensorRT 是英伟达发布的基于CUDA和cuDNN的高性能的深度学习推理优化引擎,部署推理时自动选择最优算法,在CPU/GPU模式下实现10倍甚至100倍的加速,TensorRT可以改善YOLOv5烟火检测,提高了烟火检测模型在移动端的推理速度,设备离线化程度也极大增加,降低了延迟时间,提高了吞吐量。TensorRT是用于优化训练后的烟火检测深度学习模型以实现高性能推理的SDK。TensorRT包含用于训练后的深度学习模型的深度学习推理优化器,以及用于执行的Runtime,TensorRT能够以更高的吞吐量和更低的延迟运行烟火检测深度学习模型。
深度学习模型前向具体过程一般为首先神经网络的层,比如卷积池化的实现;随后管理内存,实现数据在各层之间的流动;引擎用来调用各层的实现并执行推断(Inference)。TensorRT整体部署过程可以大致分三个步骤: 将训练后的烟火检测深度学习网络经过TensorRT推理优化器,再经过Engine优化和执行(Execution),最终得以部署成功。使用TensorRT进行深度学习推理的主要流程如下图1所示,具体的TensorRT构成如下图2所示。
图1
图2
上图中Network Definition为TensorRT中模型的表示,网络定义是张量和运算符的图;Builder构建器是TensorRT的模型优化器,构建器将网络定义为输入,执行与设备无关,针对特定设备的优化并创建引擎;Engine是由TensorRT构建器优化的模型的表示;Plan是序列化格式优化后的推理引擎,典型的应用程序将构建一次引擎,然后将其序列化为计划文件供以后使用,初始化推理引擎应用程序需要首先从Plan文件中反序列化模型。
TensorRT生态系统分为两个部分:Conversion(转换)和Deployment(部署),Conversion part(转换部分),用户可以遵循各种路径将其模型转换为优化的TensorRT引擎;Deployment part(部署部分),部署优化的TensorRT引擎时,各种Runtime用户可以使用TensorRT到不同的目标平台。转换和部署分别三种主要选择,如下表5.5所示。
表5.5 转换和部署选择
Conversion part |
Deployment part |
Using TF-TRT |
Deploying within TensorFlow |
Automatic ONNX conversion from .onnx files |
Using the standalone TensorRT runtime API |
Manually constructing a network using the TensorRT API(either in C++ or Python) |
Using NVIDIA Triton Inference Server |
在转换部分,为了获得最佳性能和可定制性,可以使用TensorRT网络定义API手动创建TensorRT引擎,所以选择第三种转换方式来进行模型转换。仅使用TensorRT操作按目标平台构建与原模型相同/近似相同的网络。创建TensorRT网络后,可从框架中导出模型的权重,然后将其加载到TensorRT网络中。
在部署部分,TensorRT的runtimeAPI允许最低的开销和最细粒度的控制,但是TensorRT本身不支持的运算符必须实现为plugin(插件),所以选择第二种部署方式来部署模型。TensorRT库将链接到部署应用程序,部署应用程序在需要推断结果时将调用该库。要初始化推理引擎,应用程序首先将模型从plan文件中反序列化为推理引擎。TensorRT通常异步使用,输入数据到达时,程序将调用一个enquene函数。
TensorRT加速推理的原理是什么呢?TensorRT基本上支持现在所有的主流框架训练出来的模型,把模型输入进来,然后TensorRT帮助做解析,做网络层之间的优化。另外是TensorRT的输入输出,TensorRT的输入是一个已经训练好的32位的数据类型FP32的网络模型,而它的输出是可执行的一个推理引擎。这个推理引擎指的是输出这个推理引擎之后,可以直接在代码里被调用。此外TensorRT还有一个很方便的功能:在已经建立好引擎之后,把它序列化出来,下次再重新调用这个引擎的时候,直接把序列化的文件反序列化,就可以使用了,不用再从头开始创建。TensorRT 4.0之后的一个更新,RNN对NLP这块的支持变得越来越好。除了TensorFlow和Caffe这两个训练出来的模型以外,基本上现在都支持Onnx的网络格式。Onnx网络格式是一个通用的标准,通过Onnx的支持,不同的框架都可以转化到这个模型,相互之间就变得更加协调了。
TensorRT广泛应用于深度学习、人工智能、边缘设备、大数据处理等推理,牺牲小部分推理精度来很大程度上提高推理时间,更满足了许多实时检测和嵌入式开发的要求。导入训练好的烟火检测深度学习模型到TensorRT引擎中,根据模型选择内核推理优化模型,其中包含前向传播训练网络模型,反向传播不断优化网络权重值两个阶段。模型训练过程主要针对训练集,推理过程仅针对除训练集以外的测试集或其他,TensorRT优化推理引擎只有前向传播,将网络模型解析后与TensorRT中对应的层进行一一映射,将改进后的YOLOv5模型转换到TensorRT中,随后可以执行优化策略针对不同的GPU来选择最优算法,还可以加速部署模型。
第一件事是权重精度的校正。比如现在通常用的是FP32的数据类型,如果在做HPC的时候,就可能都会用double类型的float,我们为什么要double类型?因为精度需要非常大的动态范围。但是深度学习在做训练的时候可能并不需要那么大的动态范围,它非常小,可能连FP32都用不了,这个时候就可以用一个更小的动态数据类型。现在TensorRT提出一个FP16半精度的数据类型,还有int8以及最新出的int4的一些数据类型。用这个工具可以帮助把一个较大范围的数据映射到一个较小的范围之内。这样的话在做计算的时候,转换数据的速度非常快,因为数据类型的原因,它所占用的资源也非常少,这个时候的计算速度就会变得很快。
第二件事是网络层的合并,包括一些张量的重新规划。
第三件事是内核调用。内核调用跟GPU底层相关,NVIDIA所有的工具基本上都是基于CUDA这个生态所建立,CUDA里核心的内容是两个方面。一个方面是内存中各种显存的调用,多流的执行。并行计算最有一个难点是数据传输之间那部分很难消掉,硬件卡住的部分无法并行,而CUDA里边多流的执行把这些数据在传输的过程中进行计算,这样就把传输的部分给隐藏了。另外一个方面是怎么调用CUDA核,怎么分配,每个block里边分配多少个线程,每个grid里边有多少个block。这些内容都对GPU要求或者对CUDA的计算功底要求比较高,需要花更多时间,也需要对硬件底层更了解。而TensorRT里边调用了一些方法,以一个最合理的方式去调用、操作这些数据。
举一个网络融合的例子,GoogleNet的Inception结构,很多网络模型也都借鉴这个格式。数据出来之后,经过这么多步骤,TensorRT怎么进行网络结构优化?数据出来之后,它要经过一个卷积层,一个bias,一个Relu,也就是三个网络层,而在底层就是在CUDA里边实现的。
数据到卷积层的时候,会把数据放到GPU里边去计算,然后再翻回来。我们的框架是这样处理的,因为框架是需要所有的硬件平台都能够实现这功能,而TensorRT是针对GPU进行优化的,它是专门针对于前端推理的优化。推理这样一个操作的优化的时候,TensorRT把三个网络层结合到一起了,数据出来后分析网络结构。针对Inference,把三个网络层结合到一起,数据出来后直接计算,然后返还给CPU。这样就相当于减少了四次访问次数。现在的网络都变得越来越宽,所以网络层也越来越多,那么减少数据传输的时间就会变得很重要。这也符合CUDA的核心思想:把零碎的数据整理到一起去传输,减传输次数。
三个网络层是一样的,可以放在一起。然后再往下,Concat也不用了,因为TensorRT会自动帮你把它拼接好。那么接下来怎样继续优化?到现在还能怎么去优化?之前提到过多流执行的概念。假设三个计算的时间是三秒,两个计算出来是两秒,那么如果我们把它分在两个流里边去执行,就可以节省两秒。这些网络层现在是越来越深,网络层的个数越来越多,那么把这些融合到一起,减少读取数据访存的次数。于是就又把横向的时间减少了。这就是TensorRT在这两个方向上优化的底层的原理。TensorRT现在能支持的网络层有很多,基本上所有的网络模型都是支持的。除了这些之外,还有一个重点,就是对不同的用户,对网络层的设计是不一样的,并不是通用的。
TensorRT Inference Server
刚才介绍了TensorRT是一个加速工具,用TensorRT并不是把它放在一个课题实验里,核心目的是把TensorRT部署到产品上。NVIDIA提出了这样一个工具:TensorRT Inference Server,它针对于互联网企业。这个工具支持一个或者多个GPU的调用,支持所有的流行框架训练出来的模型,也能够动态处理。这就能帮助大家建立一个流程,特别是以核心算法为中心的这些公司,不用再因为使用率、利用率等等事情费神。除此之外,把模型仓库和引擎分开,整个项目管理起来更方便。
TensorRT的主要工作流程分为以下六步:
使用TensorRT的必要步骤为:首先根据模型创建TensorRT的网络定义;然后调用TensorRT构建器以从网络创建优化的runtime引擎;序列化和反序列化引擎可以在runtime快速重新创建;最后向引擎提供数据以执行推理。TensorRT优化方式主要有以下几点:
第一:重建网络结构,将一些可以组合的网络层进行层间融合或张量融合优化,这种优化方式也是最重要的优化方式。YOLOv5包含较多的网络层,部署推理目标检测模型的每层张量的计算都需要GPU来进行,GPU调用内部CUDA核心资源时,每层输入输出张量节点运算时都消耗较多时间在读写操作,内存带宽和GPU资源消耗都较多,层之间进行水平或垂直合并可以减少层数,提高了显存和带宽利用率。CUDA在多数据流传输时测量和计算数据信息,读写、输入输出启用/关闭并流过每一层消耗了大部分逻辑推理时间,层间合并/张量合并降低了使用CUDA的频率,零碎数据整合为整体传输,减少了向CPU 传输的次数,减少运行时间。
比如卷积神经网络框架一般包含一个卷积层、一个偏置层和一个激活层,所以需要调用三次cuDNN对应的API,这三层网络就是可以合并到一起的;再比如YOLOv5的网络比较深也比较宽,并行运行若干个卷积层,这些卷积层也是可以合并的,合并一般分为网络结构的垂直集成和水平组合,例如将GoogleNetInception中三个卷积层、BN 质量层和 Relu 非线性激活层合并为一个网络层(CBR层),即垂直集成;水平组合即将输入为相同张量和执行相同操作的层融合一起,例如将GoogleNetInception中三个相连的1×1的CBR为一个大的1×1的CBR。
第二:去除concat层,降低传输吞吐量,不单独输入contcat,将输入直接传送至下一网络层,TensorRT可以不需要concat的操作而直接实现cancat,所以concat这层没有必要可以去除。例如可以将计算结果1×3×24×24和1×5×24×24 concat到一起变成一个1×8×24×24的矩阵。
第三:TensorRT预先写好了较多的GPU实现,Kernel根据不同的batch size大小和问题的复杂程度自动选择最合适的算法。
第四:不同的batch size做相应的tuning。
第五:精度优化,训练改进烟火检测模型时使用全精度FP32位数据,部署推理无需反向传播更新相应的计算节点的张量值,虽然引入了噪声,误差噪声影响各层的激活值输出,但对结果影响甚微,所以TensorRT推理时可以选用半精度浮点型INT8或FP16部署神经网络来加速推断,极大地提高了系统的吞吐量,降低了系统延迟时间,提高了准确率。TensorRT推理在模型层面和语言层面均可以获得加速,本文采用的TensorRT加速的YOLOv5模型更简单、推理更迅速、准确度更高,Jetson Nano内含嵌入式GPU支持 TensorRT,本论文采取的TensorRT加速的方案即为目前最成熟且优化的方式。表5.6为不同数据类型精度的动态范围。
为了优化推理模型,TensorRT会采用网络定义执行包括平台特定的优化并生成推理引擎,此过程为Build阶段,此阶段在嵌入式平台上运行时会花费大量时间,典型的应用程序只构建一次引擎,然后将其反序列化为plan文件供以后使用。构建阶段可以对图执行以下优化:
①消除不使用其输出的层。
②消除等同于无操作的操作。
③卷积、偏置和ReLU操作的融合。
④使用完全相似的参数和相同的源张量进行的操作聚合(aggregation),例如GoogleNet v5的初始模块中的1×1卷积。
⑤通过将层输出定向到正确的最终目的地来合并拼接层。
必要时,builder还可以修改权重的精度,生成8位整数精度的网络时使用校准(calibration)过程来确定中间激活的动态范围,从而确定用于量化的适当缩放因子。此外,build阶段还会在dummy数据上运行各层,以从其kernel目录中选择最快的文件,并在适当的情况下执行权重预格式化和内存优化。
Q&A
Faster Rcnn的Pytorch和Caffe2模型是否支持?
现在是支持检测,只要转化到Onnx模型应该都支持的。
Ft32,怎么转化成Int8,用什么算法,怎么计算,能说明下原理吗?
Ft32转化Int8,首先NVIDIA里有一个工具,Nvinfer,在库里有一个专门矫正数据的类,直接调用就行。
在实际操作中,随便挑了几百张图,能转到int8,实际的计算速度大概是3.6倍,但是精度下降了,这是为什么?
用一个高精度的网络模型训练出来,转化到一个低精度数据类型的网络模型,在低精度网络模型里精度下降一点,很正常。但是为什么精度下降了,我们还要做这个呢?就是因为在可接受的范围内提高了很多速度。
那该选哪些样本做计算呢?另外就是数量,官方建议是500到1000张图,不知道是不是数量越多精度下降越少?
可以给更多的图片,但是精度肯定是会下降的少一些,但是这个不会说差别非常大。选样本最好是选择特征照片,首先得涵盖各种特征,除了各个类别之外,有正样本负样本等等。
别人转后的TensorRT的模型,转给我用,会给好几个不同的batch size,这几个会有区别吗?对速度有什么影响呢?
首先TensorRT转的并不是模型,转过来的是TensorRT的一个引擎,引擎需要调用模型,这个引擎里边有不同batch size,但速度应该是不变,更多的batch意味着这吞吐量不同,也就是同时的计算能力不用,关系到是否能处理更多数据,跟效率有关。