Глава 3. Персептроны

В предыдущей главе вы усвоили необходимые общие теоретические сведения по ИНС: устройство искусственного нейрона и нейронных сетей, общие подходы к их обучению.

Тема данной главы – простейший вид искусственных нейронных сетей – персептроны. Вы узнаете об их устройстве, научитесь их создавать и обучать.

Оглавление

История персептрона

Понятия искусственного нейрона и искусственной нейронной сети появились достаточно давно, еще в 1943 году. Эта была чуть ли не первая статья, в которой предпринимались попытки смоделировать работу мозга. Ее автором был Уоррен Мак-Каллок.

mcculloch

Эти идеи продолжил нейрофизиолог Фрэнк Розенблатт. Он предложил схему устройства, моделирующего процесс человеческого восприятия, и назвал его «персептроном» (от латинского perceptio – восприятие). В 1960 году Розенблатт представил первый нейрокомпьютер – «Марк-1», который был способен распознавать некоторые буквы английского алфавита.

mark1

Таким образом персептрон является одной из первых моделей нейросетей, а «Марк-1» – первым в мире нейрокомпьютером.

Персептроны стали очень активно исследовать. На них возлагали большие надежды. Однако, как оказалось, они имели серьезные ограничения. Был такой ученый Минский, который был сокурсником Розенблатта. Видимо, ему не очень понравилось, как все вокруг боготворили персептроны, и он написал целую книгу (1971 год), в которой провел детальнейший их анализ, попутно показав, что они не так уж много и умеют, да и вообще сильно ограничены.

minsky

Розенблатт не успел написать ответ Минскому, так как погиб в свой 43 день рождения при крушении лодки.

С тех пор энтузиазм ученых в исследовании персептронов и искусственных сетей поутих. Хотя Минский позднее говорил, что сожалеет, что его книга нанесла такой удар по концепции персептронов. Стали перспективными другие области. Про нейросети забыли. Но потом были открыты новые виды сетей, а также алгоритмы их обучения, что вновь возродило интерес к этой области.

Теперь подробно разберем, что из себя представляет персептрон.

Персептрон

В основе персептрона лежит математическая модель восприятия информации мозгом. Разные исследователи по-разному его определяют. В самом общем своем виде (как его описывал Розенблатт) он представляет систему из элементов трех разных типов: сенсоров, ассоциативных элементов и реагирующих элементов.

Рассмотрим принцип работы персептрона.

Первыми в работу включаются S-элементы. Они могут находиться либо в состоянии покоя (сигнал равен 0), либо в состоянии возбуждения (сигнал равен 1).

Далее сигналы от S-элементов передаются A-элементам по так называемым S-A связям. Эти связи могут иметь веса, равные только -1, 0 или 1.

Затем сигналы от сенсорных элементов, прошедших по S-A связям попадают в A-элементы, которые еще называют ассоциативными элементами. Стоит заметить, что одному A-элементу может соответствовать несколько S-элементов. Если сигналы, поступившие на A-элемент, в совокупности превышают некоторый его порог \theta , то этот A-элемент возбуждается и выдает сигнал, равный 1. В противном случае (сигнал от S-элементов не превысил порога A-элемента), генерируется нулевой сигнал.

Почему A-элементы назвали ассоциативными? Дело в том, что A-элементы являются агрегаторами сигналов от сенсорных элементов. Например, у нас есть группа сенсоров, каждый из которых распознает кусок буквы «Д» на исследуемой картинке. Однако только их совокупность (то есть когда несколько сенсоров выдали сигнал, равный 1) может возбудить A-элемент целиком. На другие буквы А-элемент не реагирует, только на букву «Д». То есть он ассоциируется с буквой «Д». Отсюда и такое название.

Можно привести  и другой пример. На самом деле ваши глаза состоят из невероятного количества S-элементов (сенсоров), улавливающих падающий свет (около 140 000 000). И у вас какой-то A-элемент, который распознает конкретную часть лица. И вот вы увидели на улице человека. Некоторые A-элементы, которые распознали конкретные части лица, возбуждаются.

Далее сигналы, которые произвели возбужденные A-элементы, направляются к сумматору (R-элемент), действие которого вам уже известно. Однако, чтобы добраться до R-элемента, они проходят по A-R связям, у которых тоже есть веса. Однако здесь они уже могут принимать любые значения (в отличие от S-A связей).

Финальный аккорд. R-элемент складывает друг с другом взвешенные сигналы от A-элементов и, если превышен определенный порог, генерирует выходной сигнал, равный 1. Это означает, что в общем потоке информации от глаз мы распознали лицо человека.

Если порог не превышен, то выход персептрона равен -1. То есть мы не выделили лицо из общего потока информации.

Так как R-элемент определяет выход персептрона в целом, его назвали реагирующим.

Теперь вы знаете, что такое персептрон и как он работает. Сформулируем теперь его точное определение:

Персептрон (Perceptron) – простейший вид нейронных сетей. В основе лежит математическая модель восприятия информации мозгом, состоящая из сенсоров, ассоциативных и реагирующих элементов.

Выше я рассказал о персептроне в самом общем виде. Есть несколько подвидов персептронов, на некоторых из которых мы и сконцентрируем все внимание.

Классификация персептронов

Исторически сложилось несколько типов персептронов. Их часто путают, так как разные авторы, писавшие статьи на эту тему, зачастую понимали под персептроном похожие, но все же разные математические модели. Именно поэтому человеку, который только начинает изучение ИНС бывает трудно разобраться, что такое персептрон, ведь в разных книгах на эту тему его определяют по-разному. Я постараюсь разъяснить все так, что вы не будете путаться в терминологии, читая другие книги.

Персептрон с одним скрытым слоем

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

Почему слой именно скрытый? Потому что слой А-элементов расположен между слоями S-элементов и R-элементов.

Персептрон с одним скрытым слоем – персептрон, у которого имеется только по одному слою S, A и R элементов.

Обе картинки выше изображают именно персептрон с одним скрытым слоем.

Однослойный персептрон

Названия похожие. Но это не тоже самое, что и персептрон с одним скрытым слоем, хотя так может показаться. Именно этот тип персептронов мы и будем изучать подробнее всего. Этот тип персептронов, как и элементарные персептроны, тоже часто подразумевают, когда говорят о персептронах вообще.

Его ключевая особенность состоит в том, что каждый S-элемент однозначно соответствует одному A-элементу, все S-A связи имеют вес, равный +1, а порог A элементов равен 1.

Объясню подробнее. Возьмем картинку персептрона в общем смысле и преобразуем ее в картинку однослойного персептрона.

Изначально персептрон в общем смысле выглядит так:

perceptroncommon1

Исходя из ключевой особенности однослойного персептрона сенсор может быть однозначно связан только с одним ассоциативным элементом. Посмотрим на белый сенсор на картинке (левый верхний угол). Он передает сигнал салатовому (первому) и серому (четвертому) ассоциативным элементам. Непорядок. Сенсор может передавать сигнал только одному А-элементу. Убираем лишнюю связь. Ту же операцию проводим и с другими сенсорами.

onelayercorrection1

Обязательно убедитесь, что поняли фразу «каждый S-элемент однозначно соответствует одному A-элементу». Это означает, что каждый сенсор может передавать сигнал только одному А-элементу. Однако это утверждение вовсе не запрещает ситуации, когда несколько сенсоров передают сигнал на один А-элемент, что и продемонстрировано на картинке выше (1, 2 и 3 А-элементы).

