Я могу запустить простую «сохраненную_модель тензорного потока Python» с input_tensor(-1,1) в c. Но когда я меняю свою модель на модель с input_tensor(-1,2), я получаю ошибку сегментации.
использованные версии
Вот как я создал простую модель Python:
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')
Я проверил модель с помощью инструмента командной строки:
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
C-код для запуска модели:
#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;
}
мой вывод GDB:
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
извини! я исправлю свой вопрос
Вы все еще используете g++?
@WeatherVane спасибо за ваш второй комментарий. Я вообще-то использую gcc. Я боролся с этой проблемой в течение многих дней. Для тестов я переключался между gcc и g++ (и обратно). Но недостаточно проверил мой вопрос.
Вы проверили значения входных данных из кода Python. Например, для значения, которое работает, вы получаете тот же результат? Каков результат, когда вы пропускаете сломанные значения?
Итак, вы создаете две разные модели, одна с входной формой -1, 1 работает. Тот, у которого входная форма -1, 2, сломан? Я думал, вы имели в виду, что он ломается, когда вы меняете входные значения.
int64_t in_dims[] = {2,1};
разве это не должно быть {1, 2} в качестве размера пакета, а затем размер входного измерения?
@matt, спасибо за уделенное время. Действительно: «Итак, вы создаете две разные модели: одна с входной формой -1, 1 работает. Модель с входной формой -1, 2 сломана?». Прежде чем опубликовать, я попробовал ваше предложение «{1, 2}». Но это не помогает.
Я нашел tensorflow-lite, который соответствует моим потребностям. Я успешно использую облегченную версию. ссылка.
Вы можете отладить ошибку сегментации, скомпилировав с отладочными символами (например, gcc -g
), а затем запустив двоичный файл в gdb
.
Например.:
$ gcc -g model.c
$ gdb ./a.out
(gdb) run
[SEGFAULT occurs]
(gdb) backtrace
[calltrace shown]
Дезинфицирующие средства Valgrind и clang/gcc также являются отличным инструментом для устранения таких проблем.
Спасибо за ваш ответ. Поскольку у меня не получилось с библиотекой Sensorflow, я переключился на библиотеку tensorflow-lite, чтобы запустить свою модель. Очистив свой код, я потерял приведенный выше код....
Я исправил код, чтобы он работал в Linux, но возникла та же ошибка, что и в Windows.
У вас было две ошибки. Первая ошибка, количество входов.
TF_SessionRun(session, NULL, &input, &input_tensor, 1, &output, &output_tensor, 1, NULL, 0, NULL, status);
У вас их 2, и это вызвало ошибку сегментации.
Вторая ошибка, которую я упомянул в комментариях, — ваши входные размеры были обратными.
сбой: несовместимость размера матрицы: In[0]: [2,1], In[1]: [2,1] [[{{function_node __inference__wrapped_model_2222}}{{node sequential/dense/BiasAdd}}]]
Это исправляется путем правильного создания входных размеров. int64_t in_dims[] = {1,2};
Я скомпилировал пример, используя:
gcc -Iinclude -Llib sample.c -ltensorflow
Где include и lib — папки из библиотеки tensorflow.
#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;
}
Спасибо, что нашли время решить мою проблему! Вы правы, я допустил две ошибки. Из-за неправильного размера, указанного в TF_SessionRun, мои изменения и ошибки в in_dims мне не помогли. Теперь код работает.
Некоторые из этих заголовков библиотек не написаны на C, а код содержит C++.