How Artificial Neural Networks Learns

Минимизация функций стоимости методом градиентного спуска (gradient descent)

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

Таким образом мы относительно легко можем найти локальный миниум, но не можем быть уверены является ли он ещё и глобальным.

Число же таких локальных минимумов может исчисляться миллионами, поэтому пересчитать все нет никакой возможности. Объяснение количества локальных минимумов от Сергея Николенко:

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

А это значит, что если у функции ошибки нейронной сети есть какой-то локальный максимум, то другой локальный максимум легко получить, просто переставив веса нейронов на внутреннем слое. Сколько таких перестановок? Правильно, $n!$, где $n$ — число нейронов, которые мы переставляем; вот вам и экспоненциальное число локальных максимумов. Конечно, данный конкретный пример не очень содержателен: нам все равно, какой из эквивалентных максимумов выбрать; но существенно разных максимумов тоже может быть очень много.

Сергей Николенко. Глубокое обучение. Погружение в мир нейронных сетей, стр. 70-71 [1].

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

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

Метод называет эвристическим (от греческого εὑρίσκω «я нахожу, открываю»), если он предназначен для более быстрого решения проблемы в случае, когда классические методы слишком медленные, или для поиска приближенного решения, когда классические методы не могут найти какое-либо точное решение.

Самое важное здесь разобраться с тем, что из себя представляет градиент — это вектор вида Если $\varphi$ — функция $n$ переменных $x_{1},\ldots, x_{n}$, то её градиентом называется $n$-мерный вектор

$$\left(\frac {\partial \varphi }{\partial x_{1}},\ldots ,\frac{\partial \varphi }{\partial x_{n}}\right),$$ компоненты которого равны частным производным $\varphi$ по всем её аргументам.

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

Дано: функция $u = x^2 + 2xy + y^2 + z^2$. Найдите градиент этой функции в точке $A$ с координатами $(1;1;1)$.

Решение. Первым делом найдём частную производную по каждой переменной:

  • $\frac{\partial u}{\partial x}=2x+2y$;
  • $\frac{\partial u}{\partial y}=2x+2y$;
  • $\frac{\partial u}{\partial z}=2z$.

По определению градиента получаем следующий вектор градиента: $$\nabla u = (2x+2y)\bar{i} + (2x+2y)\bar{j} +2z\bar{k},$$ где $i$, $j$ и $k$ — это базисные вектора. Этот вектор также можно записать как $(2x+2y; 2x+2y; 2z)$.

Для определения значения градиента функции $u$ в точке $A$ подставляем координаты в полученную функцию:

$$\nabla u_A = (2\cdot 1+2\cdot 1)\bar{i} + (2\cdot 1+2\cdot 1)\bar{j} +2\cdot 1z\bar{k} = \\ =4\bar{i}+4\bar{j}+2\bar{k}.$$

Готово, вы прекрасны!

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

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

Дальше всё просто [2]. Зная направление уменьшения функции, мы можем подбирать веса переменных таким образом, чтобы двигаться в этом направлении. Итак, у нас есть веса переменных (коэффициенты, параметры) $\theta_1, \theta_2\dots,\theta_n$ и фукнция ошибок $E(\Theta)$. Для изменения веса $j$-ого признака в нужную сторону на шаге $t$ мы вычитаем из его веса частную производную функции ошибок по этому параметру на шаге $t-1$:

$$\theta_j^t=\theta_j^{t-1}-\alpha\frac{\partial E(\Theta)}{\partial \theta_j^{t-1}}$$.

Получается, что при градиентном спуске больше всего изменяется тот параметр, который имеет самую большую по модулю производную. В этой формуле $\alpha$ — это его скорость обучения, она регулирует размер шага, который мы делаем в направлении градиента.

