C нейросети: Истинная реализация нейросети с нуля на языке программирования C# / Хабр

Содержание

Нейронная сеть — Википедия

Эта статья о понятии в программировании; о сетях нервных клеток живых организмов см. Нервная сеть.

Нейро́нная сеть[1] (также искусственная нейронная сеть, ИНС) — математическая модель, а также её программное или аппаратное воплощение, построенная по принципу организации и функционирования биологических нейронных сетей — сетей нервных клеток живого организма. Это понятие возникло при изучении процессов, протекающих в мозге, и при попытке смоделировать эти процессы. Первой такой попыткой были нейронные сети У. Маккалока и У. Питтса[2]. После разработки алгоритмов обучения получаемые модели стали использовать в практических целях: в задачах прогнозирования, для распознавания образов, в задачах управления и др.

Схема простой нейросети. Зелёным цветом обозначены входные нейроны, голубым — скрытые нейроны, жёлтым — выходной нейрон

ИНС представляет собой систему соединённых и взаимодействующих между собой простых процессоров (искусственных нейронов).

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

Нейронные сети не программируются в привычном смысле этого слова, они обучаются. Возможность обучения — одно из главных преимуществ нейронных сетей перед традиционными алгоритмами. Технически обучение заключается в нахождении коэффициентов связей между нейронами. В процессе обучения нейронная сеть способна выявлять сложные зависимости между входными данными и выходными, а также выполнять обобщение. Это значит, что в случае успешного обучения сеть сможет вернуть верный результат на основании данных, которые отсутствовали в обучающей выборке, а также неполных и/или «зашумленных», частично искажённых данных.

Распознавание образов и классификацияПравить

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

Топология такой сети характеризуется тем, что количество нейронов в выходном слое, как правило, равно количеству определяемых классов. При этом устанавливается соответствие между выходом нейронной сети и классом, который он представляет. Когда сети предъявляется некий образ, на одном из её выходов должен появиться признак того, что образ принадлежит этому классу. В то же время на других выходах должен быть признак того, что образ данному классу не принадлежит[17]. Если на двух или более выходах есть признак принадлежности к классу, считается, что сеть «не уверена» в своём ответе.

Используемые архитектуры нейросетейПравить
  • Обучение с учителем:
  • Обучение без учителя:
  • Смешанное обучение:

Принятие решений и управлениеПравить

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

КластеризацияПравить

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

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

Нейронные сети в простом варианте Кохонена не могут быть огромными, поэтому их делят на гиперслои (гиперколонки) и ядра (микроколонки). Если сравнивать с мозгом человека, то идеальное количество параллельных слоёв не должно быть более 112. Эти слои в свою очередь составляют гиперслои (гиперколонку), в которой от 500 до 2000 микроколонок (ядер). При этом каждый слой делится на множество гиперколонок, пронизывающих насквозь эти слои. Микроколонки кодируются цифрами и единицами с получением результата на выходе. Если требуется, то лишние слои и нейроны удаляются или добавляются.

Идеально для подбора числа нейронов и слоёв использовать суперкомпьютер. Такая система позволяет нейронным сетям быть пластичными.

Используемые архитектуры нейросетейПравить
  • Обучение без учителя:

ПрогнозированиеПравить

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

Используемые архитектуры нейросетейПравить
  • Обучение с учителем:
  • Смешанное обучение:

АппроксимацияПравить

Нейронные сети могут аппроксимировать непрерывные функции. Доказана обобщённая аппроксимационная теорема[19]: с помощью линейных операций и каскадного соединения можно из произвольного нелинейного элемента получить устройство, вычисляющее любую непрерывную функцию с некоторой наперёд заданной точностью. Это означает, что нелинейная характеристика нейрона может быть произвольной: от сигмоидальной до произвольного волнового пакета или вейвлета, синуса или многочлена. От выбора нелинейной функции может зависеть сложность конкретной сети, но с любой нелинейностью сеть остаётся универсальным аппроксиматором и при правильном выборе структуры может достаточно точно аппроксимировать функционирование любого непрерывного автомата.

Используемые архитектуры нейросетейПравить
  • Обучение с учителем:
  • Смешанное обучение:

Сжатие данных и ассоциативная памятьПравить

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

[18].

Используемые архитектуры нейросетейПравить
  • Обучение с учителем:
  • Обучение без учителя:

Анализ данныхПравить

Используемые архитектуры нейросетейПравить
  • Обучение с учителем:
  • Обучение без учителя:

ОптимизацияПравить

Используемые архитектуры нейросетейПравить
  • Обучение без учителя:

Рекуррентная нейронная сеть — Recurrent neural network

Вычислительная модель, используемая в машинном обучении

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

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

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

История

Рекуррентные нейронные сети были основаны на работе Дэвида Рамелхарта в 1986 году. Сети Хопфилда — особый вид RNN — были обнаружены Джоном Хопфилдом в 1982 году. В 1993 году система компрессора нейронной истории решила задачу «очень глубокого обучения», которая требовала большего. более 1000 последующих слоев в РНС разворачиваются во времени.

LSTM

Сети с долговременной краткосрочной памятью (LSTM) были изобретены Хохрайтером и Шмидхубером в 1997 году и установили рекорды точности во многих областях применения.

Примерно в 2007 году LSTM начала революцию в распознавании речи , превзойдя традиционные модели в некоторых речевых приложениях. В 2009 году сеть LSTM, обученная методом Connectionist Temporal Classification (CTC), стала первой RNN, выигравшей соревнования по распознаванию образов, когда она выиграла несколько соревнований по распознаванию рукописного ввода . В 2014 году китайский поисковый гигант Baidu использовал обученные CTC RNN, чтобы превзойти тест набора данных распознавания речи Switchboard Hub5’00 без использования каких-либо традиционных методов обработки речи.

LSTM также улучшил распознавание речи с большим словарным запасом и синтез текста в речь и использовался в Google Android . Сообщается, что в 2015 году производительность распознавания речи Google резко выросла на 49% благодаря обученному CTC LSTM.

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

Архитектура

RNN бывают разных вариантов.

Полностью повторяющийся

Развернутая базовая рекуррентная нейронная сеть

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

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

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

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

Сети Элмана и Иорданские сети

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

Сети Jordan похожи на сети Элмана. Единицы контекста загружаются из выходного слоя вместо скрытого. Блоки контекста в сети Иордании также называются уровнем состояния. У них есть постоянная связь с собой.

Сети Элмана и Джордана также известны как «Простые рекуррентные сети» (SRN).

Сеть Эльмана
частзнак равноσчас(WчасИкст+Uчасчаст-1+бчас)утзнак равноσу(Wучаст+бу){\ displaystyle {\ begin {align} h_ {t} & = \ sigma _ {h} (W_ {h} x_ {t} + U_ {h} h_ {t-1} + b_ {h}) \\ y_ {t} & = \ sigma _ {y} (W_ {y} h_ {t} + b_ {y}) \ end {выравнивается}}}
Иорданская сеть
частзнак равноσчас(WчасИкст+Uчасут-1+бчас)утзнак равноσу(Wучаст+бу){\ displaystyle {\ begin {align} h_ {t} & = \ sigma _ {h} (W_ {h} x_ {t} + U_ {h} y_ {t-1} + b_ {h}) \\ y_ {t} & = \ sigma _ {y} (W_ {y} h_ {t} + b_ {y}) \ end {выравнивается}}}

Переменные и функции

Hopfield

Сеть Хопфилда — это RNN, в которой все соединения симметричны. Он требует стационарных входов и, следовательно, не является обычной RNN, так как не обрабатывает последовательности шаблонов. Это гарантирует, что он сойдется. Если соединения обучаются с использованием обучения Hebbian, тогда сеть Hopfield может работать как надежная адресно-адресная память , устойчивая к изменению соединения.

Двунаправленная ассоциативная память

Представленная Бартом Коско сеть двунаправленной ассоциативной памяти (BAM) представляет собой вариант сети Хопфилда, в которой ассоциативные данные хранятся в виде вектора. Двунаправленность возникает из-за прохождения информации через матрицу и ее транспонирования . Обычно биполярное кодирование предпочтительнее двоичного кодирования ассоциативных пар. Недавно стохастические модели BAM с использованием марковского шага были оптимизированы для повышения стабильности сети и соответствия реальным приложениям.

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

Состояние эха

Сеть состояний эха (ESN) имеет редко связанный случайный скрытый слой. Веса выходных нейронов — единственная часть сети, которая может изменяться (обучаться). ESN хорошо воспроизводят определенные временные ряды . Вариант импульсных нейронов известен как машина с жидким состоянием .

Самостоятельно RNN (IndRNN)

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

Рекурсивный

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

Компрессор нейронной истории

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

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

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

Порождающая модель частично преодолела исчезающий градиент проблемы с автоматической дифференцировки или обратного распространения в нейронных сетей в 1992 г. В 1993 г. такая система решена «Очень Глубокое изучение» задачи , которые требуют более 1000 последующих слоев в RNN развернулась во времени.

РНС второго порядка

RNN второго порядка используют веса более высокого порядка вместо стандартных , и состояния могут быть продуктом. Это позволяет напрямую отображать конечный автомат как в обучении, так и в стабильности и представлении. Примером этого является долговременная краткосрочная память, но у нее нет таких формальных отображений или доказательства стабильности. шяjk{\ displaystyle w {} _ {ijk}}шяj{\ displaystyle w {} _ {ij}}

Долговременная кратковременная память

Блок долговременной кратковременной памяти

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

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

LSTM может научиться распознавать контекстно-зависимые языки, в отличие от предыдущих моделей, основанных на скрытых марковских моделях (HMM) и подобных концепциях.

Закрытый рекуррентный блок

Закрытый рекуррентный блок

Стробирующие рекуррентные блоки (ГРУ) — это стробирующий механизм в рекуррентных нейронных сетях, представленных в 2014 году. Они используются в полной форме и в нескольких упрощенных вариантах. Их производительность при моделировании полифонической музыки и моделирования речевых сигналов оказалась аналогичной работе с долговременной краткосрочной памятью. У них меньше параметров, чем у LSTM, так как у них отсутствует выходной вентиль.

Двунаправленный

Двунаправленные RNN используют конечную последовательность для прогнозирования или маркировки каждого элемента последовательности на основе прошлого и будущего контекстов элемента. Это делается путем объединения выходных данных двух RNN, одна обрабатывает последовательность слева направо, а другая — справа налево. Комбинированные выходные данные — это предсказания заданных учителем целевых сигналов. Этот метод оказался особенно полезным в сочетании с LSTM RNN. {n} w_ {ji} \ sigma (y_ {j} — \ Theta _ {j}) + I_ {i} (t)}

Куда:

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

Обратите внимание, что согласно теореме выборки Шеннона , рекуррентные нейронные сети с дискретным временем могут рассматриваться как рекуррентные нейронные сети с непрерывным временем, в которых дифференциальные уравнения преобразованы в эквивалентные разностные уравнения . Это преобразование можно рассматривать как происходящее после того, как функции активации постсинаптического узла были отфильтрованы фильтром нижних частот, но до выборки. уя(т){\ Displaystyle у_ {я} (т)}

Иерархический

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

Рекуррентная многослойная сеть персептронов

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

Модель с несколькими временными шкалами

Рекуррентная нейронная сеть с несколькими временными шкалами (MTRNN) — это нейронная вычислительная модель, которая может моделировать функциональную иерархию мозга посредством самоорганизации, которая зависит от пространственной связи между нейронами и от различных типов активности нейронов, каждый из которых имеет свои временные свойства. При такой разнообразной нейронной активности непрерывные последовательности любого набора поведений сегментируются в примитивы многократного использования, которые, в свою очередь, гибко интегрируются в разнообразные последовательные поведения. Биологическое одобрение такого типа иерархии обсуждалось в теории прогнозирования функций мозга Хокинса в его книге « Об интеллекте» .

Нейронные машины Тьюринга

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

Дифференцируемый нейронный компьютер

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

Автоматические выталкивающие устройства нейронной сети

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

Memristive Networks

Грег Снайдер из HP Labs описывает систему корковых вычислений с мемристивными наноустройствами. В пизасторах (резисторы памяти) реализованы с помощью тонких пленочных материалов , в которых сопротивление электрический настроенные с помощью переноса ионов или вакансий кислорода внутри пленки. DARPA «s Проект Synapse финансировала IBM Research и HP Labs в сотрудничестве с Университетом Департамента Бостонского когнитивных и нейронных систем (ЦНС), для разработки neuromorphic архитектуры , которые могут быть основаны на memristive системах. Мемристивные сети — это особый тип физических нейронных сетей, которые имеют очень похожие свойства с (Литтл-) сетями Хопфилда, поскольку они имеют непрерывную динамику, имеют ограниченный объем памяти и естественным образом расслабляются за счет минимизации функции, которая является асимптотической для Модель Изинга. В этом смысле динамика мемристической схемы имеет преимущество по сравнению с схемой резистор-конденсатор в том, что она имеет более интересное нелинейное поведение. С этой точки зрения разработка аналоговых мемристивных сетей представляет собой особый тип нейроморфной инженерии, в которой поведение устройства зависит от схемы подключения или топологии.

Обучение

Градиентный спуск