Далее, S-A связи всегда имеют вес, равный единице, а порог А-элементов всегда равен +1. С другой стороны нам известно, что сенсоры могут подавать сигнал равный только 0 или 1.

Рассмотрим первый S-элемент на последней картинке. Пусть он генерирует сигнал, равный единице. Сигнал проходит по S-A связи и не изменяется, так как любое число, умноженное на 1 равно самому себе. Порог любого А-элемента равен 1. Так как сенсор произвел сигнал, равный 1, то А-элемент однозначно возбудился. Это означает, что он выдал сигнал, равный 1 (так как он тоже может генерировать только 1 или 0 на своем выходе). Далее этот единичный сигнал умножается на произвольный вес A-R связи и попадает в соответствующий R-элемент, который суммирует все поступившие на него взвешенные сигналы, и если они превышают его порог, выдает +1. В противном случае выход данного R-элемента равен -1.

Ничего на напоминает? Правильно, не считая сенсорных элементов и S-A связей, мы только что описали схему работы искусственного нейрона. И это неслучайно. Однослойный персептрон действительно представляет собой искусственный нейрон с небольшим отличием. В отличие от искусственного нейрона, у однослойного персептрона входные сигналы могут принимать фиксированные значения: 0 или 1. У искусственного нейрона на вход можно подавать любые значения.

onelayercorrection2В персептроне R-элементы суммируют взвешенные входные сигналы и, если взвешенная сумма выше некоторого порога, выдают 1. Иначе выходы R-элементов были бы равны -1.

Нетрудно догадаться, что такое поведение легко задается функцией активации под названием функция единичного скачка, которую мы уже рассматривали во 2 главе. Отличие заключается в том, что функция единичного скачка выдает 0, если порог не превышен, а здесь выдает -1, но это не существенно.

Таким образом становится ясно, что часть однослойного персептрона (выделена черным прямоугольником на картинке выше) можно представить в виде искусственного нейрона, но ни в коем случае не путайте два этих понятия. Во-первых, никто не отменял S-элементы, которых в искусственном нейроне просто нет. Во-вторых, в однослойном персептроне S-элементы и A-элементы могут принимать только фиксированные значения 0 и 1, тогда как в искусственном нейроне таких ограничений нет.

Однослойный персептрон – персептрон, каждый S-элемент которого однозначно соответствует одному А-элементу, S-A связи всегда равны 1, а порог любого А-элемента равен 1.

Часть однослойного персептрона соответствует модели искусственного нейрона.

Однослойный персептрон может быть и элементарным персептроном, у которого только по одному слою S,A,R-элементов.

Многослойный персептрон

Под многослойным персептроном понимают два разных вида: многослойный персептрон по Розенблатту и многослойный персептрон по Румельхарту.

Многослойный персептрон по Розенблатту содержит более 1 слоя А-элементов.

Многослойный персептрон по Румельхарту является частным случаем многослойного персептрона по Розенблатту, с двумя особенностями:

  1. S-A связи могут иметь произвольные веса и обучаться наравне с A-R связями.
  2. Обучение производится по специальному алгоритму, который называется обучением по методу обратного распространения ошибки.

Этот метод является краеугольным камнем обучения всех многослойных  ИНС. Во многом благодаря ему возобновился интерес к нейронным сетям. Но обсуждать мы его будем в других главах.

manylayer

Многослойный персептрон по Розеблатту – персептрон, у которого имеется более 1 слоя А-элементов.

Многослойный персептрон по Румельхарту – многослойный персептрон по Розенблатту, у которого обучению подлежат еще и S-A связи, а также само обучение производится по методу обратного распространения ошибки.

Опорная схема

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

perceptronclaassif

Мы разобрались с видами персептронов. Далее в этой главе рассмотрим только однослойный персептрон с одним скрытым слоем.

Говоря про персептрон я буду иметь ввиду именно его.

Какие задачи решает персептрон?

Перед началом практики я хотел бы рассказать подробнее о том, какие задачи персептрон способен решать, а какие нет. Также я приведу несколько удобных аналогий, позволяющих понять, возможно ли использовать персептрон в данной задаче или нет. Это крайне важно, так как персептрон, как простейший вид нейросети, не так уж много и умеет.

Персептроны очень хорошо решают задачи классификации. Что это означает? Если у вас есть группы объектов (например, кошки и собаки), то персептрон после обучения сможет указывать к какой группе относится объект (к кошкам или собакам).

«Очень хорошо» – понятие растяжимое. Насколько хорошо? Розенблатт доказал несколько теорем, суть которых я попытаюсь донести максимально понятным образом.

1. Если имеется поле сенсоров (матрица) и какая-то классификация, зависящая от него, то множество элементарных персептронов, проводящих успешную классификацию не является пустым.

Объясняю на пальцах. Под полем сенсоров понимается множество всех S-элементов. Под классификацией – придуманные нами классы (те же кошки и собаки). Под «непустым множеством элементарных персептронов, проводящих успешную классификацию» понимается, что найдется хотя бы один перспетрон, справившийся с классификацией объектов.

Рассмотрим на примере.

Я хочу, чтобы персептрон научился различать кошек и собак. Это задача довольно трудная, но мы ее существенно упростим.

У нас будет 3 сенсора: длина лап, окрас и форма морды. Так как S-элементы могут принимать значения 0 или 1, то условимся, что значения 1 будут соответствовать коротким лапам, смешанному окрасу и округлая морда соответственно. Значения 0 будут означать признак собаки на данном S-элементе (длинные лапы, однотонный окрас и вытянутая морда). Вот мы и получили сенсорное поле. Если хотите, его можно представить в виде множества возможных значений 0 и 1 у каждого S-элемента. Например, абсолютная кошка должна вызвать срабатывание всех S-элементов \{1,1,1\} .

cat2

Идеальной же собаке соответствует следующий набор выходов S-элементов: \{0,0,0\} .

dog1

Сами по себе сенсоры не играют роли. Но добавив к набору выходов сенсоров смысл: кошка или собака, мы тем самым задали некоторую классификацию. Математически это означает, что мы задали некоторую функцию, которая принимает набор выходов S-элементов, а ее значением является 0 или 1 (кошка или собака).

Из приведенной выше теоремы следует, что множество персептронов, правильно проводящих нашу классификацию не является пустым. То есть такие персептроны есть!

Но ведь можно выбрать любой набор S-элементов и любую классификацию. И множество «решений» все равно не будет пустым!

Это означает, что теоретически персептроны способны решать любую задачу на классификацию.

Важное замечание!
1. Речь идет об элементарных персептронах.
2. Объекты классификации должны обладать свойством линейной разделимости (подробнее о ней ниже).

Но есть и вторая теорема, доказанная Розенблаттом:

2. Если имеется поле сенсоров (матрица) и какая-то классификация, зависящая от него, то процесс обучения с коррекцией ошибок, начинающийся с произвольного исходного состояния, всегда приведёт к достижению решения в течение конечного промежутка времени.

Под произвольным исходным состоянием тут понимается персептрон с произвольными S-A и A-R весами связей. Под решением в теореме понимается персептрон с определенными весами, успешно решающий нашу задачу на классификацию.

Эта теорема не оставляет задачам на классификацию никаких шансов. Теперь нам известно, что мы всегда сможем решить нашу задачу за конечный промежуток времени. Единственный нюанс заключается в том, что никто не говорит о длительности «конечного промежутка времени». Секунда, минута, час, год, 1 000 лет?