Есть несколько разновидностей градиентного спуска [3]. Тот, который мы разобрали, называется пакетным (batch), потому что для одного шага градиентного спуска, нужно вычислить функцию ошибок по всему "пакету" — тренировочному множеству. Это часто крайне затратно, поэтому чаще используется стохастический (т.е. случайный) градиентный спуск. Его отличие в том, что веса подправляются не после прохода по всему тренировочному множеству, а после каждого примера. У этого подхода два преимущества:

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

Однако и тут есть недостатки — обновлять веса модели после каждого тренировочного примера может быть накладно, поэтому можно скрестить два этих варианта, получив мини-пакетный (mini-batch) спуск, который за раз обрабатывает, к примеру, 100 элементов, а не все или один. За счёт возможности распрараллерирования это всё равно быстрее, чем в случае с пакетным спуском, а результат даёт даже лучше [4].

Ну и наполследок видео по теме с канала Гранта Сандерсона.

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

Итак, для поиска направления уменьшения ошибок функции и обновления весов используется метод градиентного спуска. Алгоритмически градиентный спуск реализуется через обратное распространение ошибки: мы постепенно считаем градиент сложной композиции элементарных функций и передаем эти градиенты по сети в обратном направлении. Хорошее объяснение метода обратного распространения ошибки от Andrej Karpathy есть в чётвертой лекции курса CS231n Convolutional Neural Networks for Visual Recognition [5], и важно понимать[6] его.

Прямое распространение можно рассматривать как длинный ряд вложенных уравнений, решая которые мы расчитываем ошибку при текущих параметрах: $$f(x) = A(B(C(x))),$$ где $A$, $B$, и $C$ — функции активации на различных слоях.

Обратное распространение — это просто приложение правила цепочки (дифференцирования сложной функции) для поиска производных потерь по любой переменной во вложенном уравнении [7]. Пользуясь правилом цепочки, мы легко вычисляем производную $f(x)$ по $x$: $$f′(x)=f′(A)⋅A′(B)⋅B′(C)⋅C′(x).$$

Чтобы найти производную по $B$, вы можете сделать вид, что $B(C(x))$ является константой, заменить ее переменной-заполнителем $B$, и продолжить поиск производной по $B$ стандартно: $$f′(B)=f′(A)⋅A′(B).$$ Аналогично находятся прозиводные и по другим переменным.

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

Источник.

В конце, как обычно, видео с канала 3Blue1Brown.

References

  1. Николенко, С., Кадурин, А., & Архангельская, Е. (2018). Глубокое обучение. Погружение в мир нейронных сетей. Санкт-Петербург: Питер.
  2. Jay, P. (2017, April 20). Back-Propagation is very simple. Who made it Complicated ? Retrieved January 7, 2019, from https://medium.com/@14prakash/back-propagation-is-very-simple-who-made-it-complicated-97b794c97e5c
  3. Dabbura, I. (2017, December 21). Gradient Descent Algorithm and Its Variants. Retrieved January 7, 2019, from https://towardsdatascience.com/gradient-descent-algorithm-and-its-variants-10f652806a3
  4. Stochastic Gradient Descent - Mini-batch and more. (2017, March 30). Retrieved January 11, 2019, from https://adventuresinmachinelearning.com/stochastic-gradient-descent/
  5. Andrej Karpathy. (n.d.). CS231n Winter 2016: Lecture 4: Backpropagation, Neural Networks 1. Retrieved from https://www.youtube.com/watch?v=i94OvYb6noo
  6. Karpathy, A. (2016, December 19). Yes you should understand backprop. Retrieved January 7, 2019, from https://medium.com/@karpathy/yes-you-should-understand-backprop-e2f06eab496b
  7. Фарид Гасратов. (2018, November 26). Метод обратного распространения ошибки: математика, примеры, код. Retrieved January 7, 2019, from https://neurohive.io/ru/osnovy-data-science/obratnoe-rasprostranenie/
  8. Backpropagation demo. (n.d.). Retrieved January 11, 2019, from https://google-developers.appspot.com/machine-learning/crash-course/backprop-scroll/

Comments