Введение

Обратное распространение — это основной механизм, который позволяет нейронным сетям обучаться.

В этой статье я объясню обратное распространение как математически, так и описательно, чтобы эта важная концепция была хорошо понята.

Надеюсь, тебе понравится.

Математический вид нейронной сети

Модель нейронной сети, которую мы будем использовать для этого объяснения, — это мультиклассовый персептрон (звучит красиво, не правда ли?).

В основном каждый персептрон представлен строкой в ​​матрице A, вектор-столбец x представляет входные данные, а вектор-столбец y представляет выходные данные. Элементы матрицы A называются весами.

Возможно, вы уже видели эту форму:

Функция, применяемая к результату умножения матриц, называется функцией активации; это нелинейная функция, которую опять же нужно выбирать в зависимости от приложения. Популярным выбором являются softmax и ReLu.

Вектор b называется bias и содержит набор ненулевых значений; это необходимо для того, чтобы убедиться, что если входные данные x полностью равны нулю, сеть все равно может выводить ненулевое значение, которое можно использовать для обучения/оценки.

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

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

Смысл вывода зависит от входных данных и назначения нейронной сети. При классификации данных каждый элемент выходного вектора сопоставляется с классом входных данных.

Задача состоит в том, чтобы найти такие веса, чтобы с высокой вероятностью класс соответствовал входным данным.

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

Как мы можем определить значения A?

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

Давайте посмотрим, как это работает.

Что мы ожидаем против того, что мы получаем

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

Математически говоря, это эквивалентно этому алгоритму:

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

Функция, использованная на шаге 3, называется функцией потерь.

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

Давайте рассмотрим их более подробно, не так ли?

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

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

Как мы можем написать алгоритм для этого? Хорошо, давайте посмотрим на значение производной до и после минимума функции (наша основная гипотеза здесь состоит в том, что у нашей функции действительно есть минимум).

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

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

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

Хм, интересно.

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

  1. Получить случайный x
  2. Вычислите производную в этой точке
  3. Вычислите следующий x, используя:

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

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

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

Этот алгоритм получил название градиентный спуск.

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

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

Функция потерь

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

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

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

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

Давайте проверим, соответствует ли эта функция потерь критериям, которые мы установили выше.

Это дифференцируемо?

Безусловно, так как это композиция логарифмов. Вот производная по предсказанию

Есть ли у него единый минимум?

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

Оно быстро сходится к решению?

Не вопрос, просто посмотрите на график ее производной (помните, производная функции потерь используется в методе градиентного спуска)

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

Одна вещь, которую мы должны обратить внимание читателя, это то, что для перехода от 100 к 10 функции потребовалось около 20 баллов, но потребовалось еще 80 баллов, чтобы перейти от 10 примерно к 0. Это характеристика, присущая обучению нейронных сетей: время обучения растет в геометрической прогрессии, чем более точным оно должно быть. Это одна из причин, по которой нам нужны огромные вычислительные мощности для обучения очень точных нейронных сетей в разумные сроки.

Все выглядит хорошо. Нам просто нужна последняя порция информации.

Производная функции потерь по весу

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

Но с тех пор

тогда мы можем написать

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

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

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

Хорошо, давайте все вместе.

Расчет весов

Теперь, когда у нас есть все части вместе, давайте обучим нашу сеть.

  1. Создайте матрицу A со случайным набором весов.

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

3. Рассчитайте функцию потерь для каждого прогноза, используя уравнение 1.

4. Рассчитайте новые веса, используя уравнение 3.

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

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

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

Статью, описывающую метод определения оптимальной скорости обучения, можно найти здесь: https://arxiv.org/abs/1506.01186.

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

Вот пример из TensorFlow:

import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)<--training is done here
model.evaluate(x_test, y_test)

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

Обратное распространение может показаться относительно простым. Нет. Вот некоторые из его недостатков:

Подгонка

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

Недооснащение

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

Функция потерь не сходится

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

Минимум функции потерь слишком плоский

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

Скорость обучения слишком высока или слишком низка

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

Вывод

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

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

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

Спасибо за чтение.