Подробный вывод алгоритма обратного распространения (BP) нейронной сети

Нейронные сети

Подробный вывод алгоритма обратного распространения

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

Мы будем использовать полносвязный слой с функцией активацииSigmoidфункция, функция ошибкиSoftmax+MSEВозьмем в качестве примера нейронную сеть функции потерь и выведем ее метод распространения градиента.

Готов к работе

1. Производная сигмовидной функции

обзорsigmoidВыражение функции:

\sigma(x) = \frac{1}{1+e^{-x}}

Его производная:

\frac{d}{dx}\sigma(x) = \frac{d}{dx} \left(\frac{1}{1+e^{-x}} \right)
= \frac{e^{-x}}{(1+e^{-x})^2}
= \frac{(1 + e^{-x})-1}{(1+e^{-x})^2}
=\frac{1+e^{-x}}{(1+e^{-x})^2} - \left(\frac{1}{1+e^{-x}}\right)^2
= \sigma(x) - \sigma(x)^2
= \sigma(1-\sigma)

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

import numpy as np # 导入 numpy

def sigmoid(x): # sigmoid 函数
	return 1 / (1 + np.exp(-x))

def derivative(x): # sigmoid 导数的计算
	return sigmoid(x)*(1-sigmoid(x))

2. Градиент функции среднеквадратичной ошибки

Выражение функции потери среднеквадратичной ошибки:

L = \frac{1}{2}\sum_{k=1}^{K}(y_k-o_k)^2

вy_kэто реальная стоимость,o_kявляется выходным значением. то его частная производная\frac{\partial L}{\partial o_i}Может быть расширен до:

\frac{\partial L}{\partial o_i} = \frac{1}{2}\sum_{k=1}^{K}\frac{\partial}{\partial o_i}(y_k - o_k)^2

Используйте цепное правило, чтобы разложить на

\frac{\partial L}{\partial o_i} = \frac{1}{2}\sum_{k=1}^{K}\cdot2\cdot(y_k-o_k)\cdot\frac{\partial(y_k-o_k)}{\partial o_i}
\frac{\partial L}{\partial o_i} = \sum_{k=1}^{K}(y_k-o_k)\cdot(-1)\cdot\frac{\partial o_k}{\partial o_i}

\frac{\partial o_k}{\partial o_i}только еслиk = iкогда1, остальные точки0, то есть\frac{\partial o_k}{\partial o_i}только сiКоличество узлов связано и не имеет ничего общего с другими узлами, поэтому символ суммирования в приведенной выше формуле можно удалить, а производную среднеквадратической ошибки можно вывести как

\frac{\partial L}{\partial o_i} = (o_i - y_i)

градиент одного нейрона

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

o^1 = \sigma(w^1x+b^1)

в

  • Верхний индекс переменной указывает количество слоев, напримерo^1представляет вывод первого скрытого слоя
  • xпредставляет вход сети

Модель одного нейрона показана на рисунке ниже.

  • Количество входных узловJ
    • где ввестиjузел для выводаo^1Весовая связь записывается какw^1_{j1}
  • Верхний индекс указывает количество слоев, к которым принадлежит вес, а нижний индекс указывает номер начального узла и номер конечного узла текущего соединения.
    • как показано нижеj1Указывает на первыйjNode No. 1 – Node No. 1 текущего слоя
  • Выходная переменная без функции активацииz_1^1, выход после функции активацииo_1^1
  • Так как есть только один выходной узел,o_1^1 = o^1

单个神经元模型

Далее вычисляем среднеквадратичную ошибку как градиент функции

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

L = \frac{1}{2}(o_1^1 - t)^2

Добавить к\frac{1}{2}Для удобства расчета воспользуемся весами для соединения первогоj\in[1,J]Вес номера узлаw_{j1}В качестве примера рассмотрим функцию потерьLчастная производная от него\frac{\partial L}{\partial w_{j1}}

