1 апреля 2011 в 08:29

Многослойный перцептрон (с примером на PHP) из песочницы

Читая Хабр на предмет материалов по нейросетям и вообще по теме искусственного интеллекта я нашел пост о однослойном перцептроне и решил из любопытства начать изучение нейросетей с него, а потом и расширить опыт до многослойного перцептрона. О чем и повествую.

Теория


Многослойный перцептрон неплохо описан в Вики, но там описана лишь структура, мы же попробуем его на деле, вместе с алгоритмом обучения. Кстати, он тоже описан в Вики, хотя, сравнивая его с несколькими другими источниками (книги и aiportal.ru), я нашел несколько проблемных мест и там и там.
Итак, многослойный перцептрон — нейронная сеть, состоящая из слоев, каждый из которых состоит из элементов — нейронов (точнее их моделей). Эти элементы бывают трех типов: сенсорные (входные, S), ассоциативные (обучаемые «скрытые» слои, A) и реагирующие (выходные, R). Многослойным этот тип перцептронов называется не потому, что состоит из нескольких слоев, ведь входной и выходной слои можно вообще не оформлять в коде, а потому, что содержит несколько (обычно, не более двух — трех) обучаемых (A) слоев.
Модель нейрона (будем называть его просто нейрон) — это элемент сети, который имеет несколько входов, каждый из которых имеет вес. Нейрон, получая сигнал, помножает сигналы на веса и суммирует получившиеся величины, после чего передает результат к другому нейрону или на выход сети. Здесь тоже многослойный перцептрон имеет отличия. Его функция — сигмоид, она выдает значения на промежутке от 0 до 1. К сигмоидам относится несколько функций, мы будем иметь ввиду логистическую функцию. В ходе рассмотрения метода Вы поймете, почему это так хорошо.
Несколько слоев, которые могут обучаться (точнее, подстраиваться) позволяют аппроксимировать очень сложные нелинейные функции, то есть их область применения шире, нежели однослойных.

Пробуем на практике


Сразу будем перекладывать теорию на практику, дабы запомнилось лучше и все могли попробовать.
Рекомендую прочитать вышеуказанный пост, если вы не ас в нейросетях, конечно.
Итак, возьмем простую задачу — распознать цифры без поворота и искажений. В такой задаче многослойного перцептрона будет достаточно, более того, он менее чувствителен к шумам.

Структура сети

Сеть будет иметь два скрытых слоя, размером в 5 раз меньше, чем входной. То есть, если у нас 20 входов, то на скрытых слоях будет по 4 нейрона. В случае данной задачи я позволю себе смелость подобрать количество слоев и нейронов эмпирически. Слоев возьмем 2, при увеличении количества слоев результат не улучшается.

Алгоритм обучения

Обучение нейросетей выбранного типа проводится по алгоритму обратного распространения ошибки. То есть если при ответе у нас слои передают сигнал в выходу сети, то мы будем сравнивать ответ нейросети с верным и вычислять ошибку, которая потом пойдет «вверх» по сети — от выходов к входам.

Оценивать ошибку сети мы будем как половину суммы квадратов разниц сигналов на выходах. Попроще: делим пополам сумму по i таких вот выражений: (ti — oi)^2, где ti — значение i-го сигнала в правильном ответе, а oi — значение i-го выхода нейросети. То есть мы суммируем квадраты ошибок по входам и делим все пополам. Если эта ошибка (в коде примера это $d) достаточно велика (не укладывается в нужную нам точность), правим веса нейронов.

