如何从[c_api.h]

时间:2019-08-30 14:47:42

标签: python c tensorflow keras mnist

我正在尝试使用TF 2.0beta C api(c_api.h)实现fashion-mnist教程的培训部分。

简而言之,按照前面提到的教程使用python创建模型。然后将模型另存为.pb文件,然后将其与训练数据(28 * 28灰度图像)和训练标签(标量范围为[0-9])一起加载到我的C程序中。

您可能知道,TF C api的文档质量很差(充满挫败感的插入物here),并且在互联网上herehere经过大量阅读和搜索之后, herehere等许多其他地方,我仍然无法完成此任务(详情请参见下文)。

所以我们开始吧:

我不想在代码中淹没这个问题,但我希望您能够访问我已经完成的工作。

生成模型的python script通过以下方式将其保存: keras.experimental.export_saved_model。

要简单地执行代码: python3 createModel.py

已保存的模型将存储在一个名为“ saved_model”的新文件夹中。 这很重要,因为此名称在C代码中进行了硬编码

Data也可以通过python TF获得训练模型的方法。

再次:python getData.py

将数据和相应的标签另存为data.txt和labels.txt ,这些名称很重要,因为它们是在我的C代码中硬编码的

现在我们可以进入C代码了!

所有代码都驻留在single文件中,并提供了我认为必要的注释。只要您具有libtensorflow.so.2和libtensorflow_framework.so.2.0.0

,编译就应该很简单

gcc -Wall -I /path/to/TFlib/include -L /path/to/TFlib/lib -o trainMnist trainMnist.c

在x86_64系统中,不应有警告(至少在我尝试过的两台计算机中)

编译后执行:

LD_LIBRARY_PATH=/path/to/TFlib/lib ./trainMnist

如果.so文件已经可以访问,则可以跳过LD_LIBRARY_PATH。

如果您没有TF共享对象文件,那么如果您敢于信任某个随机人士的编译代码,我很乐意与任何人共享它们。您可以使用以下方法自己生成它:

git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow
git checkout r2.0
./configure
bazel build -c opt //tensorflow/tools/lib_package:libtensorflow 

头文件和.so文件将位于bazel-bin / tensorflow / tensorflow / tools / lib_package / libtensorflow.tar.gz

假设saved_modeldata.txtlabels.txt与./trainMnist运行所在的目录相同,则仅应打印TF警告,并从代码本身输出一些详细信息。

但感兴趣的功能是:

int Belly_ModelTrain(model_t *model,
                     float **train_data,
                     float **label_data,
                     int numPoints)

model是容纳重要成员以开始TF会话的结构

train_data包含28 * 28 = 784个浮点数的numPoints数组(图像的像素值)

label_data包含10个浮点数的numPoints数组(除该图像的真实标签外,其余均为0)。

numPoints是已加载的图像数。 numPoints的值在main中进行了硬编码。

在此功能中,训练通过以下方式进行:

  // The actual tensors that will hold the data and be passed to TF_SessionRun
  TF_Tensor *x, *y;

  // Establish the dimentions of the input data
  const int64_t dimTrain[] = {numPoints, 784}; //pixel values
  const int64_t dimLabel[] = {numPoints, 10};  //labels

  {
  //Boilerplate allocation code happens here 
  size_t nbytesT = (numPoints*784) * sizeof(float);
  x = TF_AllocateTensor(TF_FLOAT, dimTrain, 2, nbytesT);

  size_t nbytesL = (numPoints*10) * sizeof(float);
  y = TF_AllocateTensor(TF_FLOAT, dimLabel, 2, nbytesL);
  }

  //Copy the data in my arrays to the tensors
  memcpy(TF_TensorData(x), train_data, nbytesT);
  memcpy(TF_TensorData(y), label_data, nbytesL);

  //TBH I really don't know what is going on in these two lines
  //Establish model inputs and model targets(labels)
  TF_Output inputs[2] = {model->input, model->target};
  TF_Tensor* input_values[2] = {x, y};
  //training operation defined in model
  const TF_Operation* train_op[1] = {model->train_op};

  //Run the model with the data
  TF_SessionRun(model->session,
                NULL,
                inputs, input_values, 2,
                NULL, NULL, 0,
                train_op, 1,
                NULL, model->status);

  TF_DeleteTensor(x);
  TF_DeleteTensor(y);
  //Return 0 on success
  return Belly_CheckStatus(model->status);

我希望该函数运行良好,并根据模型的状态返回TF_OK,返回0。当然这失败了,我得到了:

错误:节点'dense_2_target'(类型:'占位符',输出数量:1)没有输出[有些疯狂的击中数字]

从错误消息中我了解到我的target输入的格式错误。我尝试更改label_data的传递方式以及更改dimL都没有成功。

1 个答案:

答案 0 :(得分:0)

因此,事实证明我在使用C api时仍在用python进行思考。

trainMnist.c中,数据被读入一个数组数组(浮点数):

int Belly_ReadData(float **points, int numSamples) {
  ...
  ...
  ...
  for(int i = 0; i < numSamples; i++) {
    //Allocate memory for datapoint
    points[i] = (float *)malloc(784*sizeof(float));
  ...
  ...
  ...
    //Read other 783 pixels
    for(int j = 0; j < 783; j++) {
      point = strtok(NULL,"\t");
      points[i][j+1] = strtof(point,&err);
      if(*err != 0) return -1;
    }
  ...
  }
}

此后,将这个数组数组馈入输入张量“ x”:

int Belly_ModelTrain(model_t *model,
                     float **train_data,
                     float **label_data,
                     int numPoints) {
  ...
  ...
  ...

  // Allocate data for tensors
  x = TF_AllocateTensor(TF_FLOAT, dimTrain, 2, nbytesT);
  if(x==NULL) {
    printf("ERROR allocate x\n");
    return -1;
  }

  y = TF_AllocateTensor(TF_FLOAT, dimLabel, 2, nbytesL);
  if(y==NULL) {
    printf("ERROR allocate y\n");
    return -1;
  }

  // Copy data from arrays into tensors
  memcpy(TF_TensorData(x), train_data, nbytesT); //<===== "train_data should be an array of floats"
  memcpy(TF_TensorData(y), label_data, nbytesL); //<===== "label_data should be an array of floats"
  ...
  ...
  ...

按照我理解的方式,我将垃圾数据同时传递到张量x和y。

将为想要尝试的任何人发布更正的代码。