Градиентный спуск — это итеративный алгоритм оптимизации первого порядка для поиска минимума функции. В нейронных сетях, он может быть использован , чтобы свести к минимуму ошибки термина, изменяя каждый вес в пропорции к производному от ошибки по отношению к этой массе, при условии , что нелинейные функции активаций являются дифференцируемы . Различные методы для этого были разработаны в 1980-х и начале 1990-х годов Вербосом , Уильямсом , Робинсоном , Шмидхубером , Хохрайтером , Перлмуттером и другими.

Стандартный метод называется « обратное распространение во времени » или BPTT и является обобщением обратного распространения для сетей с прямой связью. Подобно этому методу, это пример автоматического дифференцирования в режиме обратного накопления принципа минимума Понтрягина . Более затратный в вычислительном отношении онлайновый вариант называется «Рекуррентное обучение в реальном времени» или RTRL, который представляет собой пример автоматического дифференцирования в режиме прямого накопления со сложенными касательными векторами. В отличие от BPTT, этот алгоритм является локальным во времени, но не локальным в пространстве.

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

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

Основная проблема с градиентным спуском для стандартных архитектур RNN заключается в том, что градиенты ошибок исчезают экспоненциально быстро с увеличением временного интервала между важными событиями. LSTM в сочетании с гибридным методом обучения BPTT / RTRL пытается решить эти проблемы. Эта проблема также решается в независимой рекуррентной нейронной сети (IndRNN) за счет сведения контекста нейрона к его собственному прошлому состоянию, а информация о кросс-нейроне может быть затем исследована на следующих уровнях. Воспоминания различного диапазона, включая долговременную память, могут быть изучены без проблемы исчезновения и взрыва градиента.

Онлайновый алгоритм, называемый причинно-рекурсивным обратным распространением (CRBP), реализует и объединяет парадигмы BPTT и RTRL для локально рекуррентных сетей. Он работает с наиболее распространенными локально повторяющимися сетями. Алгоритм CRBP может минимизировать глобальную ошибку. Этот факт повышает стабильность алгоритма, обеспечивая единый взгляд на методы расчета градиента для рекуррентных сетей с локальной обратной связью.

Один из подходов к вычислению градиентной информации в RNN с произвольной архитектурой основан на построении диаграмм потоков сигналов. Он использует пакетный алгоритм BPTT, основанный на теореме Ли для расчета чувствительности сети. Его предложили Ван и Бофайс, а его быстрая онлайн-версия — Камполуччи, Унчини и Пьяцца.

Методы глобальной оптимизации

Обучение весов в нейронной с

Азбука ИИ: «Рекуррентные нейросети»

N+1 совместно с МФТИ продолжает знакомить читателя с наиболее яркими аспектами современных исследований в области искусственного интеллекта. В прошлый раз мы писали об общих принципах машинного обучения и конкретно о методе обратного распространения ошибки для обучения нейросетей. Сегодня наш собеседник — Валентин Малых, младший научный сотрудник Лаборатории нейронных систем и глубокого обучения. Вместе с ним мы поговорим о необычном классе этих систем — рекуррентных нейросетях, их особенностях и перспективах, как на поприще всевозможных развлечений в стиле DeepDream, так и в «полезных» областях. Поехали.

Что такое рекуррентные нейросети (РНС) и чем они отличаются от обычных?

Давайте сначала вспомним, что такое «обычные» нейросети, и тогда сразу станет понятно, чем они отличаются от реккурентных. Представим себе самую простую нейросеть — перцептрон. Он представляет собой один слой нейронов, каждый из которых принимает кусочек входных данных (один или несколько битов, действительных чисел, пикселей и т.п.), модифицирует его с учетом собственного веса и передает дальше. В однослойном перцептроне выдача всех нейронов объединяется тем или иным образом, и нейросеть дает ответ, но возможности такой архитектуры сильно ограниченны. Если вы хотите получить более продвинутый функционал, можно пойти несколькими путями, например, увеличить количество слоев и добавить операцию свертки, которая бы «расслаивала» входящие данные на кусочки разных масштабов. В этом случае у вас получатся сверточные нейросети для глубинного обучения, которые преуспели в обработке изображений и распознавании котиков. Однако что у примитивного перцептрона, что у сверточной нейросети есть общее ограничение: и входные и выходные данные имеют фиксированный, заранее обозначенный размер, например, картинка 100×100 пикселей или последовательность из 256 бит. Нейросеть с математической точки зрения ведет себя как обычная функция, хоть и очень сложно устроенная: у нее есть заранее обозначенное число аргументов, а также обозначенный формат, в котором она выдает ответ. Простой пример — функция x2, она принимает один аргумент и выдает одно значение. 

Вышеперечисленные особенности не представляет больших трудностей, если речь идет о тех же картинках или заранее определенных последовательностях символов. Но что, если вы хотите использовать нейросеть для обработки текста или музыки? В общем случае — любой условно бесконечной последовательности, в которой важно не только содержание, но и порядок, в котором следует информация. Вот для этих задач и были придуманы рекуррентные нейросети. Их противоположности, которые мы называли «обычными», имеют более строгое название — нейросети прямого распространения (feed-forward neural networks), так как в них информация передается только вперед по сети, от слоя к слою. В рекуррентных нейросетях нейроны обмениваются информацией между собой: например, вдобавок к новому кусочку входящих данных нейрон также получает некоторую информацию о предыдущем состоянии сети. Таким образом в сети реализуется «память», что принципиально меняет характер ее работы и позволяет анализировать любые последовательности данных, в которых важно, в каком порядке идут значения — от звукозаписей до котировок акций.

Схема однойслойной рекуррентной нейронной сети: на каждом цикле работы внутренний слой нейронов получает набор входных данных Х и информацию о предыдущем состоянии внутреннего слоя А, на основании чего генерирует ответ h.

Christopher Olah / colah.github.io

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

Немного углубимся в историю: когда были придуманы РНС, для каких задач и в чем, как тогда казалось, должно было заключаться их преимущество перед обычным перцептроном?

Вероятно, первой РНС была сеть Хопфилда (впервые упомянута в 1974 году, окончательно оформилась в 1982-м), которая реализовывала на практике ячейку ассоциативной памяти. От современных РНС она отличается тем, что работает с последовательностями фиксированного размера. В простейшем случае сеть Хопфилда имеет один слой внутренних нейронов, связанных между собой, а каждая связь характеризуется определенным весом, задающим ее значимость. С такой сетью ассоциируется некий эквивалент физической «энергии», который зависит от всех весов в системе. Сеть можно обучить при помощи градиентного спуска по энергии, когда минимум соответствует состоянию, в котором сеть «запомнила» определенный шаблон, например 10101. Теперь, если ей на вход подать искаженный, зашумленный или неполный шаблон, скажем, 10000, она «вспомнит» и восстановит его аналогично тому, как работает ассоциативная память у человека. Эта аналогия достаточно отдаленна, поэтому не стоит воспринимать ее чересчур серьезно. Тем не менее, сети Хопфилда успешно справлялись со своей задачей и обходили по возможностям существовавшие тогда перцептроны. Интересно, что оригинальная публикация Джона Хопфилда в Proceedings of the National Academy of Sciences вышла в разделе «Биофизика».

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

Christopher Olah / colah.github.io

Следующим шагом в эволюции РНС была «простая рекуррентная сеть» Джеффа Элмана, описанная в 1990 году. В ней автор подробно затронул вопрос о том, как можно (и можно ли вообще) обучить нейросеть распознавать временные последовательности. Например, если есть входящие данные 1100 и 0110, можно ли их считать одним и тем же набором, сдвинутым во времени? Конечно, можно, но как обучить этому нейросеть? Обычный перцептрон легко запомнит эту закономерность для любых примеров, которые ему предложат, но каждый раз это будет задачей сравнения двух разных сигналов, а не задачей об эволюции или сдвиге одного и того же сигнала. Решение Элмана, основанное на предыдущих наработках в этой области, основывалось на том, что в простую нейросеть добавлялся еще один — «контекстный» — слой, в который просто копировалось состояние внутреннего слоя нейронов на каждом цикле работы сети. При этом связь между контекстным и внутренним слоями можно было обучать. Такая архитектура позволяла сравнительно легко воспроизводить временные ряды, а также обрабатывать последовательности произвольной длины, что резко отличало простую РНС Элмана от предыдущих концепций. Более того, эта сеть смогла распознать и даже классифицировать существительные и глаголы в предложении, основываясь только на порядке слов, что было настоящим прорывом для своего времени и вызвало огромный интерес как лингвистов, так и специалистов по исследованию сознания.

За простой РНС Элмана последовали все новые разработки, а в 1997 году Хохрейтер и Шмидхубер опубликовали статью «Long Short-term memory» («долгосрочная краткосрочная память», также существует множество других вариаций перевода), заложившую основу для большинства современных РНС. В своей работе авторы описывали модификацию, решавшую проблему долгосрочной памяти простых РНС: их нейроны хорошо «помнят» недавно полученную информацию, но не имеют возможности надолго сохранить в памяти что-то, что обработали много циклов назад, какой бы важной та информация ни была. В LSTM-сетях внутренние нейроны «оборудованы» сложной системой так называемых ворот (gates), а также концепцией клеточного состояния (cell state), которая и представляет собой некий вид долгосрочной памяти. Ворота же определяют, какая информация попадет в клеточное состояние, какая сотрется из него, и какая повлияет на результат, который выдаст РНС на данном шаге. Подробно разбирать LSTM мы не будем, однако отметим, что именно эти вариации РНС широко используется сейчас, например, для машинного перевода Google.

Принцип работы РНС типа LSTM: нейроны внутренних слоев могут считывать и изменять состояние ячейки (cell state), которое сочетает в себе функции краткосрочной и долгосрочной памяти.

Christopher Olah / colah.github.io

Все прекрасно звучит на словах, но что все-таки РНС умеют делать? Вот дали им текст почитать или музыку послушать — а дальше что?

Одна из главных областей применения РНС на сегодняшний день — работа с языковыми моделями, в частности — анализ контекста и общей связи слов в тексте. Для РНС структура языка — это долгосрочная информация, которую надо запомнить. К ней относятся грамматика, а также стилистические особенности того корпуса текстов, на которых производится обучение. Фактически РНС запоминает, в каком порядке обычно следуют слова, и может дописать предложение, получив некоторую затравку. Если эта затравка случайная, может получиться совершенно бессмысленный текст, стилистически напоминающий шаблон, на котором училась РНС. Если же исходный текст был осмысленным, РНС поможет его стилизовать, однако в последнем случае одной РНС будет мало, так как результат должен представлять собой «смесь» случайного, но стилизованного текста от РНС и осмысленной, но «неокрашенной» исходной части. Эта задача уже настолько напоминает популярные ныне программы для обработки фотографий в стиле Моне и Ван Гога, что невольно напрашивается аналогия.

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

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

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

Daniel Johnson / hexahedria.com

Особый случай в этом вопросе — это автоматическое написание программного кода. Действительно, поскольку язык программирования по определению представляет собой язык, РНС может его выучить. На практике оказывается, что программы, написанные РНС, вполне успешно компилируются и запускаются, однако они не делают ничего полезного, если им заранее не обозначить задачу. А причина этого та же, что и в случае литературных текстов: для РНС язык программирования — не более чем стилизация, в которую они, к сожалению, не могут вложить никакого смысла.

«Генерация бреда» это забавно, но бессмысленно, а для каких настоящих задач применяются РНС?

Разумеется, РНС, помимо развлекательных, должны преследовать и более прагматичные цели. Из их дизайна автоматически следует, что главные области их применения должны быть требовательны к контексту и/или временной зависимости в данных, что по сути одно и то же. Поэтому РНС используются, к примеру, для анализа изображений. Казалось бы, эта область обычно воспринимается в контексте сверточных нейросетей, однако и для РНС здесь находятся задачи: их архитектура позволяет быстрее распознавать детали, основываясь на контексте и окружении. Аналогичным образом РНС работают в сферах анализа и генерации текстов. Из более необычных задач можно вспомнить попытки использовать ранние РНС для классификации углеродных спектров ядерного магнитного резонанса различных производных бензола, а из современных — анализ появления негативных отзывов о товарах.

А каковы успехи РНС в машинном переводе? В Google Translate ведь именно они используются?

На текущий момент в Google для машинного перевода используются РНС типа LSTM, что позволило добиться наибольшей точности по сравнению с существующими аналогами, однако, по словам самих авторов, машинному переводу еще очень далеко до уровня человека. Сложности, с которыми сталкиваются нейросети в задачах перевода, обусловлены сразу несколькими факторами: во-первых, в любой задаче существует неизбежный размен между качеством и скоростью. На данный момент человек очень сильно опережает искусственный интеллект по этому показателю. Поскольку машинный перевод чаще всего используется в онлайн-сервисах, разработчики вынуждены жертвовать точностью в угоду быстродействию. В недавней публикации Google на эту тему разработчики подробно описывают многие решения, которые позволили оптимизировать текущую версию Google Translate, однако проблема до сих пор остается. Например, редкие слова, или сленг, или нарочитое искажение слова (например, для более яркого заголовка) может сбить с толку даже переводчика-человека, которому придется потратить время, чтобы подобрать наиболее адекватный аналог в другом языке. Машину же такая ситуация поставит в полный тупик, и переводчик будет вынужден «выбросить» сложное слово и оставить его без перевода. В итоге проблема машинного перевода не настолько обусловлена архитектурой (РНС успешно справляются с рутинными задачами в этой области), насколько сложностью и многообразием языка. Радует то, что эта проблема имеет более технический характер, чем написание осмысленных текстов, где, вероятно, требуется кардинально новый подход.