Формулы поправок весов целиком выложены в Вики, репостить не буду. Хочу только заметить, что старался буквально повторить формулы, чтобы было понятно, как оно на практике. Здесь всплывает преимущество выбора функции активации — у нее простая производная ( σ'(x)=σ(x)*(1-σ(x)) ), и она и применяется для коррекции весов. Веса каждого слоя корректируются отдельно. То есть слой за слоем от последнего к первому. И вот здесь я допустил ошибку, сначала я корректировал веса на каждом примере в отдельности, и нейросеть училась решать только один «примерчик». Правильно же в таком алгоритме давать на входы по очереди все примеры обучающей выборки, это называется эпохой. И только с концом эпохи считать ошибку (суммарную по всем примерам выборки) и корректировать веса.

Во время обучения возможны скачки в погрешностях, но такое бывает. Подбор коэффициентов α (определяет влияние весов на обучение) и η (определяет влияние величины поправки δ) очень важен — от него зависят скорость сходимости и попадания в локальные экстремумы. Наиболее универсальным я считаю α=0.7 и η=0.001, хотя попробуйте ими поиграть: увеличение α и η ускоряет обучение, но мы можем пролететь минимум.

Далее выкладываю пример на PHP. Код далек от идеала, но свои задачи выполняет.
+11
4468
71
ctajiuh 1,1 G+

Комментарии (18)

0
HomoLuden, #
Сеть будет иметь два скрытых слоя, размером в 5 раз меньше, чем входной. То есть, если у нас 20 входов, то на скрытых слоях будет по 4 нейрона. Почему так мало? Ну вообще-то подбор количества нейронов на слоях — вещь чисто эмпирическая, точных правил никто не знает. Просто так сеть будет быстрее обучаться, при этом увеличение количества нейронов особой пользы не принесет, да и по советам авторов книг


Вы меня извините, но формулировки такого вида попахивают дилетантщиной. Можно было употребить более гибкие формулировки типа: «в моем случае нет четкой методики выбора...» или «в данном случае нет смысла искать некую красивую методику выбора структуры» и т.д. А то получается: «по совету автора книги...». Он вас, возможно и не видел и не слышал о ваших задачах.

Вот, например, есть схема рекуррентной нейросети для приближенного решения переопределенной СЛАУ. Там структура сети совершенно четко вытекает из постановки задачи. Размерность входного вектора (n) больше размерности выходного (m) — поэтому первый слой имеет «n» нейронов с «m» входами. Первый слой осуществляет регуляризацию, т.е. редукцию размерности входа к размерности выхода. Второй слой выполняет вычисление частных производных невязки по элементам входного вектора, а третий слой уже вычисляет производные по времени элементов выхода и интегрирует их. Выход замыкается на вход и так сеть работает. При этом структура ее четко завязана на размерности входа и выхода.
Нужно быть осторожнее с формулировками. В разных задачах валидны разные подходы.
+1
tzlom, #
Речь идёт о многослойном персептроне, никаких формул показывающих сколько нейронов хватит для обучения и сколько нейронов приведёт к переобучению для таких сетей нет, а гибкие формулировки просто завуалируют причину за красивыми словами не имеющими отношения к действительности. Фраза про бессмысленность поиска методики имеет смысл, но выглядит необоснованной, фраза про отсутствие чёткой методики вообще враньё, методика есть, нету инструмента получить решение сразу, а методика проверки сети и принятия решения увеличивать или уменьшать сеть есть.
Нужно быть осторожнее с формулировками. В разных задачах валидны разные подходы.
0
ctajiuh, #
Спасибо за поправку, да, с формулировкой я был не осторожен. HomoLuden, ваш пример со СЛАУ говорит о задаче решения системы, где структура сети определяется методикой решения, в моей же задаче нет такой четкой логики решения. Потому и подбор количества слоев и размерностей слоев я проводил эмпирически.
0
Artemeey, #
Верно, это своего рода черный:

Чёрный я́щик — термин, используемый для обозначения системы, внутреннее устройство и механизм работы которой очень сложны, неизвестны или неважны в рамках данной задачи. «Метод черного ящика» — метод исследования таких систем, когда вместо свойств и взаимосвязей составных частей системы, изучается реакция системы, как целого, на изменяющиеся условия. Подход чёрного ящика сформировался в точных науках (в кибернетике, системотехнике и физике) в 20-40 годах XX века и был заимствован другими науками (прежде всего, бихевиористической психологией).

А по этому и «нет такой четкой логики решения».
0
highw, #
Написать перцептрон это половина дела. и половина поставленной задачи.
Другое дело правильно его обучить для конкретной задачи — найти правильную конфигурацию.

По этому сам по себе перцептрон по себе не интересен, интересна задача и способы определения оптимальной конфигурации.

+1
highw, #
я что-то повторяюсь повторяюсь, но смысл думаю донес :) Пишите лучше какая задача — и как вы искали оптимус
0
3d6, #
>Правильно же в таком алгоритме давать на входы по очереди все примеры обучающей выборки, это называется эпохой. И только с концом эпохи считать ошибку (суммарную по всем примерам выборки) и корректировать веса.

