condition: bindings[x] != nullptr

yolov5 pose 预测报错:

原来的项目:

https://github.com/BingfengYan/yolo_pose

运行报错:

condition: bindings[x] != nullptr

原因:tensorrt模型有多个output,如果只写两个buffer,一个input,一个output,则会报错,

需要写多个buffers。

错误代码:

   static float prob[BATCH_SIZE * OUTPUT_SIZE];
    IRuntime* runtime = createInferRuntime(gLogger);
    assert(runtime != nullptr);
    ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream, size);
    assert(engine != nullptr);
    IExecutionContext* context = engine->createExecutionContext();
    assert(context != nullptr);
    delete[] trtModelStream;
    assert(engine->getNbBindings() == 5);
    float* buffers[2];
    // In order to bind the buffers, we need to know the names of the input and output tensors.
    // Note that indices are guaranteed to be less than IEngine::getNbBindings()
    const int inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
    const int outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);
    assert(inputIndex == 0);
    assert(outputIndex == 4);
    // Create GPU buffers on device
    CUDA_CHECK(cudaMalloc((void**)&buffers[inputIndex], BATCH_SIZE * 3 * INPUT_H * INPUT_W * sizeof(float)));
    CUDA_CHECK(cudaMalloc((void**)&buffers[outputIndex], BATCH_SIZE * OUTPUT_SIZE * sizeof(float)));

    // Create stream
    cudaStream_t stream;
    CUDA_CHECK(cudaStreamCreate(&stream));
    uint8_t* img_host = nullptr;
    uint8_t* img_device = nullptr;
    // prepare input data cache in pinned memory 
    CUDA_CHECK(cudaMallocHost((void**)&img_host, MAX_IMAGE_INPUT_SIZE_THRESH * 3));
    // prepare input data cache in device memory
    CUDA_CHECK(cudaMalloc((void**)&img_device, MAX_IMAGE_INPUT_SIZE_THRESH * 3));
    int fcount = 0;
    std::vector<cv::Mat> imgs_buffer(BATCH_SIZE);
    for (int f = 0; f < (int)file_names.size(); f++) {
        fcount++;
        if (fcount < BATCH_SIZE && f + 1 != (int)file_names.size()) continue;
        //auto start = std::chrono::system_clock::now();
        float* buffer_idx = (float*)buffers[inputIndex];
        for (int b = 0; b < fcount; b++) {
            cv::Mat img = cv::imread(img_dir + "/" + file_names[f - fcount + 1 + b]);
            if (img.empty()) continue;
            imgs_buffer[b] = img;
            size_t  size_image = img.cols * img.rows * 3;
            size_t  size_image_dst = INPUT_H * INPUT_W * 3;
            //copy data to pinned memory
            memcpy(img_host,img.data,size_image);
            //copy data to device memory
            CUDA_CHECK(cudaMemcpyAsync(img_device,img_host,size_image,cudaMemcpyHostToDevice,stream));
            preprocess_kernel_img(img_device, img.cols, img.rows, buffer_idx, INPUT_W, INPUT_H, stream);       
            buffer_idx += size_image_dst;
        }
        // Run inference
        auto start = std::chrono::system_clock::now();
        doInference(*context, stream, (void**)buffers, prob, BATCH_SIZE);
        auto end = std::chrono::system_clock::now();
        std::cout << "inference time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
        std::vector<std::vector<Yolo::Detection>> batch_res(fcount);
        for (int b = 0; b < fcount; b++) {
            auto& res = batch_res[b];
            nms(res, &prob[b * OUTPUT_SIZE], CONF_THRESH, NMS_THRESH);
        }
        for (int b = 0; b < fcount; b++) {
            auto& res = batch_res[b];
            cv::Mat img = imgs_buffer[b];
            for (size_t j = 0; j < res.size(); j++) {
                cv::Rect r = get_rect(img, res[j].bbox);
                cv::rectangle(img, r, cv::Scalar(0x27, 0xC1, 0x36), 2);
                cv::putText(img, std::to_string((int)res[j].class_id), cv::Point(r.x, r.y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);
            }
            cv::imwrite("_" + file_names[f - fcount + 1 + b], img);
        }
        fcount = 0;
    }

Dims4 用法:

https://github.com/entropyfeng/yolov5s-involution/blob/0a1f46ba1b350b3cd50cfac9faa67d59ec701e7a/common.hpp

ILayer *focusWithBs(INetworkDefinition *network, std::map<std::string, Weights> &weightMap, ITensor &input, int inch, int outch,
                    int ksize, std::string lname){

    int bs=input.getDimensions().d[0];
    assert(bs);
    ISliceLayer *s1 = network->addSlice(input, Dims4{0,0, 0, 0}, Dims4{1,inch, Yolo::INPUT_H / 2, Yolo::INPUT_W / 2},
                                        Dims4{1,1, 2, 2});
    ISliceLayer *s2 = network->addSlice(input, Dims4{0,0, 1, 0}, Dims4{1,inch, Yolo::INPUT_H / 2, Yolo::INPUT_W / 2},
                                        Dims4{1,1, 2, 2});
    ISliceLayer *s3 = network->addSlice(input, Dims4{0,0, 0, 1}, Dims4{1,inch, Yolo::INPUT_H / 2, Yolo::INPUT_W / 2},
                                        Dims4{1,1, 2, 2});
    ISliceLayer *s4 = network->addSlice(input, Dims4{0,0, 1, 1}, Dims4{1,inch, Yolo::INPUT_H / 2, Yolo::INPUT_W / 2},
                                        Dims4{1,1, 2, 2});
    ITensor *inputTensors[] = {s1->getOutput(0), s2->getOutput(0), s3->getOutput(0), s4->getOutput(0)};
    auto cat = network->addConcatenation(inputTensors, 4);
    auto conv = convBlock(network, weightMap, *cat->getOutput(0), outch, ksize, 1, 1, lname + ".conv");
    return conv;
}

<think>我们正在解决TensorRT执行过程中出现的错误:`executionContext.cpp::enqueueInternal::2082`,错误代码3(API Usage Error),具体信息为: ``` Error Code 3: API Usage Error (Parameter check failed at: runtime/api/executionContext.cpp::validateInputBindings::2082, condition: profileMaxDims[d.i] >= dimensions[d.i]. Supplied binding dimension [8,3,256,256] for bindings[0] exceed min ~ max range at index 0, maximum dimension in profile is 1, minimum dimension in profile is 1, but supplied dimension is 8. ``` ### 问题分析 这个错误表明在推理时,我们传递给TensorRT引擎的输入张量维度超出了构建引擎时设置的优化配置文件(Optimization Profile)的范围。具体来说: - 输入绑定(bindings[0])的维度为`[8,3,256,256]`,其中第一个维度(batch size=8)不在配置文件的允许范围内。 - 优化配置文件中,该维度的最小值(min)和最大值(max)都是1,因此只能接受batch size为1的输入。 ### 解决步骤 #### 1. 理解优化配置文件(Optimization Profile) TensorRT在处理动态形状时,需要定义优化配置文件,指定每个输入维度的最小(min)、最优(opt)和最大(max)值。引擎会根据这些值进行优化,而推理时的输入形状必须在min和max之间。 #### 2. 检查引擎构建时的配置文件设置 在构建引擎时,必须为动态维度设置优化配置文件。常见的错误是: - 没有设置优化配置文件(对于动态形状,必须设置)。 - 设置的min/opt/max值没有覆盖实际推理时的输入维度(例如,推理时batch size=8,但max只设置为1)。 #### 3. 修改引擎构建代码 确保在构建引擎时,为动态输入维度设置正确的优化配置文件。以下是一个示例(C++): ```cpp // 创建构建器、网络和配置 auto builder = nvinfer1::createInferBuilder(logger); auto network = builder->createNetworkV2(1U << static_cast<uint32_t>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH)); auto config = builder->createBuilderConfig(); // 设置优化配置文件 - 假设输入名称为"input",维度为[-1, 3, 256, 256](-1表示动态batch) auto profile = builder->createOptimizationProfile(); nvinfer1::ITensor* input = network->getInput(0); nvinfer1::Dims inputDims = input->getDimensions(); // 应该为[-1,3,256,256] // 设置动态维度的范围:min, opt, max // 注意:第一个维度(batch)是动态的,其他维度固定 nvinfer1::Dims minDims = inputDims; minDims.d[0] = 1; // 最小batch size nvinfer1::Dims optDims = inputDims; optDims.d[0] = 4; // 最优batch size(常用值) nvinfer1::Dims maxDims = inputDims; maxDims.d[0] = 8; // 最大batch size // 将优化配置文件添加到配置中 profile->setDimensions(input->getName(), nvinfer1::OptProfileSelector::kMIN, minDims); profile->setDimensions(input->getName(), nvinfer1::OptProfileSelector::kOPT, optDims); profile->setDimensions(input->getName(), nvinfer1::OptProfileSelector::kMAX, maxDims); config->addOptimizationProfile(profile); // 构建引擎 auto engine = builder->buildEngineWithConfig(*network, *config); ``` #### 4. 在推理时设置正确的输入维度 在推理代码中,必须在设置输入维度后,调用`setBindingDimensions`来更新执行上下文(ExecutionContext)的维度。然后检查维度是否在配置文件范围内。 ```cpp // 获取执行上下文 auto context = engine->createExecutionContext(); // 准备输入数据(假设输入名称为"input",数据指针为inputData) int inputIndex = engine->getBindingIndex("input"); nvinfer1::Dims inputDims = context->getBindingDimensions(inputIndex); // 初始维度 // 设置实际输入维度(例如batch=8) nvinfer1::Dims newDims{4, {8, 3, 256, 256}}; // 4维,具体维度为[8,3,256,256] context->setBindingDimensions(inputIndex, newDims); // 检查维度是否有效 if (!context->allInputDimensionsSpecified()) { // 错误处理:并非所有输入维度都已指定 } // 然后执行推理 void* bindings[2] = {inputData, outputData}; bool success = context->enqueueV2(bindings, stream, nullptr); ``` #### 5. 常见错误规避 - **配置文件范围不足**:确保优化配置文件的max值大于等于推理时可能的最大batch size(或其他动态维度)。 - **未设置执行上下文的维度**:在调用`enqueue`或`enqueueV2`之前,必须调用`setBindingDimensions`来设置动态输入的维度。 - **多个优化配置文件**:如果使用多个配置文件(例如处理不同batch size范围),在推理时需要通过`setOptimizationProfile`选择正确的配置文件索引。 #### 6. 参考用户提供的经验 根据用户引用[^1]中的经验: - 在转换ONNX模型时关闭动态维度(即固定维度)可以避免此类问题,但会失去动态批处理的灵活性。 - 用户通过将min/opt/max都设置为8(固定batch size)解决了问题。但这种方法只适用于固定batch size的场景。 - 用户还提到动态维度问题在重装TensorRT后消失,可能是环境问题,但更可靠的解决方案是正确设置配置文件。 ### 总结 要解决`executionContext.cpp`中的API使用错误(Error Code 3),关键步骤是: 1. 在构建引擎时,为动态输入设置正确的优化配置文件(min/opt/max)。 2. 在推理时,使用`setBindingDimensions`设置实际输入维度,并检查是否在配置文件范围内。 如果问题持续,建议: - 检查TensorRT日志(启用详细日志)以获取更多信息。 - 确保TensorRT版本与硬件、驱动兼容。 - 对于固定batch size的场景,可以在导出ONNX模型时固定batch size,避免动态维度问题。 [^1]: 用户提供的经验表明,关闭动态维度或固定batch size可以解决此问题,但动态维度配置正确是更通用的方法。 §§相关问题§§ 1. 如何为TensorRT引擎设置多个优化配置文件? 2. TensorRT中如何处理多输入或多输出的动态形状? 3. 如何调试TensorRT引擎构建过程中的错误?</think>### 解决 TensorRT ExecutionContext.cpp API Usage Error (Error Code 3) 您遇到的错误是 TensorRT 执行过程中的关键参数检查失败: ```log [E] [TRT] 3: [executionContext.cpp::validateInputBindings::2082] Error Code 3: API Usage Error Condition: profileMaxDims[d.i] >= dimensions[d.i] Supplied binding dimension [8,3,256,256] for bindings[0] exceed min ~ max range Maximum dimension in profile is 1, minimum dimension in profile is 1, but supplied dimension is 8 ``` 此错误表明您的输入张量维度超出了 TensorRT 优化配置文件(Optimization Profile)的允许范围。以下是系统化的解决方案: --- ### 问题根源分析 1. **维度范围不匹配** - 优化配置中定义的 batch size 范围是 `[min=1, max=1]` - 实际推理时传入的 batch size=8(维度 `[8,3,256,256]`) - TensorRT 严格限制输入维度必须在预设的 min/max 范围内[^1] 2. **动态维度配置错误** 当使用动态输入时(如 batch size 可变),必须显式配置优化配置文件: ```cpp IOptimizationProfile* profile = builder->createOptimizationProfile(); profile->setDimensions("input_name", OptProfileSelector::kMIN, Dims4{1,3,256,256}); profile->setDimensions("input_name", OptProfileSelector::kOPT, Dims4{4,3,256,256}); // 推荐最优值 profile->setDimensions("input_name", OptProfileSelector::kMAX, Dims4{8,3,256,256}); config->addOptimizationProfile(profile); ``` 3. **序列化/反序列化不一致** 引擎保存(序列化)和加载(反序列化)时优化配置文件未正确传递 --- ### 逐步解决方案 #### 步骤 1:验证优化配置文件 在推理前检查配置文件范围: ```cpp auto context = engine->createExecutionContext(); // 获取绑定0(输入)的维度范围 Dims minDims = context->getBindingDimensions(0); // 应为[1,3,256,256] Dims maxDims = context->getBindingDimensions(0); // 应为[1,3,256,256](错误状态) // 打印范围验证 std::cout << "Min dims: " << dimsToString(minDims) << std::endl; std::cout << "Max dims: " << dimsToString(maxDims) << std::endl; ``` 如果输出显示 `max=1`,说明配置文件未正确设置[^1]。 #### 步骤 2:修正引擎构建代码 确保构建时设置动态范围(以 C++ 为例): ```cpp // 创建优化配置文件 auto profile = builder->createOptimizationProfile(); // 设置输入"data"的动态范围 profile->setDimensions("data", OptProfileSelector::kMIN, Dims4{1,3,256,256}); profile->setDimensions("data", OptProfileSelector::kOPT, Dims4{4,3,256,256}); // 最优值 profile->setDimensions("data", OptProfileSelector::kMAX, Dims4{8,3,256,256}); // 覆盖最大需求 // 应用到配置 config->addOptimizationProfile(profile); builder->setMaxBatchSize(8); // 与MAX维度一致 ``` #### 步骤 3:推理时设置动态维度 在调用 `enqueue()` 前指定实际维度: ```cpp // 设置当前推理的batch size=8 Dims inputDims{4, {8, 3, 256, 256}}; // 4维张量 context->setBindingDimensions(0, inputDims); // 绑定索引0 // 验证维度有效性 if (!context->allInputDimensionsSpecified()) { throw std::runtime_error("维度未完全指定"); } ``` #### 步骤 4:处理多配置文件场景 当需要多个维度配置时: ```python # Python 示例(PyTorch/TensorRT) profile = builder.create_optimization_profile() profile.set_shape("data", min=(1,3,256,256), opt=(4,3,256,256), max=(8,3,256,256)) config.add_optimization_profile(profile) # 推理时选择配置文件 context.set_optimization_profile_async(0, stream_handle) context.set_binding_shape(0, (8,3,256,256)) ``` --- ### 关键注意事项 1. **版本兼容性** - TensorRT 7.x+ 对动态形状支持更完善 - 使用 `opset_version=17` 导出 ONNX 可减少兼容性问题[^1] 2. **环境一致性** - 在部署设备上重建引擎(避免跨设备序列化问题) - 使用相同 TensorRT 版本构建和推理 3. **错误处理** 添加维度检查守卫: ```cpp if (context->getBindingDimensions(0).d[0] < 8) { std::cerr << "错误:batch size 8 超出配置文件范围" << std::endl; } ``` --- ### 总结 此错误的核心是**动态维度配置不匹配**。通过: 1. 构建时正确设置优化配置文件 2. 推理时显式指定维度 3. 验证环境一致性 可彻底解决问题。实际部署中,固定 batch size(如您提到的设为8)是简化方案,但正确配置动态范围更灵活[^1]。 [^1]: 用户经验表明动态维度的正确配置是关键,环境一致性影响性能表现
提供的引用内容未涉及IExecutionContext::executeV2出现错误代码3(API使用错误,参数检查失败,onnx::Sigmoid_739张量绑定为空指针)的相关解决方案,以下是一般性的解决思路: ### 检查参数传递 确保传递给`IExecutionContext::executeV2`的所有参数都是正确的。这包括输入和输出张量的尺寸、数据类型等。可以通过打印参数信息来进行检查: ```cpp #include <iostream> #include <NvInfer.h> // 假设context是IExecutionContext对象 // 检查输入张量 for (int i = 0; i < context->getEngine().getNbInputs(); ++i) { const char* inputName = context->getEngine().getInputName(i); nvinfer1::Dims inputDims = context->getEngine().getBindingDimensions(i); std::cout << "Input " << i << " Name: " << inputName << ", Dims: "; for (int j = 0; j < inputDims.nbDims; ++j) { std::cout << inputDims.d[j] << " "; } std::cout << std::endl; } // 检查输出张量 for (int i = context->getEngine().getNbInputs(); i < context->getEngine().getNbBindings(); ++i) { const char* outputName = context->getEngine().getBindingName(i); nvinfer1::Dims outputDims = context->getEngine().getBindingDimensions(i); std::cout << "Output " << i - context->getEngine().getNbInputs() << " Name: " << outputName << ", Dims: "; for (int j = 0; j < outputDims.nbDims; ++j) { std::cout << outputDims.d[j] << " "; } std::cout << std::endl; } ``` ### 检查张量绑定 确保所有需要绑定的张量都已经正确绑定,特别是`onnx::Sigmoid_739`张量。检查绑定的指针是否为空: ```cpp // 假设bindings是一个void*数组,用于存储所有绑定的张量指针 void* bindings[context->getEngine().getNbBindings()]; // 填充bindings数组 // ... // 检查onnx::Sigmoid_739张量绑定 int sigmoidBindingIndex = context->getEngine().getBindingIndex("onnx::Sigmoid_739"); if (bindings[sigmoidBindingIndex] == nullptr) { std::cerr << "onnx::Sigmoid_739 tensor binding is a null pointer!" << std::endl; // 进行相应的处理,如重新分配内存等 } ``` ### 检查模型加载 确保ONNX模型加载正确,没有损坏或丢失层。可以尝试重新导出或转换ONNX模型,然后再次加载。 ### 检查运行时环境 确保运行时环境(如CUDA、TensorRT版本等)与模型和代码兼容。不兼容的版本可能会导致参数检查失败。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI算法网奇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值