Обе теоремы имеют доказательства, но здесь мы их рассматривать не будем.

Метод коррекции ошибок – один из алгоритмов изменения весов. В этой главе мы его также разберем ниже в своем разделе.

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

Линейная разделимость

Давайте, для понятности, визуализируем классификацию линейно разделимых объектов на примере кошек и собак. Чтобы их различать (классифицировать) введем для простоты всего два параметра: размер и прирученность. По сочетанию размера и прирученности нейронная сеть должна будет принять решение: кошка это или собака. Не может быть одновременно кошка и собака для одинаковых показателей размера и прирученности.

В этом случае потребуется всего два S-элемента, определяющие размер и прирученность. Так как размер животного и степень его прирученности могут быть разными и иметь промежуточные значения, то давайте немного отойдем от принятого определения S-элемента. Представим, что он может выдавать не только 0 (маленький размер, совсем дикий) или 1 (большой, полностью ручной), но и другие значения.

Так как у нас есть два сенсорных элемента, то их значения можно расположить вдоль двух координатных осей. На получившейся координатной плоскости можно размещать точки, каждая из которых характеризует какой-то вид кошки или собаки. Как вы знаете, у каждой точки есть координаты. В нашем случае их две: размер и прирученность. Так вот, задачей персептрона в данном случае (основанного на двух S-элементах) – провести некоторую прямую, которая максимально точно разделит два множества точек (кошек и собак). На рисунке ниже видно 4 этапа обучения сети на все более большой обучающей выборке.

linear

Естественно, что у нас может быть больше признаков, а значит, и больше сенсорных элементов. В случае трех признаков будет три S-элемента, то есть имеем уже трехмерное пространство. В таком случае, между точками, каждая из которых соответствует определенным значениям всех трех S-элементов, проводилась бы плоскость. И так далее. В общем случае для n S-элементов в n -мерном пространстве строится так называемая гиперплоскость с размерностью n-1 .

Вы заметили, что в картинках выше в качестве разделителя используется прямая? А ведь мы могли бы в качестве разделителя использовать и любую другую кривую. Но прямая – проще. Именно поэтому в этой главе я рассматриваю задачи на классификацию линейно (от слова линия) разделимых объектов. Именно такие задачи способны решать элементарные персептроны.

Конечно, бывают и такие множества объектов, которые невозможно разделить линией (плоскостью/гиперплоскостью). В общем случае, такие множества называют линейно неразделимыми и в этой главе мы не будем их рассматривать. Теоремы о сходимости элементарных пересептронов на них не распространяются.

Задача на классификацию

Можно ли классифицировать логические функции? Да, и к тому же эта задача отлично проиллюстрирует такую классификацию.

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

Математическая справка

Логические функции очень красиво иллюстрируют идею классификации. Любая такая функция принимает на вход два аргумента. По счастливой случайности точки на плоскости задаются двумя числами (x и y)! Но логические функции могут принимать только дискретные аргументы (0 или 1). В итоге получаем, что для изображения любой логической функции на плоскости достаточно 4 точки (с координатами (0,0) \ (1,0) \ (0,1) \ (1,1)  ). Вот так это выглядит:

logicempty

Рассмотрим логическую функцию И. Она равна нулю для любого набора входных аргументов, кроме набора (1,1) .

X1 X2 Логическое И
0 0 0
1 0 0
0 1 0
1 1 1

Налицо задача классификации: у нас есть 4 точки. Мы должны провести прямую так, чтобы по одну сторону у нас оказались точки, для которых значения логического И равно 1, а по другую, для которых это значение равно 0.

В случае с логическим И эту прямую, например, можно провести так, как показано на рисунке ниже. Все точки, находящиеся под этой прямой, приводят к 0 значению этой функции. Единственная точка над этой прямой приводит к значению логического И, равному 1.

logicAND

Похожим образом ведет себя логическое ИЛИ, имеющее следующую таблицу истинности:

X1 X2 Логическое ИЛИ
0 0 0
1 0 1
0 1 1
1 1 1

Для такой функции графическое представление будет выглядеть так:

logicOR

Нетрудно заметить, что данная картинка представляет собой графическое представление логического И, но наоборот (тоже одна точка, но для которой значение функции равно 0 и уже под прямой).

На этом мы завершаем рассмотрение задач классификации. Я думаю, теперь вы вполне представляете, что многие проблемы можно решить, если суметь переформулировать их в виде задач на классификацию.

Теперь мы переходим к краеугольному камню нейронных сетей — их обучению. Ведь без этого свойства они не имеют никакого смысла.

Обучение персептронов

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

Упрощаем до предела

Начнем обучение наших нейронных сетей с самого простого случая. Для этого мы сильно упростим и без того простой однослойный персептрон с одним скрытым слоем:
1. Будем считать, что его A-R связи могут принимать только целые значения (…, -2, -1, 0, 1, 2, …).
2. Более того, у каждого А-элемента может быть только один S-элемент.
3. И у нас будет только 1 R-элемент.

На словах такое большое количество упрощений может выглядеть сложно. Поясним сказанное на схеме. Возьмем уже использовавшуюся картинку однослойного персептрона с одним скрытым слоем и преобразуем ее.

Изначально мы имеем следующий персептрон.

onelayercorrection1

Мы должны упростить его. Теперь A-элементы могут быть соединены только с одним S-элементом. Убираем все лишние связи.

На картинке выше 3 R-элемента. Оставляем только один.

S-A веса и пороги A элементов у нас теперь равны +1. Отмечаем это на рисунке.

В итоге получаем следующую картину.

supersimpleperceptron

Однако получается, что у нас слой A-элементов не выполняет никакие функции. Он эквивалентен S-слою. Поэтому мы проводим следующее упрощение. Выбрасываем слой сенсоров. Теперь роль сенсоров у нас будут выполнять ассоциативные элементы (или наоборот, без разницы).

supersimpleperceptronend

Итак, мы только что ну очень упростили однослойный персептрон с одним скрытым слоем.

Вы не поверите! Даже в таком кастрированном виде нейронная сеть будет работать и даже решать задачи на классификацию. И не только…

Сначала попробуем научить такую простую модель (к тому же полностью копирующую модель искусственного нейрона) решать простейшую задачу на классификацию. Например, распознавание цифр.

Практика: распознавание цифр

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

Сейчас мы запрограммируем простейшую нейросеть, которая будет распознавать цифры. На самом деле это трудная задача, поэтому мы ее  в очередной раз упростим:
1. Будем распознавать только черно-белые цифры от 0 до 9.
2. Цифры будут состоять из черных квадратиков в табличке 3х5 квадратов.
3. Распознать нейросеть должна будет научиться только одну цифру.

Вот как выглядят  наши цифры.

trainingset

В нашей сети будет по 1 S-элементу (он же А-элемент) на каждый квадратик из таблички. Поэтому для распознавания цифры нам потребуется 15 сенсоров. Черный цвет квадрата соответствует возбуждению S-элемента (значение передаваемого сигнала равно 1). Белый цвет – выход соответствующего S-элемента равен 0.

Цифры в строковом формате

Чтобы работать с нейросетью, мы должны на ее входы подавать сигналы в виде чисел (0 или 1). Таким образом изображение цифры мы должны перевести в последовательность сигналов в виде чисел. Это легко сделать, если представить цифры в строковом формате.