Принцип работы машинного переводчика Google Translate, основанного на комбинации несколько рекуррентных нейросетей.

research.googleblog.com / Google

А более необычные способы применения РНС есть? Вот нейронная машина Тьюринга, например, в чем тут идея?

Нейронная машина Тьюринга (Neural Turing Machine), предложенная два года назад коллективом из Google DeepMind, отличается от других РНС тем, что последние на самом деле не хранят информацию в явном виде — она кодируется в весах нейронов и связей, даже в продвинутых вариациях вроде LSTM. В нейронной машине Тьюринга разработчики придерживались более понятной идеи «ленты памяти», как в классической машине Тьюринга: в ней информация в явном виде записывается «на ленту» и может быть считана в случае необходимости. При этом отслеживание того, какая информация нужна, ложится на особую нейросеть-контроллер. В целом можно отметить, что идея НМТ действительно завораживает своей простотой и доступностью для понимания. С другой стороны, в силу технических ограничений современного аппаратного обеспечения применить НМТ на практике не представляется возможным, потому что обучение такой сети становится чрезвычайно долгим. В этом смысле РНС являются промежуточным звеном между более простыми нейросетями и НМТ, так как хранят некий «слепок» информации, который при этом не смертельно ограничивает их быстродействие.

А что такое концепция внимания применительно к РНС? Что нового она позволяет делать?


Концепция внимания (attention) — это способ «подсказать» сети, на что следует потратить больше внимания при обработке данных. Другими словами, внимание в рекуррентной нейронной сети — это способ увеличить важность одних данных по сравнению с другими. Поскольку человек не может выдавать подсказки каждый раз (это нивелировало бы всю пользу от РНС), сеть должна научиться подсказывать себе сама. Вообще, концепция внимания является очень сильным инструментом в работе с РНС, так как позволяет быстрее и качественнее подсказать сети, на какие данные стоит обращать внимание, а на какие — нет. Также этот подход может в перспективе решить проблему быстродействия в системах с большим объемом памяти. Чтобы лучше понять, как это работает, надо рассмотреть две модели внимания: «мягкую» (soft) и «жесткую» (hard). В первом случае сеть все равно обратится ко всем данным, к которым имеет доступ, но значимость (то есть вес) этих данных будет разной. Это делает РНС более точной, но не более быстрой. Во втором случае из всех существующих данных сеть обратится лишь к некоторым (у остальных будут нулевые веса), что решает сразу две проблемы. Минусом «жесткой» концепции внимания является тот факт, что эта модель перестает быть непрерывной, а значит — дифференцируемой, что резко усложняет задачу ее обучения. Тем не менее, существуют решения, позволяющие исправить этот недостаток. Поскольку концепция внимания активно развивается в последние пару лет, нам остается ждать в ближайшее время новостей с этого поля.

Под конец можно привести пример системы, использующей концепцию внимания: это Dynamic Memory Networks — разновидность, предложенная исследовательским подразделением Facebook. В ней разработчики описывают «модуль эпизодической памяти» (episodic memory module), который на основании памяти о событиях, заданных в виде входных данных, а также вопроса об этих событиях, создает «эпизоды», которые в итоге помогают сети найти правильный ответ на вопрос. Такая архитектура была опробована на bAbI, крупной базе сгенерированных заданий на простой логический вывод (например, дается цепочка из трех фактов, нужно выдать правильный ответ: «Мэри дома. Она вышла во двор. Где Мэри? Во дворе».), и показала результаты, превосходящие классические архитектуры вроде LSTM.

Что еще происходит в мире рекуррентных нейросетей прямо сейчас?

По словам Андрея Карпатого (Andrej Karpathy) — специалиста по нейросетям и автора превосходного блога, «концепция внимания — это самое интересное из недавних архитектурных решений в мире нейросетей». Однако не только на внимании акцентируются исследования в области РНС. Если постараться кратко сформулировать основной тренд, то им сейчас стало сочетание различных архитектур и применение наработок из других областей для улучшения РНС. Из примеров можно назвать уже упомянутые нейросети от Google, в которых используют методы, взятые из работ по обучению с подкреплением, нейронные машины Тьюринга, алгоритмы оптимизации вроде Batch Normalization и многое другое, — все это вместе заслуживает отдельной статьи. В целом отметим, что хотя РНС не привлекли столь же широкого внимания, как любимцы публики — сверточные нейросети, это объясняется лишь тем, что объекты и задачи, с которыми работают РНС, не так бросаются в глаза, как DeepDream или Prisma. Это как в социальных сетях — если пост публикуют без картинки, ажиотажа вокруг него будет меньше.

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


Тарас Молотилин

Нейросеть за пять минут! Is it real?! – CODE BLOG

Добрый день, уважаемые читатели. Сатирический заголовок говорит о том, что сегодняшней темой станут нейронные сети, а точнее «алгоритм» их обучения. Ведь обучить нейросеть не значит создать класс модели и вызвать метод fit (sklearn) или заполнить её слоями (keras). Это значит предобработать данные, подобрать гиперпараметры, сохранить её для дальнейшего использования и многое другое. Сегодня мы и сделаем это, исключив подбор гиперпараметров модели, это я доверяю вам, чтобы добавить интерактива.

Будет полезным:

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.

А на моем YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Импорт

В качестве примера мы будем использовать обычную реализацию нейросети из sklearn.

In[1]:
import pandas as pd
import pandas_profiling as pprf
import numpy as np

from sklearn.externals import joblib
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import normaliz

Команды для установки пакетов:

pip install -U scikit-learn
pip install pandas
pip install numpy
pip install pandas_profiling

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

Предобработка (preprocessing) данных

In[2]:
path = r'E:\datasets\mlcourse\adult_data.csv'
df = pd.read_csv(path)
df.head()

Загрузим данные с помощью pandas, в частности функции read_csv.

Нам необходимо получше «узнать» датасет, чтобы продолжить с ним работу. В этом нам поможет профилирование.

In[3]:
profiler = pprf.ProfileReport(df)
profiler.to_file(r'C:\profiling.html')

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

У нас довольно много категориальных данных, которые мы будем кодировать с помощью One-Hot encoding.

Однако столбец education-num является кодированием меток из столбца education, потому он нам не нужен.

In[4]:
df = df.drop('education-num', axis=1)
df.head()

Также нам необходимо закодировать наш target — столбец salary. Для этого воспользуемся методом map класса Series. Он принимает словарь типа:

<value : coding>

Метод возвращает новый объект Series, потому следующая наша команда выглядит так:

In[5]:
df['salary'] = df['salary'].map({'<=50K': 0, '>50K': 1})
df.head()

По привычке, в качестве Out в Jupyter Notebook я выдаю первые 5 строк таблицы, дабы посмотреть, корректно ли сработала та или иная конструкция.

Далее нам необходимо закодировать категориальные переменные. Мы не будем делать это вручную: за нас это сделает функция get_dummies из библиотеки pandas.

In[6]:
df = pd.get_dummies(df)
df.values.shape

Out[6]:
(32561, 108)

Итого у нас получилось 108 столбцов — не так много, как могло казаться ранее. Теперь проверим информацию о таблице, чтобы точно убедиться, что всё верно.

In[7]:
df.info()

Out[7]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32561 entries, 0 to 32560
Columns: 108 entries, age to native-country_Yugoslavia
dtypes: int64(6), uint8(102)
memory usage: 4.7 MB

Отлично, мы имеем все столбцы в числовом виде, однако это ещё не всё.

Нам необходимо нормализировать данные: именно в таком виде лучше передавать числовые значения

Отделим нашу цель и образцы из общего набора:

In[8]:
y = df['salary']
del df['salary']
X = normalize(df.values)
X.shape, y.shape

Out[8]:
((32561, 107), (32561,))

Теперь же разделим данные на тренировочные и тестовые с помощью train_test_split:

In[9]:
X_train, X_test, y_train, y_test = train_test_split(X, 
                                                    y, 
                                                    test_size=0.2)
X_train.shape

Out[9]:
(26048, 107)

26 тысячи тренировочных образцов мы получили в итоге. Теперь начнём создавать наш классификатор.

Нейросеть (neural network)

In[10]:
nntw = MLPClassifier(activation='logistic', 
                     hidden_layer_sizes=100,
                     alpha=0.0001,
                     learning_rate_init=0.2,
                     shuffle=True,
                     max_iter=300)

100 скрытых слоёв, сигмоидальная функция активации, штраф L2-регуляризации в 0.0001, перемешивание и т.д. указываем при создании экземпляра класса. Далее обучаем модель:

In[11]:
nntw.fit(X_train, y_train)
nntw.score(X_test, y_test), nntw.score(X_train, y_train)

Out[11]:
(0.7868877629356671, 0.7953777641277642)

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

Недавно от меня была статья про консервацию объектов Python с помощью pickle и json. Однако сегодня мы будем использовать joblib — подмодуль sklearn для сохранения модели в бинарный файл и её загрузки в объект Python.

Программный интерфейс joblib, который нам необходим, такой же, как и у pickle:

In[12]:
with open(r'C:\model.pkl', 'wb') as f:
  joblib.dump(nntw, f) 
In[13]:
with open(r'C:\model.pkl', 'rb') as f:
  nntw = joblib.load(f)

nntw  

Out[13]:
MLPClassifier(activation='logistic', alpha=0.0001, batch_size='auto',
       beta_1=0.9, beta_2=0.999, early_stopping=False, epsilon=1e-08,
       hidden_layer_sizes=100, learning_rate='constant',
       learning_rate_init=0.2, max_iter=300, momentum=0.9,
       nesterovs_momentum=True, power_t=0.5, random_state=None,
       shuffle=True, solver='adam', tol=0.0001,validation_fraction=0.1,
       verbose=False, warm_start=False)

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

In[14]:
nntw.score(X_test, y_test), nntw.score(X_train, y_train)

Out[14]:
(0.7868877629356671, 0.7953777641277642)

Отлично, всё сходится.

Заключение

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

Документ .ipynb для полного его разбора вы можете найти здесь.

Также рекомендую прочитать статью Начальные функции NumPy. Подпишитесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для разработчиков.

Похожее

Что такое нейронная сеть?

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

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

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

Как нейронные сети обучаются

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

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

История нейронных сетей

Хотя нейронные сети, безусловно, представляют собой мощную современную компьютерную технологию, идея восходит к 1943 году, когда двое исследователей из Чикагского университета: нейрофизиолог Уоррен Маккалоу и математик Уолтер Питтс.

Их статья «Логическое исчисление идей, присущих нервной деятельности» была впервые опубликована в журнале Brain Theory , который популяризировал теорию о том, что активация нейрона является основной единицей мозговой активности. Однако эта статья была больше связана с развитием когнитивных теорий того времени, и два исследователя переехали в Массачусетский технологический институт в 1952 году, чтобы открыть первый отдел когнитивных наук.

Нейронные сети в 1950-х были плодородной областью для исследований компьютерных нейронных сетей, в том числе Perceptron , который выполнял распознавание визуальных образов на основе сложного глаза мухи.В 1959 году два исследователя из Стэнфордского университета разработали MADALINE (Multiple ADAptive LINear Elements) с нейронной сетью, выходящей за рамки теоретической и решающей реальную проблему. MADALINE был специально применен для уменьшения количества эха в телефонной линии, для повышения качества голоса и оказался настолько успешным, что до сих пор используется в коммерческих целях.

Несмотря на первоначальный энтузиазм в области искусственных нейронных сетей, заслуживающая внимания книга 1969 года из Массачусетского технологического института « Персептроны: введение в вычислительную геометрию » смягчила это.Авторы выразили скептицизм по поводу искусственных нейронных сетей и того, что это, вероятно, тупик в поисках настоящего искусственного интеллекта. Это значительно притупило эту область исследований на протяжении 1970-х годов как в плане общего интереса, так и в плане финансирования. Несмотря на это, некоторые усилия все же продолжались, и в 1975 году была разработана первая многослойная сеть, открывшая путь для дальнейшего развития нейронных сетей, достижение, которое некоторые считали невозможным менее десяти лет назад.

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

Использование нейронных сетей в реальном мире

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

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

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

Нейронные сети и глубокое обучение

Зрительная система человека — одно из чудес света.Рассмотреть возможность следующая последовательность рукописных цифр:

Большинство людей легко распознают эти цифры как 504192. Эта простота обманчиво. В каждом полушарии нашего мозга у человека есть основная зрительная кора, также известная как V1, содержащая 140 миллионов нейронов, с десятки миллиардов связей между ними. И все же человеческое видение включает не только V1, но и целую серию зрительных кортик — V2, V3, V4 и V5 — выполнение все более сложной обработки изображений.Мы несем в голове суперкомпьютер, настроенный эволюцией над сотни миллионов лет и прекрасно приспособлены для понимания визуальный мир. Распознать рукописные цифры непросто. Скорее мы люди изумительно, поразительно хороши в понимании того, что глаза показывают нам. Но почти вся эта работа выполняется бессознательно. Так что мы обычно не понимаем, насколько серьезна проблема наших зрительных систем решить.

