TensorRT,由NVIDIA精心打造,是一款专为深度学习推理任务设计的高效优化工具。它能够显著降低应用的延迟同时提升处理速度,是大规模数据中心、嵌入式设备以及自动驾驶技术等领域推理加速的理想选择。TensorRT的兼容性广泛,支持包括TensorFlow、Caffe、Mxnet和Pytorch在内的主流深度学习框架,与NVIDIA GPU的结合使用,实现了在各种框架下的快速且高效的模型部署。
自TensorRT 3版本起,它提供了C++和Python两种编程接口,进一步加速了深度学习模型的推理过程。在某些情况下,使用TensorRT的应用程序在执行速度上可比纯CPU平台快达40倍。值得注意的是,TensorRT本质上是一个推理加速器,它允许用户在模型训练完成后,直接将模型文件导入TensorRT进行优化,无需再依赖原始的深度学习框架。
TensorRT 采用多种优化技术来提升深度学习模型的推理性能:
层间融合技术:
TensorRT 通过层间融合,将卷积层、偏置层和ReLU激活层合并为单一的CBR结构,实现横向和纵向的层融合。横向融合将这些层合并为单一操作,仅消耗一个CUDA核心,而纵向融合则将具有相同结构但不同权重的层合并成更宽的层,同样只占用一个CUDA核心。这种融合减少了计算图中的层数,降低了CUDA核心的使用量,从而使得模型结构更加紧凑、运行速度更快、效率更高。
数据精度优化:
在深度学习模型训练过程中,通常使用32位浮点数(FP32)来保证精度。然而,在推理阶段,由于不需要进行反向传播,可以安全地降低数据精度至FP16或INT8,这不仅减少了内存占用和延迟,还使得模型体积更小,提高了推理速度。
Kernel自动调优:
TensorRT 能够自动调整CUDA核心的计算方式,以适应不同的算法、模型结构和GPU平台。这种自动调优确保了模型在特定硬件上以最佳性能运行。
平台特定的优化:
针对不同的GPU平台,如NVIDIA的3090和T4,需要在各自的平台上进行TensorRT模型的转换和优化。这意味着不能在一种平台上完成转换后,直接在另一种平台上使用,而应该针对每个目标平台进行专门的优化和部署。
TensorRT的部署过程可以概括为五个核心步骤:
-
模型训练:首先,需要对深度学习模型进行训练,以获得基础的模型结构和参数。
-
模型导出:训练完成后,将模型导出为ONNX格式,这是一种开放的、标准化的模型表示方式,便于不同平台间的模型迁移和部署。
-
精度选择:在模型转换过程中,需要根据应用需求选择合适的精度级别,这通常涉及到模型性能和准确性之间的权衡。
-
模型转换:将ONNX格式的模型进一步转换为TensorRT模型,这一步骤中TensorRT会应用各种优化技术,以适应NVIDIA GPU的架构,从而提高推理效率。
ONNX 是 Open Neural Network Exchange 的简称,也叫开放神经网络交换,是一个用于表示深度学习模型的标准,可使模型在不同框架直接转换。
ONNX 是迈向开放式生态系统的第一步,使得开发人员不局限于某种特定的开发工具,为模型提供了开源格式。
ONNX 目前支持的框架有:Caffe2、PyTorch、TensorFlow、MXNet、TensorRT、CNTK 等
ONNX 通常来说就是一个中介,是一种手段,在把模型转换成 ONNX 之后,再转换成可部署的形式,如 TensorRT。
典型的结构转换路线
Pytorch → ONNX → TensorRT
Pytorch → ONNX → TVM
TF → ONNX → NCNNimport onnxruntime import torch torch.onnx.export( model, (img_list, ), 'tmp.onnx', input_names=['input.1'], output_names=['output'], export_params=True, keep_initializers_as_inputs=False, verbose=show, opset_version=opset_version, dynamic_axes=dynamic_axes))
-
模型部署:最后,将转换后的TensorRT模型部署到目标平台,实现快速且高效的推理操作。
-
相关推理配置
需要配置logger,builder,builder_config
import numpy as np
import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit
# autoinit是cuda初始化要用的,必须导入
logger = trt.Logger(trt.Logger.INFO)
# 日志器,等级分为:VERBOSE, INFO, WARNING, ERROR, INTERNAL_ERROR
# VERBOSE和INFO最常用,VERBOSE会输出模型优化的详细信息,INFO只会输出模型的输入输出信息
builder = trt.Builder(logger)
# 网络构建器,仅作为构建网络的工具,不用于设置网络属性
builder_conf = builder.create_builder_config()
# 构建器配置,用于设置构建器的属性,可以设置的有:最大显存,int8量化的校正器,设置推理精度等
TensorRT对于batchsize有两种模式:
explicit batch模式:显式指定batchsize
explicit batch模式支持BN层,支持reshape层,支持Loop结构,而implicit batch模式不支持
implicit batch模式【为了向后兼容而保留的,不推荐使用】
根据输入尺寸的不同,可以分为dynamic shape模式
生成Engine并进行推理
engine = trt.Runtime(logger).deserialize_cuda_engine(serializedNetwork)
# 反序列化网络,将序列化的网络反序列化为可执行的引擎,可以用于推理
lTensorName = [engine.get_tensor_name(i) for i in range(engine.num_io_tensors)]
print(lTensorName)
# 获取引擎的输入输出名称
context = engine.create_execution_context()
# 创建执行上下文,用于执行推理,可以理解为GPU进程
context.set_input_shape(lTensorName[0], (1, 1, 28, 28))
# 设置输入形状
hInput = np.random.random((1, 1, 28, 28)).astype(np.float32)
# 创建输入数据,host端
dInput = cuda.mem_alloc(hInput.nbytes)
# 分配显存
houtput = np.empty((1, 1, 28, 28), dtype=np.float32)
# 创建输出数据
doutput = cuda.mem_alloc(houtput.nbytes)
# 分配显存
context.set_tensor_address(lTensorName[0], int(dInput))
context.set_tensor_address(lTensorName[1], int(doutput))
# 设置输入输出显存地址
#复制数据从host到device
cuda.memcpy_htod(dInput, hInput)
# 执行推理
context.execute_async_v3(0)
# 复制数据从device到host
cuda.memcpy_dtoh(houtput, doutput)
print(houtput)
TensorRT的性能提升效果受多种因素影响,包括模型的复杂性、规模以及使用的GPU型号。
GPU因其硬件架构的优势,特别适合处理并行和密集型计算任务。TensorRT的优化策略正是基于GPU的这一特点,更倾向于优化大规模矩阵运算。对于具有大量通道的卷积层和反卷积层,TensorRT的优化效果尤为显著;然而,对于包含许多小规模操作(如reshape、gather、split等)的复杂模型,TensorRT的优化效果可能就不那么显著。
为了最大化GPU的性能,模型设计时应注重并行性。在相同的计算量下,大规模的GPU运算通常比小规模的分散运算效率更高。
在工业应用中,人们倾向于选择结构简单、直接的模型和基础架构。例如,2020年推出的RepVGG模型就是专为GPU和专用硬件设计的,它强调速度和内存效率,而不是参数数量或理论计算量。与ResNet系列相比,RepVGG更适合作为检测或识别模型的基础架构。
以下是对TensorRT加速效果的一些实际应用总结:
- SSD检测模型:使用Caffe框架,加速约3倍。
- CenterNet检测模型:使用Pytorch框架,加速约3到5倍。
- LSTM、Transformer等包含细粒度操作的模型:使用TensorFlow框架,加速约0.5到1倍。
- ResNet系列分类模型:使用Keras框架,加速约3倍左右。
- GAN、分割模型等大型模型:使用Pytorch框架,加速可达7到20倍。
这些数据表明,TensorRT在不同类型的模型和框架中都能提供显著的加速效果,尤其是在处理大规模并行计算时。