\frac{\partial L}{\partial w_{j1}} = (o_1 - t)\frac{\partial o_1}{\partial w_{j1}}

так какo_1 = \sigma(z_1), из приведенного выше вывода видно, что производная сигмовидной функции\sigma' = \sigma(1-\sigma)

\frac{\partial L}{\partial w_{j1}} = (o_1 - t)\frac{\partial \sigma(z_1)}{\partial w_{j1}}
= (o_1-t)\sigma(z_1)(1-\sigma(z_1))\frac{\partial z_1}{\partial w_{j1}}

Пучок\sigma(z_1)написано какo_1

= (o_1-t)o_1(1-o_1)\frac{\partial z_1}{\partial w_{j1}}

так как\frac{\partial z_1}{\partial w_{j1}} = x_j

\frac{\partial L}{\partial w_{j1}} = (o_1-t)o_1(1-o_1)x_j

Из приведенного выше уравнения видно, что ошибка имеетw_{j1}Частная производная связана только с выходным значениемo_1,реальная стоимостьtи вывод текущего веса связиx_jСвязанный

Полностью связанный градиент слоя

Мы обобщаем модель одного нейрона на сеть с одним полносвязным слоем, как показано на следующем рисунке. Входной слой получает выходной вектор через полносвязный слой.o^1, с достоверным вектором метокtВычислите среднеквадратичную ошибку. Количество входных узловJ, число выходных узлов равноK.

В отличие от одного нейрона, полносвязный слой имеет несколько выходных узлов.o_1^1, o_2^1, o_3^1,...,o_K^1, каждый выходной узел соответствует другой истинной меткеt_1, t_2, t_3,..., t_K, среднеквадратическая ошибка может быть выражена как

L = \frac{1}{2}\sum_{i=1}^K(o_i^1-t_i)^2

так как\frac{\partial L}{\partial w_{jk}}только сo_k^1связанных, символ суммирования в приведенной выше формуле может быть удален, то естьi = k

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\frac{\partial o_k}{\partial w_{jk}}

будетo_k=\sigma(z_k)принести

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\frac{\partial \sigma(z_k)}{\partial w_{jk}}

учитыватьSigmoidПроизводная функции\sigma' = \sigma(1-\sigma)

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\sigma(z_k)(1-\sigma(z_k))\frac{\partial z_k^1}{\partial w_{jk}}

будет\sigma(z_k)отмечен какo_k

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\frac{\partial z_k^1}{\partial w_{jk}}

наконец-то доступно

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\cdot x_j

Отсюда видно, что связьw_{jk}Вышеупомянутое соединение, только с подключенным в данный момент выходным узломo_k^1, метка соответствующего узла истинного значенияt_k^1, и соответствующий входной узелxСвязанный.

мы заказываем\delta_k = (o_k-t_k)o_k(1-o_k),но\frac{\partial L}{\partial w_{jk}}можно выразить как

\frac{\partial L}{\partial w_{jk}}=\delta_k\cdot x_j

в\delta _kПеременная характеризует некоторое свойство градиентного распространения конечного узла связи, используя\delta_kПосле выражения,\frac{\partial L}{\partial w_{jk}}Частные производные относятся только к начальному узлу текущего соединения.x_j, в конечном узле\delta_kЭто более интуитивно понятно.

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

Всех здесь увидеть не просто, ведь столько формул хахаха, но самое интересное время пришло

Сначала просмотрите формулу частной производной выходного слоя.

\frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\cdot x_j = \delta_k \cdot x_j

Многослойный полносвязный слой показан на следующем рисунке.

  • Количество выходных узловK, выводo^k = [o_1^k, o_2^k, o_3^k,..., o_k^k]
  • Количество узлов в обратном втором слое равноJ, выходo^J=[o_1^J, o_2^J,..., o_J^J]
  • Количество узлов в предпоследнем слое равноI, выходo^I = [o_1^I, o_2^I,..., o_I^I]

функция среднеквадратичной ошибки