Сложность распознавания визуальных образов становится очевидной, если вы попытаться написать компьютерную программу для распознавания таких цифр над.То, что кажется простым, когда мы делаем это сами, внезапно становится крайне сложно. Простая интуиция о том, как мы распознаем формы — «9 имеет петлю вверху и вертикальную черту внизу. правильно »- оказывается, не так-то просто алгоритмически выразить. Когда вы пытаетесь уточнить такие правила, вы быстро теряетесь в болото исключений, предостережений и особых случаев. Это выглядит безнадежно.

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

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

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

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

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

Персептроны

Что такое нейронная сеть? Для начала я объясню тип Искусственный нейрон называется персептроном . Персептроны были развитый в 1950-х и 1960-х годах ученым Фрэнк Розенблатт, вдохновленный более ранним Работа Уоррен Маккаллох и Уолтер Питтс.Сегодня более распространено использование других модели искусственных нейронов — в этой книге и во многих современных работах в нейронных сетях используется основная модель нейрона, называемая сигмовидный нейрон . Вскоре мы перейдем к сигмовидным нейронам. Но понять, почему сигмовидные нейроны определены именно так, это стоит потратить время, чтобы сначала понять перцептроны.

Так как же работают перцептроны? Персептрон принимает несколько двоичных входов, $ x_1, x_2, \ ldots $ и производит один двоичный вывод:

В показанном примере перцептрон имеет три входа: $ x_1, x_2, x_3 $.В общем, входов может быть больше или меньше. Розенблатт предложил простое правило для вычисления вывода. Он представил веса , $ w_1, w_2, \ ldots $, действительные числа выражая важность соответствующих входов для выхода. В выход нейрона, $ 0 $ или $ 1 $, определяется тем, является ли взвешенная сумма $ \ sum_j w_j x_j $ меньше или больше порогового значения значение . Как и веса, Порог — это действительное число, которое является параметром нейрона. Класть это в более точных алгебраических терминах: \ begin {eqnarray} \ mbox {output} & = & \ left \ {\ begin {array} {ll} 0 & \ mbox {if} \ sum_j w_j x_j \ leq \ mbox {threshold} \\ 1 & \ mbox {if} \ sum_j w_j x_j> \ mbox {порог} \ end {array} \ right.\ tag {1} \ end {eqnarray} Вот и все, как работает перцептрон!

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

  1. Погода хорошая?
  2. Твой парень или девушка хочет тебя сопровождать?
  3. Находится ли фестиваль рядом с остановками общественного транспорта? (У вас нет машины).
Мы можем представить эти три фактора соответствующими двоичными переменными $ x_1, x_2 $ и $ x_3 $. Например, у нас было бы $ x_1 = 1 $, если бы погода хорошая, и $ x_1 = 0 $, если погода плохая. Аналогично $ x_2 = 1 $, если ваш парень или девушка хочет уйти, и $ x_2 = 0 $, если не.И снова аналогично для $ x_3 $ и общественного транспорта.

А теперь предположим, что вы абсолютно обожаете сыр, настолько, что вы счастливы пойти на фестиваль, даже если твой парень или девушка неинтересно, и до фестиваля трудно добраться. Но возможно ты действительно ненавижу плохую погоду, и ты ни за что не пойдешь на фестиваль если погода плохая. Вы можете использовать перцептроны для моделирования такого рода принятие решений. Один из способов сделать это — выбрать вес $ w_1 = 6 $. для погоды и $ w_2 = 2 $ и $ w_3 = 2 $ для других условий.Большее значение $ w_1 $ указывает на то, что погода имеет большое значение для вы, гораздо больше, чем то, присоединится ли к вам ваш парень или девушка, или близость общественного транспорта. Наконец, предположим, что вы выбрали порог 5 $ для перцептрона. С этим выбором перцептрон реализует желаемую модель принятия решений, выводя 1 доллар в хорошую погоду и 0 долларов в плохую. Не имеет значения, будет ли ваш парень или подруга хочет поехать, ни то рядом общественный транспорт.

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

Очевидно, перцептрон не является полной моделью человека. принятие решений! Но пример показывает, как перцептрон может взвесить различные доказательства для принятия решений. И должно казаться правдоподобным, что сложная сеть перцептронов мог принимать довольно тонкие решения:

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

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

Давайте упростим описание перцептронов. Условие $ \ sum_j w_j x_j> \ mbox {threshold} $ громоздко, и мы можем сделать два изменения обозначений, чтобы упростить его.Первое изменение — написать $ \ sum_j w_j x_j $ как скалярное произведение, $ w \ cdot x \ Equiv \ sum_j w_j x_j $, где $ w $ и $ x $ — векторы, компоненты которых являются весами и входы соответственно. Второе изменение — переместить порог на другая сторона неравенства, и заменить ее тем, что известно как смещение персептрона , $ b \ эквив. — \ mbox {threshold} $. Используя смещение вместо порога, правило перцептрона может быть переписано: \ begin {eqnarray} \ mbox {output} = \ left \ { \ begin {array} {ll} 0 & \ mbox {if} w \ cdot x + b \ leq 0 \\ 1 & \ mbox {if} w \ cdot x + b> 0 \ end {массив} \верно.\ tag {2} \ end {eqnarray} Вы можете рассматривать предвзятость как меру того, насколько легко получить персептрон для вывода 1 $. Или, говоря более биологическим языком, смещение — это мера того, насколько легко перцептрон пожар . Для перцептрона с действительно большим уклоном это чрезвычайно перцептрону легко выдать 1 доллар. Но если предвзятость очень отрицательный, то перцептрону сложно выдать 1 доллар. Очевидно, что введение предвзятости — это лишь небольшое изменение в том, как мы описывают перцептроны, но позже мы увидим, что это ведет к дальнейшим условные упрощения.Из-за этого в оставшейся части книга мы не будем использовать порог, мы всегда будем использовать смещение.

Я описал перцептроны как метод взвешивания доказательств для получения решения. Другой способ использования перцептронов — вычисление элементарные логические функции, которые мы обычно считаем лежащими в основе вычисление, такие функции, как И , ИЛИ и НЕИ . Например, предположим, что у нас есть перцептрон с двумя входные данные, каждый с весом -2 доллара и общим смещением 3 доллара.Вот наш перцептрон:

Затем мы видим, что вход $ 00 $ дает выход $ 1 $, поскольку $ (- 2) * 0 + (- 2) * 0 + 3 = 3 $ положительно. Здесь я ввел $ * $ символ, чтобы сделать умножение явным. Подобные расчеты показывают, что входы $ 01 $ и $ 10 $ дают выход $ 1 $. Но вход $ 11 $ производит вывод $ 0 $, так как $ (- 2) * 1 + (- 2) * 1 + 3 = -1 $ отрицательно. Итак, наш перцептрон реализует NAND Ворота!

Пример NAND показывает, что мы можем использовать перцептроны для вычисления простые логические функции.Фактически, мы можем использовать сети перцептронов для вычисления любой логической функции вообще. Причина в том, что шлюз NAND универсален для вычисление, то есть мы можем построить любое вычисление из NAND ворот. Например, мы можем использовать ворота NAND для построить схему, которая складывает два бита, $ x_1 $ и $ x_2 $. Это требует вычисление побитовой суммы, $ x_1 \ oplus x_2 $, а также бит переноса который устанавливается в $ 1 $, когда и $ x_1 $, и $ x_2 $ равны $ 1 $, i.е., перенос bit — это просто побитовое произведение $ x_1 x_2 $:

Чтобы получить эквивалентную сеть перцептронов, заменим все NAND вентили перцептронами с двумя входами, каждый с весом -2 доллара, а общая систематическая ошибка — 3 доллара. Вот получившаяся сеть. Заметка что я переместил перцептрон в правый нижний угол NAND калитка немного, просто чтоб стрелки было проще рисовать на схеме: Одним из примечательных аспектов этой сети перцептронов является то, что на выходе от крайнего левого перцептрона используется дважды как вход до самого нижнего перцептрон.Когда я определил модель перцептрона, я не сказал, такой вид двойного вывода в одно и то же место был разрешен. Фактически, это не имеет большого значения. Если мы не хотим этого допустить, тогда можно просто объединить две строки в одну соединение с весом -4 вместо двух соединений с -2 веса. (Если вы не находите это очевидным, вам следует остановиться и доказать себе, что это эквивалентно.) С этим изменением сеть выглядит следующим образом: все немаркированные веса равны -2, все смещения равный 3, и единичный вес -4, как отмечено: До сих пор я рисовал входные данные, такие как $ x_1 $ и $ x_2 $, как переменные. плавающий слева от сети перцептронов.На самом деле это обычный для рисования дополнительного слоя перцептронов — вход слой — для кодирования входов: Это обозначение для входных перцептронов, в которых у нас есть выход, но нет входов, это сокращение. На самом деле это не означает перцептрон без входов. Чтобы убедиться в этом, предположим, что у нас есть перцептрон без входов. затем взвешенная сумма $ \ sum_j w_j x_j $ всегда будет равна нулю, и поэтому перцептрон выдаст $ 1 $, если $ b> 0 $, и $ 0 $, если $ b \ leq 0 $. Что то есть перцептрон просто выводит фиксированное значение, а не желаемое. значение ($ x_1 $ в примере выше).Лучше подумать о вводить перцептроны как не совсем перцептроны, а скорее специальные единицы, которые просто определены для вывода желаемых значений, $ x_1, x_2, \ ldots $.

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

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

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

Сигмовидные нейроны

Алгоритмы обучения звучат потрясающе.Но как мы можем придумать такие алгоритмы для нейронной сети? Предположим, у нас есть сеть перцептроны, которые мы хотели бы использовать, чтобы научиться решать некоторые проблемы. За Например, входами в сеть могут быть необработанные данные пикселей из отсканированное рукописное изображение цифры. И мы бы хотели, чтобы сеть узнать веса и смещения, чтобы вывод из сети правильно классифицирует цифру. Чтобы увидеть, как может работать обучение, предположим, что мы делаем небольшое изменение веса (или предвзятости) в сети.Что мы как если бы это небольшое изменение веса вызвало лишь небольшое соответствующее изменение выхода из сети. Как мы увидим в мгновение, это свойство сделает обучение возможным. Схематично, вот что мы хотим (очевидно, что эта сеть слишком проста для распознавание почерка!):

Если бы это правда, что небольшое изменение веса (или смещения) вызывает только небольшое изменение вывода, то мы могли бы использовать этот факт для изменения весов и предубеждений, чтобы заставить нашу сеть вести себя так, как мы хотеть.Например, предположим, что сеть по ошибке классифицирует изображение как «8», когда оно должно быть «9». Мы могли понять, как внести небольшое изменение в веса и смещения, чтобы сеть получила Немного ближе к отнесению изображения к «9». А потом мы повторяйте это, снова и снова меняя веса и смещения, чтобы получить все лучше и лучше. Сеть будет учиться.

Проблема в том, что этого не происходит, когда наша сеть содержит перцептроны.Фактически, небольшое изменение весов или смещения любого один персептрон в сети может иногда вызывать выход этот перцептрон полностью перевернуть, скажем, с 0 долларов на 1 доллар. Этот флип может затем привести к тому, что поведение остальной сети полностью изменится. изменить очень сложным образом. Итак, пока ваша цифра 9 может быть классифицировано правильно, поведение сети на всех остальных изображения, вероятно, полностью изменились в некоторых трудноуправляемых путь. Это затрудняет понимание того, как постепенно изменять веса и смещения, чтобы сеть приближалась к желаемому поведение.Возможно, есть какой-нибудь умный способ обойти это проблема. Но не сразу очевидно, как мы можем получить сеть перцептроны, чтобы учиться.

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

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

Подобно перцептрону, сигмовидный нейрон имеет входы, $ x_1, x_2, \ ldots $. Но вместо того, чтобы быть просто 0 или 1 долларом, эти входные данные также могут принимает любые значения от $ 0 $ до 1 $. Так, например, $ 0.638 \ ldots $ — допустимый вход для сигмовидного нейрона. Также как и перцептрон, сигмовидный нейрон имеет веса для каждого входа, $ w_1, w_2, \ ldots $ и общий уклон $ b $. {- z}}.\ tag {3} \ end {eqnarray} Проще говоря, выход сигмовидного нейрона с входами $ x_1, x_2, \ ldots $, весами $ w_1, w_2, \ ldots $ и смещением $ b $ \ begin {eqnarray} \ frac {1} {1+ \ exp (- \ sum_j w_j x_j-b)}. \ tag {4} \ end {eqnarray}

На первый взгляд сигмовидные нейроны сильно отличаются от перцептронов. Алгебраическая форма сигмовидной функции может показаться непрозрачной и непрозрачной. запрещающий, если вы еще не знакомы с этим. На самом деле есть много общего между перцептронами и сигмовидными нейронами, и алгебраическая форма сигмовидной функции оказывается больше технические детали, чем настоящий барьер для понимания.{-z} \ rightarrow \ infty $ и $ \ sigma (z) \ приблизительно 0 $. Так когда $ z = w \ cdot x + b $ очень негативно, поведение сигмовидного нейрона также очень похож на перцептрон. Только когда $ w \ cdot x + b $ имеет скромный размер, что сильно отклоняется от перцептрона модель.

А как насчет алгебраической формы $ \ sigma $? Как мы можем понять что? На самом деле, точный вид $ \ sigma $ не так важен — какой действительно имеет значение форма функции при построении графика.Вот форма:

Эта форма представляет собой сглаженную версию ступенчатой ​​функции:

Если бы $ \ sigma $ на самом деле была ступенчатой ​​функцией, то сигмовидный нейрон будет персептроном, так как на выходе будет 1 доллар или 0 долларов в зависимости от того, было ли $ w \ cdot x + b $ положительным или отрицательный * * На самом деле, когда $ w \ cdot x + b = 0 $, перцептрон выводит $ 0 $, а пошаговая функция выводит $ 1 $. Итак, строго говоря, нам нужно будет изменить пошаговую функцию именно в этот момент.Но вы поняли идею … Используя фактическую функцию $ \ sigma $, мы получить, как уже говорилось выше, сглаженный перцептрон. На самом деле, решающим моментом является гладкость функции $ \ sigma $, не его подробная форма. Гладкость $ \ sigma $ означает, что малые изменяет $ \ Delta w_j $ в весах и $ \ Delta b $ в смещении будет произвести небольшое изменение $ \ Delta \ mbox {output} $ в выводе из нейрон. Фактически, исчисление говорит нам, что $ \ Delta \ mbox {output} $ — это хорошо приближается \ begin {eqnarray} \ Delta \ mbox {output} \ приблизительно \ sum_j \ frac {\ partial \, \ mbox {output}} {\ partial w_j} \ Delta w_j + \ frac {\ partial \, \ mbox {output}} {\ partial b} \ Delta b, \ tag {5} \ end {eqnarray} где сумма берется по всем весам, $ w_j $ и $ \ partial \, \ mbox {output} / \ partial w_j $ и $ \ partial \, \ mbox {output} / \ partial b $ обозначают частные производные $ \ mbox {output} $ по $ w_j $ и $ b $ соответственно.Не паникуйте, если вам неудобно с частными производными! Хотя выражение выше выглядит сложно, со всеми частными производными, на самом деле он говорит что-то очень простое (и это очень хорошие новости): $ \ Delta \ mbox {output} $ — это линейная функция изменений $ \ Delta w_j $ и $ \ Delta b $ в весах и смещении. Эта линейность позволяет легко выбирать небольшие изменения весов и смещений для достижения любых желаемое небольшое изменение на выходе.{-z}} \ nonumber \ end {eqnarray}? Фактически, позже в книге мы иногда рассматривают нейроны с выходом $ f (w \ cdot x + b) $ для некоторых других функций активации $ f (\ cdot) $. Главное что меняется, когда мы используем другую функцию активации, заключается в том, что частные значения частных производных в Уравнение (5) \ begin {eqnarray} \ Delta \ mbox {output} \ приблизительно \ sum_j \ frac {\ partial \, \ mbox {output}} {\ partial w_j} \ Delta w_j + \ frac {\ partial \, \ mbox {output}} {\ partial b} \ Delta b \ nonumber \ end {eqnarray} изменение.Оказывается, когда мы вычислить эти частные производные позже, использование $ \ sigma $ упростит алгебру просто потому, что экспоненты обладают прекрасными свойствами, когда дифференцированный. В любом случае $ \ sigma $ обычно используется в работе над нейронные сети, и это функция активации, которую мы будем чаще всего использовать в эта книга.