Каждая цифра представляет собой всего пятнадцать квадратиков, причем только двух возможных цветов. Как и говорилось в предыдущем разделе, за белый квадратик отвечает 0, а черный квадратик – 1. Поэтому наши десять цифр от 0 до 9 в строковом формате будут выглядеть вот так:

trainingsetnums

Для записи каждой цифры у нас используется по 5 строк с 3 символами в каждой. Теперь уберем все переносы строк, чтобы получить для каждой цифры от 0 до 9 одну длинную строку длиной в 15 символов.

1 – 001001001001001

………………………………….

9 – 111101111001111

0 – 111101101101111

Цифры в таком строковом формате уже можно использовать для работы с нейросетью.

Еще раз поясню, почему мы не используем картинки, а перешли к строчкам символов. Взгляните на картинку ниже.

noimgtotext

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

Такой простой пример не стоит таких больших усилий. Поэтому мы пропустим первые два этапа, указанные на картинке, и будем сразу подавать на вход нейросети цифры в строковом формате.

Постановка задачи

Мы хотим создать программу, которая из всех 10 цифр будет распознавать нужную нам цифру. Например, пусть это будет цифра 5 (можно и любую другую). Только и всего.

Нашей обучающей выборкой будут все цифры от 0 до 9. Когда нейросеть обучиться безошибочно распознавать нужную нам цифру (5), тогда мы проверим ее «интеллект» уже на тестовой выборке. Она будет уже похитрее: на вход будут подаваться уже искаженные изображения пятерки.

Посмотрим, сможет ли обученная нейросеть с высокой точностью распознавать пятерку?

Понятно, что ряд искаженных изображений пятерки мы тоже должны преобразовать в строковый формат. А это мы уже делали выше, поэтому не будем здесь расписывать.

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

Наконец-то мы дошли до главного: как обучать сеть. В общих чертах процесс понятен. Мы будем случайным образом выбирать цифру и прогонять ее через сеть, модифицируя ее веса. Но как их модифицировать?

Мы знаем, что важность тем или иным входам (в нашем случае – S-элементам) придают веса, связывающие их с R-элементом. Таким образом, чем сильнее повлиял какой-то вес связи на результат, тем сильнее надо его изменить.

Следовательно, мы должны учесть следующие важные моменты:

  • Если наша нейросеть правильно распознала/отвергла цифру 5, то мы ничего не предпринимаем (все ведь замечательно!).
  • Если нейросеть ошиблась и распознала неверную цифру как 5, то мы должны ее наказать – мы уменьшаем веса тех связей, через которые прошел сигнал. Другими словами веса, связанные с возбудившимися входами, уменьшаются.
  • Если нейросеть ошиблась и не распознала цифру 5, то мы должны увеличить все веса, через которые прошел сигнал. Таким образом мы как бы говорим сети, что такие связи, а значит и связанные с ними входы – правильные.

Теперь запишем непосредственно алгоритм обучения, который мы будем реализовывать в программе:

  1. Подать на входы нейросети цифру в строковом формате.
  2. Если цифра распознана/отвергнута верно, то перейти к шагу 1.
  3. Если сеть ошиблась и распознала неверную цифру как 5, то вычесть из всех связей, связанных с возбудившимися S-элементами единицу.
  4. Если сеть ошиблась и отвергла цифру 5, то добавить единицу ко всем связям, связанным с возбудившимися S-элементами.

Почему в алгоритме мы прибавляем или отнимаем именно 1. На самом деле эту величину можно задать любой. Понятно, что эта величина влияет на эффективность обучения. Какой шаг обучения выбрать – это отдельный вопрос, который мы рассмотрим позднее.

Программа

Если вы не знакомы с языком программирования Python и/или не знаете, как приступить к работе, то рекомендую ознакомиться (можно бегло) с самым популярным самоучителем по Python.

Совершенно не обязательно писать нейросети на Python! Искусственные нейросети – математическая модель, и их можно запрограммировать с помощью любого языка. Так что если вам больше по душе Java, C, C#… то можете реализовывать сети на них. Никаких принципиальных различий нет. Алгоритм один и тот же. Реализация на разных языках разная.

Для начала импортируем модуль для работы со случайными числами.

Теперь давайте запишем все цифры от 0 до 9. Просто записывайте цифру в 5 строк по 3 символа, а затем удаляйте переносы строк (выше мы это уже рассматривали).

Функция list(*) позволяет нам создать список (массив), состоящий из отдельных символов, на которые разбивается длинная строка.

Далее, для простоты добавим все эти 10 цифр в список (для быстрого доступа к ним).


Теперь запишем 6 видов искаженной пятерки в строковом формате.

Теперь нам необходимо создать список весов. Помните теоремы об обучении персептронов? Там сказано, что сеть из любого состояния может обучиться правильно отвечать. Так что, чтобы не загадывать, пусть все веса вначале у нас будут равны 0. Так как у нас 15 входов и все они сразу соединены с одним R-элементом, то нам потребуется 15 связей.

Здесь я упростил запись, использовав генератор списков. Вместо этой записи вполне правомерно использовать обычный цикл, повторяющийся 15 раз и присваивающий всем элементам нашего списка весов 0:

Так как мы используем пороговую функцию активации, то нам необходимо установить какое-то число (порог). Если взвешенная сумма будет больше или равна ему, то сеть выдаст 1 (что означает, что она считает предоставленную цифру пятеркой). Порог можно выбрать любой. Пусть будет равен 7.

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

Результатом работы выражения return net >= bias этой функции может быть True (Правда/Да), что означает 1 или False (Ложь/Нет), что означает 0.

Теперь определим еще две вспомогательные функции.

Первая функция вызывается, когда сеть считает за 5 неверную цифру (выход равен 1 при демонстрации не 5) и уменьшает на единицу все веса, связанные с возбужденным входами. Напомню, что мы считаем вход возбужденным, если он получил черный пиксель (то есть 1).

Я использовал функцию  int(number[i]) для преобразования символа  '1' в цифру 1. Если бы я этого не сделал, то возникла бы ошибка здесь  if int(number[i]) == 1:, так как Python не умеет сравнивать символы (текст) с цифрами.

Вторая функция вызывается, если сеть не смогла распознать цифру пять (выход равен 0 при демонстрации 5) и увеличивает на единицу все веса, связанные с возбужденными входами.

Теперь начнем обучать нашу нейронную сеть. Делать мы это будем в цикле, который будет повторятся достаточно большое количество раз. Для примера возьмем 10 000 раз. Действия за каждый этап повторения мы описали выше в алгоритме обучения.

Осталось только вывести результаты обучения. Выводить их мы будем следующим образом. Сначала выведем результирующие значения весов. Героев надо знать в лицо. После этого еще раз прогоним сеть по всем цифрам от 0 до 9, но уже без обучения. Просто чтобы удостоверится, что она обучилась. А в конце опробуем сеть на нашей тестовой выборке.

Если у вас отображаются какие-то ошибки или вы просто запутались в структуре, то под спойлером ниже расположен полный код программы.

NumberRecogniser.py

Готовы? Запускайте! Пробуйте! Должно сработать.

Мои результаты — сеть стала распознавать пятерку во все случаях только
с 3 попытки. Картинка кликабельна.

firstlaunch

Не обязательно сеть научится распознавать пятерки из тестовой выборки с первой попытки. Если результат программы вас не устраивает (не вся тестовая выборка успешно прошла проверку), то просто запустите программу снова. Все будет сброшено и начнется с чистого листа.

