Запуск простой сохраненной модели тензорного потока в c (ошибка сегментации)

Я могу запустить простую «сохраненную_модель тензорного потока Python» с input_tensor(-1,1) в c. Но когда я меняю свою модель на модель с input_tensor(-1,2), я получаю ошибку сегментации.

использованные версии

  • gcc (x86_64-posix-seh-rev0, создан в рамках проекта MinGW-W64) 8.1.0
  • tensorflow 2.15.0 (как python, так и c-lib)

Вот как я создал простую модель 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

Некоторые из этих заголовков библиотек не написаны на C, а код содержит C++.

Weather Vane 21.06.2024 14:17

извини! я исправлю свой вопрос

Martin 21.06.2024 14:22

Вы все еще используете g++?

Weather Vane 21.06.2024 14:36

@WeatherVane спасибо за ваш второй комментарий. Я вообще-то использую gcc. Я боролся с этой проблемой в течение многих дней. Для тестов я переключался между gcc и g++ (и обратно). Но недостаточно проверил мой вопрос.

Martin 24.06.2024 09:09

Вы проверили значения входных данных из кода Python. Например, для значения, которое работает, вы получаете тот же результат? Каков результат, когда вы пропускаете сломанные значения?

matt 24.06.2024 09:39

Итак, вы создаете две разные модели, одна с входной формой -1, 1 работает. Тот, у которого входная форма -1, 2, сломан? Я думал, вы имели в виду, что он ломается, когда вы меняете входные значения.

matt 24.06.2024 09:53
int64_t in_dims[] = {2,1}; разве это не должно быть {1, 2} в качестве размера пакета, а затем размер входного измерения?
matt 24.06.2024 10:03

@matt, спасибо за уделенное время. Действительно: «Итак, вы создаете две разные модели: одна с входной формой -1, 1 работает. Модель с входной формой -1, 2 сломана?». Прежде чем опубликовать, я попробовал ваше предложение «{1, 2}». Но это не помогает.

Martin 08.07.2024 09:45

Я нашел tensorflow-lite, который соответствует моим потребностям. Я успешно использую облегченную версию. ссылка.

Martin 08.07.2024 09:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете отладить ошибку сегментации, скомпилировав с отладочными символами (например, gcc -g), а затем запустив двоичный файл в gdb.

Например.:

$ gcc -g model.c
$ gdb ./a.out
(gdb) run
[SEGFAULT occurs]
(gdb) backtrace
[calltrace shown]

Дезинфицирующие средства Valgrind и clang/gcc также являются отличным инструментом для устранения таких проблем.

Спасибо за ваш ответ. Поскольку у меня не получилось с библиотекой Sensorflow, я переключился на библиотеку tensorflow-lite, чтобы запустить свою модель. Очистив свой код, я потерял приведенный выше код....

Martin 08.07.2024 09:56
Ответ принят как подходящий

Я исправил код, чтобы он работал в 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 мне не помогли. Теперь код работает.

Martin 18.07.2024 09:13

Другие вопросы по теме