Биографии Характеристики Анализ

Алгоритм обратного распространения ошибки c реализация. Обучение методом обратного распространения ошибок

Обратное распространение ошибки - стандартный способ обучения нейронной сети, хотя существуют и другие методы (о них в одной из следующих глав). Принцип работы примерно такой:

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

2. Полученные данные сравниваются с известными выходными данными для рассматриваемого входного набора. Разница между полученными и известными (опытными) данными - вектор ошибки.


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

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

5. Наконец, если в сети существует входной слой (именно слой, а не ряд входных значений), то проводятся аналогичные действия и с ним.

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

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

Запомните
Обозначим через переменную NUM_HID количество нейронов в скрытом слое (нумерация начинается с индекса 1). NUM_OUT - количество нейронов в выходном слое.

Обратное распространение и формулы.
А теперь, настройтесь! Я собираюсь привести ниже множество математических выкладок.

    Во-первых, инициализируем пороговые значения и весовые коэффициенты небольшими случайными величинами (не более 0.4)

    Теперь прогоним сеть в режиме прямого функционирования - процедура run_network (см. прошлую главу)

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

    E i = (t i - a i).a i .(1 - a i)

    Здесь E i - ошибка для i-ого узла выходного слоя, a i - активность данного узла, t i - требуемая активность для него же (т.е. требуемое выходное значение).

    Вот код на паскале:

    procedure calculate_output_layer_errors; var i : byte; {for loop variable} begin for i: = 1 to NUM_OUT do with ol[ i] do E: = (desired_output[ i] - a) * a * (1 - a) end ;

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

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

    E i = a i . (1 - a i) . S j E j .w ij

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

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

    procedure calculate_hidden_layer_errors; var i,j : byte; sum : real ; begin for i: = 1 to NUM_HID do {обсчитываем весь скрытый слой} with hl[ i] do begin sum: = 0; {sum error values from O/P layer} for j: = 1 to NUM_OUT do sum: = sum + ol[ j] .E * ol[ j] .w[ i] {только веса, относящиеся к нейрону i} E: = a * (1 - a) * sum {no other w value} end ; end ;
  • Полученные значения ошибок для выходного слоя мы используем для изменения весовых коэффициентов между скрытым и выходным слоями.Мы должны вычислить все значения ошибок до модификации весовых коэффициентов, так как в формуле присутствуют и старые значения весов. Если же мы вычислим сначала весовые коэффициенты, а уже затем - значения ошибок, то процесс обучения застопорится.

    Применяем уравнение:

    new w ij = old w ij + h.d j .x i

    где w ij - вес связи между нейроном i скрытого слоя и нейроном j выходного, d j - приращение ошибки для выходного нейрона j и x i - сигнал на выходе скрытого нейрона i, h - константа. Эта константа используется для того, чтобы обучение не проводилось слишком быстро, то есть весовые коэффициенты не изменялись слишком сильно за один шаг обучения (что является причиной прыжков сходимости при обучении сети).

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

    new threshold = old threshold + h.d j .(-1)

    или (в более удобном виде):

    new threshold = old threshold - h.d j

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

    В этом коде я использовал j для индексирования узлов выходного слоя, чтобы привести в соответствие с уравнением (т.е. E соответствует d j ). Таким же образом hl[i].out соответствует x i , а w[i] - w ij .

  • Наконец, мы должны модифицировать веса скрытого слоя. В реальности, если имеются дополнительные слои, приведенный код также работает.

    procedure update_hidden_weights; const LEARNING_RATE = 0.025; {нет никаких причин, чтобы это значение не отличалось от использованного для выходных узлов} var i,j : byte; begin for j : = 1 to NUM_HID do {обходим все скрытые узлы} with hl[ j] do begin {обрабатываем все связи от входного слоя к этому узлу} for i : = 1 to NUM_INP do w[ i] : = w[ i] + LEARNING_RATE * E * test_pat[ i] ; {модифицируем пороговый уровень этого узла} threshold : = threshold - LEARNING_RATE * E end end ;

Все то же самое на JAVA
Ниже приведена реализация нейронной сети, обучаемой методом обратного распространения ошибки на JAVA:

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

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

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

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

Эта комбинация, например, обозначает, что для входного набора установлены данные (1, 0, 0, 0.3, 0, 0.7), а для выходного набора - (0, 0, 0.7, 0.7, 0). Кликните на символ + или - (около словосочетания "Training patterns") для изменения количества наборов.

Для того, чтобы обучить сеть, кликните на кнопку "Train". Для тестирования сети введите значение компонента входного набора в слот наверху, а затем кликните на компонент входного набора (на одно из тех текстовых значений в рамке слева на структурной схеме сети). Запустите сеть - кнопка "Run"

