Нейросети для чайников. Начало
Так получилось, что в университете тема нейросетей успешно прошла мимо моей специальности, несмотря на огромный интерес с моей стороны. Попытки самообразования несколько раз разбивались невежественным челом о несокрушимые стены цитадели науки в облике непонятных «с наскока» терминов и путанных объяснений сухим языком вузовских учебников.
В данной статье (цикле статей?) я попытаюсь осветить тему нейросетей с точки зрения человека непосвященного, простым языком, на простых примерах, раскладывая все по полочкам, а не «массив нейронов образует перцептрон, работающий по известной, зарекомендовавшей себя схеме».
Заинтересовавшихся прошу под кат.
Для чего же нужны нейросети? Нейросеть – это обучаемая система. Она действует не только в соответствии с заданным алгоритмом и формулами, но и на основании прошлого опыта. Этакий ребенок, который с каждым разом складывает пазл, делая все меньше ошибок.
И, как принято писать у модных авторов – нейросеть состоит из нейронов. Тут нужно сделать остановку и разобраться.
Договоримся, что нейрон – это просто некая воображаемая чёрная коробка, у которой кучка входных отверстий и одно выходное. Причем как входящая, так и исходящая информация может быть аналоговой (чаще всего так и будет).
Как выходной сигнал формируется из кучи входных – определяет внутренний алгоритм нейрона.
Для примера напишем небольшую программу, которая будет распознавать простые изображения, скажем, буквы русского языка на растровых изображениях. Условимся, что в исходном состоянии наша система будет иметь «пустую» память, т.е. этакий новорожденный мозг, готовый к бою. Для того чтобы заставить его корректно работать, нам нужно будет потратить время на обучение.
Уворачиваясь от летящих в меня помидоров, скажу, что писать будем на Delphi (на момент написания статьи была под рукой). Если возникнет необходимость – помогу перевести пример на другие языки.
Также прошу легкомысленно отнестись к качеству кода – программа писалась за час, просто чтобы разобраться с темой, для серьезных задач такой код вряд ли применим.
Итак, исходя из поставленной задачи — сколько вариантов выхода может быть? Правильно, столько, сколько букв мы будем уметь определять. В алфавите их пока только 33, на том и остановимся.
Далее, определимся со входными данными.Чтобы слишком не заморачиватсья – будем подавать на вход битовый массив 30х30 в виде растрового изображения:
В итоге – нужно создать 33 нейрона, у каждого из которых будет 30х30=900 входов. Создадим класс для нашего нейрона:
Создадим массив нейронов, по количеству букв:
Теперь вопрос – где мы будем хранить «память» нейросети, когда программа не работает? Чтобы не углубляться в INI или, не дай бог, базы данных, я решил хранить их в тех же растровых изображениях 30х30. Вот например, память нейрона «К» после прогона программы по разным шрифтам:
Как видно, самые насыщенные области соответствуют наиболее часто встречаемым пикселям. Будем загружать «память» в каждый нейрон при его создании:
В начале работы необученной программы, память каждого нейрона будет белым пятном 30х30.
Распознавать нейрон будет так:
— Берем 1й пиксель — Сравниваем его с 1м пикселем в памяти (там лежит значение 0..255) — Сравниваем разницу с неким порогом — Если разница меньше порога – считаем, что в данной точке буква похожа на лежащую в памяти, добавляем +1 к весу нейрона.
И так по всем пикселям.
Вес нейрона – это некоторое число (в теории до 900), которое определяется степенью сходства обработанной информации с хранимой в памяти. В конце распознавания у нас будет набор нейронов, каждый из которых считает, что он прав на сколько-то процентов. Эти проценты – и есть вес нейрона. Чем больше вес, тем вероятнее, что именно этот нейрон прав.
Теперь будем скармливать программе произвольное изображение и пробегать каждым нейроном по нему:
Как только закончится цикл для последнего нейрона – будем выбирать из всех тот, у которого вес больше:
Именно по вот этому значению max_n, программа и скажет нам, что, по её мнению, мы ей подсунули. По началу это будет не всегда верно, поэтому нужно сделать алгоритм обучения.
Само обновление памяти будем делать так:
Т.е. если данная точка в памяти нейрона отсутствует, но учитель говорит, что она есть в этой букве – мы её запоминаем, но не полностью, а только наполовину. С дальнейшим обучением, степень влияния данного урока будет увеличиваться.
Вот несколько итераций для буквы Г:
На этом наша программа готова.
ОбучениеНачнем обучение. Открываем изображения букв и терпеливо указываем программе на её ошибки:
Через некоторое время программа начнет стабильно определять даже не знакомые ей ранее буквы:
ЗаключениеПрограмма представляет собой один сплошной недостаток – наша нейросеть очень глупа, она не защищена от ошибок пользователя при обучении и алгоритмы распознавания просты как палка. Зато она дает базовые знания о функционировании нейросетей.
Если данная статья заинтересует уважаемых хабравчан, то я продолжу цикл, постепенно усложняя систему, вводя дополнительные связи и веса, рассмотрю какую-нибудь из популярных архитектур нейросетей и т.д.
Поиздеваться над нашим свежерожденный интеллектом вы можете, скачав программу вместе с исходниками тут.
За сим откланяюсь, спасибо за чтение.
UPD: У нас получилась заготовка для нейросети. Пока что это ещё ей не является, но в следующей статье мы постараемся сделать из неё полноценную нейросеть. Спасибо Shultc за замечание.