Пока TensorFlow активно завоевывает мир, воюет за аудиторию с такими крупными игроками рынка машинного обучения и глубоких нейронных сетей как Keras, Theano и Caffe, другие менее грандиозные проекты тем временем партизанят, пытаясь занять хоть какую-нибудь нишу. Про один из таких проектов я как раз и хотел сегодня рассказать ввиду полного отсутствия информации о нем на Хабрахабре. Итак, tiny-dnn — это полностью автономная C++11 реализация глубинного обучения, созданная для применения в условиях ограниченных вычислительных ресурсов, встроенных систем или IoT. Подробности под катом.
Что же предлагают нам разработчики
- Скорость даже без GPU. Достигается засчет TBB и векторизации SSE/AVX. 98.8 процентов точности на MNIST за 13 минут обучения
- Портируемость. Об этом далее
- Возможность импортировать модели Caffe. Но понадобится protobuf
- Предсказуемая производительность. Простая многопоточная модель + отсутствие GC (стоило ли им это писать, ведь библиотека для C++ программистов)
В целом, ничего революционного, но и упрекнуть особо не за что. Предлагается все делать на C++ и довольно прямолинейно. Есть возможность сохранения и загрузки модели в файл и из файла (опять же без зависимостей). Полный список см. в ссылке на GitHub.
Установка и сборка
Библиотека распространяется исходными кодами. Иного способа для этой библиотеки физически быть не может, так как весь код содержится в h-файлах, то есть собирать в библиотеку вовсе нечего. Сомнительное решение, но в погоне за дикой переносимостью и простотой — почему бы и нет?
Для запуска примеров или тестов потребуется cmake. Доступен с десяток опций, в том числе и USE_OPENCL — на данный момент экспериментальная возможность, которая в будущем может дать весомую выгоду. Полный список предлагаю так же смотреть на странице проекта.
Опыт использования в MS Visual Studio
После вызова «cmake .» сгенерируется *.sln файл для MS Visual Studio 2015 (Community Edition вполне подходит). В этом солюшене два проекта, собственно сама библиотека и тесты. ТУда можно просто добавить свой проект, а для начала использования библиотеки прописать:
#include "tiny_dnn/tiny_dnn.h"
но при этом следует не забыть добавить в «Include directories» каталог с tiny-dnn.
Так же в моем случае возникла проблема сборки, а именно:
error C4996: 'std::copy::_Unchecked_iterators::_Deprecate': Call to 'std::copy' with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
для решения потребовалось добавить define _SCL_SECURE_NO_WARNINGS в параметрах проекта (C/C++ -> Preprocessor).
Пример использования
На странице можно найти примеры, но они про затертый до дыр MNIST, для него нужны данные, функции разбора (которые на самом деле встроеные в библиотеку) и т.д. Лично мне хотелось банального «Hello, world» в мире нейросетей — реализации xor. Гугление не дало быстрых результатов, что вылилось в желание сделать самому и поделиться в статье. Вот что получилось:
#include "tiny_dnn/tiny_dnn.h"
using namespace tiny_dnn;
using namespace tiny_dnn::activation;
network<sequential> construct_mlp()
{
//auto mynet = make_mlp<tan_h>({ 2, 8, 2 });
auto mynet = make_mlp<relu>({ 2, 8, 2 });
assert(mynet.in_data_size() == 2);
assert(mynet.out_data_size() == 2);
return mynet;
}
int main(int argc, char** argv)
{
auto net = construct_mlp();
std::vector<label_t> train_labels {0, 1, 1, 0};
std::vector<vec_t> train_numbers{ {0, 0}, {0, 1}, {1, 0}, {1, 1} };
adagrad optimizer; // use gradient_descent?
net.train<mse>(optimizer, train_numbers, train_labels, 4, 1000); // batch size 4, 1000 epochs
for (auto& tn : train_numbers)
{
auto res_label = net.predict_label(tn);
auto res = net.predict(tn);
std::cout << "In: (" << tn[0] << "," << tn[1] << ") Prediction: " << res_label << std::endl;
}
std::cin.get();
return 0;
}
Первые впечатления
Они спорные. С одной стороны все очень просто и гарантированно везде заведется, с другой стороны на банальном XOR'е сеть как-то долго сходится, например за 100 эпох на выходе получаются правильные, но крайне неуверенные результаты вроде 0.15, за 1000 эпох что-то вроде 0.8. Кажется, аналогичная модель на tensorflow сходится быстрее, но это неточно :)
Далее, сам демо-проект собирается дольше, чем хотелось бы. Похоже, это из-за подхода с хидерами. Возможно в более крупном проекте даже заметно не будет, в маленьком проекте с одним C++ файлом очень даже. Кстати, возможно на помощь придется решение от MS с т.н. precompiled headers…
То, как в библиотеке предлагается использовать синтаксис и фичи C++11, как ни странно, порадовало — я не так много программирую на «голом» C++ (чаще Qt), но тестовый пример дался с первой попытки. Кстати замечания к нему приветствуются.
Ссылка на GitHub: github.com/tiny-dnn/tiny-dnn
Ссылка на полезную презентацию: www.slideshare.net/ssuser756ec5/deep-learning-with-c-an-introduction-to-tinydnn
Автор: QtRoS