Метод обратного распространения ошибки

Метод обратного распространения ошибки - метод обучения многослойного персептрона, один из вариантов обучения с учителем. Впервые метод был описан Полом Дж. Вербосом. Далее существенно развит в 1986 г. Дэвидом И. Румельхартом, Дж. Е. Хинтоном и Рональдом Дж. Вильямсом. Это итеративный градиентный алгоритм, который используется с целью минимизации ошибки работы многослойного перцептрона и получения желаемого выхода.

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

Метод является модификацией классического метода градиентного спуска.

Алгоритм метода обратного распространения ошибки

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

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

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

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

где весовой коэффициент j-го нейрона n-го слоя для связи с i-м нейроном (n-1)-го слоя.

Параметр называется параметром скорости обучения.

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

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

Третий сомножитель / есть ни что иное, как выход i-го нейрона (n-1)-го слоя, то есть

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

Введем обозначение

Тогда для нейронов выходного слоя

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

Заметим, что в этой формуле первые два сомножителя есть не что иное, как. Таким образом, с помощью (9) можно выражать величины для нейронов n-го слоя черездля нейронов (n+1)-го. Поскольку для последнего слоя легко вычисляется по (8), то можно с помощью рекурсивной формулы

получить значения для вех нейронов всех слоев.

Окончательно формулу (2) для модификации весовых коэффициентов можно записать в виде

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

Присваиваем всем весовым коэффициентам сети случайные начальные значения. При этом сеть будет осуществлять какое-то случайное преобразование входных сигналов и значения целевой функции (1) будут велики.

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

Скорректировать веса сети:

Оценка работы сети

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

где - требуемое значение выходного сигнала.

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

Недостатки алгоритма

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

Паралич сети

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

Локальные минимумы

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

Размер шага

Внимательный разбор доказательства сходимости показывает, что коррекции весов предполагаются бесконечно малыми. Ясно, что это неосуществимо на практике, так как ведёт к бесконечному времени обучения. Размер шага должен браться конечным. Если размер шага фиксирован и очень мал, то сходимость слишком медленная, если же он фиксирован и слишком велик, то может возникнуть паралич или постоянная неустойчивость. Эффективно увеличивать шаг до тех пор, пока не прекратится улучшение оценки в данном направлении антиградиента и уменьшать, если такого улучшения не происходит. П. Д. Вассерман описал адаптивный алгоритм выбора шага, автоматически корректирующий размер шага в процессе обучения. В книге А. Н. Горбаня предложена разветвлённая технология оптимизации обучения.

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

Среда разработки и причины ее выбора

Разработка приложения будет осуществляться на языке программирования C# с фреймворком.NETFramework4.0 в среде разработки MicrosoftVisualStudio 2010. Фрагменты кода, требующие массивных вычислений, разработаны на языке C++. MSVisualStudio 2010 включает в себя полный набор новых и улучшенных функций, упрощающих все этапы процесса разработки от проектирования до развертывания.

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

Разработка приложений в MicrosoftVisualStudio2010 Ultimate на языке C# с фреймворком.NETFramework4.0 осуществляется с применением объектно-ориентированного программирования и визуального программирования.

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

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

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

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

Дельта правило (правило Видроу-Хоффа).

Определим ошибку :

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

Дельта-правило заключается в следующем – изменение величины весового коэффициента должно быть равно:

Где – норма обучения. Это число мы сами задаем перед началом обучения. – это сигнал, приходящий к элементу k от элемента j . А – ошибка элемента k .

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

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

Алгоритм обратного распространения ошибок.

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

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

Я, пожалуй, не буду приводить математические выводы и расчеты (несмотря на мою любовь к математике 🙂), чтобы не перегружать статью, ограничимся только итоговыми результатами:

Функция – это функция активности элемента. Давайте использовать логистическую функцию, для нее:

Подставляем в предыдущую формулу и получаем величину ошибки:

В этой формуле:

Наверняка сейчас еще все это кажется не совсем понятным, но не переживайте, при рассмотрении практического примера все встанет на свои места 😉

Собственно, давайте к нему и перейдем.

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

Рассмотрим нейронную сеть и вручную проведем расчеты для прямого и обратного “потоков” в сети.

На вход мы должны подать образец, пусть это будет (0.2, 0.5) . Ожидаемый выход сети – 0.4 . Норма обучения пусть будет равна 0.85 . Давайте проведем все расчеты поэтапно. Кстати, совсем забыл, в качестве функции активности мы будем использовать логистическую функцию:

