AdaDelta

Описание

Info

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

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

AdaDelta (root mean square propagation) - это алгоритм оптимизации, являющийся наследником идей, заложенных в AdaGrad.

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

Первый принцип AdaDelta - вместо полной суммы обновлений G_t будет использоваться усреднённый по истории квадрат градиента. Метод напоминает принцип, используемый в MomentumSGD - метод экспоненциально затухающего бегущего среднего.

Введём обозначение E[g^2]_t - бегущее среднее квадрата градиента в момент времени t. Формула для его вычисления следующая:

E[g^2]_t = \gamma E[g^2]_{t-1} + (1 - \gamma)g_t^2

Тогда, подставив E[g^2]_t в формулу обновления параметров для AdaGrad вместо G_t, получим (матричные операции опущены для упрощения):

\theta_{t + 1} = \theta_t - \frac {\eta}{\sqrt{E[g^2]_t + \epsilon}} g_t

Знаменатель - корень из среднего квадратов градиентов, т.е. root mean square, RMS:

RMS[g]_t = \sqrt{E[g^2]_t + \epsilon}

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

\Delta\theta_t = - \frac {\eta}{RMS[g]_t} g_t

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

Сделать это можно, убрав коэффициент обучения из формулы. Определим для этого другое скользящее среднее - среднее квадратов величин обновления параметров:

E[\Delta\theta^2]_t = \gamma E[\Delta\theta^2]_{t-1} + (1 - \gamma)\Delta\theta_t^2

Тогда:

RMS[\Delta\theta]_t = \sqrt{E[\Delta\theta^2]_t + \epsilon}

Подставив RMS[\Delta\theta]_t в формулу для обновления параметров, получим выражение для AdaDelta алгоритма:

\begin{equation} \Delta\theta_t = -\frac {RMS[\Delta\theta]_{t-1}} {RMS[g]_t} g_t \end{equation}

\begin{equation} \theta_{t + 1} = \theta_t + \Delta\theta_t \end{equation}

Параметр \gamma рекомендуется выставлять равным 0.9.

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

def __init__(self, rho=0.95, epsilon=1e-6, nodeinfo=None):

Параметры

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

Пояснения

-

Примеры


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

import numpy as np
from PuzzleLib.Optimizers import AdaDelta
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 = AdaDelta()

Пусть уже есть некоторая сеть 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))