解决报错Internal Error (Network has dynamic or shape inputs, but no optimization profile has been defined.

英伟达关于dynamic shape的官方说明:

https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#work_dynamic_shapes
我的解决方案也是看官方说明来操作的,
建议大家看原文,因为以后写代码总会遇到没人解答的问题,所以推荐培养看原文的习惯。
不想看英文的可以看我博客接下来写的部分。

使用TensorRT在前端部署加速推断的时候,为了效率使用了onnx的通用模型,但是onnx的模型在python里面导出的时候会有两种格式:

  • 启用dynamic_axes获得的是动态输入尺寸的模型
  • 取消dynamic_axes获得的是静态输入尺寸的模型, 如下面代码所示

#静态输入就是注释掉最后的两行dynamic_axes,动态输入的话就是启用动态输入模型
torch.onnx.export(network_decompressor,  # model being run
                              input,  # model input (or a tuple for multiple inputs)
                              "network_decompressor"+ "_loss=" + str(format(loss.item(), ".5f"))+"_nodynamic.onnx",
                              # where to save the model (can be a file or file-like object)
                              export_params=True,  # store the trained parameter weights inside the model file
                              opset_version=10,  # the ONNX version to export the model to
                              do_constant_folding=True,  # whether to execute constant folding for optimization
                              input_names=['input'],  # the model's input names
                              output_names=['output'],  # the model's output names
                              # dynamic_axes={'input': {0: 'batch_size'},  # variable lenght axes
                              #               'output': {0: 'batch_size'}}
                              )

他俩的区别就在于推理的时候输入的尺寸是否是根据实际数据动态适应的,直接在onnx在线查看器里面能看出来:
差别就在于一个输入是batch_size,另一个是固定值(我这里是因为batchsize是32所以输入size的第一维是32)。

在这里插入图片描述
在这里插入图片描述
这里有人建议直接弃用动态模型选用静态模型导出,我觉得这些人很不负责,且不说模型适用性差了很多,核心问题是在infer的时候输入的shape基本都是1维的,但是导出静态模型的时候一般都是根据训练的batchsize自动导出的,也就是说拿到的模型输入是[batchsize, ...]这种形状的,但是infer的时候需要输入[1, ...]这种形状的张量, 这俩的形状依然对不上,infer的时候还需要单独设置一次,操作上也更麻烦。

接下来记录我自己的修改:

//[==需要做的新改动==] 在推理引擎 engine 初始化之前 生成profile配置文件(默认会生成一个index=0)
	IOptimizationProfile* profile = builder->createOptimizationProfile();
	profile->setDimensions("input", OptProfileSelector::kMIN, Dims2(MINSIZE,59));	//这里的尺寸更具你自己的输入修改(最小尺寸)
    profile->setDimensions("input", OptProfileSelector::kOPT, Dims2(DEFAULTSIZE,59));	//这里的尺寸更具你自己的输入修改(默认尺寸)
    profile->setDimensions("input", OptProfileSelector::kMAX, Dims2(MAXSIZE,59));	//这里的尺寸更具你自己的输入修改(最大尺寸)
    config->addOptimizationProfile(profile);	//添加进 IBuilderConfig
    //...

// 	构建引擎
    ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);	
    IExecutionContext* context = engine->createExecutionContext();
    //...

// 创建cuda流
    cudaStream_t stream;
    cudaStreamCreate(&stream);
    //...

//[==需要做的新改动=-=]激活profile配置
	//调用推理之前调用setOptimizationProfileAsync激活profile配置
	context->setOptimizationProfileAsync(0, stream);	//这里的0是index,默认我们profile没有特殊编号的话就是编号0
    // 推理
    context->enqueueV2(buffers, stream, nullptr);
    //...


以上涉及到的主要步骤:
1. createOptimizationProfile生成profile配置(默认会给个编号index=0)
2. setDimensions设置输入尺寸
3. 在推理之前调用setOptimizationProfileAsync(编号, stream) 激活profile

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