Но почему сеть не обучается с первого раза?

При любом запуске программы 10 тысяч обучающих цифр генерятся случайным образом. Таким образом при каждом запуске программы процесс обучения сети уникален.

Из-за случайности генерации обучающих цифр они могут подаваться на вход неравномерно, а значит обучение будет идти однобоко. Действительно, если показывать только одну или две цифры, то сеть ничему не научиться.

Чтобы сеть гарантированно научилась распознавать нужную нам цифру надо соблюсти два условия:

  1. Добиться равномерности показа всех обучающих цифр.
  2. Увеличить общее количество шагов обучения (50 тысяч или 100 тысяч).

Давайте поближе рассмотрим созданного нами монстра!
Что еще за Скайнет?

Рассмотрим мой результат. Начнем с первой строчки (это веса сети):

[1, 1, 1, 3, 0, -8, 1, 2, 1, -8, 0, 1, 1, 1, 1]

Теперь расположим эти цифры в виде «цифры».

1 1 1
3 0 -8
1 2 1
-8 0 1
1 1 1

Если приглядеться, то можно заметить цифру пять. Важно то, что все квадраты, составляющие силуэт пятерки положительные. Некоторые даже больше 1 (3 и 2). Мы получили как бы слепок весов нашей сети, наложенной на цифру пять.

Давайте предположим, что цифра указывает яркость конкретного квадрата. Получим следующую картинку.

fivetrace

Более темные квадраты уверяют нашу суеверную нейросеть, что предлагаемая цифра несомненно является пятеркой и вносят большой вклад в взвешенную сумму (3 и 2). Соответственно если в предлагаемой сети картинке эти квадраты черные, то взвешенная сумма наверняка будет больше порога. Серые области вносят обычный вклад (по 1) в взвешенную сумму. Красные квадратики вызывают отвращение у сети и их появление на входах приводит аж к отрицательным значениям (-8), что сильно снизит взвешенную сумму и она будет гарантированно ниже порога.

Получается, что сеть сама выделила хорошие/противные области, нужные ей для распознавания. Невероятно, да?

Но это еще не все. Дальше идет 9 строк обучающей выборки.

0 это 5? False
1 это 5? False
2 это 5? False
3 это 5? False
4 это 5? False
6 это 5? False
7 это 5? False
8 это 5? False
9 это 5? False

Все предложенные цифры наша нейросеть смело отвергает, клеймя их False.

Наконец, итоговый и самый желанный результат программы – тестовая выборка. Как вы видите, сеть прекрасно распознала и цифру 5, и шесть ее искаженных вариаций.

Узнал 5? True
Узнал 5 — 1? True
Узнал 5 — 2? True
Узнал 5 — 3? True
Узнал 5 — 4? True
Узнал 5 — 5? True
Узнал 5 — 6? True

Тем самым, даже на предельно упрощенном однослойном персептроне с одним скрытым слоем, который, кстати, представляет собой фактически один искусственный нейрон, мы смогли программно добиться эффекта обобщения. Сеть никогда не видела искаженные пятерки. Но она их узнала.

Напомню, что мы рассматривали очень упрощенный вариант сети, связи и входы которой могли быть только целыми числами. Название алгоритма обучения, который мы использовали: правила Хебба. Всего этих правил два и они соответствуют двум пунктам уже описанного выше алгоритма обучения.

Правила Хебба (Hebb’s rule, Hebbian learning rule) – два правила, составляющие алгоритм обучения персептронов для решения простейших задач классификации, когда входы могут быть равны только 0 или 1:

1 Правило. Если сигнал персептрона неверен и равен 0, то необходимо увеличить веса тех входов, на которые была подана единица.

2 Правило. Если сигнал персептрона неверен и равен 1, то необходимо уменьшить веса тех входов, на которые была подана единица.

Правила Хебба часто встречается в литературе, как обучение с коррекцией ошибки.

Дельта-правило

Теперь попробуем обобщить правила Хебба на произвольные (не только 0/1) входы и связи (не только целые числа).

Пусть мы заранее знаем правильный выход нашей сети. Обозначим его за d . Однако в процессе обучения сеть ошибается. Обозначим ответ сети за y . Тогда мы можем получить ошибку/погрешность сети как разницу правильного и реального ответов:

\delta=d-y

Мы знаем, что решающую роль в преобразовании сигнала играют связи. Значит необходимо каким-то образом их изменять. Классический алгоритм изменения связей: дельта-правило.

Дельта-правило (Delta rule) – алгоритм обучения персептронов. При обучении сети новое значение i -го веса связи на t+1 шаге рассчитывается по следующей формуле:

w_i(t+1)=w_i(t) + \delta x_i \eta 

Разберем эту формулу. Сначала в общих чертах.

Для отображения количества шагов обучения сети я использую переменную t . Очевидно, что наша цель – получить из старого значения веса связи w_i(t) новое значение w_i(t+1) .

Для этого мы, как и в правилах Хебба, должны прибавить какое-то число к весу связи. Как раз эта добавка вычисляется по формуле \delta x_i \eta . Разберем эту формулу.

Переменная \delta есть ошибка нейросети. Заметим сходство с правилами Хебба. Если нейросеть ответила правильно, то ожидаемый и реальный результаты равны и \delta = 0 , а значит и вся добавка к весу связи равна 0 . Вес не изменился.

В случае, если \delta>0 , а значит d>y , то значение добавки к весу будет положительное. Вес связи увеличится (1 правило Хебба). Это соответствует случаю, когда сеть получила на вход 5, но не узнала ее.

В случае, если \delta<0 , а значит d<y , то значение добавки к весу будет отрицательное. Вес связи уменьшится (2 правило Хебба). Это соответствует случаю, когда сеть неверно посчитала данное число за 5.

С \delta разобрались. Теперь перейдем к x_i . Это значение, которое пришло на i -ый вход сети. Опять же, чем более сильный сигнал поступил на вход, тем сильнее изменится вес, с этим входом связанный. Это логично. Ведь если на вход вообще не поступило сигнала (x_i=0 ), то и соответствующий вес не должен изменится (добавка будет равна нулю).

А теперь самое интересное: Скорость обучения \eta .

Скорость обучения

Если с первыми двумя членами формулы добавки к весу \delta x_i \eta все просто и понятно, то постоянный коэффициент \eta , называемый коэффициентом скорости обучения, вызывает вопросы. Зачем он нужен?

Результат сети зависит от ее весов. Но раз зависит результат сети, то от весов зависит и ее ошибка (как разность постоянного «правильного» значения и результата сети). Представим, что погрешность нашей сети \delta зависит от какого-то веса сети w_i следующим образом.

kengustart

Положение кенгуру означает конкретный вес связи. Так в чем же фишка? А фишка в том, что кенгуру надо попасть в низину, так как именно в ней ошибка сети будет минимальна. Однако наш кенгуру может только прыгать. И именно за «длину прыжка» и отвечает коэффициент \eta в формуле добавки к весу.

Пусть коэффициент \eta маленький. Тогда наш кенгуру будет маленькими прыжками продвигаться к низине. Это будет очень доооооолго…

kengulooongОк, сделаем коэффициент \eta большим. Ведь большими прыжками мы быстрее доскачем до низины? Нет. При большом значении скорости обучения есть опасность так и не доскакать до самого низа из-за того, что вы постоянно будете прыгать вправо-влево оставаясь на одной и той же высоте.

kengubigjump