Как мы должны интерпретировать выходной сигнал сигмовидного нейрона? Очевидно, одно большое различие между перцептронами и сигмовидными нейронами состоит в том, что сигмовидные нейроны не просто выводят 0 или 1 доллар.Они могут иметь на выходе любое действительное число от $ 0 $ до $ 1 $, поэтому такие значения, как $ 0.173 \ ldots $ и $ 0.689 \ ldots $ являются допустимыми выходными данными. Это может быть полезно для Например, если мы хотим использовать выходное значение для представления среднего интенсивность пикселей в изображении, вводимом в нейронную сеть. Но иногда это может быть неприятно. Предположим, нам нужен вывод сеть, чтобы указать либо «входное изображение — 9», либо «входное изображение не 9 «. Очевидно, было бы проще сделать это, если бы выход был 0 или 1 доллар, как в перцептроне.Но на практике мы можем создать соглашение, чтобы справиться с этим, например, решив интерпретировать любой результат на сумму не менее 0,5 доллара США как цифру «9», а любой вывод менее 0,5 доллара США, что означает «не 9». Я всегда явно указать, когда мы используем такое соглашение, поэтому не следует вызвать путаницу.

Упражнения
  • Сигмовидные нейроны, моделирующие перцептроны, часть I $ \ mbox {} $
    Предположим, мы берем все веса и смещения в сети перцептроны, и умножьте их на положительную константу, $ c> 0 $.Покажите, что поведение сети не меняется.
  • Сигмовидные нейроны, имитирующие перцептроны, часть II $ \ mbox {} $
    Предположим, у нас есть та же установка, что и в последней задаче — сеть перцептронов. Предположим также, что общий вход в выбрана сеть перцептронов. Нам не понадобятся настоящие входное значение, нам просто нужно, чтобы вход был исправлен. Предположим, что веса и смещения таковы, что $ w \ cdot x + b \ neq 0 $ для введите $ x $ в любой конкретный перцептрон в сети.Теперь замените все перцептроны в сети сигмовидными нейронами и умножаются веса и смещения на положительную константу $ c> 0 $. Показать это в предел как $ c \ rightarrow \ infty $ поведение этой сети сигмовидные нейроны точно такие же, как сеть перцептронов. Как это может потерпеть неудачу, если $ w \ cdot x + b = 0 $ для одного из перцептроны?

Архитектура нейронных сетей

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

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

Дизайн входных и выходных слоев в сети часто просто. Например, предположим, что мы пытаемся определить отображается ли на рукописном изображении цифра «9» или нет. Естественный способ дизайн сети заключается в кодировании интенсивности пикселей изображения во входные нейроны. Если изображение имеет оттенки серого 64 $ на 64 $ изображения, то у нас будет $ 4096 = 64 \ times 64 $ входных нейронов, с интенсивность соответствующим образом масштабировалась от 0 до 1 доллара.Выход слой будет содержать только один нейрон, с выходными значениями меньше чем $ 0,5 $, что означает «входное изображение не 9», и значения больше чем $ 0,5 $, что означает «входное изображение — 9».

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

До сих пор мы обсуждали нейронные сети, в которых вывод один слой используется как вход для следующего слоя.Такие сети называется прямой связи нейронные сети. Это означает, что в сети нет петель — информация всегда поступает вперед и никогда не возвращается. Если бы у нас было циклов, мы получим ситуации, когда вход в $ \ sigma $ функция зависела от вывода. Это было бы трудно понять, и поэтому мы не допускаем таких петель.

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

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

Простая сеть для классификации рукописных цифр

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

на шесть отдельных изображений,

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

, равна 5.

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

Для распознавания отдельных цифр мы будем использовать трехслойный нейронный сеть:

Входной слой сети содержит нейроны, кодирующие значения входные пиксели. Как обсуждается в следующем разделе, наши обучающие данные для сети будет состоять из множества изображений размером $ 28 на $ 28 пикселей отсканированные рукописные цифры, поэтому входной слой содержит 784 доллара = 28 \ times 28 $ нейронов. Для простоты я опустил большую часть 784 $. входные нейроны на диаграмме выше.Входные пиксели имеют оттенки серого, со значением 0,0 $ представляет белый цвет, значение 1,0 $ представляет черный цвет, а промежуточные значения представляют постепенно затемняющие оттенки серого.

Второй уровень сети является скрытым. Обозначим количество нейронов в этом скрытом слое на $ n $, и мы будем экспериментировать с разными значениями для $ n $. Показанный пример иллюстрирует небольшой скрытый слой, содержащий всего $ n = 15 $ нейронов.

Выходной слой сети содержит 10 нейронов.Если первый нейрон срабатывает, т.е. имеет выход $ \ приблизительно 1 $, тогда это будет указывать что сеть считает цифру равной 0 долларов. Если второй нейрон срабатывает, что указывает на то, что сеть считает цифру $ 1 $. И так далее. Чуть точнее нумеруем выход нейронов от $ 0 $ до $ 9 $, и выясните, какой нейрон имеет максимальное значение активации. Если этот нейрон, скажем, нейрон номер $ 6 $, тогда наша сеть угадает, что введенная цифра была 6 долларов.4 = 16 $ больше 10 возможных значений входной цифры. Почему вместо этого наша сеть должна использовать нейроны за 10 долларов? Разве это не неэффективно? Окончательное обоснование эмпирическое: мы можем попробовать обе схемы сети, и оказывается, что для этой конкретной проблема, сеть с выходными нейронами за $ 10 учится распознавать цифр лучше, чем сеть с выходными нейронами по $ 4 $. Но затем заставляет задуматься о том, что , почему с выходными нейронами за 10 долларов работает лучше. Есть ли какая-то эвристика, которая заранее скажет нам, что мы должны использовать кодировку $ 10 $ -output вместо кодировки $ 4 $ -output?

Чтобы понять, почему мы это делаем, полезно подумать о том, что сеть делает из первых принципов.Рассмотрим сначала случай, когда мы используем выходные нейроны по $ 10 $. Сконцентрируемся на первом выходе нейрон, тот, который пытается решить, является ли цифра $ 0 $. Он делает это, взвешивая доказательства из скрытого слоя нейроны. Что делают эти скрытые нейроны? Ну, просто предположим ради аргумента, что первый нейрон в скрытом слое обнаруживает присутствует ли изображение, подобное приведенному ниже:

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

Как вы уже догадались, эти четыре изображения вместе составляют $ 0 $ изображение, которое мы видели в строке цифр, показанной ранее:

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

Предполагая, что нейронная сеть функционирует таким образом, мы можем дать правдоподобное объяснение того, почему лучше получать 10 долларов от сеть, а не 4 $. Если бы у нас было 4 доллара на выходе, то первый выходной нейрон будет пытаться решить, какой самый старший бит цифры было. И нет простого способа связать это значащий бит для простых форм, подобных показанным выше.Это трудно представьте, что существует какая-то веская историческая причина, по которой компонент формирует цифры будут тесно связаны (скажем) со старшим битом на выходе.

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

Exercise
  • Существует способ определения побитового представления цифру, добавив дополнительный уровень к трехуровневой сети выше. Дополнительный слой преобразует результат предыдущего слоя в двоичное представление, как показано на рисунке ниже. Найди набор весов и смещений для нового выходного слоя.Предположим, что первые $ 3 $ слоя нейронов таковы, что правильный выход в третий слой (то есть старый выходной слой) имеет активацию как минимум 0,99 доллара США, а активация неправильных выходов меньше 0,01 доллара США.

Обучение с градиентным спуском

Теперь, когда у нас есть дизайн для нашей нейронной сети, как она может научиться распознать цифры? Первое, что нам понадобится, это набор данных для изучения from — так называемый обучающий набор данных. Мы будем использовать MNIST набор данных, содержащий десятки тысяч отсканированных изображений рукописные цифры вместе с их правильной классификацией.Название MNIST происходит от того факта, что это модифицированное подмножество двух наборы данных, собранные NIST, Национальный институт стандартов США и Технологии. Вот несколько изображений из MNIST:

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

Данные MNIST состоят из двух частей.Первая часть содержит 60 000 изображения, которые будут использоваться в качестве обучающих данных. Эти изображения отсканированы образцы почерка от 250 человек, половина из которых были переписаны США Сотрудники бюро, половина из которых были старшеклассниками. В изображения имеют оттенки серого и имеют размер 28 на 28 пикселей. Вторая часть набор данных MNIST составляет 10 000 изображений, которые будут использоваться в качестве тестовых данных. Еще раз, это 28 на 28 изображений в оттенках серого. Мы будем использовать тестовые данные для оценить, насколько хорошо наша нейронная сеть научилась распознавать цифры.Чтобы сделать этот тест производительности хорошим, тестовые данные были взяты из другой набор из 250 человек, чем исходные данные обучения (хотя по-прежнему существует разделение на сотрудников Бюро переписи населения и школьники). Это дает нам уверенность в том, что наша система может распознавать цифры от людей, чьи записи он не видел во время обучение.

Мы будем использовать обозначение $ x $ для обозначения обучающего ввода. Это будет удобно рассматривать каждый обучающий вход $ x $ как $ 28 \ times 28 = 784 $ -мерный вектор.T $ — желаемый результат сеть. Обратите внимание, что $ T $ здесь — операция транспонирования, вектор-строку в обычный вектор (столбец).

