Pull to refresh

tiny-dnn — анонс библиотеки

Reading time 3 min
Views 16K
image

Пока TensorFlow активно завоевывает мир, воюет за аудиторию с такими крупными игроками рынка машинного обучения и глубоких нейронных сетей как Keras, Theano и Caffe, другие менее грандиозные проекты тем временем партизанят, пытаясь занять хоть какую-нибудь нишу. Про один из таких проектов я как раз и хотел сегодня рассказать ввиду полного отсутствия информации о нем на Хабрахабре. Итак, tiny-dnn — это полностью автономная C++11 реализация глубинного обучения, созданная для применения в условиях ограниченных вычислительных ресурсов, встроенных систем или IoT. Подробности под катом.

Что же предлагают нам разработчики


  1. Скорость даже без GPU. Достигается засчет TBB и векторизации SSE/AVX. 98.8 процентов точности на MNIST за 13 минут обучения
  2. Портируемость. Об этом далее
  3. Возможность импортировать модели Caffe. Но понадобится protobuf
  4. Предсказуемая производительность. Простая многопоточная модель + отсутствие 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
Ссылка на полезную презентацию
Tags:
Hubs:
+30
Comments 23
Comments Comments 23

Articles