Итак, наша
задача вычислить весовые коэффициенты НС
с помощью градиентного алгоритма:
который мы с
вами расписывали следующим образом:
Отсюда хорошо
видно, что конкретный вид градиента меняется в зависимости от выбранной функции
потерь и
функций активации НС .
Кроме того, учитывая, как правило, большой объем обучающей выборки ,
выполнять суммирование по всем образам на каждой итерации работы градиентного
алгоритма слишком расточительно. Поэтому на практике выбирают случайно
отобранных образов из обучающей выборки и только по ним считается градиент:
Набор из таких образов часто
называют батчем (batch, англ. пакет) или мини-батчем. А сам
градиентный алгоритм превращается в стохастический градиентный спуск (SGD).
Но и это еще не
все. Современные НС часто содержат огромное количество параметров :
от десятков тысяч до триллионов. И если вычислять градиент функции потерь
стандартным способом, то потребовалось бы порядка операций,
где –
число коэффицентов .
Это очень много. Поэтому
был придуман алгоритм, применимый именно к НС, который позволяет вычислять тот
же самый градиент за линейное число операций, примерно:
где –
число слоев НС. Этот алгоритм получил название back propagation (обратное
распространение ошибки). Впервые, в 1974 году, его предложил советский
математик Галушкин А. И. Позже, в 1986 году, он был немного усовершенствован группой
американских ученых, которые и дали ему такое название back propagation.
Математический
вывод алгоритма обратного распространения ошибки при квадратической функции
потерь я уже приводил в курсе по машинному обучению. Здесь же наглядно
продемонстрирую принцип его работы на примере простой трехслойной НС.
Пусть начальные
веса связей выбираются случайным образом в диапазоне [-0.5; 0,5]. Верхний
индекс у весовых коэффициентов показывает их принадлежность к тому или иному
слою. Каждый нейрон имеет дифференцируемую функцию активации .
На первом шаге
делается прямой проход по сети. Пропускаем через нее вектор наблюдения и
запоминаем все выходные значения нейронов скрытых слоев:
и последнее
выходное значение d:
После этого
вычисляется величина ошибки, как производная по функции потерь:
В частности, при
квадратической функции потерь, имеем:
На данный момент
все должно быть понятно. Мы много раз подробно рассматривали процесс
распространения сигнала по НС, и вы это уже хорошо себе представляете. А вот
дальше начинается самое главное – обратное распространение ошибки.
Итак, у нас есть
ошибка и
выбранная функция активации .
Первое, что нам нужно, – это вычислить локальный градиент для выходного
нейрона. Это делается по формуле:
Используя
вычисленный локальный градиент, пропускаем его обратно по весам связей и
вычисляем ошибки для предыдущего слоя:
А затем, по
аналогии, вычисляются следующие значения локальных градиентов:
Для первого
скрытого слоя, снова выполняется пересчет ошибок:
и
соответствующих локальных градиентов:
После этого
выполняется корректировка весов связей в соответствии с градиентным алгоритмом,
начиная с последнего (выходного) слоя и доходя до первого:
при
при
В результате, мы
выполнили одну итерацию алгоритма обучения НС. На следующей итерации следует
взять другой входной вектор из обучающего множества. Лучше всего это сделать
случайным образом, чтобы не формировались возможные ложные закономерности в
последовательности данных при обучении НС. Повторяя много раз этот процесс,
весовые коэффициенты будут
все точнее формировать выходные значения для обучающей выборки.
Вот так, в целом
выглядит идея работы алгоритма обучения по методу back propagation (обратного
распространения ошибки). Давайте теперь в качестве примера обучим следующую НС:
В качестве
обучающего множества выберем все возможные варианты (здесь 1 – это да, -1 – это
нет):
Вектор
наблюдений
|
Требуемый
отклик
|
[-1, -1, -1]
|
-1
|
[-1, -1,
1]
|
1
|
[-1, 1, -1]
|
-1
|
[-1, 1, 1]
|
1
|
[1, -1, -1]
|
-1
|
[1, -1, 1]
|
1
|
[1, 1, -1]
|
-1
|
[1, 1, 1]
|
-1
|
На каждой
итерации работы алгоритма, мы будем подавать случайно выбранный вектор и
корректировать веса, чтобы приблизиться к значению требуемого отклика. В
качестве функции активации выберем гиперболический тангенс:
со значением
производной:
Пример
реализации алгоритма back propagation на Python с
использованием тензоров пакета PyTorch:
neuro_net_12.py: https://github.com/selfedu-rus/neuro-pytorch/
Конечно, это
довольно простой, примитивный пример, частный случай, когда можно обучить НС
так, чтобы она вообще не выдавала никаких ошибок. Чаще всего в реальных задачах
остается некоторый процент ошибок и наша задача сделать так, чтобы этих ошибок
было как можно меньше.