Нам нужен алгоритм, который позволяет нам находить веса и смещения так что выход из сети приблизительно равен $ y (x) $ для всех учебные ресурсы $ x $. Чтобы количественно оценить, насколько хорошо мы достигаем этой цели мы определяем функцию стоимости * * Иногда упоминается как потеря или цель функция.2. \ tag {6} \ end {eqnarray} Здесь $ w $ обозначает набор всех весов в сети, $ b $ все смещения, $ n $ — общее количество обучающих входов, $ a $ — вектор выходов из сети при вводе $ x $, а сумма равна по всем обучающим входам $ x $. Конечно, результат $ a $ зависит от $ x $, $ w $ и $ b $, но для простоты обозначений я явно не указал на эту зависимость. Обозначение $ \ | v \ | $ просто обозначает обычная функция длины для вектора $ v $.Мы назовем $ C $ квадратичная функция стоимости ; это также иногда известная как ошибка среднего квадрата или просто MSE . Рассматривая форму квадратичной функции стоимости, мы видим, что $ C (w, b) $ неотрицательно, так как каждый член в сумме неотрицателен. Кроме того, стоимость $ C (w, b) $ становится малой, т.е. $ C (w, b) \ приблизительно 0 $, именно тогда, когда $ y (x) $ приблизительно равно выходу, $ a $, для всех обучающих входов $ x $. Итак, наш алгоритм обучения выполнил хорошая работа, если он может найти веса и смещения так, чтобы $ C (w, b) \ приблизительно 0 $.Напротив, это не так хорошо, когда $ C (w, b) $ велико — это будет означать, что $ y (x) $ не близок к выходу $ a $ для большого количество входов. Итак, цель нашего алгоритма обучения будет заключаться в том, чтобы минимизировать стоимость $ C (w, b) $ как функцию весов и смещений. Другими словами, мы хотим найти набор весов и смещений, которые делают стоимость как можно меньше. Мы сделаем это, используя известный алгоритм как градиентный спуск .

Зачем вводить квадратичную стоимость? В конце концов, разве мы не в первую очередь интересует количество изображений, правильно классифицированных сеть? Почему бы не попытаться увеличить это число напрямую, а не минимизировать косвенный показатель, такой как квадратичная стоимость? Проблема с то есть количество правильно классифицированных изображений не является гладким функция весов и смещений в сети.По большей части, внесение небольших изменений в веса и смещения не вызовет никаких изменений вообще по количеству тренировочных образов классифицированных правильно. Что затрудняет понимание того, как изменить веса и смещения для повышения производительности. Если вместо этого использовать гладкую функцию стоимости как и квадратичная стоимость, оказывается легко выяснить, как внести небольшие изменения в веса и смещения, чтобы получить улучшение стоимости. Вот почему мы в первую очередь сосредотачиваемся на минимизации квадратичная стоимость, и только после этого мы рассмотрим классификацию точность.2 \ nonumber \ end {eqnarray} отлично работает для понимание основ обучения в нейронных сетях, поэтому мы придерживайся этого пока.

Напомним, наша цель при обучении нейронной сети — найти веса и смещения, которые минимизируют квадратичную функцию стоимости $ C (w, b) $. Этот хорошо поставленная задача, но в ней много отвлекающей структуры в нынешней постановке — интерпретация $ w $ и $ b $ как весов и смещения, скрывающаяся в фоновом режиме функция $ \ sigma $, выбор сетевой архитектуры, MNIST и т. д.Оказывается, что мы можем понять огромное количество, игнорируя большую часть этого структура, и просто сосредоточившись на аспекте минимизации. Таким образом, для Теперь мы забудем про конкретную форму стоимости функция, подключение к нейронным сетям и т. д. Вместо, мы собираемся представить, что нам просто дали функцию многих переменные, и мы хотим минимизировать эту функцию. Шли в разработать метод под названием градиентный спуск , который можно использовать для решения таких задач минимизации.Тогда мы вернемся к конкретная функция, которую мы хотим минимизировать для нейронных сетей.

Хорошо, предположим, мы пытаемся минимизировать некоторую функцию, $ C (v) $. Это может быть любая действительная функция многих переменных, $ v = v_1, v_2, \ ldots $. Обратите внимание, что я заменил обозначения $ w $ и $ b $ на $ v $ чтобы подчеркнуть, что это может быть любая функция — мы не больше не думать конкретно в контексте нейронных сетей. Чтобы минимизировать $ C (v) $, это помогает представить $ C $ как функцию всего двух переменные, которые мы назовем $ v_1 $ и $ v_2 $:

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

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

(После утверждения, что мы получим понимание, представив $ C $ как функция всего двух переменных, я дважды перевернул абзацев и сказал: «Эй, а что, если это функция многих других чем две переменные? »Извините за это.Пожалуйста, поверьте мне, когда я говорю что действительно помогает представить $ C $ как функцию двух переменные. Просто так бывает, что картина иногда ломается, и последние два абзаца были посвящены таким поломкам. Хороший размышления о математике часто связаны с манипуляциями с несколькими интуитивными картинки, узнавая, когда уместно использовать каждую картинку, а когда это не так.)

Хорошо, значит, исчисление не работает. К счастью, есть красивый аналогия, которая предлагает алгоритм, который работает довольно хорошо.Мы начинаем считая нашу функцию своего рода долиной. Если ты прищуришься просто немного на сюжете выше, это не должно быть слишком сложно. И мы Представьте себе мяч, катящийся по склону долины. Наши повседневные опыт подсказывает нам, что мяч в конечном итоге катится ко дну долины. Возможно, мы сможем использовать эту идею как способ найти минимум для функции? Мы бы случайно выбрали отправную точку для (воображаемый) мяч, а затем смоделировать движение мяча, когда он скатился на дно долины.Мы могли бы сделать это моделирование просто вычисляя производные (и, возможно, некоторые вторые производные) $ C $ — эти производные сообщат нам все, что нам нужно знать о местной «форме» долины и, следовательно, о том, как наш мяч должен катиться.

На основании того, что я только что написал, можно предположить, что мы будем пытаясь записать уравнения движения Ньютона для мяча, учитывая влияние трения и силы тяжести и так далее. Фактически, мы не собираемся относиться к аналогии с мячом так серьезно — мы разрабатываем алгоритм минимизации $ C $, а не разрабатываем точное моделирование законов физики! Взгляд мяча предназначен для стимулирования нашего воображения, а не для ограничения нашего мышления.Так вместо того, чтобы вдаваться во все беспорядочные детали физики, давайте просто спросите себя: если бы мы были объявлены Богом на один день и могли бы помириться наши собственные законы физики, диктующие мячу, как он должен катиться, какой закон или законы движения мы могли бы выбрать, чтобы мяч всегда катился на дно долины?

Чтобы уточнить этот вопрос, давайте подумаем, что происходит когда мы перемещаем мяч на небольшую сумму $ \ Delta v_1 $ в $ v_1 $ направление, и небольшая сумма $ \ Delta v_2 $ в направлении $ v_2 $. T $, где $ T $ снова операция транспонирования, превращающая векторы-строки в векторы-столбцы.Т. \ tag {8} \ end {eqnarray} Сейчас мы перепишем замену $ \ Delta C $ в терминах $ \ Delta v $. и градиент $ \ nabla C $. Но прежде чем перейти к этому, я хочу чтобы прояснить то, что иногда заставляет людей зацикливаться на градиент. При первом знакомстве с обозначением $ \ nabla C $, люди иногда задаются вопросом, как они должны думать о $ \ nabla $ символ. Что именно означает $ \ nabla $? На самом деле это прекрасно нормально думать о $ \ nabla C $ как об одном математическом объекте — вектор, определенный выше, который записывается с использованием двух символы.С этой точки зрения $ \ nabla $ — это всего лишь кусок обозначение размахивания флагом, говорящее «эй, $ \ nabla C $ это градиент вектор «. Есть более продвинутые точки зрения, в которых $ \ nabla $ может рассматриваться как самостоятельный математический объект (для пример, как дифференциальный оператор), но нам не понадобятся такие точки Посмотреть.

С этими определениями выражение (7) \ begin {eqnarray} \ Delta C \ приблизительно \ frac {\ partial C} {\ partial v_1} \ Delta v_1 + \ frac {\ partial C} {\ partial v_2} \ Delta v_2 \ nonumber \ end {eqnarray} для $ \ Delta C $ можно переписать как \ begin {eqnarray} \ Delta C \ приблизительно \ набла C \ cdot \ Delta v.\ tag {9} \ end {eqnarray} Это уравнение помогает объяснить, почему $ \ nabla C $ называется градиентом vector: $ \ nabla C $ связывает изменения в $ v $ с изменениями в $ C $, так же как мы ожидаем чего-то, что называется градиентом. Но что на самом деле В уравнении интересно то, что оно позволяет нам увидеть, как выбрать $ \ Delta v $, чтобы сделать $ \ Delta C $ отрицательным. В частности, предположим мы выбираем \ begin {eqnarray} \ Delta v = — \ eta \ nabla C, \ tag {10} \ end {eqnarray} где $ \ eta $ — небольшой положительный параметр (известный как скорость обучения ).2 \ geq 0 $, это гарантирует, что $ \ Delta C \ leq 0 $, т.е. $ C $ будет всегда уменьшаться, никогда не увеличиваться, если мы изменим $ v $ в соответствии с рецепт в (10) \ begin {eqnarray} \ Delta v = — \ eta \ nabla C \ nonumber \ end {eqnarray}. (В пределах, конечно, пределы приближения в уравнении (9) \ begin {eqnarray} \ Delta C \ приблизительно \ nabla C \ cdot \ Delta v \ nonumber \ end {eqnarray}). Это именно та недвижимость, которую мы хотели! Итак, мы возьмем Уравнение (10) \ begin {eqnarray} \ Delta v = — \ eta \ nabla C \ nonumber \ end {eqnarray} для определения «закона движения» для мяча в нашем алгоритме градиентного спуска.То есть мы будем использовать Уравнение (10) \ begin {eqnarray} \ Delta v = — \ eta \ nabla C \ nonumber \ end {eqnarray} для вычисления значения для $ \ Delta v $, затем переместите положение шара $ v $ на эту величину: \ begin {eqnarray} v \ rightarrow v ‘= v — \ eta \ nabla C. \ tag {11} \ end {eqnarray} Затем мы снова воспользуемся этим правилом обновления, чтобы сделать еще один ход. Если мы продолжайте делать это снова и снова, мы будем продолжать снижать $ C $ до тех пор, пока … надеюсь — мы достигли глобального минимума.

Подводя итог, алгоритм градиентного спуска работает следующим образом: многократно вычислить градиент $ \ nabla C $, а затем перейти в против направления , «падающего» по склону долины.Мы можем визуализировать это так:

Обратите внимание, что с этим правилом градиентный спуск не воспроизводит реальный физическое движение. В реальной жизни мяч имеет импульс, и этот импульс может позволить ему катиться по склону или даже (на мгновение) катиться в гору. Только после того, как в нем возникло трение, мяч гарантированно скатится в долину. Напротив, наше правило для выбор $ \ Delta v $ просто говорит «спустись, прямо сейчас». Это все еще неплохое правило для поиска минимума!

Чтобы градиентный спуск работал правильно, нам нужно выбрать скорость обучения $ \ eta $ быть маленькой достаточно, чтобы уравнение (9) \ begin {eqnarray} \ Delta C \ приблизительно \ nabla C \ cdot \ Delta v \ nonumber \ end {eqnarray} — хорошее приближение.Если мы этого не делаем, мы можем получить $ \ Delta C> 0 $, что, очевидно, не будь хорошим! В то же время мы не хотим, чтобы $ \ eta $ было слишком маленьким, так как это сделает изменения $ \ Delta v $ крошечными, и, следовательно, Алгоритм градиентного спуска будет работать очень медленно. В практике реализации, $ \ eta $ часто меняется так, чтобы Уравнение (9) \ begin {eqnarray} \ Delta C \ приблизительно \ nabla C \ cdot \ Delta v \ nonumber \ end {eqnarray} остается хорошим приближением, но алгоритм не слишком медленный.Т. \ tag {13} \ end {eqnarray} Как и в случае с двумя переменными, мы можем выбирать \ begin {eqnarray} \ Delta v = — \ eta \ nabla C, \ tag {14} \ end {eqnarray} и нам гарантируется, что наш (приблизительный) выражение (12) \ begin {eqnarray} \ Delta C \ приблизительно \ nabla C \ cdot \ Delta v \ nonumber \ end {eqnarray} для $ \ Delta C $ будет отрицательным. Это дает нам возможность минимизировать градиент, даже если $ C $ является функцией многих переменных, многократно применяя обновление правило \ begin {eqnarray} v \ rightarrow v ‘= v- \ eta \ nabla C.\ tag {15} \ end {eqnarray} Вы можете думать об этом правиле обновления как о , определяющем градиент алгоритм спуска. Это дает нам возможность многократно менять позиция $ v $, чтобы найти минимум функции $ C $. Правило не всегда работает — несколько вещей могут пойти не так и помешать градиентный спуск от нахождения глобального минимума $ C $, точку мы вернитесь к исследованию в следующих главах. Но на практике градиент спуск часто работает очень хорошо, и в нейронных сетях мы найдем что это мощный способ минимизировать функцию затрат, и поэтому помогая сети учиться.

