[Из песочницы] Как я Keras на C++ запускал
Как ни странно, решение оказалось вообще не тривиальным. Не так давно передо мной встала производственная задача – запустить обученную модель нейронной сети Kesas
на нативном C++
коде. О том, как же это – нейросети на чистых крестах и будет сегодняшняя небольшая статья. В результате чего появилась собственная библиотека, дающая такую возможность.
Ну а всех остальных прошу под кат… Тем, кому не терпится – вот тут репозитарий на github, с подробным описанием использования.
Постановка проблемы.
Но вот незадача: на сегодняшний день нет практически никакой возможности запустить модель Keras на C++. В процессе работы мне понадобилась запустить обученную модель на C++
приложении (Unreal Engune 4).
Еще одним вариантом было конвертация модели Keras в модель TensorFlow и потом сборка TensoFflow под кресты и вызов API TF уже из C++ кода. Вариант с вызовом Python
из C++
не представлялся мне хорошим.
Но с этим также возникают трудности. Сей процесс метаморфозов хорошо описан в этой статье. А сам безель штука капризная и отказался собираться под UE4. Во-первых, TensorFlow собирается через Bzzel
. Могу лишь сказать, что на просторах github был найден полупабочий проект, с нужным мне функционалом. Во-вторых, сам TF
довольно большая и громоздкая штуковина, а мне хотелось чего-то более легкого и производительного. А попытки переделать его, не увенчались успехом: С++ приложение валилась с ошибкой Core Dump
. Но, он не поддерживал актуальные версии Python
и Keras
. Было принято писать свою реализацию…
Пишем свою библиотеку!
Во многом в реализации этой библиотеки мне помог код TensorFlow, попытки реабилитации найденного на гит
кода, некоторые знания об алгоритмах и структурах данных (спасибо ИТМО за его курсы) и хорошая музыка в ушах. Включив рок потяжелее, закинувшись бутылкой пиваса энергетика, я сел за код. Так или иначе библиотека была написана за одну ночь.
И так встречайте: Keras2cpp!
Первая чать библиотеки – это Python модуль для сохранения обученной модели в собственный бинарный формат.
Мы просто читаем модель Keras
и записываем побитово в файл: сначала тип слоя
, потом размерность
, потом матрицу весов
в формате float
. Ничего сложного в этой операции нет.
Теперь перейдем к самому вкусному – C++ реализации.
Пользователю доступны 2 сущности tensor
и model
.
Размерность каждого измерения хранится в поле std::vector<int> dims_;
а вес каждого элемента тензора – в std::vector<int> data_;
. Tensor – переделяет собой данные с которыми работает нейросеть и является компьютерной реализацией тензора. На данный момент поддерживается максимальная размерность в 4 измерения. Остальные операции вы можете посмотреть в исходном коде. Из доступных методов можно выделить void Print()
и Tensor Select(int row)
. После того как математика для тензоров была написана я приступил к реализации моделей.
Model – представляет собой набор слоев в каждом из которых прописаны операции над тензорами и матрица весов. Для пользователя доступны 2 функции virtual bool LoadModel(const std::string& filename);
и virtual bool Apply(Tensor* in, Tensor* out);
.
Вот полный пример кода.
python_model.py:
import numpy as np
from keras import Sequential
from keras.layers import Dense #create random data
test_x = np.random.rand(10, 10).astype('f')
test_y = np.random.rand(10).astype('f')
model = Sequential([ Dense(1, input_dim=10)
])
model.compile(loss='mse', optimizer='adam') #train model by 1 iteration
model.fit(test_x, test_y, epochs=1, verbose=False) #predict
data = np.array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
prediction = model.predict(data)
print(prediction) #save model
from keras2cpp import export_model
export_model(model, 'example.model')
cpp_mpdel.cc:
#include "keras_model.h" int main() }; // Run prediction. Tensor out; model.Apply(&in, &out); out.Print(); return 0;
}
Приятного использования, а я пойду к любимому C# и Python писать нейросети дальше. На этом я думаю все.
P.S.
Когда пишешь все сам с нуля – больше понимаешь, а как оно работает… В планах добавить поддержку других архитектур и GPU… Мне понравилось писать эту библиотеку.
github репозиторий
Источник