Оптимизаторы градиентных алгоритмов: RMSProp, AdaDelta, Adam, Nadam

Практический курс по ML: https://stepik.org/course/209247/

Смотреть материал на YouTube | RuTube

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

Очевидно, в таких точках производная равна нулю, а значит, дальнейшее изменение весов по правилу:

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

Метод импульсов (momentum)

Для некоторого исправления этих недостатков было придумано множество эвристик. Одна из первых была предложена Борисом Теодоровичем Поляком в 1964 году. Он предложил усреднять градиент по шагам с помощью экспоненциального скользящего среднего:

или, переобозначая:

метод импульсов часто записывают в виде:

(Мы с вами уже знаем, что означает экспоненциальное скользящее среднее по примерно последним  отсчетам). Затем, полученное значение v, используют для корректировки весов:

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

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

Стохастический градиент с импульсом Нестерова (NAG – Nesterov’s accelerated gradient)

Давайте еще раз посмотрим на формулу вычисления импульса (усредненного значения) градиента:

Здесь, фактически, выполняется сложение двух векторов: v и . Графически, это можно представить, так:

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

И такой подход, как правило, показывает лучшую сходимость к точке оптимума.

Алгоритм был предложен Нестеровым в 1983 году и активно применяется (наряду с другими оптимизаторами) при обучении алгоритмов, в частности, нейронных сетей.

RMSProp (running mean square)

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

О чем здесь речь? Часто в задачах многомерной оптимизации, когда число подбираемых весовых коэффициентов не 2-3, а десятки, сотни, тысячи и более, частные производные по функции потерь от каждого из них могут сильно различаться:

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

Так вот, чтобы нормализовать скорость адаптации весов вектора , Джефри Хинтон на своем курсе по Deep Learning (глубокое обучение) предложил делать следующую перенормировку шага обучения:

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

AdaDelta (adaptive learning rate)

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

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

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

То есть,  - это экспоненциальное среднее нормированных квадратов градиентов. Именно эта величина и используется для регулирования скорости сходимости псевдоградиентного алгоритма:

Причем, гиперпараметр  (можно просто положить равным 1).

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

Adam (adaptive momentum)

Следующая очень популярная эвристика, часто используемая для оптимизации стохастических градиентных алгоритмов, - это адаптивный импульс (Adam). Он был получен путем объединения метода импульсов и RMSProp. В результате, получился следующий алгоритм:

Здесь  - номер итерации;  - нормированные векторы  (нормировка увеличивает  на первых итерациях – для ускорения сходимости алгоритма); .

Любители строгой математики сейчас могут в недоумении смотреть на все эти формулы и задаваться вопросом, откуда вообще все это взялось? Из каких соображений? На самом деле, смотреть на все это следует лишь как на математическую формализацию некой идеи, которая пришла в голову их создателям. Конечно, каждая разумная идея содержит некую гипотезу об ускорении градиентных алгоритмов. Но доказательство ее справедливости часто сводится к экспериментам. Если метод действительно в ряде задач показывает хорошую эффективность, его оставляют и начинают применять. В противном случае – забывают.  Поэтому приведенные формулы служат лишь для общего понимания идей, заложенных в тот или иной оптимизатор, чтобы вы понимали принцип его работы. Это главная цель данного занятия. Когда вам придется применять их на практике, то все приведенные здесь алгоритмы уже реализованы в стандартных пакетах, таких как:

Scikit-Learn, Keras, Pytorch, Tensorflow и др.

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

Nadam (Nesterov-accelerated adaptive momentum)

Естественное развитие оптимизатора Adam – это добавление момента Нестерова при вычислении градиентов. В результате получаем все те же самые формулы для , а корректировка весов принимает вид:

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

Диагональный метод Левенберга-Марквардта

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

Здесь  (можно не задавать), а  - матрица Гессе (гессиан), размерностью n x n:

Если вычислить саму матрицу еще как-то можно, то на каждом шаге брать обратную матрицу в признаковом пространстве n, когда n = 100 000 и более, вычислительно очень затратно, а при размерностях 1 000 000 и выше – практически невозможно даже на современных компьютерах. Поэтому была предложена очередная эвристика (хитрость) – считать матрицу Гессе диагональной, то есть, обнулить все смешанные частные производные. Тогда для ее вычисления будет достаточно взять n вторых частных производных (по главной диагонали) и еще n операций деления при вычислении обратной матрицы, так как:

Обращать диагональные матрицы не составляет больших проблем. Именно это и предложили Левенберг и Марквардт – считать гессиан диагональной матрицей. Тогда алгоритм оптимизации можно записать в виде:

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

Какой оптимизатор выбрать

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

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

Tensorflow – строим градиентные алгоритмы оптимизации: https://www.youtube.com/watch?v=WYme8F384as&list=PLA0M1Bcd0w8ynD1umfubKq1OBYRXhXkmH

Keras – обучение сети распознаванию рукописных цифр: https://www.youtube.com/watch?v=oCXh_GFMmOE&list=PLA0M1Bcd0w8yv0XGiF1wjerjSZVSrYbjh

Практический курс по ML: https://stepik.org/course/209247/

Видео по теме