Действительно, есть даже смысл, в котором градиентный спуск является оптимальным. Стратегия поиска минимум. Предположим, мы пытаемся сделать перемещение $ \ Delta v $ в позицию так, чтобы уменьшить $ C $ на возможный. Это эквивалентно минимизации $ \ Delta C \ приблизительно \ nabla C \ cdot \ Delta v $. Мы ограничим размер хода так, чтобы $ \ | \ Delta v \ | = \ epsilon $ для небольшого фиксированного $ \ epsilon> 0 $. В другом словами, нам нужен небольшой шаг фиксированного размера, и мы пытаясь найти направление движения, которое уменьшает $ C $ на столько, возможный.Можно доказать, что выбор $ \ Delta v $, который минимизирует $ \ nabla C \ cdot \ Delta v $ is $ \ Delta v = — \ eta \ nabla C $, где $ \ eta = \ epsilon / \ | \ nabla C \ | $ определяется размером ограничение $ \ | \ Delta v \ | = \ эпсилон $. Итак, градиентный спуск может быть рассматривается как способ делать небольшие шаги в направлении, которое большинство, чтобы немедленно уменьшить $ C $.

Упражнения
  • Докажите утверждение последнего абзаца. Подсказка: Если вы еще не знакомы с Коши-Шварц неравенство, возможно, вам будет полезно ознакомиться с этим.
  • Я объяснил градиентный спуск, когда $ C $ является функцией двух переменные, и когда это функция более двух переменных. Что происходит, когда $ C $ является функцией только одной переменной? Ты можешь предоставить геометрическую интерпретацию того, что делает градиентный спуск в одномерном случае?

Люди исследовали множество вариантов градиентного спуска, включая варианты, которые более точно имитируют настоящий физический мяч. Эти варианты имитации мяча имеют некоторые преимущества, но также имеют главный недостаток: оказывается, что необходимо вычислить второй частные производные от $ C $, и это может быть довольно дорогостоящим. 2 \ nonumber \ end {eqnarray}.Чтобы увидеть, как это работает, давайте повторно сформулируйте правило обновления градиентного спуска с весами и смещениями заменяя переменные $ v_j $. Другими словами, наша «позиция» сейчас имеет компоненты $ w_k $ и $ b_l $, а вектор градиента $ \ nabla C $ имеет соответствующие компоненты $ \ partial C / \ partial w_k $ и $ \ partial C / \ частичный b_l $. Записываем правило обновления градиентного спуска в с точки зрения компонентов, мы имеем \ begin {eqnarray} w_k & \ rightarrow & w_k ‘= w_k- \ eta \ frac {\ partial C} {\ partial w_k} \ tag {16} \\ b_l & \ rightarrow & b_l ‘= b_l- \ eta \ frac {\ partial C} {\ partial b_l}.\ tag {17} \ end {eqnarray} Повторно применяя это правило обновления, мы можем «скатиться с холма», и надеюсь найти минимум функции стоимости. Другими словами, это правило можно использовать для обучения в нейронной сети.

При применении градиентного спуска возникает ряд проблем. правило. Мы подробно рассмотрим их в следующих главах. 2 \ nonumber \ end {eqnarray}.2} {2} $ для физических лиц обучающие примеры. На практике для вычисления градиента $ \ nabla C $ мы необходимо вычислить градиенты $ \ nabla C_x $ отдельно для каждого обучающий ввод, $ x $, а затем их усреднение, $ \ nabla C = \ frac {1} {n} \ sum_x \ nabla C_x $. К сожалению, когда количество обучающих входов очень большой, это может занять много времени, поэтому обучение происходит медленно.

Идея под названием стохастический градиентный спуск может быть использована для ускорения до обучения. Идея состоит в том, чтобы оценить градиент $ \ nabla C $ как вычисление $ \ nabla C_x $ для небольшой выборки случайно выбранного обучения входы.При усреднении по этой небольшой выборке оказывается, что мы можем быстро получить хорошую оценку истинного градиента $ \ nabla C $, и это помогает ускорить градиентный спуск, а значит, и обучение.

Чтобы сделать эти идеи более точными, работает стохастический градиентный спуск. случайный выбор небольшого количества $ m $ случайно выбранных тренировок входы. m \ nabla C_ {X_ {j}}} {m} \ приблизительно \ frac {\ sum_x \ nabla C_x} {n} = \ nabla C, \ tag {18} \ end {eqnarray} где вторая сумма — по всему набору обучающих данных.m \ nabla C_ {X_ {j}}, \ tag {19} \ end {eqnarray} подтверждая, что мы можем оценить общий градиент путем вычисления градиенты только для случайно выбранной мини-партии.

Чтобы явно связать это с обучением в нейронных сетях, предположим $ w_k $ и $ b_l $ обозначают веса и смещения в нашей нейронной сети. Тогда стохастический градиентный спуск работает, выбирая случайным образом выбранный мини-пакет обучающих входов, и обучение с ними, \ begin {eqnarray} w_k & \ rightarrow & w_k ‘= w_k- \ frac {\ eta} {m} \ sum_j \ frac {\ partial C_ {X_j}} {\ partial w_k} \ tag {20} \\ b_l & \ rightarrow & b_l ‘= b_l- \ frac {\ eta} {m} \ sum_j \ frac {\ partial C_ {X_j}} {\ partial b_l}, \ tag {21} \ end {eqnarray} где суммы взяты по всем обучающим примерам $ X_j $ в текущем мини-партия.Затем выбираем еще одну случайно выбранную мини-партию и тренируйтесь с ними. 2 \ nonumber \ end {eqnarray} мы масштабировали общую стоимость функция множителем $ \ frac {1} {n} $.Иногда люди пропускают $ \ frac {1} {n} $, суммируя затраты на отдельные примеры обучения вместо усреднения. Это особенно полезно, когда общая количество обучающих примеров заранее не известно. Это может произойти, если например, в режиме реального времени создается больше обучающих данных. И аналогичным образом правила мини-пакетного обновления (20) \ begin {eqnarray} w_k & \ rightarrow & w_k ‘= w_k- \ frac {\ eta} {m} \ sum_j \ frac {\ partial C_ {X_j}} {\ partial w_k} \ nonumber \ end {eqnarray} и (21) \ begin {eqnarray} b_l & \ rightarrow & b_l ‘= b_l- \ frac {\ eta} {m} \ sum_j \ frac {\ partial C_ {X_j}} {\ partial b_l} \ nonumber \ end {eqnarray} иногда пропускают член $ \ frac {1} {m} $ из перед суммами.Концептуально это не имеет большого значения, поскольку это эквивалентно изменению масштаба скорости обучения $ \ eta $. Но когда делаешь стоит обратить внимание на подробные сравнения разных работ.

Мы можем рассматривать стохастический градиентный спуск как политический опрос: намного проще отобрать небольшую мини-серию, чем применить градиентный спуск ко всему пакету, как при проведении опроса легче, чем провести полные выборы. Например, если у нас есть обучающий набор размером $ n = 60 000 $, как в MNIST, и выберите размер мини-партии (скажем) $ m = 10 $, это означает, что мы получим коэффициент Ускорение оценки градиента на 6000 долларов! Конечно, оценка не будет идеальным — будут статистические колебания — но это не обязательно быть идеальным: все, что нас действительно волнует, — это двигаться в общее направление, которое поможет снизить $ C $, а это значит, что мы не нужен точный расчет градиента.На практике стохастический градиентный спуск — широко используемый и мощный метод для обучение в нейронных сетях, и это основа для большинства методы обучения, которые мы разработаем в этой книге.

Упражнение
  • Экстремальный вариант градиентного спуска — использовать мини-пакет. размером всего 1. То есть, учитывая ввод для обучения, $ x $, мы обновляем наши веса и смещения по правилам $ w_k \ rightarrow w_k ‘= w_k — \ eta \ partial C_x / \ partial w_k $ и $ b_l \ rightarrow b_l ‘= b_l — \ eta \ partial C_x / \ partial b_l $.Затем мы выбираем другой обучающий ввод и снова обновите веса и смещения. И так далее, несколько раз. Эта процедура известна как онлайн , онлайн или инкрементальное обучение. В онлайн-обучении нейронная сеть обучается только по одному обучающему входу за раз (просто как люди). Назовите одно преимущество и один недостаток онлайн-обучение по сравнению со стохастическим градиентным спуском с размер мини-партии, скажем, 20 $.

Позвольте мне завершить этот раздел, обсудив момент, в котором иногда возникают ошибки люди, плохо знакомые с градиентным спуском. В нейронных сетях стоимость $ C $ составляет, конечно, функция многих переменных — все веса и смещения — и таким образом в некотором смысле определяет поверхность в очень многомерной Космос. Некоторые люди зацикливаются на мысли: «Эй, я должен уметь визуализируйте все эти дополнительные измерения ». И они могут начать волноваться: «Я не могу мыслить в четырех измерениях, не говоря уже о пяти (или пяти миллион) ».Есть ли у них какие-то особые способности? способности, которые есть у «настоящих» суперматематиков? Конечно, ответ нет. Даже самые профессиональные математики не могут представить себе четыре габариты особенно хорошо, если вообще. Вместо этого они используют трюк заключается в разработке других способов представления того, что происходит. Это именно то, что мы сделали выше: мы использовали алгебраический (а не визуальный) представление $ \ Delta C $, чтобы выяснить, как двигаться, чтобы уменьшить $ C $. Люди, которые умеют мыслить большими измерениями, имеют ментальная библиотека, содержащая множество различных техник по этим линии; наш алгебраический трюк — лишь один пример.Эти методы могут не иметь той простоты, к которой мы привыкли при визуализации трех размеров, но как только вы создадите библиотеку таких методов, вы может довольно хорошо мыслить в больших измерениях. Я не буду вдаваться в подробнее здесь, но если вам интересно, то можете почитать этот обсуждение некоторых методик профессиональных математиков привык мыслить большими измерениями. Хотя некоторые приемы обсуждаются довольно сложно, большая часть лучшего контента интуитивно понятна и доступны и могут быть освоены кем угодно.

Реализация нашей сети для классификации цифр

Хорошо, давайте напишем программу, которая научится распознавать рукописные цифры с использованием стохастического градиентного спуска и MNIST данные обучения. Мы сделаем это с помощью небольшой программы на Python (2.7), просто 74 строки кода! Первое, что нам нужно, это получить данные MNIST. Если вы являетесь пользователем git, вы можете получить данные путем клонирования репозиторий кода для этой книги,

 git clone https://github.com/mnielsen/neural-networks-and-deep-learning.мерзавец
 

Если вы не используете git, вы можете скачать данные и код Вот.

Между прочим, когда я описывал данные MNIST ранее, я сказал, что это разделить на 60 000 обучающих изображений и 10 000 тестовых изображений. Это официальное описание MNIST. Собственно, мы собираемся разделить данные на немного иначе. Мы оставим тестовые изображения как есть, но разделим Обучающий набор MNIST из 60000 изображений состоит из двух частей: набор из 50000 изображений. изображения, которые мы будем использовать для обучения нашей нейронной сети, и отдельный Набор для проверки 10 000 изображений .Мы не будем используйте данные проверки из этой главы, но позже в книге мы найти его полезным при выяснении того, как установить определенные гиперпараметры нейронной сети — например, скорость обучения и т. д., которые не выбираются напрямую нашими алгоритм обучения. Хотя данные проверки не являются частью оригинальная спецификация MNIST, многие люди используют MNIST таким образом, и использование данных проверки является обычным явлением в нейронных сетях. Когда я обращайтесь к «обучающим данным MNIST», я буду иметь в виду наш набор данных из 50000 изображений, а не исходные данные из 60000 изображений задавать* * Как отмечалось ранее, набор данных MNIST основан на двух данных наборы, собранные NIST, Национальным институтом США Стандарты и технологии.Для построения MNIST наборы данных NIST были урезаны и помещены в более удобный формат Янном ЛеКун, Коринна Кортес и Кристофер Дж. С. Берджес. Увидеть эта ссылка для получения дополнительной информации Детали. Набор данных в моем репозитории находится в форме, которая делает его легко загружать данные MNIST и манипулировать ими в Python. Я получил эта конкретная форма данных из машинного обучения LISA лаборатория Монреальского университета (ссылка) ..

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

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

 класс Сеть (объект):

    def __init __ (себя, размеры):
        self.num_layers = len (размеры)
        self.sizes = размеры
        self.biases = [np.random.randn (y, 1) для y в размерах [1:]]
        я.веса = [np.random.randn (y, x)
                        для x, y в zip (размеры [: - 1], размеры [1:])]
 

В этом коде размеры списка содержат количество нейронов в соответствующие слои. Так, например, если мы хотим создать Сетевой объект с 2 нейронами в первом слое, 3 нейронами в второй слой и 1 нейрон в последнем слое, мы бы сделали это с код:

Предубеждения и веса в объекте Network инициализируются случайным образом, используя Numpy np.random.randn функция для генерации Гаусса распределения со средним значением $ 0 $ и стандартным отклонением $ 1 $. Этот случайный инициализация дает нашему алгоритму стохастического градиентного спуска место начать с. В следующих главах мы найдем лучшие способы инициализация весов и смещений, но пока этого достаточно. Заметка что код инициализации сети предполагает, что первый слой нейронов является входным слоем и не устанавливает каких-либо смещений для эти нейроны, поскольку смещения используются только при вычислении выходы из более поздних слоев.{\ rm th} $ нейрон в третьем слое. Этот заказ индексов $ j $ и $ k $ может показаться странным — наверняка это принесет больше смысл поменять местами индексы $ j $ и $ k $? Большое преимущество использование этого порядка состоит в том, что это означает, что вектор активации третий слой нейронов: \ begin {eqnarray} а ‘= \ сигма (ш а + Ь). \ tag {22} \ end {eqnarray} В этом уравнении много чего происходит, так что давайте разберемся. кусочек за кусочком. $ a $ — вектор активаций второго слоя нейронов.Чтобы получить $ a ‘$, умножаем $ a $ на весовую матрицу $ w $, и добавьте вектор смещений $ b $. Затем мы применяем функцию $ \ sigma $ поэлементно к каждой записи в векторе $ w a + b $. (Это называется векторизация функция $ \ sigma $.) Легко проверить, что Уравнение (22) \ begin {eqnarray} a ‘= \ sigma (w a + b) \ nonumber \ end {eqnarray} дает тот же результат, что и наш предыдущее правило, уравнение (4) \ begin {eqnarray} \ frac {1} {1+ \ exp (- \ sum_j w_j x_j-b)} \ nonumber \ end {eqnarray}, для вычисление выхода сигмовидного нейрона.

