ctensorflow2.0mingw-w64

running simple tensorflow saved model in c (Segmentation fault)


I am able to run a simple "python tensorflow saved_model" with a input_tensor(-1,1) in c. But when I change my model to an model with input_tensor(-1,2), I get a Segmentation fault.

used versions

This is how I created a simple python model:

import tensorflow as tf
import numpy as np

print(tf.__version__)

np.random.seed(0)
X = np.random.rand(100, 2)
y = 2 * X + 1 + 0.1 * np.random.randn(100, 1)

# Define the model architecture
model = tf.keras.Sequential([
    tf.keras.layers.Dense(1, input_shape=(2,))
])

# Compile and train the model
model.compile(optimizer='sgd', loss='mean_squared_error')
model.fit(X, y, epochs=100)

tf.saved_model.save(model, 'simple_example')

I checked the model with the command line tool:

saved_model_cli show --dir simple_example --tag_set serve --signature_def serving_default

The given SavedModel SignatureDef contains the following input(s):
  inputs['dense_input'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 2)
      name: serving_default_dense_input:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['dense'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict

The c-code to run the model is:

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

int main(int argc, char *argv[])
{
  TF_Status* status = TF_NewStatus();
  TF_Graph*  graph  = TF_NewGraph();
  TF_Buffer* r_opts = TF_NewBufferFromString("",0);
  TF_Buffer* meta_g = TF_NewBuffer();
  
  const char* dir_name = "..\\data\\simple_example";
  const char* InputOperationName = "serving_default_dense_input";
  int64_t in_dims[] = {2,1};
  int64_t out_dims[] = {1,1};
  
  //load the model
  TF_SessionOptions* opts = TF_NewSessionOptions();
  const char* tags[] = {"serve"};
  TF_Session* session = TF_LoadSessionFromSavedModel(opts, r_opts, dir_name, tags, 1, graph, meta_g, status);
  if (session == NULL || TF_GetCode(status) != TF_OK )
    return -1;
  
  TF_Output input_op = {TF_GraphOperationByName(graph, InputOperationName ), 0};
  if (input_op.oper == NULL)
    return -1;

  // Define the input tensor
  TF_Tensor* input_tensor = TF_AllocateTensor(TF_FLOAT, in_dims, 2, in_dims[0] * in_dims[1] * sizeof(float));
  float* input_values = (float*)TF_TensorData(input_tensor);
  for (int n=0;n<(in_dims[0] * in_dims[1]);n++)
    input_values[n] = n;

  // Define the output tensor
  TF_Output output_op = {TF_GraphOperationByName(graph, "StatefulPartitionedCall"), 0};
  if (output_op.oper == NULL)
    return -1;
  TF_Tensor* output_tensor = TF_AllocateTensor(TF_FLOAT, out_dims, 2, out_dims[0] * out_dims[1] * sizeof(float));
  
  // Run the session
  TF_SessionRun(session, NULL, &input_op, &input_tensor, in_dims[0]*in_dims[1], &output_op, &output_tensor, out_dims[0]*out_dims[1], NULL, 0, NULL, status);
  if (TF_GetCode(status) != TF_OK)
  {
      printf("failed: %s\n", TF_Message(status));
      return -1;
  }
  
  float* output_values = (float*)TF_TensorData(output_tensor);
  printf("Output value: %d\n", output_values[0]);
  
  return 0;
}

my gdb output:

2024-06-21 14:10:16.608082: I tensorflow/cc/saved_model/loader.cc:217] Running initialization op on SavedModel bundle at path: ..\data\simple_example
2024-06-21 14:10:17.113501: I tensorflow/cc/saved_model/loader.cc:316] SavedModel load for tags { serve }; Status: success: OK. Took 3129450 microseconds.

Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ff980b2c346 in tensorflow!?CopyFromInternal@Tensor@tensorflow@@AEAAXAEBV12@AEBVTensorShape@2@@Z ()
   from tensorflow\tensorflow.dll

Solution

  • I fixed the code so it works on linux but it had the same error as you get on windows.

    You had two errors. The first error, the number of inputs.

    TF_SessionRun(session, NULL, &input, &input_tensor, 1, &output, &output_tensor, 1, NULL, 0, NULL, status);
    

    You have 2 and that was causing the segmentation fault.

    The second error I mentioned in the comments, your input dimensions were backwards.

    failed: Matrix size-incompatible: In[0]: [2,1], In[1]: [2,1] [[{{function_node __inference__wrapped_model_2222}}{{node sequential/dense/BiasAdd}}]]

    That is fixed by creating the input dimensions correctly. int64_t in_dims[] = {1,2};

    I compiled the example using:

     gcc -Iinclude -Llib sample.c -ltensorflow
    

    Where include and lib are the folders from the tensorflow library.

    #include <stdio.h>
    #include <tensorflow/c/c_api.h>
    
    int main(int argc, char *argv[])
    {
      TF_Status* status = TF_NewStatus();
      TF_Graph*  graph  = TF_NewGraph();
      TF_Buffer* r_opts = TF_NewBufferFromString("",0);
      TF_Buffer* meta_g = TF_NewBuffer();
      
      const char* dir_name = "simple_example";
      const char* InputOperationName = "serving_default_dense_input";
      int64_t in_dims[] = {1,2};
      int64_t out_dims[] = {1,1};
      
      //load the model
      TF_SessionOptions* opts = TF_NewSessionOptions();
      const char* tags[] = {"serve"};
      TF_Session* session = TF_LoadSessionFromSavedModel(opts, r_opts, dir_name, tags, 1, graph, meta_g, status);
      if (session == NULL || TF_GetCode(status) != TF_OK ){
        printf("couldn't start a session\n");
        return -1;
      }  
      TF_Operation* input_op = TF_GraphOperationByName(graph, InputOperationName );
      TF_Output input = {input_op, 0};
    
      if (input.oper == NULL){
        printf("couldn't load input\n");
        return -1;
      }
    
      // Define the output tensor
      TF_Operation* output_op = TF_GraphOperationByName(graph, "StatefulPartitionedCall");
      TF_Output output = {output_op, 0};
      
      if (output.oper == NULL){
        printf("couldn't load op\n");
        return -1;
      }
        // Define the input tensor
      TF_Tensor* input_tensor = TF_AllocateTensor(TF_FLOAT, in_dims, 2, in_dims[0] * in_dims[1] * TF_DataTypeSize(TF_FLOAT));
      
      float* input_values = (float*)TF_TensorData(input_tensor);
      for (int n=0;n<(in_dims[0] * in_dims[1]);n++)
        input_values[n] = n;
    
      TF_Tensor* output_tensor = TF_AllocateTensor(TF_FLOAT, out_dims, 2, out_dims[0] * out_dims[1] * TF_DataTypeSize(TF_FLOAT));
      
      // Run the session
      TF_SessionRun(session, NULL, &input, &input_tensor, 1, &output, &output_tensor, 1, NULL, 0, NULL, status);
      if (TF_GetCode(status) != TF_OK)
      {
          printf("failed: %s\n", TF_Message(status));
          return -1;
      }
      printf("ran the code!\n");
      float* output_values = (float*)TF_TensorData(output_tensor);
      printf("Output value: %f\n", output_values[0]);
      
      return 0;
    }