tensorrt动态输入分辨率尺寸

举报
风吹稻花香 发表于 2022/03/27 22:18:12 2022/03/27
【摘要】 本文只有 tensorrt python部分涉动态分辨率设置,没有c++的。 目录 pytorch转onnx: onnx转tensorrt: python tensorrt推理: 知乎博客也可以参考: tensorrt动态输入(Dynamic shapes) - 知乎 记录此贴的原因有两个:1.肯定也有很多人需要...

本文只有 tensorrt python部分涉动态分辨率设置,没有c++的。

目录

pytorch转onnx:

onnx转tensorrt:

python tensorrt推理:


知乎博客也可以参考:

tensorrt动态输入(Dynamic shapes) - 知乎

记录此贴的原因有两个:1.肯定也有很多人需要 。2.就我搜索的帖子没一个讲的明明白白的,官方文档也不利索,需要连蒙带猜。话不多少,直接上代码。

以pytorch转onnx转tensorrt为例,动态shape是图像的长宽。

pytorch转onnx:


  
  1. def export_onnx(model,image_shape,onnx_path, batch_size=1):
  2.     x,y=image_shape
  3.     img = torch.zeros((batch_size, 3, x, y))
  4.     dynamic_onnx=True
  5.     if dynamic_onnx:
  6.         dynamic_ax = {'input_1' : {2 : 'image_height',3:'image_wdith'},   
  7.                                 'output_1' : {2 : 'image_height',3:'image_wdith'}}
  8.         torch.onnx.export(model, (img), onnx_path, 
  9.            input_names=["input_1"], output_names=["output_1"], verbose=False, opset_version=11,dynamic_axes=dynamic_ax)
  10.     else:
  11.         torch.onnx.export(model, (img), onnx_path, 
  12.            input_names=["input_1"], output_names=["output_1"], verbose=False, opset_version=11
  13.     )


onnx转tensorrt:

按照nvidia官方文档对dynamic shape的定义,所谓动态,无非是定义engine的时候不指定,用-1代替,在推理的时候再确定,因此建立engine 和推理部分的代码都需要修改。

建立engine时,从onnx读取的network,本身的输入输出就是dynamic shapes,只需要增加optimization_profile来确定一下输入的尺寸范围。


  
  1. def build_engine(onnx_path, using_half,engine_file,dynamic_input=True):
  2.     trt.init_libnvinfer_plugins(None, '')
  3.     with trt.Builder(TRT_LOGGER) as builder, builder.create_network(EXPLICIT_BATCH) as network, trt.OnnxParser(network, TRT_LOGGER) as parser:
  4.         builder.max_batch_size = 1 # always 1 for explicit batch
  5.         config = builder.create_builder_config()
  6.         config.max_workspace_size = GiB(1)
  7.         if using_half:
  8.             config.set_flag(trt.BuilderFlag.FP16)
  9.         # Load the Onnx model and parse it in order to populate the TensorRT network.
  10.         with open(onnx_path, 'rb') as model:
  11.             if not parser.parse(model.read()):
  12.                 print ('ERROR: Failed to parse the ONNX file.')
  13.                 for error in range(parser.num_errors):
  14.                     print (parser.get_error(error))
  15.                 return None
  16.         ##增加部分
  17.         if dynamic_input:
  18.             profile = builder.create_optimization_profile();
  19.             profile.set_shape("input_1", (1,3,512,512), (1,3,1024,1024), (1,3,1600,1600)) 
  20.             config.add_optimization_profile(profile)
  21.         #加上一个sigmoid层
  22.         previous_output = network.get_output(0)
  23.         network.unmark_output(previous_output)
  24.         sigmoid_layer=network.add_activation(previous_output,trt.ActivationType.SIGMOID)
  25.         network.mark_output(sigmoid_layer.get_output(0))
  26.         return builder.build_engine(network, config) 

python tensorrt推理:


进行推理时,有个不小的暗坑,按照我之前的理解,既然动态输入,我只需要在给输入分配合适的缓存,然后不管什么尺寸直接推理就行了呗,事实证明还是年轻了。按照官方文档的提示,在推理的时候一定要增加这么一行,context.active_optimization_profile = 0,来选择对应的optimization_profile,ok,我加了,但是还是报错了,原因是我们既然在定义engine的时候没有定义输入尺寸,那么在推理的时候就需要根据实际的输入定义好输入尺寸。


  
  1. def profile_trt(engine, imagepath,batch_size):
  2.     assert(engine is not None)  
  3.     
  4.     input_image,input_shape=preprocess_image(imagepath)
  5.  
  6.     segment_inputs, segment_outputs, segment_bindings = allocate_buffers(engine, True,input_shape)
  7.     
  8.     stream = cuda.Stream()    
  9.     with engine.create_execution_context() as context:
  10.         context.active_optimization_profile = 0#增加部分
  11.         origin_inputshape=context.get_binding_shape(0)
  12.         #增加部分
  13.         if (origin_inputshape[-1]==-1):
  14.             origin_inputshape[-2],origin_inputshape[-1]=(input_shape)
  15.             context.set_binding_shape(0,(origin_inputshape))
  16.         input_img_array = np.array([input_image] * batch_size)
  17.         img = torch.from_numpy(input_img_array).float().numpy()
  18.         segment_inputs[0].host = img
  19.         [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in segment_inputs]#Copy from the Python buffer src to the device pointer dest (an int or a DeviceAllocation) asynchronously,
  20.         stream.synchronize()#Wait for all activity on this stream to cease, then return.
  21.        
  22.         context.execute_async(bindings=segment_bindings, stream_handle=stream.handle)#Asynchronously execute inference on a batch. 
  23.         stream.synchronize()
  24.         [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in segment_outputs]#Copy from the device pointer src (an int or a DeviceAllocation) to the Python buffer dest asynchronously
  25.         stream.synchronize()
  26.         results = np.array(segment_outputs[0].host).reshape(batch_size, input_shape[0],input_shape[1])    
  27.     return results.transpose(1,2,0)


只是短短几行代码,结果折腾了一整天,不过好在解决了动态输入的问题,不需要再写一堆乱七八糟的代码,希望让有缘人少走一点弯路。

原文链接:https://blog.csdn.net/weixin_42365510/article/details/112088887

文章来源: blog.csdn.net,作者:AI视觉网奇,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/jacke121/article/details/123767395

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。