Поэтому подбирать коэффициент скорости обучения надо с умом. Иногда его представляют в виде некоторой функции, которая постепенно уменьшается. То есть \eta уменьшается (а значит уменьшается и длина прыжка) по мере приближения к низине.

kengulend

Вот мы и разобрались в предназначении коэффициента скорости обучения. Мы можем изменять вес связи только скачками. Этот коэффициент определяет величину скачков.

Практика: линейная интерполяция

А теперь снова займемся практикой. На этот раз возьмем нестандартную задачу, которая относится не к классификации (как в примере с распознаванием цифр выше), а к интерполяции, то есть поиску промежуточных значений при заданном наборе конкретных значений. И тут нам как раз и пригодится дельта-правило.

Пусть у нас имеется какой-то набор точек на плоскости.

X Y
1 2
2 4.2
2.5 5
3.8 7.9
4 9
6 10.2
6.6 13
7.2 15.3
8 17.1
8.5 19.5

Теперь давайте представим эти данные в виде картинки:

Мы видим, что полученные данные подозрительно напоминают прямую линию. Наша задача состоит в том, чтобы как можно более точно провести прямую, по которой можно будет предсказать по данному X значение Y. В этом и состоит принцип интерполирования.

Например, у нас нет данных о Y координате точки с X = 3. Задача интерполирования – с наибольшей вероятностью предсказать, какой будет Y для этой точки.

Вы можете предположить, что для этого можно использовать метод наименьших квадратов. Его действительно используют очень часто. Однако, он не единственный.

Сейчас для нас важно то, что эту задачу мы можем решить и с помощью нейронной сети. Сделать это можно достаточно хитрым образом.

Нам нужна прямая. Из алгебры мы помним, что любая прямая в декартовых координатах задается уравнением:

y = kx + c

Коэффициент k отвечает за крутизну наклона прямой, а c указывает точку на оси Y, через которую проходит эта прямая.

Математическая справка

Мы ищем уравнение прямой, интерполирующее наши данные. Значит y у нас будет выходом сети. Теперь определимся со входами. Совершенно точно, что одним входом будет являться переменная x . Однако в уравнении прямой фигурирует еще одно слагаемое: c . О нем тоже нельзя забывать. c  – постоянная величина. Поэтому мы добавим в нашу сеть второй вход, на который всегда будет подаваться единица. Таким образом произведение этого входа на вес всегда будет равно только этому весу, вне зависимости от входа (он всегда равен 1).

Функции активации у нас не будет. Взвешенная сумма и будет являться выходом нашей сети.

Вот так графически выглядит наш персептрон:

Давайте определим математически, чему равен выход нашей сети. Я уже рассказывал об этом во 2 главе, когда описывал математическую модель искусственного нейрона. Наш персептрон по факту является искусственным нейроном.

out = \left(\sum\limits_{i=1}^n w_i x_i\right)

Это была запись в общем виде. А для нашего случая имеем:

out = w_2 x + w_1

Ничего эта запись вам не напоминает? Да это же уравнение прямой линии, где out = y, \ w_2=k, \ w_1=c ! Мы построили персептрон так, что в процессе обучения его весовые коэффициенты станут коэффициентами прямой, которую мы ищем!

Программа

Для начала вновь импортируем модуль для работы со случайными числами.

Далее мы создаем переменную, являющуюся весом связи при входе x (а по совместительству и коэффициентом крутизны наклона прямой).

Функция  uniform(from, to)  генерирует случайное вещественное число от from и до to включительно. Заметьте, что мы уже не работаем с целыми числами.

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


Его значение опять же выбирается случайным образом.

Задав эти два члена, мы определили прямую. Так как оба члена заданы случайным образом, мы определили случайную прямую. Этим фактом я хочу показать, что изначальное положение прямой абсолютно несущественно. Она может быть какой угодно. Прямо как и в предыдущем примере с цифрами. Там сеть приходила к правильной конфигурации независимо от начальных значений весов.

Далее мы должны вывести в консоль созданные переменные.

Теперь задаем данные о наборе точек.

Здесь я использую не список, а словарь. Это практически тоже самое, что и список, только используются не числовые индексы, а собственноручно заданные имена – ключи. В данном словаре ключи это X, а соответствующие им значения это Y.

Теперь нам необходимо задать коэффициент скорости обучения. Я определил ее экспериментально. Сначала начал с 0.1, но при этом сеть не обучалась. По мере роста шагов ошибка сети только увеличивалась. Этот случай соответствует картинке с кенгуру, делающей слишком большие прыжки.

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

Теперь нужно создать функцию, высчитывающую ответ нашего персептрона:

Как видите, никакой функции активации тут нет. Ответ нашей сети есть взвешенная сумма, где k  – вес связи при x, а c  – вес связи при входе, всегда равном единице.

Теперь надо обучить нашу сеть. Чем больше шагов заложим, тем лучше. Возьмем, например, 100 000 шагов обучения. Хотя, возможно, для получения результата подошло бы и меньшее количество шагов. Тут есть простор для экспериментирования.

На протяжении 100 000 раз мы выбираем из нашего словаря случайный ключ (так как ключ у меня это и есть значение X).

После этого создается переменная  true_result , в которой хранится правильный Y для соответствующего X.

Далее, в переменную  out мы помещаем ответ нашей сети для данного X.

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

Осталось только вывести данные о новой прямой.


Привожу полный код программы:

LinearInterpolation.py

Можно запускать! Корректные результаты должны получиться уже с первого раза. Как понять, что ваши результаты корректные? Значение k у вас должно быть в районе 2, а значение c  – чем ближе к 0, тем лучше.

Вот, что получилось у меня.

interpolationout

На самом деле я намеренно задал уравнение вида y = 2x и, как видно по результатам, сеть практически полностью повторила его.

Цифры это конечно хорошо, но на графиках выглядит еще лучше.

datainterpolate1

Здесь синие точки – это набор исходных данных. Коричневая прямая – это случайно полученная в начале программы прямая. Она может проходить как угодно и где угодно.

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

Если вы построите свою готовую прямую по данным, выведенным в консоли, то она должна практически идеально совпасть с моей.

И ваша, и моя прямые, в свою очередь, практически идеально совпадают с первоначальной прямой (y = 2x ), из которой я намеренным искажением получил точки набора.

На данном примере хорошо видно, что иногда персептроны могут выполнять не только задачи на классификацию.

Выводы

Это одна из самых информативных глав в учебнике. Более того, здесь впервые встречаются примеры программирования нейронных сетей, а именно – простейших видов персептронов.

В первой половине главы я разъяснил используемую терминологию. Ввел понятия персептронов и их видов. Помните, что чаще всего под персептронами понимают именно элементарные и однослойные песептроны.

Далее вы узнали, что такое задачи классификации и ознакомились с теоремами о сходимости персептрона. Не обязательно наизусть помнить их формулировки. Достаточно понимать, что они означают.

Затем вы ознакомились с правилами Хебба и создали первую искусственную нейросеть, которая не только умеет отличать цифру 5 от всех остальных, но еще и умудряется распознавать ее в искаженных картинках. Это был пример использования персептрона как классификатора.

Последние разделы главы посвящены дельта-правилу, как обобщению правил Хебба, и созданию персептрона, реализующего линейную интерполяцию.

Этой главой я лишь приоткрыл достаточно обширную и, безусловно, интересную тему персептронов. Есть еще много вариантов их использования. Все в одной главе охватить невозможно.

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

