Комментарии 34
Спасибо за статью. Хотелось бы итоговую статистику - процент правильных ответов, возможно скорость работы
Не подумал, что это может оказаться интересным в рамках такой довольно игрушечной задачи, поэтому решил не вставлять.
Вообще, обучение и валидацию проводил на двух наборах по 60 картинок, поэтому временные задержки больше вызваны созданием объектов и всякими такими довольно техническими вещами, поэтому относиться к ним надо с долей скептицизма.
Время обучения на 50 эпохах 0.1 секунда
Время валидации 0.01 секунда
Ошибка у меня возникла только в случае, когда картинка валидации вида: круг с двумя зашумленными углами (или он же квадрат с двумя отсутствующими углами), все остальные картинки корректно определяются, то есть процент ошибок где-то 0-2%
За нейронку - 5, за С++ - 2.
1. Вы передаете вектора в функцию не по ссылке.
2. void аргументах это уже не нужно даже в современном С, не говоря уже о С++.
3. for (size_t layer = 0; layer <= layer_count; layer++)
- здесь UB.
4. Часть циклов можно переписать на алгоритмы типа:std::transform(expected.begin(), expected.end(),
layers[layer_count + 1].begin(), delta[layer_count].begin(),
[](double t, double y) {return y * (1 - y) * (t - y);});
Я к тому, что С++ - в данном случае неудачный вариант для изучения нейросети. Потому что здесь нельзя так расслаблено писать. Если бы на питоне дали пример, вопросов бы не было.
P.S. Открыл исходники. Вы в целом недавно начали изучать плюсы.
using namespace std да еще и в хедере - это расстрельная статья.
Вы бросаете исключения, а где вы их перехватываете? Или у вас план вызывать std::terminate при каждом исключении? Тогда вопросов нет. И там где надо не бросаете, например при делении.
У вас магические числа при том что есть дефайны. Кстати о них. Дефайны - это С, но ни как не С++. Для констант лучше constexpr и enum class.
Разбирать на самом деле еще очень много, я описал только что бросилось в глаза.
В общем если эту лабу приняли, у меня серьезные вопросы к компетенциям препода.
Вот этих ваших std::transform(expected.begin(), expected.end() нету в других сиподобных языках - так что с ними было бы непонятнее. И этот ваш питон непонятен знающим сиподобные языки.
Вообще в идеале надо было писать на c# или java, но в нейтральном стиле (например, не используя linq) чтобы всем было понятно. Там и в обоих языках много схожести, и плюсовики поймут (так как эти языки просто обезжиренный cpp), и не надо особо заморачиваться с хедерами и ссылками на вектора, и нету наследия от си чтобы спорить о его уместности
Я дал советы человеку, чтобы он лучше знал плюсы, а не чтобы читателю было легче. Тем более всегда можно сделать пояснения в непонятных моментах. Ну и понять что transform - это аналог map или zip в любом другом языке не сложно.
...не надо особо заморачиваться с хедерами и ссылками на вектора...
В плюсах либо сразу писать нормально либо никак.
Вы тут не даете советы, а занимаетесь самоутверждением за счет студента и его преподавателя.
С таким подходом вы ничего так и не напишете.
Вектор передавать по значению - это сильно. Если в нём миллиард значений будет - ничего, и так сойдёт?
Если нет приоритета производительности, то сойдёт.
Ну и если так рассуждать, что угодно сойдёт. Зачем тогда вообще C++?
Потому что он всемогущ. Если в следующий раз понадобится производительность - автор сможет, не будучи ограниченным языком.
Почему вы считаете, что Python непонятен знающим C-подобные языки? Мне, например, вполне понятен.
Я согласен со всеми замечаниями ув. @Gay_Lussak. Раз взялся за C++, то нужно писать именно на нём, а не на пресловутом "C с классами". Благо, современный C++ предоставляет много полезных инструментов. Помимо упомянутых алгоритмов есть также ranges, позволяющие писать ещё более компактный и выразительный код.
Спасибо за замечания, обязательно приму к сведению при дальнейшей доработке кода.
Можете пояснить в чем заключается UB в строке с циклами?
transform же сознательно не использовал для более наглядного потактового контроля за каждой итерацией вычислений. В будущем данная модель будет переносится на аппаратуру и будет неудобно выполнять отладку, если слишком инкапсулировать логику подсчета в недра стандартных библиотек.
Если правая граница цикла максимальное значение.
Можете пояснить в чем заключается UB в строке с циклами?
Нет там УБ, просто товарищ скор на расправу. Ваш грех в том, что ограничивающая переменная не очень корректно названа и реальное количество слоёв на самом деле больше.
Не знаю, о какой аппаратуре речь, но для весьма многих устройств код можно писать на C++. Arduino IDE, например, поддерживает C++20.
Прям на ностальгию пробило.. 98й год, разбирался с нейросетями для дипломной работы и в качестве примера написал как раз на плюсах распознавание букв алфавита. Такие же монохромные буковки, проверка устойчивости распознавания на зашумлённой картинке и рукописных символах.. В качестве мануала были какие-то ксеры пары английских статей про многослойные персептроны :)
Извините, а где вы учитесь и на какую специальность? Где нынче такие интересные лабораторки дают?
ИТМО, Компьютерные Системы и Технологии, эта задача - часть большой задачи по реализации аппаратного ускорителя нейронных сетей.
По ЕГЭ поступали?
Вообще-то, всё это делается матричным умножением. Особенно для аппаратного ускорителя. О чём много-много раз уже писалось. Можете посмотреть реализацию для CUDA.
Последние лет 20 практически у всех прикладников курс по сеткам есть. За исключением какихто университетов села кукуево разве что.
w^i_{ij}
Подправьте в начале, там сверху k должно быть
Хорошая, статья. Портировал на TypeScript https://github.com/tormozz48/simlpe-neural-network
Простая нейронная сеть на C++