tensorrt动态输入分辨率尺寸

目录

c++图片补齐实战:

pytorch wts tensorrt

pytorch onnx tensorrt设置

pytorch转onnx:

onnx转tensorrt:

python tensorrt推理:


关于动态分辨率,当做产品时,比如监控场景,一般摄像头分辨率是固定的,不需要动态分辨率

如果验证网上图片时,可能需要动态分辨率。

c++图片补齐实战:

opencv c++ 贴图补齐实战_AI视觉网奇的博客-CSDN博客_opencv 贴图

pytorch wts tensorrt

yolov5是序列化为wts,再转成tensorrt。

anchors与动态分辨率无关。

没有设置动态分辨率的地方

pytorch onnx tensorrt设置

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

目录

pytorch转onnx:

onnx转tensorrt:

python tensorrt推理:


知乎博客也可以参考:

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

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

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

pytorch转onnx:

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


onnx转tensorrt:

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

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

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

python tensorrt推理:


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

def profile_trt(engine, imagepath,batch_size):
    assert(engine is not None)  
    
    input_image,input_shape=preprocess_image(imagepath)
 
    segment_inputs, segment_outputs, segment_bindings = allocate_buffers(engine, True,input_shape)
    
    stream = cuda.Stream()    
    with engine.create_execution_context() as context:
        context.active_optimization_profile = 0#增加部分
        origin_inputshape=context.get_binding_shape(0)
        #增加部分
        if (origin_inputshape[-1]==-1):
            origin_inputshape[-2],origin_inputshape[-1]=(input_shape)
            context.set_binding_shape(0,(origin_inputshape))
        input_img_array = np.array([input_image] * batch_size)
        img = torch.from_numpy(input_img_array).float().numpy()
        segment_inputs[0].host = img
        [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,
        stream.synchronize()#Wait for all activity on this stream to cease, then return.
       
        context.execute_async(bindings=segment_bindings, stream_handle=stream.handle)#Asynchronously execute inference on a batch. 
        stream.synchronize()
        [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
        stream.synchronize()
        results = np.array(segment_outputs[0].host).reshape(batch_size, input_shape[0],input_shape[1])    
    return results.transpose(1,2,0)


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

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

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
TensorRT 支持动态输入和输出形状。这意味着您可以在推理期间更改张量的形状,而不需要重新构建引擎。 在 TensorRT 中使用动态形状需要以下步骤: 1. 创建一个 ICudaEngine 对象,并使用 Dims 类型的最大形状定义输入和输出张量的形状。 2. 在运行时使用 IExecutionContext::setBindingDimensions 方法指定实际输入和输出形状。 3. 在执行推理之前,使用 IExecutionContext::executeV2 方法传递输入和输出缓冲区。 下面是一个使用 TensorRT 动态形状的示例代码: ```python import tensorrt as trt # 创建一个 ICudaEngine 对象 with trt.Builder(TRT_LOGGER) as builder, builder.create_network() as network, \ trt.OnnxParser(network, TRT_LOGGER) as parser: builder.max_workspace_size = 1 << 30 builder.max_batch_size = 1 builder.fp16_mode = True with open(onnx_file_path, 'rb') as model: parser.parse(model.read()) engine = builder.build_cuda_engine(network) # 创建 IExecutionContext 对象 with engine.create_execution_context() as context: # 获取输入和输出绑定信息 input_binding_info = context.get_binding_shape(0) output_binding_info = context.get_binding_shape(1) # 设置实际输入和输出形状 input_shape = (1, 3, 224, 224) output_shape = (1, 1000) context.set_binding_shape(0, input_shape) context.set_binding_shape(1, output_shape) # 创建输入和输出缓冲区 input_buffer = np.zeros(input_shape, dtype=np.float32) output_buffer = np.zeros(output_shape, dtype=np.float32) # 执行推理 context.execute_v2(bindings=[input_buffer, output_buffer]) ``` 在上面的示例中,我们首先使用 TensorRT 的 ONNX 解析器解析 ONNX 模型,并创建一个 ICudaEngine 对象。然后,我们使用 IExecutionContext::get_binding_shape 方法获取输入和输出张量的绑定信息,然后使用 IExecutionContext::set_binding_shape 方法设置实际输入和输出形状。最后,我们创建输入和输出缓冲区,并使用 IExecutionContext::execute_v2 方法进行推理。 需要注意的是,使用动态形状可能会导致一些性能损失,因为 TensorRT 无法在编译时优化缓冲区大小。此外,动态形状功能在某些硬件上可能不受支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值