Итак, приступаем…

Вычислим комбинированный ввод элементов 2 , 3 и 4 :

Активность этих элементов равна:

Комбинированный ввод пятого элемента:

Активность пятого элемента и в то же время вывод нейронной сети равен:

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

Тогда ошибки для элементов 2 , 3 и 4 равны соответственно:

Здесь значения -0.014, -0.028 и -0.056 получаются в результате прохода ошибки выходного элемента –0.014 по взвешенным связям в направлении к элементам 2 , 3 и 4 соответственно.

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

Аналогичным образом производим расчеты и для остальных элементов:

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

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

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

Итак, добавляем в нашу сеть два новых элемента (X и Y), которые теперь будут выполнять роль входных. На вход также подаем образец (0.2, 0.5) . Рассмотрим алгоритм в данном случае:

1. Прямой проход сети. Здесь все точно также как и для сети с одним скрытым слоем. Результатом будет значение .

2. Вычисляем ошибку выходного элемента:

3. Теперь нам нужно вычислить ошибки элементов 2, 3 и 4.

Ошибки от выходов сети к её входам, в направлении, обратном прямому распространению сигналов в обычном режиме работы. Барцев и Охонин предложили сразу общий метод («принцип двойственности »), приложимый к более широкому классу систем, включая системы с запаздыванием, распределённые системы , и т. п.

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

Сигмоидальные функции активации

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

Функция Ферми (экспоненциальная сигмоида):

Рациональная сигмоида:

Гиперболический тангенс:

,

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

Менее всего, сравнительно с другими сигмоидами, процессорного времени требует расчет рациональной сигмоиды. Для вычисления гиперболического тангенса требуется больше всего тактов работы процессора. Если же сравнивать с пороговыми функциями активации, то сигмоиды рассчитываются очень медленно. Если после суммирования в пороговой функции сразу можно начинать сравнение с определенной величиной (порогом), то в случае сигмоидальной функции активации нужно рассчитать сигмоид (затратить время в лучшем случае на три операции: взятие модуля, сложение и деление), и только потом сравнивать с пороговой величиной (например, нулём). Если считать, что все простейшие операции рассчитываются процессором за примерно одинаковое время, то работа сигмоидальной функции активации после произведённого суммирования (которое займёт одинаковое время) будет медленнее пороговой функции активации как 1:4.

Функция оценки работы сети

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

,

где - требуемое значение выходного сигнала.

Описание алгоритма

Архитектура многослойного перцептрона

Алгоритм обратного распространения ошибки применяется для многослойного перцептрона . У сети есть множество входов , множество выходов Outputs и множество внутренних узлов. Перенумеруем все узлы (включая входы и выходы) числами от 1 до N (сквозная нумерация, вне зависимости от топологии слоёв). Обозначим через вес, стоящий на ребре, соединяющем i-й и j-й узлы, а через - выход i-го узла. Если нам известен обучающий пример (правильные ответы сети , ), то функция ошибки, полученная по методу наименьших квадратов , выглядит так:

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

,

где - множитель, задающий скорость «движения».

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

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

Если же j-й узел - не на последнем уровне, то у него есть выходы; обозначим их через Children(j). В этом случае

, .

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

  • для узла последнего уровня
  • для внутреннего узла сети
  • для всех узлов

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

Алгоритм

Алгоритм: BackPropagation

где - коэффициент инерциальнности для сглаживания резких скачков при перемещении по поверхности целевой функции

Математическая интерпретация обучения нейронной сети

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

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

Недостатки алгоритма

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

Паралич сети

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

Локальные минимумы

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

Размер шага

Внимательный разбор доказательства сходимости показывает, что коррекции весов предполагаются бесконечно малыми. Ясно, что это неосуществимо на практике, так как ведёт к бесконечному времени обучения. Размер шага должен браться конечным. Если размер шага фиксирован и очень мал, то сходимость слишком медленная, если же он фиксирован и слишком велик, то может возникнуть паралич или постоянная неустойчивость. Эффективно увеличивать шаг до тех пор, пока не прекратится улучшение оценки в данном направлении антиградиента и уменьшать, если такого улучшения не происходит. П. Д. Вассерман описал адаптивный алгоритм выбора шага, автоматически корректирующий размер шага в процессе обучения. В книге А. Н. Горбаня предложена разветвлённая технология оптимизации обучения.

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

См. также

  • Алгоритм скоростного градиента

Литература

  1. Уоссермен Ф. Нейрокомпьютерная техника: Теория и практика . - М .: «Мир», 1992.
  2. Хайкин С. Нейронные сети: Полный курс. Пер. с англ. Н. Н. Куссуль, А. Ю. Шелестова. 2-е изд., испр. - М.: Издательский дом Вильямс, 2008, 1103 с.

Ссылки

  1. Копосов А. И., Щербаков И. Б., Кисленко Н. А., Кисленко О. П., Варивода Ю. В. и др. . - М .: ВНИИГАЗ, 1995.

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

Обновление правила цепочки

Можно рассматривать как длинный ряд вложенных уравнений. Если вы так думаете о прямом распространении, то обратное распространение — это просто приложение правила цепочки (дифференцирования сложной функции) для поиска производных потерь по любой переменной во вложенном уравнении. С учётом функции прямого распространения:

F(x)=A(B(C(x)))

A, B, и C — на различных слоях. Пользуясь правилом цепочки, мы легко вычисляем производную f(x) по x:

F′(x)=f′(A)⋅A′(B)⋅B′(C)⋅C′(x)

Что насчёт производной относительно B ? Чтобы найти производную по B , вы можете сделать вид, что B (C(x)) является константой, заменить ее переменной-заполнителем B , и продолжить поиск производной по B стандартно.

F′(B)=f′(A)⋅A′(B)

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

Применение правила цепочки

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

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

Cost=C(R(Z(XW)))

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

C′(W)=C′(R)⋅R′(Z)⋅Z′(W)=(y^−y)⋅R′(Z)⋅X

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

Какова производная от потери по Wo ?

C′(WO)=C′(y^)⋅y^′(ZO)⋅Z′O(WO)=(y^−y)⋅R′(ZO)⋅H

А что насчет Wh ? Чтобы узнать это, мы просто продолжаем возвращаться в нашу функцию, рекурсивно применяя правило цепочки, пока не доберемся до функции, которая имеет элемент Wh .

C′(Wh)=C′(y^)⋅O′(Zo)⋅Z′o(H)⋅H′(Zh)⋅Z′h(Wh)=(y^−y)⋅R′(Zo)⋅Wo⋅R′(Zh)⋅X

И просто забавы ради, что, если в нашей сети было бы 10 скрытых слоев. Что такое производная потери для первого веса w1?

C(w1)=(dC/dy^)⋅(dy^/dZ11)⋅(dZ11/dH10)⋅(dH10/dZ10)⋅(dZ10/dH9)⋅(dH9/dZ9)⋅(dZ9/dH8)⋅(dH8/dZ8)⋅(dZ8/dH7)⋅(dH7/dZ7)⋅(dZ7/dH6)⋅(dH6/dZ6)⋅(dZ6/dH5)⋅(dH5/dZ5)⋅(dZ5/dH4)⋅(dH4/dZ4)⋅(dZ4/dH3)⋅(dH3/dZ3)⋅(dZ3/dH2)⋅(dH2/dZ2)⋅(dZ2/dH1)⋅(dH1/dZ1)⋅(dZ1/dW1)

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

Сохранение работы с мемоизацией

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

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

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

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

Ошибка выходного слоя

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

C′(Zo)=(y^−y)⋅R′(Zo)

Чтобы упростить запись, практикующие МО обычно заменяют последовательность (y^−y)∗R"(Zo) термином Eo . Итак, наша формула для ошибки выходного слоя равна:

Eo=(y^−y)⋅R′(Zo)

Ошибка скрытого слоя

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

Eh=Eo⋅Wo⋅R′(Zh)

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

Производная потерь по любому весу

Вернемся к нашей формуле для производной потерь по весу выходного слоя Wo .

C′(WO)=(y^−y)⋅R′(ZO)⋅H

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

C′(Wo)=Eo⋅H

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

C′(w)=CurrentLayerError⋅CurrentLayerInput

Примечание: вход относится к активации с предыдущего слоя, а не к взвешенному входу, Z.

Подводя итог

Вот последние 3 уравнения, которые вместе образуют основу обратного распространения.

Вот процесс, визуализированный с использованием нашего примера нейронной сети выше:

Обратное распространение: пример кода

def relu_prime(z): if z > 0: return 1 return 0 def cost(yHat, y): return 0.5 * (yHat - y)**2 def cost_prime(yHat, y): return yHat - y def backprop(x, y, Wh, Wo, lr): yHat = feed_forward(x, Wh, Wo) # Layer Error Eo = (yHat - y) * relu_prime(Zo) Eh = Eo * Wo * relu_prime(Zh) # Cost derivative for weights dWo = Eo * H dWh = Eh * x # Update weights Wh -= lr * dWh Wo -= lr * dWo