Adam

Описание

Info

Родительский класс: Optimizer

Производные классы: -

Adam (adaptive moment estimation) - это алгоритм оптимизации, совмещающий принципы инерции MomentumSGD и адаптивного обновления параметров AdaGrad и его модификаций.

Для реализации алгоритма необходимо использование подхода экспоненциально затухающего бегущего среднего для градиентов целевой функции и их квадратов:

\begin{equation} m_t = \beta_1{m_{t-1}} + (1 - \beta_1)g_t \end{equation}

\begin{equation} \upsilon_t = \beta_2{\upsilon_{t-1}} + (1 - \beta_2)g_t^2 \end{equation}

где

m_t - оценка первого момента (среднее градиентов);

\upsilon_t - оценка второго момента (средняя нецентрированная дисперсия градиентов).

Однако в такой постановке существует проблема долгого накопления m_t и \upsilon_t в начале работы алгоритма, особенно когда коэффициенты сохранения \beta_1 и \beta_2 близки к 1.

Чтобы избавиться от этой проблемы и не вводить новые гиперпараметры, оценки первого и второго моментов немного видоизменяются:

\begin{equation} \hat{m_t} = \frac{m_t}{1 - \beta_1^t} \end{equation}

\begin{equation} \hat{\upsilon_t} = \frac{\upsilon_t}{1 - \beta_2^t} \end{equation}

Тогда выражение для обновления параметров:

\theta_{t + 1} = \theta_t - \frac {\eta}{\sqrt{\hat{\upsilon_t}} + \epsilon} \hat{m_t}

Авторы алгоритма рекомендуют использовать следующие значения параметров: \beta_1=0.9, \beta_2=0.999, \epsilon=1e-8.

Инициализация

def __init__(self, alpha=1e-3, beta1=0.9, beta2=0.999, epsilon=1e-8, nodeinfo=None):

Параметры

Параметр Возможные типы Описание По умолчанию
alpha float Скорость обучения 1e-3
beta1 float Коэффициент сохранения 1 момента 0.9
beta2 float Коэффициент сохранения 2 момента 0.999
epsilon float Сглаживающий параметр 1e-6
nodeinfo NodeInfo Объект, содержащий информацию о вычислительном узле None

Пояснения

-

Примеры


Необходимые импорты:

import numpy as np
from PuzzleLib.Optimizers import Adam
from PuzzleLib.Backend import gpuarray

Info

gpuarray необходим для правильного размещения тензора на GPU.

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

data = gpuarray.to_gpu(np.random.randn(16, 128).astype(np.float32))
target = gpuarray.to_gpu(np.random.randn(16, 1).astype(np.float32))

Объявляем оптимизатор:

optimizer = Adam()

Пусть уже есть некоторая сеть net, определённая, например, через Graph, тогда, чтобы установить оптимизатор на сеть, требуется следующее:

optimizer.setupOn(net, useGlobalState=True)

Info

Подробнее про методы оптимизаторов и их параметры читайте в описании родительского класса Optimizer

Также пусть есть некая функция ошибки loss, наследованная от Cost, рассчитывающая в т.ч. её градиент. Тогда получаем реализацию процесса оптимизации:

for i in range(100):
... predictions = net(data)
... error, grad = loss(predictions, target)

... optimizer.zeroGradParams()
... net.backward(grad)
... optimizer.update()

... if (i + 1) % 5 == 0:
...   print("Iteration #%d error: %s" % (i + 1, error))