Adam¶
Описание¶
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}
Тогда выражение для обновления параметров:
Авторы алгоритма рекомендуют использовать следующие значения параметров: \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))