TF Lite C API 在第二次迭代时崩溃

TF Lite C API crashes on second iteration

我正在尝试使用 TF Lite 的 C API 循环执行推理,例如我设置了解释器并每隔一秒左右向他提供输入以获得预测。

为此,我通过 bazel 构建了 libtensorflowlite_c.so。如记录 here,我尝试像这样进行推理,但在 for 循环中模拟循环执行:

#include "tensorflow/lite/c/c_api.h"
#include <stdio.h>
#include <stdlib.h>


int main (int argc, char* argv[]) {

   for(int i = 0; i < 3; i++)
    {
        printf("Iteration: %d\n", i);

        float input[49] = { 0.0 };
        TfLiteModel* model = TfLiteModelCreateFromFile("model.tflite");
        TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
        TfLiteInterpreterOptionsSetNumThreads(options, 2);
        TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
        TfLiteInterpreterAllocateTensors(interpreter);

        TfLiteTensor* input_tensor = TfLiteInterpreterGetInputTensor(interpreter, 0);
        TfLiteTensorCopyFromBuffer(input_tensor, input, 49 * sizeof(float));

        TfLiteInterpreterInvoke(interpreter);

        const TfLiteTensor* output_tensor = TfLiteInterpreterGetOutputTensor(interpreter, 14);

        float output[49];
        TfLiteTensorCopyToBuffer(output_tensor, output, 49 * sizeof(float));

        printf("Output: \n\n");
        for (int j = 0; j < 49; j++) {
            printf("%d: %f\n", j, output[j]);
        }

        TfLiteInterpreterDelete(interpreter);
        TfLiteInterpreterOptionsDelete(options);
        TfLiteModelDelete(model);
    }
    return 0;
}

第一次迭代 运行 很好 returns 一些。但是在第二次迭代中,我在调用 TfLiteTensorCopyToBuffer(output_tensor, output, 49 * sizeof(float)); 时得到了一个 SegFault。原因是前面的函数 TfLiteInterpreterGetOutputTensor returns 一个空指针。

我希望 运行 这多次没有任何问题,因为我在 for 循环结束时销毁了所有旧的变量实例,因此每次都启动一个新的解释器。显然,事实并非如此。

有人可以提供任何指导吗?此外,我知道我可能不必在每次迭代时都创建一个解释器,但我想确保在我重新开始时所有内容都是新创建的。

编辑:

我尝试重写代码以从实际循环中排除不必要的部分:

#include "tensorflow/lite/c/c_api.h"
#include <stdio.h>
#include <stdlib.h>


int main (int argc, char* argv[]) {

    float input[49] = {0.0};
    float output[49] = {[0 ... 48] = 2.5};

    TfLiteModel* model = TfLiteModelCreateFromFile("VariationalAutoencoder_440.tflite");
    TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
    TfLiteInterpreterOptionsSetNumThreads(options, 2);
    TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
    TfLiteInterpreterAllocateTensors(interpreter);
    TfLiteTensor* input_tensor = TfLiteInterpreterGetInputTensor(interpreter, 0);
    const TfLiteTensor* output_tensor = TfLiteInterpreterGetOutputTensor(interpreter, 14);

    for(int i = 0; i < 3; i++)
    {
        printf("\nIteration: %d\n", i);
        TfLiteTensorCopyFromBuffer(input_tensor, input, 49 * sizeof(float));
        TfLiteInterpreterInvoke(interpreter);
        TfLiteTensorCopyToBuffer(output_tensor, output, 49 * sizeof(float));

        printf("Output: \n");
        for (int j = 0; j < 49; j++)
        {
            printf("%02d: %f\n", j, output[j]);
        }
    }

    TfLiteInterpreterDelete(interpreter);
    TfLiteInterpreterOptionsDelete(options);
    TfLiteModelDelete(model);

    return 0;
}

删除for循环之外和之前的所有变量声明,例如:

int main (int argc, char* argv[]) {

   float input[49] = { 0.0 };
   float output[49] = {0.0};//also needs to be initialized
   //and others...

   for(int i = 0; i < 3; i++)
    {
        printf("Iteration: %d\n", i);
        ....

对任何创建可重用对象或分配内存的调用执行相同的操作。在循环中重新声明可重用对象(在重新声明之前不释放它们)可能会产生与在循环中调用 malloc 而不是在后续调用中使用 realloc 类似的结果。

您的代码片段显示您在循环内创建删除以下内容:

    TfLiteInterpreterDelete(interpreter);
    TfLiteInterpreterOptionsDelete(options);
    TfLiteModelDelete(model);

在循环中调用它也可能有问题。

TfLiteTensor* input_tensor = TfLiteInterpreterGetInputTensor(interpreter, 0);

input_tensor,我相信应该创建一次,然后在循环中根据需要调整大小。

根据您提供的link:

// NOTE: After a resize, the client *must* explicitly allocate tensors before
// attempting to access the resized tensor data or invoke the interpreter.
// REQUIRES: 0 <= input_index < TfLiteInterpreterGetInputTensorCount(tensor)
TFL_CAPI_EXPORT extern TfLiteStatus TfLiteInterpreterResizeInputTensor(
    TfLiteInterpreter* interpreter, int32_t input_index, const int* input_dims,
    int32_t input_dims_size);  

编辑: 另一个看起来很奇怪的项目:

const TfLiteTensor* output_tensor = TfLiteInterpreterGetOutputTensor(interpreter, 14);

修饰语 const 似乎与 output_tensor 格格不入。看来如果这个变量会在循环内部发生变化,那么它不应该被修改为 const.

如果 TfLiteInterpreterGetOutputTensor 使用下面的索引 TfLiteInterpreterGetOutputTensorCount,那么您的代码是 运行。

也许张量索引 14 应该是 13,但这取决于您的模型。

添加一些检查,例如:

    int count = TfLiteInterpreterGetOutputTensorCount(interpreter);
    printf("output tensor count:%d\n", count);
    if (count > 14) {
       const TfLiteTensor* output_tensor = TfLiteInterpreterGetOutputTensor(interpreter, 14);

       float output[49];
       TfLiteTensorCopyToBuffer(output_tensor, output, 49 * sizeof(float));

       printf("Output: \n\n");
       for (int j = 0; j < 49; j++) {
          printf("%d: %f\n", j, output[j]);
       }
    }