\frac{\partial L}{\partial w_{ij}}=\frac{\partial}{\partial w_{ij}}\frac{1}{2}\sum_{k}(o_k-t_k)2

так какLчерез каждый выходной узелo_kиw_iсвязаны, поэтому символ суммирования здесь нельзя убрать

\frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac{\partial o_k}{\partial w_{ij}}

будетo_k=\sigma(z_k)принести

\frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac{\partial \sigma(z_k)}{\partial w_{ij}}

SigmoidПроизводная функции\sigma' = \sigma(1-\sigma), продолжить вывод и положить\sigma(z_k)написать ответo_k

\frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)o_k(1-o_k)\frac{\partial z_k}{\partial w_{ij}}

за\frac{\partial z_k}{\partial w_{ij}}Цепное правило может быть применено для разложения как

\frac{\partial z_k}{\partial w_{ij}} = \frac{\partial z_k}{o_j}\cdot \frac{\partial o_j}{\partial w_{ij}}

На рисунке показано\left(z_k = o_j \cdot w_{jk} + b_k\right), так что есть

\frac{\partial z_k}{o_j} = w_{jk}

так

\frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}\cdot\frac{\partial o_j}{\partial w_{ij}}

учитывая\frac{\partial o_j}{\partial w_{ij}}иkНе беда, его можно извлечь

\frac{\partial L}{\partial w_{ij}}=\frac{\partial o_j}{\partial w_{ij}}\cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}

снова естьo_k=\sigma(z_k)и использоватьSigmoidПроизводная функции\sigma' = \sigma(1-\sigma)имеют

\frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)\frac{\partial z_j}{\partial w_{ij}} \cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}

так как\frac{\partial z_j}{\partial w_{ij}} = o_i \left(z_j = o_i\cdot w_{ij} + b_j\right)

\frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)o_i \cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}

в\delta _k^K = (o_k-t_k)o_k(1-o_k),но

\frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)o_i \cdot\sum_k\delta _k^K\cdot w_{jk}

Следуя методу записи выходного слоя, определите

\delta_j^J = o_j(1-o_j) \cdot \sum_k \delta _k^K\cdot w_{jk}

В настоящее время\frac{\partial L}{\partial w_{ij}}Может быть записано как выходное значение текущего подключенного начального узла.o_iс оконечным узломjинформация о градиенте\delta _j^JПростое умножение:

\frac{\partial L}{\partial w_{ij}} = \delta_j^J\cdot o_i^I

по определению\deltaпеременные, выражение градиента каждого слоя становится более четким и лаконичным, где\deltaЕго можно просто понимать как текущее соединениеw_{ij}Вклад в функцию ошибок.

Суммировать

выходной слой:

\frac{\partial L}{\partial w_{jk}} = \delta _k^K\cdot o_j
\delta _k^K = (o_k-t_k)o_k(1-o_k)

Предпоследний слой:

\frac{\partial L}{\partial w_{ij}} = \delta _j^J\cdot o_i
\delta_j^J = o_j(1-o_j) \cdot \sum_k \delta _k^K\cdot w_{jk}

Третий этаж снизу:

\frac{\partial L}{\partial w_{ni}} = \delta _i^I\cdot o_n
\delta _i^I = o_i(1-o_i)\cdot \sum_j\delta_j^J\cdot w_{ij}

вo_nявляется входом предпоследнего слоя, то есть выходом предпоследнего слоя

Согласно этому правилу необходимо только итеративно вычислять значение каждого узла в каждом слое.\delta _k^K, \delta_j^J, \delta_i^I,...Частная производная текущего слоя может быть получена по эквивалентному значению, и может быть получена весовая матрица каждого слоя.WЗатем параметры сети можно итеративно оптимизировать с помощью алгоритма градиентного спуска.

Что ж, алгоритм обратного распространения выведен, реализация кода может ссылаться на другой блогПрактическая реализация алгоритма обратного распространения нейронной сети (BP)