当前位置:主页 > 软件编程 > Python代码 >

Python api构建tensorrt加速模型的步骤详解

时间:2022-11-01 09:19:18 | 栏目:Python代码 | 点击:

一、创建TensorRT有以下几个步骤:

1.用TensorRT中network模块定义网络模型
2.调用TensorRT构建器从网络创建优化的运行时引擎
3.采用序列化和反序列化操作以便在运行时快速重建
4.将数据喂入engine中进行推理

二、Python api和C++ api在实现网络加速有什么区别?

个人看法
1.python比c++更容易读并且已经有很多包装很好的科学运算库(numpy,scikit等),
2.c++是接近硬件的语言,运行速度比python快很多很多,因为python是解释性语言c++是编译型语言

三、构建TensorRT加速模型

 3.1 加载tensorRT

1.import tensorrt as trt
2.为tensorrt实现日志报错接口方便报错,在下面的代码我们只允许警告和错误消息才打印,TensorRT中包含一个简单的日志记录器Python绑定。

TRT_LOGGER = trt.Logger(trt.Logger.WARNING)

3.2 创建网络

简单来说就是用tensorrt的语言来构建模型,如果自己构建的话,主要是灵活但是工作量so large,一般还是用tensorrt parser来构建
(1)Caffe框架的模型可以直接用tensorrt内部解释器构建
(2)除caffe,TF模型以外其他框架,先转成ONNX通用格式,再用ONNX parser来解析
(3)TF可以直接通过tensorrt内部的UFF包来构建,但是tensorrt uff包中并支持所有算子
(4)自己将wts放入自己构建的模型中,工作量so large,但是很灵活。

3.3 ONNX构建engine

因为博主用的ONNXparser来构建engine的,下面就介绍以下ONNX构建engine,步骤如下:
(1)导入tensorrt

import tensorrt as trt

(2)创建builder,network和相应模型的解释器,这里是onnxparser

EXPLICIT_BATCH = 1 << (int)
(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
with builder = trt.Builder(TRT_LOGGER) as builder,
	builder.create_network(EXPLICIT_BATCH) as network, trt.OnnxParser(network,
 TRT_LOGGER) as parser:
with open(model_path, 'rb') as model:
parser.parse(model.read())

这个代码的主要意思是,构建报错日志,创建build,network和onnxparser,然后用parser读取onnx权重文件。

3.3.1 builder介绍

builder功能之一是搜索cuda内核目录,找到最快的cuda以求获得最快的实现,因此有必要使用相同的GPU进行构建(相同的操作,算子进行融合,减少IO操作),engine就是在此基础上运行的,builder还可以控制网络以什么精度运行(FP32,FP16,INT8),还有两个特别重要的属性是最大批处理大小和最大工作空间大小。

builder.max_batch_size = max_batch_size
builder.max_workspace_size = 1 << 20

3.3.2序列化模型

序列化和反序列化模型的主要是因为network和定义创建engine很耗时,因此可以通过序列化一次并在推理时反序列化一次来避免每次应用程序重新运行时重新构建引擎。
note:序列化引擎不能跨平台或TensorRT版本移植。引擎是特定于它们所构建的GPU模型(除了平台和TensorRT版本)
代码如下:

#序列化模型到模型流
serialized_engine = engine.serialize()
#反序列化模型流去执行推理,反序列化需要创建一个运行时对象
with trt.Runtime(TRT_LOGGER) as runtime:
	engine = runtime.deserialize_cuda_engine(serialized_engine)
#也可以将序列化模型write
with open(“sample.engine”, “wb”) as f:
	f.write(engine.serialize())
#然后再读出来进行反序列化
with open(“sample.engine”, “rb”) as f, trt.Runtime(TRT_LOGGER) as runtime:
	engine = runtime.deserialize_cuda_engine(f.read())

3.3.3执行推理过程

note:下面过程的前提是已经创建好了engine

# 为输入和输出分配一些主机和设备缓冲区:
#确定尺寸并创建页面锁定内存缓冲区
h_input = cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(0)),dtype=np.float32)
h_output =cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(1)),dtype=np.float32)
#为输入和输出分配设备内存
d_input = cuda.mem_alloc(h_input.nbytes)
d_output = cuda.mem_alloc(h_output.nbytes)
#创建一个流,在其中复制输入/输出并运行推断
stream = cuda.Stream()
# 创建一些空间来存储中间激活值,因为engine保存了network定义和训练时的参数,这些都是构建的上下文执行的。
with engine.create_execution_context() as context:
 	# 输入数据传入GPU
	cuda.memcpy_htod_async(d_input, h_input, stream)
 	# 执行推理.
 	context.execute_async(bindings=[int(d_input), int(d_output)],
 	stream_handle=stream.handle)
 	# 将推理后的预测结果从GPU上返回.
 	cuda.memcpy_dtoh_async(h_output, d_output, stream)
 	# 同步流
 	stream.synchronize()
 	# 返回主机输出 
	return h_output

note:一个engine可以有多个执行上下文,允许一组权值用于多个重叠推理任务。例如,可以使用一个引擎和一个上下文在并行CUDA流中处理图像。每个上下文将在与引擎相同的GPU上创建。

您可能感兴趣的文章:

相关文章