Exercise

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

 сигмоид. Деф. (Z):
    возврат 1.0 / (1.0 + np.exp (-z))
 
Обратите внимание, что когда вход z является вектором или массивом Numpy, Numpy автоматически применяет сигмовидную функцию поэлементно, что есть в векторизованном виде.

Затем мы добавляем метод прямой связи в класс Network, который, учитывая вход a для сети, возвращает соответствующий вывод * * Предполагается, что вход a an (n, 1) Numpy ndarray, а не вектор (n,).Вот, n — количество входов в сеть. Если вы попытаетесь использовать вектор (n,) в качестве входных данных вы получите странные результаты. Несмотря на то что использование вектора (n,) кажется более естественным выбором, используя an (n, 1) ndarray позволяет легко изменять код для прямой передачи нескольких входных данных одновременно, и это иногда удобный. . Все, что делает метод, применяется Уравнение (22) \ begin {eqnarray} a ‘= \ sigma (w a + b) \ nonumber \ end {eqnarray} для каждого слоя:

 def с прямой связью (self, a):
        "" "Возвращает выход сети, если введено" a "."" "
        для b, w в zip (self.biases, self.weights):
            а = сигмовидная (np.dot (w, a) + b)
        вернуть
 

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

 def SGD (self, training_data, epochs, mini_batch_size, eta,
            test_data = Нет):
        "" "Обучите нейронную сеть с помощью мини-пакетного стохастика
        градиентный спуск."Training_data" - это список кортежей.
        "(x, y)", представляющий обучающие входные данные и желаемый
        выходы. Остальные необязательные параметры:
        не требует пояснений. Если указано "test_data", то
        сеть будет оцениваться по тестовым данным после каждого
        эпоха и частичный прогресс распечатаны. Это полезно для
        отслеживает прогресс, но существенно замедляет работу "" "
        если test_data: n_test = len (test_data)
        n = len (тренировочные_данные)
        для j в xrange (эпохи):
            случайный.перемешать (обучение_данные)
            mini_batches = [
                тренировочные_данные [k: k + mini_batch_size]
                для k в xrange (0, n, mini_batch_size)]
            для mini_batch в mini_batch:
                self.update_mini_batch (mini_batch, eta)
            если test_data:
                напечатайте "Эпоха {0}: {1} / {2}". формат (
                    j, self.evaluate (test_data), n_test)
            еще:
                напечатайте "Эпоха {0} завершена" .format (j)
 

Training_data — это список кортежей (x, y) представляющие обучающие входы и соответствующие желаемые выходы.Переменные epochs и mini_batch_size — это то, что вам нужно. ожидайте — количество эпох, для которых нужно тренироваться, и размер мини-партии для использования при отборе проб. eta — скорость обучения, $ \ eta $. Если указан необязательный аргумент test_data, тогда программа будет оценивать сеть после каждой эпохи обучения, и распечатать частичный прогресс. Это полезно для отслеживания прогресса, но существенно замедляет работу.

Код работает следующим образом. В каждую эпоху он начинается случайно перемешивание обучающих данных с последующим их разделением на мини-пакеты подходящего размера.Это простой способ случайной выборки из данных обучения. Затем для каждого mini_batch мы применяем пошаговый градиентный спуск. Это делается с помощью кода self.update_mini_batch (mini_batch, eta), который обновляет сетевые веса и смещения в соответствии с одной итерацией градиента descent, используя только данные обучения в mini_batch. Вот код для метода update_mini_batch:

 def update_mini_batch (self, mini_batch, eta):
        "" "Обновите веса и смещения сети, применив
        градиентный спуск с использованием обратного распространения в одну мини-серию.«Mini_batch» - это список кортежей «(x, y)» и «eta».
        скорость обучения. "" "
        nabla_b = [np.zeros (b.shape) для b в self.biases]
        nabla_w = [np.zeros (w.shape) для w в self.weights]
        для x, y в mini_batch:
            delta_nabla_b, delta_nabla_w = self.backprop (x, y)
            nabla_b = [nb + dnb для nb, dnb в zip (nabla_b, delta_nabla_b)]
            nabla_w = [nw + dnw для nw, dnw в zip (nabla_w, delta_nabla_w)]
        self.weights = [w- (eta / len (mini_batch)) * nw
                        для w, nw в zip (сам.веса, nabla_w)]
        self.biases = [b- (eta / len (mini_batch)) * nb
                       для b, nb в zip (self.biases, nabla_b)]
 
Большую часть работы выполняет линия
 delta_nabla_b, delta_nabla_w = self.backprop (x, y)
 
Это вызывает так называемый алгоритм обратного распространения , который является быстрым способом вычисления градиента функции стоимости. Итак, update_mini_batch работает просто путем вычисления этих градиентов. для каждого обучающего примера в mini_batch, а затем обновление я.веса и self.biases соответственно.

Я не собираюсь сейчас показывать код self.backprop. Мы изучим, как работает обратное распространение, в следующей главе, включая код для self.backprop. А пока просто предположим, что это ведет себя как заявлено, возвращая соответствующий градиент стоимости связанный с обучающим примером x.

Давайте посмотрим на полную программу, включая строки документации, которые я пропустил выше. Помимо self.backprop в программе есть говорит само за себя — вся тяжелая работа выполняется самостоятельно.SGD и self.update_mini_batch, о которых мы уже говорили. В Метод self.backprop использует несколько дополнительных функций, чтобы помочь при вычислении градиента, а именно sigmoid_prime, который вычисляет производная функции $ \ sigma $, и self.cost_derivative, который я здесь описывать не буду. Вы можете получить суть (и, возможно, детали), просто взглянув на строки кода и документации. Мы подробно рассмотрим их в Следующая глава. Обратите внимание, что, хотя программа кажется длинной, большая часть кода строки документации, предназначенные для облегчения понимания кода.Фактически, программа содержит всего 74 строки без пробелов, код без комментариев. Весь код можно найти на GitHub Вот.

 "" "
network.py
~~~~~~~~~~

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

#### Библиотеки
# Стандартная библиотека
случайный импорт

# Сторонние библиотеки
импортировать numpy как np

класс Сеть (объект):

    def __init __ (себя, размеры):
        "" "Список" sizes "содержит количество нейронов в
        соответствующие слои сети.Например, если список
        было [2, 3, 1], тогда это была бы трехуровневая сеть с
        первый слой содержит 2 нейрона, второй слой 3 нейрона,
        и нейрон третьего слоя 1. Смещения и веса для
        сети инициализируются случайным образом с использованием гауссовского
        распределение со средним 0 и дисперсией 1. Обратите внимание, что первый
        слой считается входным слоем, и по соглашению мы
        не будет создавать никаких смещений для этих нейронов, поскольку смещения
        когда-либо использовались при вычислении выходных данных более поздних уровней."" "
        self.num_layers = len (размеры)
        self.sizes = размеры
        self.biases = [np.random.randn (y, 1) для y в размерах [1:]]
        self.weights = [np.random.randn (y, x)
                        для x, y в zip (размеры [: - 1], размеры [1:])]

    def feedforward (self, a):
        "" "Вернуть выходной сигнал сети, если на входе" а "." ""
        для b, w в zip (self.biases, self.weights):
            а = сигмовидная (np.dot (w, a) + b)
        вернуть

    def SGD (self, тренировочные_данные, эпохи, mini_batch_size, eta,
            test_data = Нет):
        "" "Обучите нейронную сеть с помощью мини-пакетного стохастика
        градиентный спуск.Training_data - это список кортежей
        `` (x, y) '', представляющий обучающие входные данные и желаемый
        выходы. Остальные необязательные параметры:
        не требует пояснений. Если указан test_data, то
        сеть будет оцениваться по тестовым данным после каждого
        эпоха и частичный прогресс распечатаны. Это полезно для
        отслеживает прогресс, но существенно замедляет работу "" "
        если test_data: n_test = len (test_data)
        n = len (тренировочные_данные)
        для j в xrange (эпохи):
            случайный.перемешать (обучение_данные)
            mini_batches = [
                тренировочные_данные [k: k + mini_batch_size]
                для k в xrange (0, n, mini_batch_size)]
            для mini_batch в mini_batch:
                self.update_mini_batch (mini_batch, eta)
            если test_data:
                напечатайте "Эпоха {0}: {1} / {2}". формат (
                    j, self.evaluate (test_data), n_test)
            еще:
                напечатайте "Эпоха {0} завершена" .format (j)

    def update_mini_batch (self, mini_batch, eta):
        "" "Обновите веса и смещения сети, применив
        градиентный спуск с использованием обратного распространения в одну мини-серию.Mini_batch - это список кортежей (x, y) и eta.
        скорость обучения. "" "
        nabla_b = [np.zeros (b.shape) для b в self.biases]
        nabla_w = [np.zeros (w.shape) для w в self.weights]
        для x, y в mini_batch:
            delta_nabla_b, delta_nabla_w = self.backprop (x, y)
            nabla_b = [nb + dnb для nb, dnb в zip (nabla_b, delta_nabla_b)]
            nabla_w = [nw + dnw для nw, dnw в zip (nabla_w, delta_nabla_w)]
        self.weights = [w- (eta / len (mini_batch)) * nw
                        для w, nw в zip (сам.веса, nabla_w)]
        self.biases = [b- (eta / len (mini_batch)) * nb
                       для b, nb в zip (self.biases, nabla_b)]

    def backprop (self, x, y):
        "" "Вернуть кортеж` `(nabla_b, nabla_w)`, представляющий
        градиент для функции стоимости C_x. набла_б и
        nabla_w - это послойные списки массивов numpy, похожие
        на "self.biases" и "self.weights". "" "
        nabla_b = [np.zeros (b.shape) для b в self.biases]
        nabla_w = [np.zeros (w.shape) для w в сам. весе]
        # feedforward
        активация = x
        activations = [x] # список для хранения всех активаций, слой за слоем
        zs = [] # список для хранения всех векторов z, слой за слоем
        для b, w в zip (self.biases, self.weights):
            z = np.dot (w, активация) + b
            zs.append (z)
            активация = сигмовидная (z)
             

Прогнозирование ответов с помощью обученной нейронной сети глубокого обучения

Оптимизация производительности, заданная как пара, разделенная запятыми, состоящая из 'Acceleration' и одного из следующих:

  • 'auto' — автоматическое применение ряда оптимизаций подходит для ввода сетевого и аппаратного ресурса.

  • 'mex' — Скомпилировать и выполнить функцию MEX. Этот параметр доступен только при использовании графического процессора. Для использования графического процессора требуется Parallel Computing Toolbox и графический процессор NVIDIA с поддержкой CUDA и вычислительной мощностью 3.0 или выше. Если Parallel Computing Toolbox или подходящий графический процессор недоступен, программа выдает ошибку.

  • «нет» — отключить все ускорения.

Значение по умолчанию — «авто» .Если 'авто' Как указано, MATLAB ® применит ряд совместимых оптимизаций. Если вы используете 'auto' option, MATLAB никогда не генерирует MEX-функцию.

Использование «Ускорение» опции «Авто» и «mex» может обеспечить повышение производительности, но за счет увеличено начальное время работы. Последующие вызовы с совместимыми параметрами выполняются быстрее.Использовать оптимизация производительности, если вы планируете вызывать функцию несколько раз, используя новый входные данные.

Опция 'mex' генерирует и выполняет функцию MEX на основе сети и параметры, используемые в вызове функции. Вы можете связать несколько MEX-функций с единой сетью одновременно. Очистка сетевой переменной также очищает все MEX функции, связанные с этой сетью.

Параметр «mex» доступен только при использовании графического процессора.Вы должны иметь установлен компилятор C / C ++ и пакет поддержки интерфейса GPU Coder ™ для библиотек глубокого обучения. Установите опору пакет с помощью Add-On Explorer в MATLAB. Инструкции по настройке см. В разделе Настройка MEX (GPU Coder). GPU Coder не требуется.

Параметр 'mex' не поддерживает все слои. Для списка поддерживаемые слои, см. Поддерживаемые слои (GPU Coder). Рецидивирующий нейронный сети (RNN), содержащие sequenceInputLayer , не поддерживаются.

Опция 'mex' не поддерживает сети с несколькими входами слои или несколько выходных слоев.

Вы не можете использовать MATLAB Compiler ™ для развертывания вашей сети при использовании опции 'mex' .

Пример: «Ускорение», «mex»

.

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

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