Другие языки программирования

Здесь приведены исходные коды программ для различных языков программирования. (Код предоставлен пользователем под ником Geograph)

C#

Распознавание цифр
Интерполяция данных

PHP

Распознавание цифр
Интерполяция данных

Вопросы и задачи

Персептроны – простейший вид искусственных нейронных сетей. Эту тему надо усвоить хорошо, так как без знаний в этой области практически бесполезно лезть в области многослойных сетей. Обязательно ответьте на все вопросы и решите предложенные задачи.

Кроме того, решив предложенные задачи, вы глубже поймете аспекты сетей, которые лишь поверхностно были затронуты в главе.

Что такое персептрон?

Какие существуют виды персептронов? Что чаще всего имеют ввиду, когда говорят о персептроне?

Как надо понимать теоремы о сходимости персептронов?

X1 X2 Логическое НЕ И
0 0 1
1 0 1
0 1 1
1 1 0

Таблица истинности логической функции НЕ И приведена выше. Изобразите ее на плоскости и проведите прямую, по одну сторону которой будут находиться точки, для которых значение этой функции равно 1, а по другую – 0.
Сформулируйте правила Хебба.
Сформулируйте дельта-правило.
В чем смысл коэффициента скорости обучения? Чем опасны его слишком большие/маленькие значения?
В примере по распознаванию цифры 5 корректного результата можно добиться только после нескольких попыток запуска программы. Переделайте ее так, чтобы правильный результат получался с первой попытки (то есть при каждом запуске программы).

Подписаться на уведомления о новых главах

Укажите свой адрес электронной почты в поле ниже и на него придет уведомление, когда новая глава будет опубликована.

