Пока 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
> Ссылка на полезную презентацию
Комментарии (22)
barkalov
13.01.2017 19:49+1Небольшое уточнение по вступрительному параграфу:
Пока TensorFlow активно завоевывает мир, воюет за аудиторию с такими крупными игроками рынка машинного обучения и глубоких нейронных сетей как Keras, Theano и Caffe
TensorFlow не «воюет» с Keras, а является одним из его backend'ов (наряду с Theano). Другими словами, Keras работает на TensofFlow.QtRoS
13.01.2017 20:57Это как посмотреть. Не уверен, что авторы TensorFlow будут рады тому, что на слуху будет Keras, а не TF, даже если первый работает поверх второго. Все же за популярность и применение в качестве стандарта де-факто по-моему борьба есть.
BelBES
14.01.2017 12:14Особенно в свете того, что Theano как бекенд Keras'а на данный момент надирает TF по скорости)
Alert123
13.01.2017 20:24А какие у этой библиотеки способы использования?
Я вот ищу что нибудь чтобы для фиксированной базы из тысяч цветных иллюстраций очень быстро определять соответвие по изображению с камеры (или узнать что совпадений нет).
Для этих целей подойдет?QtRoS
13.01.2017 20:30Краткий ответ: да, при правильном использовании.
Длинный ответ: эта библиотека лишь одна из многих. Для проверки Вашей гипотезы я бы лично порекомендовал воспользоваться более простыми фреймворками (притом не обязательно сразу используя глубинное обучение, зависит от данных), например sklearn. Если взлетит и Вы сами найдете для себя решение, то уже тогда только стоит начинать думать о том, как же внедрить решение в условиях ваших ограничений по ресурсам, железу, фреймворку, языку. Но для проведения такой проверки Вам понадобится «понять» данные, продумать их представление и т.д., вполне себе стандартная работа специалиста по ML. Вызвать одну функцию и получить профит как например с QR-кодами вряд ли получится.
ErmIg
14.01.2017 19:12+1Начал использовать tiny_dnn, когда он еще назывался tiny_ cnn. Повелся на простоту интеграции в проект. На редкость тормознутое творение. Стал разбираться в причинах — авторы так увлеклись распараллеливанием алгоритмов и асинхронным их исполнением, что дошли до маразма. Апофеозом было копирование 10 чисел, путем распараллеливания на 8 потоков! Естественно, что из-за потерь на синхронизацию производительность была ниже плинтуса. Убрал лишнее распараллеливание, добавил где надо SIMD оптимизации — вроде стало работать более менее быстро. Только по итогу от исходного проекта практически ничего не осталось. В итоге в конце концов свой велосипед написал. В последней версии они переписали очень многое — стало гораздо лучше в плане производительности, но все равно свой велосипед в разы опережает.
Randl
14.01.2017 23:19+1А почему бы не открыть PR или хотя бы issue по тормозящим моментам?
ErmIg
16.01.2017 09:05+1Тут есть ряд моментов.
Сам мой велосипедСамо мое решение находится в открытом доступе:
https://github.com/ermig1979/Simd/blob/master/src/Simd/SimdNeural.hpp
Стоит отметить, что решение менее универсально, чем оригинальный tiny_cnn и тем более tiny_dnn. Кроме того оно завязано на библиотеку Simd. А это противоречит основной концепции tiny_dnn — все в заголовочных файлах и желательно без сторонних зависимостей. Потому просто сделать pull request будет довольно затруднительно.
Хотя я наверное был бы рад помочь.
VioletGiraffe
15.01.2017 00:04+3Интересно! Спасибо за статью. С такой простотой использования, ещё и на С++, мне захотелось всё-таки разобраться, как этими сетями польоваться на практике :)
BelBES
15.01.2017 00:26Caffe еще проще, и деплоить можно в C++ код.
Правда за счет im2col, без напильника в embedded особо не влезешь.VioletGiraffe
15.01.2017 00:34+1Embedded мне не интересно, только десктоп. Библиотека, которая просто подключается и работает без возни со сборкой и т. д. — это огромный плюс.
BelBES
15.01.2017 14:56Caffe собирается из CMake'а, т.ч. там никаких проблем нету (список зависимостей устанавливается одной командной apt-get install)...
eiennohito
20.01.2017 18:36Увы, не для текста. Рекуррентных сетей вообще нет (и похоже не предвидится).
На текст специализируются похоже только https://github.com/clab/dynet да https://github.com/pfnet/chainer
Randl
Я с сентября контрибьютурствую туда потихоньку. Сейчас работаем над поддержкой GPU. Если у кого есть вопросы или предложения, можете задавать.
erwins22
Сделайте поддержку AMD GPU и к вам потянуться те кто на нем.
TensofFlow — только NVIDIA/
Randl
У Tensorflow есть экспериментальная поддержка OpenCL (по крайней мере, когда я его последний раз компилировал, он меня спрашивал нужна ли поддержка OpenCL).
У нас OpenCL в планах одновременно с CUDA.
QtRoS
О, какой удачный случай. Что-набудь скажете про пример с XOR, выглядит сносно? Имеет смысл в примеры библиотеки заливать?
Randl
На первый взгляд прилично. Думаю лучше открыть PR и там уже пример рассмотрят всесторонне.