C++ - 坚持使用YoloV4,ONNX和TensorRT

C++ - Stuck with YoloV4, ONNX and TensorRT

提问人:Stef 提问时间:11/17/2023 更新时间:11/17/2023 访问量:26

问:

我正在使用 YoloV4/C++/OpenCV 进行一些检测,它运行得很好。 呵呵,为了改善时间消耗,我正在尝试将所有内容都转移到 NVIDIA TensorRT 上,但我在那里感到迷茫。

我使用 TensorRT 工具将 .weights 文件转换为 ONNX,然后将 ONNX 模型转换为 TensorRT 引擎,如下所示:

void ONNXConvert()
{
    MyLogger logger;
    nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(logger);
    nvinfer1::INetworkDefinition* network = builder->createNetworkV2(1U << static_cast<int>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH));

    // Load ONNX model
    const auto parser = nvonnxparser::createParser(*network, logger);

    // Parse the ONNX model
    // Some code here...

    std::ifstream onnxFile(onnxModelFile, std::ios::binary);
    if (!onnxFile)
    {
        std::cerr << "Error opening ONNX model file. " << onnxModelFile << std::endl;
        return;
    }
    onnxFile.seekg(0, onnxFile.end);
    const size_t modelSize = onnxFile.tellg();
    onnxFile.seekg(0, onnxFile.beg);

    // Allocate buffer to hold the ONNX model
    std::vector<char> onnxModelBuffer(modelSize);
    onnxFile.read(onnxModelBuffer.data(), modelSize);

    if (!parser->parse(onnxModelBuffer.data(), modelSize))
    {
        std::cerr << "Error parsing ONNX model." << std::endl;
        return;
    }

    // Create a builder configuration
    nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();

    // Set configuration options as needed
    config->setMemoryPoolLimit(nvinfer1::MemoryPoolType::kWORKSPACE, 1 << 30);

    nvinfer1::IHostMemory* serializedEngine = builder->buildSerializedNetwork(*network, *config);
    std::cout << "Number of layers in the network: " << network->getNbLayers() << std::endl;
    std::ofstream outFile("yolov4.engine", std::ios::binary);
    outFile.write(reinterpret_cast<const char*>(serializedEngine->data()), serializedEngine->size());
    outFile.close();

    builder->destroy();
    network->destroy();
    serializedEngine->destroy();
}

完成后,我可以加载生成的引擎并执行推理,在我尝试解析检测结果之前,一切似乎都很顺利。

我想知道类概率和边界框坐标,但我所拥有的一切都是不一致的值。

从我的 YoloV4 配置中,我知道我有:

  • 20节课
  • 输入宽度 = 608
  • 输入高度 = 608
  • 通道 = 3
  • 9 个尺寸为 { 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 } 的锚点

推理后,我有 2 个输出缓冲区:

  • 一个 1x22743x1x4,我想我会在其中找到边界框坐标
  • 一个 1x22743x20,我想我会在其中找到类概率

这就是我迷路的地方。 为什么有 22743 次检测?这个数字是如何计算的? 我必须如何解析检测以正确计算坐标和类概率?

我天真地尝试像这样直接解析输出:

for (int d = 0; d < 22743; d++)
{
    float maxProb = -1000.0f;
    int classId = -1;
    for (int c = 0; c < 20; c++)
    {
        if (classes[d * 20 + c] > maxProb)
        {
            maxProb = classes[d * 20 + c];
            classId = c;
        }
    }

    if (maxProb > CONFIDENCE_THRESHOLD)
    {
        float boxX = boxes[d * 4];
        float boxY = boxes[d * 4 + 1];
        float boxW = boxes[d * 4 + 2];
        float boxH = boxes[d * 4 + 3];
    }
}

但我得到的都是微小的概率(如< 1E-05),以及微小的、有时是负数的框坐标。

我知道我应该使用我对锚点的了解,但我真的不确定如何。

有人可以帮我谈谈吗?每一个帮助都会不胜感激。

C++ TensorRT

评论

0赞 Botje 11/17/2023
搜索“yolov4 22743”至少可以解释这个数字:22743 是网格大小为 19x19、38x38 和 76x76 的检测结果的总和。网格上的每个元素都可以有三个边界框,因此最终的计数是22743 = 3 * (19*19 + 38*38 + 76*76)
0赞 Stef 11/17/2023
@Botje 听起来是一个很好的线索,谢谢!

答: 暂无答案