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
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;
}