Это неверно. Да, так делать можно, но совершенно необязательно — более того, практика показывает, что в подавляющем большинстве реальных задач сеть учится куда лучше, если корректировать веса после демонстрации каждого примера (но действительно, крайне важно брать последовательно все имеющиеся примеры — так получится одна эпоха, и абсолютно необходимо повторять эпохи многократно, обычно — тысячи или десятки тысяч раз).

>Во время обучения возможны скачки в погрешностях, но такое бывает

Если погрешность при обучении одному примеру не уменьшается строго монотонно — то в алгоритме допущена ошибка. Если средняя погрешность за эпоху постоянно прыгает вверх-вниз — то это серьезный аргумент в пользу уменьшения скорости обучения.
0
ctajiuh, #
> Если средняя погрешность за эпоху постоянно прыгает вверх-вниз — то это серьезный аргумент в пользу уменьшения скорости обучения.
Совершенно согласен. Следующий топик собираюсь посвятить RProp.
0
FrimInc, #
Интересная тема. У меня в кандидатской (кусок её тут) что-то подобное делается, хотя конечно не на персептронах.
0
Ringess, #
на пхп все выглядет как-то глупо, может начнете на норм языках писать?
0
FrimInc, #
А чем вам пхп не угодил?
0
ctajiuh, #
PHP? На нем быстро пишешь и быстро пробуешь. Я пробовал писать то же на C#, C++ (думал, будет дикое ускорение и я буду счастливее с каждой эпохой), ничего серьезно не поменялось, суть та же. Была даже идея написать дополнение для PHP на Си, но это тоже не оправдано.
0
3d6, #
Ну, не знаю как на пхп, на плюсах сеть такой конфигурации при паре сотен примеров будет обучаться со скоростью порядка нескольких тысяч эпох в секунду. Даже если почему-либо на пхп в 10 раз медленнее (хотя с чего бы?), все равно это будет абсолютно несущественно на практике.
Плюсы будут очень полезны, когда сети будут на сотни и тысячи нейронов, а размеры обучающих выборок будут измеряться в сотнях мегабайт.
0
ctajiuh, #
В том-то и дело, что в моем случае, в моей «не примерной» задаче пока таких масштабов нет. Не спорю, при расширении понадобится оптимизация. Есть даже идея написать php-extension.
0
klakhman, #
Я конечно не хочу кидать ни в кого камни, но хочется задать вопрос.
Зачем этот пост?
Было бы отличие если бы Вы его записали в свой личный дневничок (бумажный или электронный) и радовались своей находке?

Кроме того, что в гораздо более приемлемом виде это можно прочитать в тысячах статей в интернете (и в сотнях книг), ваше описание еще содержит и множество ошибок и неточностей.
0
ctajiuh, #
Я прочитал на Хабре пост о перцептроне и меня расстроило отсутствие продолжения. Ну, или расширения, что-ли. Собственно, как дополнение его и стоит рассматривать.
0
radiys92, #
Сколько рылся в интернете, выкачивал книги, выискивал топики… Везде все есть, но теория, теория, теория… Впервые увидел реализацию какой-то относительно серьезной системы на относительно понятном языке (сам предпочитаю с++ либо дельфина).
Автору поста Большое Спасибо!
0
ctajiuh, #
Наконец-то кто-то попал в цель, именно поэтому я это все и написал.

Только зарегистрированные пользователи могут оставлять комментарии.
Войдите, пожалуйста.