1

我正在使用 Tensorflow 2.1 git master 分支(提交 id:db8a74a737cc735bb2a4800731d21f2de6d04961)并在本地编译它。使用 C API 进行调用TF_LoadSessionFromSavedModel,但似乎出现分段错误。我已经设法深入了解下面示例代码中的错误。

TF_NewTensor调用崩溃并导致分段错误。


int main()
{
    TF_Tensor** InputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*)*1);
    int ndims = 1;
    int64_t* dims = malloc(sizeof(int64_t));
    int ndata = sizeof(int32_t);
    int32_t* data = malloc(sizeof(int32_t));
    dims[0] = 1;
    data[0] = 10;

    // Crash on the next line
    TF_Tensor* int_tensor = TF_NewTensor(TF_INT32, dims, ndims, data, ndata, NULL, NULL);
    if(int_tensor == NULL)
    {
        printf("ERROR");
    }
    else
    {
        printf("OK");
    }
    return 0;
}

但是,当我TF_Tensor** InputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*)*1);在通话后移动时TF_NewTensor,它不会崩溃。如下所示:


int main()
{

    int ndims = 1;
    int64_t* dims = malloc(sizeof(int64_t));
    int ndata = sizeof(int32_t);
    int32_t* data = malloc(sizeof(int32_t));
    dims[0] = 1;
    data[0] = 10;

    // NO more crash
    TF_Tensor* int_tensor = TF_NewTensor(TF_INT32, dims, ndims, data, ndata, NULL, NULL);
    if(int_tensor == NULL)
    {
        printf("ERROR");
    }
    else
    {
        printf("OK");
    }

    TF_Tensor** InputValues = (TF_Tensor**)malloc(sizeof(TF_Tensor*)*1);


    return 0;
}

这是一个可能的错误还是我用错了?我不明白mallocq 自变量如何导致分段错误。

任何人都可以复制吗?

我正在使用 gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008 进行编译。

更新:

可以进一步简化错误如下。这甚至没有InputValues被分配。


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

int main()
{
    int ndims = 1;
    int ndata = 1;

    int64_t dims[] = { 1 };
    int32_t data[] = { 10 };

    TF_Tensor* int_tensor = TF_NewTensor(TF_INT32, dims, ndims, data, ndata, NULL, NULL);
    if(int_tensor == NULL)
    {
        printf("ERROR Tensor");
    }
    else
    {
        printf("OK");
    }

    return 0;
}

编译

gcc -I<tensorflow_path>/include/ -L<tensorflow_path>/lib test.c -ltensorflow -o test2.out

解决方案

正如 Raz 指出的那样,传递空deallocater而不是 NULL,并且ndata应该是字节大小。

#include "tensorflow/c/c_api.h"
void NoOpDeallocator(void* data, size_t a, void* b) {}

int main(){
    int ndims = 2;
    int64_t dims[] = {1,1};
    int64_t data[] = {20};
    int ndata = sizeof(int64_t); // This is tricky, it number of bytes not number of element

    TF_Tensor* int_tensor = TF_NewTensor(TF_INT64, dims, ndims, data, ndata, &NoOpDeallocator, 0);
    if (int_tensor != NULL)\
        printf("TF_NewTensor is OK\n");
    else
        printf("ERROR: Failed TF_NewTensor\n");
}

在这里查看我的 Github 上运行/编译 TensorFlow 的 C API 的完整代码

4

1 回答 1

3

你设置ndatasizeof(int32_t)4。你ndata作为len参数传递给TF_NewTensor()它代表元素的数量data(可以在GitHub中看到)。因此,在您的示例中应将其设置为 1,因为您只有一个元素。

顺便说一句,您可以避免malloc()在此处使用(因为您不检查返回值,这可能会出错并且通常不太优雅)而只使用局部变量。

更新

此外,您NULL同时传递 fordeallocatordeallocator_arg。我很确定这是问题所在,因为评论指出“客户必须提供自定义解除分配器功能......”(可以在这里看到)。由(可以在这里deallocator看到)调用,这可能是分段错误的原因。TF_NewTensor()

所以,总结一下,试试下面的代码:

void my_deallocator(void * data, size_t len, void * arg)
{
    printf("Deallocator called with data %p\n", data);
}

void main()
{
    int64_t dims[] = { 1 };
    int32_t data[] = { 10 };

    ... = TF_NewTensor(TF_INT32, dims, /*num_dims=*/ 1, data, /*len=*/ 1, my_deallocator, NULL);
}
于 2020-01-23T11:37:38.153 回答