Глава 3. Персептроны: 67 комментариев

  1. Спасибо! Отлично написанная глава, но есть одно замечание: ну слишком много if`ов в первой программе, не к чему не принуждаю, но как то  это не красиво. А так ещё раз спасибо за главу, с нетерпением жду новых!

  2. Очень интересно и легко читается в отличии от научной литературы. Спасибо вам за ваши старания

  3. Мне не понятно как функция активации определяет к какому именно числу относится взвешенная сумма? Например мы должны определить цифру 5, тогда другие числа имеющие схожие закрашенные пиксели будут иметь схожую взвешенную сумму, то как функция активации понимает, что это именно 5, а не 2 и т. д.. Может об этом написано во второй половине 3 главы, но я не могу сдвинуться пока не пойму.

    1. Функция активации (используемая в примере с цифрами) определяет, к какому числу относится взвешенная сумма по порогу (какое-то число). Если взвешенная сумма меньше порога, то это не 5. Если больше или равна порогу, то это 5.

      Схожие закрашенные пиксели у какой-то цифры действительно будут приближаться к схожей взвешенной сумме 5. Соль в том, что они не полностью повторяют пиксели 5. А так как повторяют они не полностью, то и взвешенные суммы не равны. Но в процессе обучения сети веса при входах (пикселях) настраиваются так, что все взвешенные суммы всех цифр (даже схожие с 5) будут ниже порога и только взвешенная сумма 5 будет больше или равна порогу.

  4. Спасибо за оперативный ответ! Когда примерно можно ожидать продолжение?

    1. Сейчас пока разбираюсь с институтом. К концу сентября будет ясно. Пока не могу ничего обещать(

  5. Пётр! Огромное тебе спасибо за труд! Подача материала просто ВЕЛИКОЛЕПНАЯ!
    Заметил недочёт, никак не влияющий на суть:) «А значит, коэффициент при отвечает за крутизну наклона прямой к оси X.» В справке про линейную функцию. Ещё раз спасибо! Успехов тебе)

  6. Спасибо за интерсную информацию Пётр!

    Насчет программы распознавания цифр хотелось бы уточнить. Фактически получается мы построили сеть с одним нейроном и 15 входами?

  7. Спасибо за ваши труды! Материал подан очень легко, читать приятно. Всегда хотел немного разобраться с нейронными сетями.
    Давно не было обновлений, не забрасывайте, пожалуйста. У вас хорошо получается, жду следующих глав)

  8. Прошу пояснить про пример «различать кошек и собак» — какая схема нейросети?
    1) Схема — 3 S-элемента и 1 R-элемент (кошка и собака в одном нейроне).
    Если вход {1,1,1}, то выход «1» (кошка), если вход {0,0,0}, то выход «0» (собака)?
    Но ноль — это ведь покой, т.е. нейрон не сработал (не опознал входной сигнал)!
    3) Если схема 3 S-элекмента и 2 R-элеметна (на кошку и собаку по отдельному нейрону).
    Тогда какие веса должны быть на связях к собаке, чтобы при входах {0,0,0} нейрон «собака» выдал «1» ?
    Спасибо за статью!

    1. Если рассматривать ситуацию, которую вы указали под номером 1.

      Тот факт, что нейрон выдает значение 0 вовсе не означает, что он «не опознал входной сигнал» или «не сработал». Как раз наоборот, он сработал и выдал 0. Это такой же осмысленный выход нейрона, как и выход 1. Все зависит от того, как интерпретировать выход 0 или 1. В примере «различие кошек и собак» выход нейрона, равный 1 я предлагаю обозначить за то, что нейрон опознал кошку. Выход же нейрона, равный 0 понимается как «НЕ кошка». Ну а так как мы сравниваем кошек и собак, то НЕ кошка может быть только собакой.

      «Но ноль — это ведь покой» — не совсем. 0 на входе в нейрон означает, что данный параметр совсем НЕ как у кошки (не имеет абсолютно ничего общего с тем, каков этот параметр у кошки). Соответственно 0 на выходе нейрона означает «НЕ кошка», так как большинство или все входные сигналы подали 0 «НЕ как у кошки».

      Короче, все зависит от того, какой смысл вы придаете значениям входов и выходов.

      Если рассматривать ситуацию 2

      Как я уже пояснял выше, наличие двух R-элементов избыточно, так как отсутствие выходного сигнала на одном R-элементе уже можно интерпретировать как «НЕ кошку», то есть собаку.

      Но хорошо. Пусть у нас два R-элемента. R-собака и R-кошка. Соответственно выход R-собаки, равный 1 означает, что входные три сигнала — собака. Так же и для кошки. При демонстрации нашей сети собаки {0,0,0} взвешенная сумма тоже будет равна 0 (вне зависимости от весов). Определим функцию активации R-собаки словами «если взвешенная сумма равна 0, то выход равен 1». Рассмотрим R-кошку. Для ее весов возьмем любые ненулевые числа. Тогда получим какую-то ненулевую взвешенную сумму. Функция активации R-кошки: «Если взвешенная сумма не равна 0, то выход 1».

      Можете легко убедится, что при входе {0,0,0} R-собака выдаст 1, а R-кошка — 0. При входе {1,1,1} все будет наоборот. Однако сразу видно, что два R-элемента для этой задачи излишни. Хватит и одного.

  9. В целом понятно, но местами не очень 🙂
    Ситуация 1 — хотелось бы иметь сеть, работающую по подобию естественных нейронов т.е. нет стимула = 0, есть = 1. Да и помещать в один нейрон два понятия (кошка = 1, собака =0) как-то не естественно по-моему, например, если будет задача опознать одно из 10-ти животных (по трем входным признакам), тогда как быть? Сколько будет выходных нейронов? 1, 5, 10? Или персептрон тут уже бессилен?
    Ситуация 2 – разве все нейроны сети не должны иметь одинаковую функцию активации? Если будет случай, когда нейронов будет очень много – как тогда распределять кому-какую функцию активации назначить?
    Какую можно нарисовать сеть (не персептрон, а обычную, 2 слоя – вход и выход) для решения данного примера («кошки / собаки»)? Получается что нужны уже 6-ть входных нейронов (лапы короткие, лапы длинные, морда круглая, морда вытянутая, окрас смешанный, окрас однотонный) и 2 выходных? Плюс кроме возбуждающих связей нужны будут и тормозящие?

    1. Дело в том, что материал для следующей главы не самый простой (в плане математики). Пытаюсь выразить его в понятом виде. Точные сроки, к сожалению, сказать не могу, чтобы не получилось как с этой главой (два переноса) 🙂

  10. Большое спасибо! Очень интересно и доходчиво! Жду следующую главу с нетерпением!

  11. Шикарная статья. Огромное спасибо!

    Подскажите, пожалуйста, как реализовать первый пример на языке Си (не С++ и C#).

  12. Всё понятно, спасибо за «разжёванность» материала. Но не понятен один момент — откуда взялось пороговое значение bias = 7 ? Почему 7, а не например 10? Как до начала обучения можно получить пороговое значение если веса меняются?

    Конкретно мой пример — есть одноранговая сеть, которая постоянно работает и обучается. Соответственно меняются и веса — в начале они могут быть от 0 до 10, а в перспективе поменяться до диапазона -100 +200.  Сеть обучается в процессе своей работы. Т.е. нет эталонных значений. Сеть ошиблась — веса изменились с целью улучшения последующего результата. Как тогда быть с пороговым значением?

    1. Вся соль в том, что пороговое значение можно взять любое. Так или иначе, рано или поздно, сеть все равно придет к правильному результату. Поэтому и выбрал 7 (можно было и любое другое число).

      Почему это происходит? Можно объяснить так. По сути мы пытаемся подобрать такие коэффициенты, чтобы и пятерка и ее искаженные варианты превышали порог (выход равен 1), а изображения всех остальных цифр были меньше порога. Все вертится вокруг порога, но его конкретное значение не играет никакой роли. Ведь мы по сути добавляем или отнимаем единицы от весов сети усиливая или ослабляя их.

      Конкретно про ваш пример. На самом деле сеть через некоторое время «замкнется», так как при правильном ответе мы оставляем ее в покое. При маленьком пороге значения весов будут в пределе от 0 до 10. При большом пороге эти значения могут быть больше (так как для получения величины больше порога нужны и большие веса, ведь в этом примере мы просто складываем их друг с другом). В любом случае они не будут постоянно расти, так как при определенных достигнутых значениях сеть будет выдавать корректные ответы на все вопросы, а значит веса перестанут меняться.

      1. т.е. в принципе можно пороговое значение всегда ставить 0? Т.е. после тренировки сети любое число из сумматора превышающее ноль будет выдавать правильное решение, а отрицательное — ошибочное?

        И ещё момент. Я так понял, сеть можно тренировать несколько раз на одной и той же выборке? У меня есть 1000 примеров. Прогнав по ним тренировку сети, она чему-то научится. Если я ещё раз 10 прогоню сеть в режиме обучения по этой же выборке, она чему-то дополнительно научится? Или имеет смысл гонять сеть по этой выборке пока веса не перестанут меняться?

  13. Очень хороший материал, отличная проделанная работа Вами! Очень интересно!

    Хотелось бы уточнить и понять разницу между задачей линейной интерполяции и линейной аппроксимации. В моем сознании интерполяция — сглаживание функции, а аппроксимация — нахождение функции, приближенной к заданной. В данном примере это можно счесть одним и тем же, из за такой выборки?

    1. Ну, терминологически получается так:

      Интерполяция — способ нахождения промежуточных значений величины по имеющемуся дискретному набору известных значений. Собственно именно это у нас и есть в задании.

      Аппроксимация — научный метод, состоящий в замене одних объектов другими, в каком-то смысле близкими к исходным, но более простыми.

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

  14. Добрый день.

    Спасибо за уроки. Переписал примеры на js, отлично работают.

    Когда будет 4 урок? Хотелось бы на примерах узнать, как обучать многослойные сети. Пока не очень улавливаю именно это.

  15. Доброго времени суток.

    Отличная статья,  всё очень подробно разобрано.

    Но есть пара вопросов:

    На своей первой попытке, я забыл добавить условие проверки в функцию decrease, но моя сеть всё равно успешно распознала 5 и отвергла другие цифры(на месте квадратов пятёрки единицы, а на месте остальных -5).  Это рабочий вариант,  т.е. может быть получен случайно,  или по странному совпадению разбирает только эти 5 вариантов пятёрки?

    Спасибо за вашу работу.

     

  16. Хочу выразить отдельно поблагодарить Вас, уважаемый автор, за Ваши труды, огромное Вам спасибо, продолжайте в том же духе!

  17. Да, честно говоря, шикарно получилось. Особенно с примерами программ. Может даже есть смысл отдельно практикум и теорию давать. Я бы до такой статьи сам не дошел. Круто. И главное просто. Спасибо!

  18. Эти статьи — самое оно, чтобы начать изучать нейронные сети. Нигде не видел столь простого и хорошего разъяснения на эту тему.

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

  19. Автор молодчина!

    Единственный адекватный материал по нейронным сетям в ненейронной сети (интернет 🙂 ) Очень нравится то, что разжевываются азы и, вместе с тем, внятная практическая реализация!

    Очень жду продолжения, хочется уже более серьезный проект посмотреть — «гаммы» уже зачитаны до дыр 🙂

  20. Как нужно изменить первый пример, чтобы распознавались 2 цифры, скажем 4 и 5 ? Не пойму, что будет на выходе.

      1. Спасибо, было бы круто 🙂

        Код второй программы «LinearInterpolation.cs»: http://pastebin.com/UUyFCrpU

        Для компиляции можно создать проект «Консольное приложение» в VisualStudio и полностью заменить содержимое файла Program.cs на то, что в файле выше.

        Или можно сохранить файл LinearInterpolation.cs и выполнить в командной строке:

        «%windir%\Microsoft.NET\Framework\v4.0.30319\csc» LinearInterpolation.cs

  21. Спасибо большое за понятное и интересное (!!! с примерами из биологии и истории) изложение не самой легкой темы. Я как раз начала недавно заниматься нейронными сетями и Ваш блог просто шикарно помогает понять всё с основных понятий! Правда здорово! Очень жду продолжения!

  22. Спасибо, за такой прекрасный материал, читать и понимать всё очень легко. Надеюсь продолжение будет.

  23. Свою первую нейронку в универе я написал по статьям из вики. Здесь всё намного понятнее, хотя большую часть этой инфы я знаю ), разве что нигде так подробно ещё не видел про разные персептроны и даже не представлял, как могут работать целочисленные персептроны. Хорошая инфа. Хотелось бы побольше почитать про обратные связи нейронов и алгоритм обратного распространения ошибки от вас, но, видимо, продолжения уже не будет?

    1. 4 глава (как раз про алгоритм обратного распространения) в процессе написания. Скоро выйдет. Проект не заброшен)

  24. Только начинаю читать эту главу. Учебник просто ИДЕАЛЬНЫЙ! Лучше не видел. Все интересно и понятно. Супер! Спасибо!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *