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

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

Время на прочтение
6 мин

Количество просмотров 45K

Всем привет! Новогодние праздники подошли к концу, а это значит, что мы вновь готовы делиться с вами полезным материалом. Перевод данной статьи подготовлен в преддверии запуска нового потока по курсу «Алгоритмы для разработчиков».

Поехали!


Метод обратного распространения ошибки – вероятно самая фундаментальная составляющая нейронной сети. Впервые он был описан в 1960-е и почти 30 лет спустя его популяризировали Румельхарт, Хинтон и Уильямс в статье под названием «Learning representations by back-propagating errors».

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

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

Определяем модель нейронной сети

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


Простое изображение четырехслойной нейронной сети.

Входной слой

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


Уравнение, описывающее входы xi.

Первый набор активаций (а) равен входным значениям. «Активация» — это значение нейрона после применения функции активации. Подробнее смотрите ниже.

Скрытые слои

Конечные значения в скрытых нейронах (на рисунке зеленого цвета) вычисляются с использованием zl – взвешенных входов в слое I и aI активаций в слое L. Для слоев 2 и 3 уравнения будут следующими:

Для l = 2:

Для l = 3:

W2 и W3 – это веса на слоях 2 и 3, а b2 и b3 – смещения на этих слоях.

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

Присмотревшись внимательно, вы увидите, что все x, z2, a2, z3, a3, W1, W2, b1 и b2 не имеют нижних индексов, представленных на рисунке четырехслойной нейронной сети. Дело в том, что мы объединили все значения параметров в матрицы, сгруппированные по слоям. Это стандартный способ работы с нейронными сетями, и он довольно комфортный. Однако я пройдусь по уравнениям, чтобы не возникло путаницы.

Давайте возьмем слой 2 и его параметры в качестве примера. Те же самые операции можно применить к любому слою нейронной сети.
W1 – это матрица весов размерности (n, m), где n – это количество выходных нейронов (нейронов на следующем слое), а m – число входных нейронов (нейронов в предыдущем слое). В нашем случае n = 2 и m = 4.

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

x – входной вектор размерностью (m, 1), где m – число входных нейронов. В нашем случае m = 4.

b1 – это вектор смещения размерности (n, 1), где n – число нейронов на текущем слое. В нашем случае n = 2.

Следуя уравнению для z2 мы можем использовать приведенные выше определения W1, x и b1 для получения уравнения z2:

Теперь внимательно посмотрите на иллюстрацию нейронной сети выше:

Как видите, z2 можно выразить через z12 и z22, где z12 и z22 – суммы произведений каждого входного значения xi на соответствующий вес Wij1.

Это приводит к тому же самому уравнению для z2 и доказывает, что матричные представления z2, a2, z3 и a3 – верны.

Выходной слой

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

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

Прямое распространение и оценка

Приведенные выше уравнения формируют прямое распространение по нейронной сети. Вот краткий обзор:

(1) – входной слой
(2) – значение нейрона на первом скрытом слое
(3) – значение активации на первом скрытом слое
(4) – значение нейрона на втором скрытом слое
(5) – значение активации на втором скрытом уровне
(6) – выходной слой

Заключительным шагом в прямом проходе является оценка прогнозируемого выходного значения s относительно ожидаемого выходного значения y.

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

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

Мы назовем эту функцию потерь С и обозначим ее следующим образом:

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

Основываясь на значении С, модель «знает», насколько нужно скорректировать ее параметры, чтобы приблизиться к ожидаемому выходному значению y. Это происходит с помощью метода обратного распространения ошибки.

Обратное распространение ошибки и вычисление градиентов

Опираясь на статью 1989 года, метод обратного распространения ошибки:

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

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

Возникает один вопрос: Зачем вычислять градиенты?

Чтобы ответить на этот вопрос, нам сначала нужно пересмотреть некоторые понятия вычислений:

Градиентом функции С(x1, x2, …, xm) в точке x называется вектор частных производных С по x.

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

Градиент показывает, насколько необходимо изменить параметр x (в положительную или отрицательную сторону), чтобы минимизировать С.

Вычисление этих градиентов происходит с помощью метода, называемого цепным правилом.
Для одного веса (wjk)l градиент равен:

(1) Цепное правило
(2) По определению m – количество нейронов на l – 1 слое
(3) Вычисление производной
(4) Окончательное значение
Аналогичный набор уравнений можно применить к (bj)l
:

(1) Цепное правило
(2) Вычисление производной
(3) Окончательное значение

Общая часть в обоих уравнениях часто называется «локальным градиентом» и выражается следующим образом:

«Локальный градиент» можно легко определить с помощью правила цепи. Этот процесс я не буду сейчас расписывать.

Градиенты позволяют оптимизировать параметры модели:

Пока не будет достигнут критерий остановки выполняется следующее:

Алгоритм оптимизации весов и смещений (также называемый градиентным спуском)

  • Начальные значения w и b выбираются случайным образом.
  • Эпсилон (e) – это скорость обучения. Он определяет влияние градиента.
  • w и b – матричные представления весов и смещений.
  • Производная C по w или b может быть вычислена с использованием частных производных С по отдельным весам или смещениям.
  • Условие завершение выполняется, как только функция потерь минимизируется.

Заключительную часть этого раздела я хочу посвятить простому примеру, в котором мы рассчитаем градиент С относительно одного веса (w22)2.

Давайте увеличим масштаб нижней части вышеупомянутой нейронной сети:

Визуальное представление обратного распространения в нейронной сети
Вес (w22)2 соединяет (a2)2 и (z2)2, поэтому вычисление градиента требует применения цепного правила на (z3)2 и (a3)2:

Вычисление конечного значения производной С по (a2)3 требует знания функции С. Поскольку С зависит от (a2)3, вычисление производной должно быть простым.

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

Заключительное замечание

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

На этом все. Приглашаем всех на бесплатный вебинар по теме «Дерево отрезков: просто и быстро».

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

Открытие метода обратного распространения ошибки стало одним из наиболее значимых событий в области искусственного интеллекта. В актуальном виде он был предложен в 1986 году Дэвидом Э. Румельхартом, Джеффри Э. Хинтоном и Рональдом Дж. Вильямсом и независимо и одновременно красноярскими математиками С. И. Барцевым и В. А. Охониным. С тех пор для нахождения градиентов параметров нейронной сети используется метод вычисления производной сложной функции, и оценка градиентов параметров сети стала хоть сложной инженерной задачей, но уже не искусством. Несмотря на простоту используемого математического аппарата, появление этого метода привело к значительному скачку в развитии искусственных нейронных сетей.

Суть метода можно записать одной формулой, тривиально следующей из формулы производной сложной функции: если $f(x) = g_m(g_{m-1}(ldots (g_1(x)) ldots))$, то $frac{partial f}{partial x} = frac{partial g_m}{partial g_{m-1}}frac{partial g_{m-1}}{partial g_{m-2}}ldots frac{partial g_2}{partial g_1}frac{partial g_1}{partial x}$. Уже сейчас мы видим, что градиенты можно вычислять последовательно, в ходе одного обратного прохода, начиная с $frac{partial g_m}{partial g_{m-1}}$ и умножая каждый раз на частные производные предыдущего слоя.

Backpropagation в одномерном случае

В одномерном случае всё выглядит особенно просто. Пусть $w_0$ — переменная, по которой мы хотим продифференцировать, причём сложная функция имеет вид

$$f(w_0) = g_m(g_{m-1}(ldots g_1(w_0)ldots)),$$

где все $g_i$ скалярные. Тогда

$$f'(w_0) = g_m'(g_{m-1}(ldots g_1(w_0)ldots))cdot g’_{m-1}(g_{m-2}(ldots g_1(w_0)ldots))cdotldots cdot g’_1(w_0)$$

Суть этой формулы такова. Если мы уже совершили forward pass, то есть уже знаем

$$g_1(w_0), g_2(g_1(w_0)),ldots,g_{m-1}(ldots g_1(w_0)ldots),$$

то мы действуем следующим образом:

  • берём производную $g_m$ в точке $g_{m-1}(ldots g_1(w_0)ldots)$;

  • умножаем на производную $g_{m-1}$ в точке $g_{m-2}(ldots g_1(w_0)ldots)$;

  • и так далее, пока не дойдём до производной $g_1$ в точке $w_0$.

Проиллюстрируем это на картинке, расписав по шагам дифференцирование по весам $w_i$ функции потерь логистической регрессии на одном объекте (то есть для батча размера 1):

17_1.png

Собирая все множители вместе, получаем:

$$frac{partial f}{partial w_0} = (-y)cdot e^{-y(w_0 + w_1x_1 + w_2x_2)}cdotfrac{-1}{1 + e^{-y(w_0 + w_1x_1 + w_2x_2)}}$$

$$frac{partial f}{partial w_1} = x_1cdot(-y)cdot e^{-y(w_0 + w_1x_1 + w_2x_2)}cdotfrac{-1}{1 + e^{-y(w_0 + w_1x_1 + w_2x_2)}}$$

$$frac{partial f}{partial w_2} = x_2cdot(-y)cdot e^{-y(w_0 + w_1x_1 + w_2x_2)}cdotfrac{-1}{1 + e^{-y(w_0 + w_1x_1 + w_2x_2)}}$$

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

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

В главе, посвящённой матричным дифференцированиям, мы поднимаем вопрос о том, что вычислять частные производные по отдельности — это зло, лучше пользоваться матричными вычислениями. Но есть и ещё одна причина: даже и с матричной производной в принципе не всегда хочется иметь дело. Рассмотрим простой пример. Допустим, что $X^r$ и $X^{r+1}$ — два последовательных промежуточных представления $Ntimes M$ и $Ntimes K$, связанных функцией $X^{r+1} = f^{r+1}(X^r)$. Предположим, что мы как-то посчитали производную $frac{partialmathcal{L}}{partial X^{r+1}_{ij}}$ функции потерь $mathcal{L}$, тогда

$$frac{partialmathcal{L}}{partial X^{r}_{st}} = sum_{i,j}frac{partial f^{r+1}_{ij}}{partial X^{r}_{st}}frac{partialmathcal{L}}{partial X^{r+1}_{ij}}$$

И мы видим, что, хотя оба градиента $frac{partialmathcal{L}}{partial X_{ij}^{r+1}}$ и $frac{partialmathcal{L}}{partial X_{st}^{r}}$ являются просто матрицами, в ходе вычислений возникает «четырёхмерный кубик» $frac{partial f_{ij}^{r+1}}{partial X_{st}^{r}}$, даже хранить который весьма болезненно: уж больно много памяти он требует ($N^2MK$ по сравнению с безобидными $NM + NK$, требуемыми для хранения градиентов). Поэтому хочется промежуточные производные $frac{partial f^{r+1}}{partial X^{r}}$ рассматривать не как вычисляемые объекты $frac{partial f_{ij}^{r+1}}{partial X_{st}^{r}}$, а как преобразования, которые превращают $frac{partialmathcal{L}}{partial X_{ij}^{r+1}}$ в $frac{partialmathcal{L}}{partial X_{st}^{r}}$. Целью следующих глав будет именно это: понять, как преобразуется градиент в ходе error backpropagation при переходе через тот или иной слой.

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

Встречный вопрос. Найдите производную функции по вектору $x$:

$$f(x) = x^TAx, Ain Mat_{n}{mathbb{R}}text{ — матрица размера }ntimes n$$

А как всё поменяется, если $A$ тоже зависит от $x$? Чему равен градиент функции, если $A$ является скаляром? Если вы готовы прямо сейчас взять ручку и бумагу и посчитать всё, то вам, вероятно, не надо читать про матричные дифференцирования. Но мы советуем всё-таки заглянуть в эту главу, если обозначения, которые мы будем дальше использовать, покажутся вам непонятными: единой нотации для матричных дифференцирований человечество пока, увы, не изобрело, и переводить с одной на другую не всегда легко.

Мы же сразу перейдём к интересующей нас вещи: к вычислению градиентов сложных функций.

Градиент сложной функции

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

$$left[D_{x_0} (color{#5002A7}{u} circ color{#4CB9C0}{v}) right](h) = color{#5002A7}{left[D_{v(x_0)} u right]} left( color{#4CB9C0}{left[D_{x_0} vright]} (h)right)$$

Теперь разберёмся с градиентами. Пусть $f(x) = g(h(x))$ – скалярная функция. Тогда

$$left[D_{x_0} f right] (x-x_0) = langlenabla_{x_0} f, x-x_0rangle.$$

С другой стороны,

$$left[D_{h(x_0)} g right] left(left[D_{x_0}h right] (x-x_0)right) = langlenabla_{h_{x_0}} g, left[D_{x_0} hright] (x-x_0)rangle = langleleft[D_{x_0} hright]^* nabla_{h(x_0)} g, x-x_0rangle.$$

То есть $color{#FFC100}{nabla_{x_0} f} = color{#348FEA}{left[D_{x_0} h right]}^* color{#FFC100}{nabla_{h(x_0)}}g$ — применение сопряжённого к $D_{x_0} h$ линейного отображения к вектору $nabla_{h(x_0)} g$.

Эта формула — сердце механизма обратного распространения ошибки. Она говорит следующее: если мы каким-то образом получили градиент функции потерь по переменным из некоторого промежуточного представления $X^k$ нейронной сети и при этом знаем, как преобразуется градиент при проходе через слой $f^k$ между $X^{k-1}$ и $X^k$ (то есть как выглядит сопряжённое к дифференциалу слоя между ними отображение), то мы сразу же находим градиент и по переменным из $X^{k-1}$:

17_2.png

Таким образом слой за слоем мы посчитаем градиенты по всем $X^i$ вплоть до самых первых слоёв.

Далее мы разберёмся, как именно преобразуются градиенты при переходе через некоторые распространённые слои.

Градиенты для типичных слоёв

Рассмотрим несколько важных примеров.

Примеры

  1. $f(x) = u(v(x))$, где $x$ — вектор, а $v(x)$ – поэлементное применение $v$:

    $$vbegin{pmatrix}
    x_1 \
    vdots\
    x_N
    end{pmatrix}
    = begin{pmatrix}
    v(x_1)\
    vdots\
    v(x_N)
    end{pmatrix}$$

    Тогда, как мы знаем,

    $$left[D_{x_0} fright] (h) = langlenabla_{x_0} f, hrangle = left[nabla_{x_0} fright]^T h.$$

    Следовательно,

    $$
    left[D_{v(x_0)} uright] left( left[ D_{x_0} vright] (h)right) = left[nabla_{v(x_0)} uright]^T left(v'(x_0) odot hright) =\
    $$

    $$
    = sumlimits_i left[nabla_{v(x_0)} uright]_i v'(x_{0i})h_i
    = langleleft[nabla_{v(x_0)} uright] odot v'(x_0), hrangle.
    ,$$

    где $odot$ означает поэлементное перемножение. Окончательно получаем

    $$color{#348FEA}{nabla_{x_0} f = left[nabla_{v(x_0)}uright] odot v'(x_0) = v'(x_0) odot left[nabla_{v(x_0)} uright]}$$

    Отметим, что если $x$ и $h(x)$ — это просто векторы, то мы могли бы вычислять всё и по формуле $frac{partial f}{partial x_i} = sum_jbig(frac{partial z_j}{partial x_i}big)cdotbig(frac{partial h}{partial z_j}big)$. В этом случае матрица $big(frac{partial z_j}{partial x_i}big)$ была бы диагональной (так как $z_j$ зависит только от $x_j$: ведь $h$ берётся поэлементно), и матричное умножение приводило бы к тому же результату. Однако если $x$ и $h(x)$ — матрицы, то $big(frac{partial z_j}{partial x_i}big)$ представлялась бы уже «четырёхмерным кубиком», и работать с ним было бы ужасно неудобно.

  2. $f(X) = g(XW)$, где $X$ и $W$ — матрицы. Как мы знаем,

    $$left[D_{X_0} f right] (X-X_0) = text{tr}, left(left[nabla_{X_0} fright]^T (X-X_0)right).$$

    Тогда

    $$
    left[ D_{X_0W} g right] left(left[D_{X_0} left( ast Wright)right] (H)right) =
    left[ D_{X_0W} g right] left(HWright)=\
    $$ $$
    = text{tr}, left( left[nabla_{X_0W} g right]^T cdot (H) W right) =\
    $$ $$
    =
    text{tr} , left(W left[nabla_{X_0W} (g) right]^T cdot (H)right) = text{tr} , left( left[left[nabla_{X_0W} gright] W^Tright]^T (H)right)
    $$

    Здесь через $ast W$ мы обозначили отображение $Y hookrightarrow YW$, а в предпоследнем переходе использовалось следующее свойство следа:

    $$
    text{tr} , (A B C) = text{tr} , (C A B),
    $$

    где $A, B, C$ — произвольные матрицы подходящих размеров (то есть допускающие перемножение в обоих приведённых порядках). Следовательно, получаем

    $$color{#348FEA}{nabla_{X_0} f = left[nabla_{X_0W} (g) right] cdot W^T}$$

  3. $f(W) = g(XW)$, где $W$ и $X$ — матрицы. Для приращения $H = W — W_0$ имеем

    $$
    left[D_{W_0} f right] (H) = text{tr} , left( left[nabla_{W_0} f right]^T (H)right)
    $$

    Тогда

    $$
    left[D_{XW_0} g right] left( left[D_{W_0} left(X astright) right] (H)right) = left[D_{XW_0} g right] left( XH right) =
    $$ $$
    = text{tr} , left( left[nabla_{XW_0} g right]^T cdot X (H)right) =
    text{tr}, left(left[X^T left[nabla_{XW_0} g right] right]^T (H)right)
    $$

    Здесь через $X ast$ обозначено отображение $Y hookrightarrow XY$. Значит,

    $$color{#348FEA}{nabla_{X_0} f = X^T cdot left[nabla_{XW_0} (g)right]}$$

  4. $f(X) = g(softmax(X))$, где $X$ — матрица $Ntimes K$, а $softmax$ — функция, которая вычисляется построчно, причём для каждой строки $x$

    $$softmax(x) = left(frac{e^{x_1}}{sum_te^{x_t}},ldots,frac{e^{x_K}}{sum_te^{x_t}}right)$$

    В этом примере нам будет удобно воспользоваться формализмом с частными производными. Сначала вычислим $frac{partial s_l}{partial x_j}$ для одной строки $x$, где через $s_l$ мы для краткости обозначим $softmax(x)_l = frac{e^{x_l}} {sum_te^{x_t}}$. Нетрудно проверить, что

    $$frac{partial s_l}{partial x_j} = begin{cases}
    s_j(1 — s_j), & j = l,
    -s_ls_j, & jne l
    end{cases}$$

    Так как softmax вычисляется независимо от каждой строчки, то

    $$frac{partial s_{rl}}{partial x_{ij}} = begin{cases}
    s_{ij}(1 — s_{ij}), & r=i, j = l,
    -s_{il}s_{ij}, & r = i, jne l,
    0, & rne i
    end{cases},$$

    где через $s_{rl}$ мы обозначили для краткости $softmax(X)_{rl}$.

    Теперь пусть $nabla_{rl} = nabla g = frac{partialmathcal{L}}{partial s_{rl}}$ (пришедший со следующего слоя, уже известный градиент). Тогда

    $$frac{partialmathcal{L}}{partial x_{ij}} = sum_{r,l}frac{partial s_{rl}}{partial x_{ij}} nabla_{rl}$$

    Так как $frac{partial s_{rl}}{partial x_{ij}} = 0$ при $rne i$, мы можем убрать суммирование по $r$:

    $$ldots = sum_{l}frac{partial s_{il}}{partial x_{ij}} nabla_{il} = -s_{i1}s_{ij}nabla_{i1} — ldots + s_{ij}(1 — s_{ij})nabla_{ij}-ldots — s_{iK}s_{ij}nabla_{iK} =$$

    $$= -s_{ij}sum_t s_{it}nabla_{it} + s_{ij}nabla_{ij}$$

    Таким образом, если мы хотим продифференцировать $f$ в какой-то конкретной точке $X_0$, то, смешивая математические обозначения с нотацией Python, мы можем записать:

    $$begin{multline*}
    color{#348FEA}{nabla_{X_0}f =}\
    color{#348FEA}{= -softmax(X_0) odot text{sum}left(
    softmax(X_0)odotnabla_{softmax(X_0)}g, text{ axis = 1}
    right) +}\
    color{#348FEA}{softmax(X_0)odot nabla_{softmax(X_0)}g}
    end{multline*}
    $$

Backpropagation в общем виде

Подытожим предыдущее обсуждение, описав алгоритм error backpropagation (алгоритм обратного распространения ошибки). Допустим, у нас есть текущие значения весов $W^i_0$ и мы хотим совершить шаг SGD по мини-батчу $X$. Мы должны сделать следующее:

  1. Совершить forward pass, вычислив и запомнив все промежуточные представления $X = X^0, X^1, ldots, X^m = widehat{y}$.
  2. Вычислить все градиенты с помощью backward pass.
  3. С помощью полученных градиентов совершить шаг SGD.

Проиллюстрируем алгоритм на примере двуслойной нейронной сети со скалярным output’ом. Для простоты опустим свободные члены в линейных слоях.

17_3.png Обучаемые параметры – матрицы $U$ и $W$. Как найти градиенты по ним в точке $U_0, W_0$?

$$nabla_{W_0}mathcal{L} = nabla_{W_0}{left({vphantom{frac12}mathcal{L}circ hcircleft[Wmapsto g(XU_0)Wright]}right)}=$$

$$=g(XU_0)^Tnabla_{g(XU_0)W_0}(mathcal{L}circ h) = underbrace{g(XU_0)^T}_{ktimes N}cdot
left[vphantom{frac12}underbrace{h’left(vphantom{int_0^1}g(XU_0)W_0right)}_{Ntimes 1}odot
underbrace{nabla_{hleft(vphantom{int_0^1}g(XU_0)W_0right)}mathcal{L}}_{Ntimes 1}right]$$

Итого матрица $ktimes 1$, как и $W_0$

$$nabla_{U_0}mathcal{L} = nabla_{U_0}left(vphantom{frac12}
mathcal{L}circ hcircleft[Ymapsto YW_0right]circ gcircleft[ Umapsto XUright]
right)=$$

$$=X^Tcdotnabla_{XU^0}left(vphantom{frac12}mathcal{L}circ hcirc [Ymapsto YW_0]circ gright) =$$

$$=X^Tcdotleft(vphantom{frac12}g'(XU_0)odot
nabla_{g(XU_0)}left[vphantom{in_0^1}mathcal{L}circ hcirc[Ymapsto YW_0right]
right)$$

$$=ldots = underset{Dtimes N}{X^T}cdotleft(vphantom{frac12}
underbrace{g'(XU_0)}_{Ntimes K}odot
underbrace{left[vphantom{int_0^1}left(
underbrace{h’left(vphantom{int_0^1}g(XU_0)W_0right)}_{Ntimes1}odotunderbrace{nabla_{h(vphantom{int_0^1}gleft(XU_0right)W_0)}mathcal{L}}_{Ntimes 1}
right)cdot underbrace{W^T}_{1times K}right]}_{Ntimes K}
right)$$

Итого $Dtimes K$, как и $U_0$

Схематически это можно представить следующим образом:

17_4.gif

Backpropagation для двуслойной нейронной сети

Подробнее о предыдущих вычисленияхЕсли вы не уследили за вычислениями в предыдущем примере, давайте более подробно разберём его чуть более конкретную версию (для $g = h = sigma$).

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

$$
widehat{y} = sigma(X^1 W^2) = sigmaBig(big(sigma(X^0 W^1 )big) W^2 Big).
$$

Пусть $W^1_0$ и $W^2_0$ — текущее приближение матриц весов. Мы хотим совершить шаг по градиенту функции потерь, и для этого мы должны вычислить её градиенты по $W^1$ и $W^2$ в точке $(W^1_0, W^2_0)$.

Прежде всего мы совершаем forward pass, в ходе которого мы должны запомнить все промежуточные представления: $X^1 = X^0 W^1_0$, $X^2 = sigma(X^0 W^1_0)$, $X^3 = sigma(X^0 W^1_0) W^2_0$, $X^4 = sigma(sigma(X^0 W^1_0) W^2_0) = widehat{y}$. Они понадобятся нам дальше.

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

$$
l = mathcal{L}(y, widehat{y}) = y log(widehat{y}) + (1-y) log(1-widehat{y}).
$$

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

  1. Градиент $mathcal{L}$ по предсказаниям имеет вид

    $$
    nabla_{widehat{y}}l = frac{y}{widehat{y}} — frac{1 — y}{1 — widehat{y}} = frac{y — widehat{y}}{widehat{y} (1 — widehat{y})},
    $$

    где, напомним, $ widehat{y} = sigma(X^3) = sigmaBig(big(sigma(X^0 W^1_0 )big) W^2_0 Big)$ (обратите внимание на то, что $W^1_0$ и $W^2_0$ тут именно те, из которых мы делаем градиентный шаг).

  2. Следующий слой — поэлементное взятие $sigma$. Как мы помним, при переходе через него градиент поэлементно умножается на производную $sigma$, в которую подставлено предыдущее промежуточное представление:

    $$
    nabla_{X^3}l = sigma'(X^3)odotnabla_{widehat{y}}l = sigma(X^3)left( 1 — sigma(X^3) right) odot frac{y — widehat{y}}{widehat{y} (1 — widehat{y})} =
    $$

    $$
    = sigma(X^3)left( 1 — sigma(X^3) right) odot frac{y — sigma(X^3)}{sigma(X^3) (1 — sigma(X^3))} =
    y — sigma(X^3)
    $$

  3. Следующий слой — умножение на $W^2_0$. В этот момент мы найдём градиент как по $W^2$, так и по $X^2$. При переходе через умножение на матрицу градиент, как мы помним, умножается с той же стороны на транспонированную матрицу, а значит:

    $$
    color{blue}{nabla_{W^2_0}l} = (X^2)^Tcdot nabla_{X^3}l = (X^2)^Tcdot(y — sigma(X^3)) =
    $$

    $$
    = color{blue}{left( sigma(X^0W^1_0) right)^T cdot (y — sigma(sigma(X^0W^1_0)W^2_0))}
    $$

    Аналогичным образом

    $$
    nabla_{X^2}l = nabla_{X^3}lcdot (W^2_0)^T = (y — sigma(X^3))cdot (W^2_0)^T =
    $$

    $$
    = (y — sigma(X^2W_0^2))cdot (W^2_0)^T
    $$

  4. Следующий слой — снова взятие $sigma$.

    $$
    nabla_{X^1}l = sigma'(X^1)odotnabla_{X^2}l = sigma(X^1)left( 1 — sigma(X^1) right) odot left( (y — sigma(X^2W_0^2))cdot (W^2_0)^T right) =
    $$

    $$
    = sigma(X^1)left( 1 — sigma(X^1) right) odotleft( (y — sigma(sigma(X^1)W_0^2))cdot (W^2_0)^T right)
    $$

  5. Наконец, последний слой — это умножение $X^0$ на $W^1_0$. Тут мы дифференцируем только по $W^1$:

    $$
    color{blue}{nabla_{W^1_0}l} = (X^0)^Tcdot nabla_{X^1}l = (X^0)^Tcdot big( sigma(X^1) left( 1 — sigma(X^1) right) odot (y — sigma(sigma(X^1)W_0^2))cdot (W^2_0)^Tbig) =
    $$

    $$
    = color{blue}{(X^0)^Tcdotbig(sigma(X^0W^1_0)left( 1 — sigma(X^0W^1_0) right) odot (y — sigma(sigma(X^0W^1_0)W_0^2))cdot (W^2_0)^Tbig) }
    $$

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

Автоматизация и autograd

Итак, чтобы нейросеть обучалась, достаточно для любого слоя $f^k: X^{k-1}mapsto X^k$ с параметрами $W^k$ уметь:

  • превращать $nabla_{X^k_0}mathcal{L}$ в $nabla_{X^{k-1}_0}mathcal{L}$ (градиент по выходу в градиент по входу);
  • считать градиент по его параметрам $nabla_{W^k_0}mathcal{L}$.

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

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

Но это лишь начало

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

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

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

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

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

4-20219-e537a8.png

2-20219-7f9b72.png

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

3-20219-2ac7f4.png

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

Сигмоид может сужать диапазон изменения таким образом, чтобы значение OUT лежало между нулем и единицей. Нейронные многослойные сети характеризуются более высокой представляющей мощностью, если сравнивать их с однослойными, но это утверждение справедливо лишь в случае нелинейности. Нужную нелинейность и обеспечивает сжимающая функция. Но на практике существует много функций, которые можно использовать. Говоря о работе алгоритма обратного распространения ошибки, скажем, что для этого нужно лишь, чтобы функция была везде дифференцируема, а данному требованию как раз и удовлетворяет сигмоид. У него есть и дополнительное преимущество — автоматический контроль усиления. Если речь идёт о слабых сигналах (OUT близко к нулю), то кривая «вход-выход» характеризуется сильным наклоном, дающим большое усиление. При увеличении сигнала усиление падает. В результате большие сигналы будут восприниматься сетью без насыщения, а слабые сигналы будут проходить по сети без чрезмерного ослабления.

Цель обучения сети

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

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

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

Пошаговая реализация метода обратного распространения ошибки

Необходимо выполнить следующие действия:
1. Инициализировать синаптические веса случайными маленькими значениями.
2. Выбрать из обучающего множества очередную обучающую пару; подать на вход сети входной вектор.
3. Выполнить вычисление выходных значений нейронной сети.
4. Посчитать разность между выходом нейросети и требуемым выходом (речь идёт о целевом векторе обучающей пары).
5. Скорректировать веса сети в целях минимизации ошибки.
6. Повторять для каждого вектора обучающего множества шаги 2-5, пока ошибка обучения нейронной сети на всём множестве не достигнет уровня, который является приемлемым.

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

Сегодня существует много модификаций алгоритма обратного распространения ошибки. Возможно обучение не «по шагам» (выходная ошибка вычисляется, веса корректируются на каждом примере), а «по эпохам» в offline-режиме (изменения весовых коэффициентов происходит после подачи на вход нейросети всех примеров обучающего множества, а ошибка обучения neural сети усредняется по всем примерам).

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

Преимущества и недостатки метода

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

Значение метода обратного распространения

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

Источники:
— «Алгоритм обратного распространения ошибки»;
— «Back propagation algorithm».

    • обратное распространение

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

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

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

      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.

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

      Далее мы можем поменять местами элемент Eo выше, чтобы избежать дублирования и создать новое упрощенное уравнение для ошибки скрытого слоя:

      Eh=Eo⋅Wo⋅R′(Zh)

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

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

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

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

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

      C′(Wo)=Eo⋅H

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

      C′(w)=CurrentLayerError⋅CurrentLayerInput

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

      Подводя итог

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

      основа обратного распространения

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

      _images/backprop_visually.png

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

      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

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

      В случае единичной
      обучающей выборки (x,
      d)
      целевая функция определяется в виде

      (51)

      При большем
      количестве обучающих выборок j
      (j=1,
      2, …, p)
      целевая функция превращается в сумму
      по всем выборкам


      (52)

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

      1. Для упрощения
        можно считать, что цель обучения состоит
        в таком определении значений весов
        нейронов каждого слоя сети, чтобы при
        заданном входном векторе получить на
        выходе значения сигналов yi,
        совпадающие с требуемой точностью с
        ожидаемыми значениями di
        при i=1,
        2, …, M.

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

      Обучение
      сети с использованием алгоритма обратного
      распространения ошибки проводится в
      несколько этапов
      .
      На первом из них предъявляется обучающая
      выборка х
      и рассчитываются значения сигналов
      соответствующих нейронов сети. При
      заданном векторе x
      определяются вначале значения выходных
      сигналов vi
      скрытого слоя, а затем значения yi
      нейронов выходного слоя. Для расчета
      применяются формулы (49) и (50).

      После получения
      значений выходных сигналов yi
      становится возможным рассчитать
      фактическое значение целевой функции
      E(w)
      заданной выражением (51). На втором этапе
      минимизируется значение этой функции.

      48. Градиентные алгоритмы обучения сети

      Если принять, что
      целевая функция непрерывна, то наиболее
      эффективными способами обучения
      оказываются градиентные методы
      оптимизации
      ,
      согласно которым уточнение вектора
      весов (обучение) производится по
      формуле

      где η
      – коэффициент обучения, p(w)
      – направление в многомерном пространстве
      w.

      Обучение
      многослойной сети с применением
      градиентных методов

      требует определения вектора градиента
      относительно весов всех слоев сети, что
      необходимо для правильного выбора
      направления p(w).
      Эта задача имеет очевидное решение
      только для весов выходного слоя. Для
      других слоев создана специальная
      стратегия, которая в теории ИНС называется
      алгоритмом обратного распространения
      ошибки (error
      backpropagation
      ),
      отождествляемым, как правило, с процедурой
      обучения сети. В соответствии с этим
      алгоритмом в каждом цикле обучения
      выделяются следующие этапы:

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

      функции активации
      каждого слоя, где m
      – количество слоев сети.

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

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

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

      Для сети с одним
      скрытым слоем

      Рассмотрим условия,
      относящиеся к сети с одним скрытым
      слоем. Используемые обозначения
      представлены на рис. 19 (уже был ранее).

      Как и ранее,
      количество входных узлов обозначим
      буквой N
      количество нейронов в скрытом слое К,
      а количество нейронов в выходном слое
      М.
      Будем использовать сигмоидальную
      функцию активации этих нейронов. Основу
      алгоритма составляет расчет значения
      целевой функции как квадратичной суммы
      разностей между фактическими и ожидаемыми
      значениями выходных сигналов сети. В
      случае единичной обучающей выборки
      (x,d)
      целевая функция задается формулой (51),
      а для множества обучающих выборок j
      (j=1,
      2, …, p)
      – формулой (52).

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

      Эта функция
      определяется выражением:

      (53)

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


      где

      Если ввести
      обозначение (54)

      то соответствующий
      компонент градиента относительно весов
      нейронов выходного слоя можно представить
      в виде

      (55)

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

      (56)

      После конкретизации
      отдельных составляющих этого выражения
      получаем:

      (57)

      Если ввести
      обозначение

      (58)

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

      (59)

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

      В классическом
      алгоритме обратного распространения
      ошибки фактор p(w)
      задает направление отрицательного
      градиента, поэтому

      (60)

      Существуют и
      другие, более эффективные методы выбора
      направления p(w).

      Градиентные
      методы обучения сети

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

      • Алгоритм переменной
        метрики

      • Алгоритм
        Левенберга-Марквардта

      • Алгоритм сопряженных
        градиентов

      А также:

      • Эвристические
        методы обучения сети

      • Элементы глобальной
        оптимизации:

          • Алгоритм имитации
            отжига

          • Генетические
            алгоритмы

      • Методы инициализации
        весов

      РАДИАЛЬНЫЕ
      НЕЙРОННЫЕ СЕТИ



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

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

      Особое семейство
      образуют сети с радиальной базисной
      функцией, в которых скрытые нейроны
      реализуют функции, радиально изменяющиеся
      вокруг выбранного центра и принимающие
      ненулевые значения только в окрестности
      этого центра. Подобные функции,
      определяемые в виде φ(x)=
      φ(||xc||)
      будем называть радиальными
      базисными функциями
      .
      В таких сетях роль скрытого нейрона
      заключается в отображении радиального
      пространства вокруг одиночной заданной
      точки либо вокруг группы таких точек,
      образующих кластер. Суперпозиция
      сигналов, поступающих от всех скрытых
      нейронов, которая выполняется выходным
      нейроном, позволяет получить отображение
      всего многомерного пространства.



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

      Такой подход
      продемонстрирован на рис. 20 а).

      Рис. 20. Иллюстрация способов разделения
      пространства данных:

      а) сигмоидальным нейроном; б) радиальным
      нейроном

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

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

      Понравилась статья? Поделить с друзьями:
    • Актеры турецкого сериала мистер ошибка турецкий
    • Акпп ошибок нет не работает задняя передача
    • Айфон не подключается к айтюнс на компьютере ошибка 0x8000000a
    • Айфон не обновляется через айтюнс ошибка
    • Айфон не обновился через айтюнс ошибка