12.9 Adadelta
Adadelta yra dar vienas AdaGrad (12.7 skyrelis) variantas. Pagrindinis skirtumas yra tas, kad jis sumažina dydį, kuriuo mokymosi greitis prisitaiko prie koordinačių. Be to, tradiciškai sakoma, kad jis neturi mokymosi greičio, nes pačią pokyčio apimtį naudoja kaip kalibravimą būsimam pokyčiui. Algoritmą pasiūlė (Zeiler, 2012). Jis gana paprastas, turint omenyje iki šiol aptartus ankstesnius algoritmus.
12.9.1 Algoritmas
Trumpai tariant, Adadelta naudoja du būsenos kintamuosius: gradiento antrojo momento nutekėjusiam vidurkiui saugoti ir paties modelio parametrų pokyčio antrojo momento nutekėjusiam vidurkiui saugoti. Atkreipkite dėmesį, kad naudojame originalius autorių žymėjimus ir pavadinimus suderinamumui su kitomis publikacijomis ir įgyvendinimais (nėra jokios kitos tikros priežasties, kodėl reikėtų naudoti skirtingus graikiškus kintamuosius tą patį tikslą atliekančiam parametrui žymėti momentų, Adagrad, RMSProp ir Adadelta metoduose).
Štai techninės Adadelta detalės. Tarkime, kad dienos parametras yra ; gauname šiuos nutekėjusius atnaujinimus, panašiai kaip 12.8 skyrelis:
Skirtumas nuo 12.8 skyrelis yra tas, kad atnaujinimus atliekame su pakartotinai sumastelintu gradientu , t. y.
Taigi kas yra pakartotinai sumastelintas gradientas ? Jį galime apskaičiuoti taip:
kur yra pakartotinai sumastelintų gradientų kvadratų nutekėjęs vidurkis. inicializuojame ir atnaujiname jį kiekviename žingsnyje su , t. y.
o (maža reikšmė, pavyzdžiui, ) pridedamas skaitiniam stabilumui išlaikyti.
12.9.2 Įgyvendinimas
Adadelta kiekvienam kintamajam turi išlaikyti du būsenos kintamuosius: ir . Taip gaunamas toks įgyvendinimas.
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()
def init_adadelta_states(feature_dim):
s_w, s_b = d2l.zeros((feature_dim, 1)), d2l.zeros(1)
delta_w, delta_b = d2l.zeros((feature_dim, 1)), d2l.zeros(1)
return ((s_w, delta_w), (s_b, delta_b))
def adadelta(params, states, hyperparams):
rho, eps = hyperparams['rho'], 1e-5
for p, (s, delta) in zip(params, states):
# In-place updates via [:]
s[:] = rho * s + (1 - rho) * np.square(p.grad)
g = (np.sqrt(delta + eps) / np.sqrt(s + eps)) * p.grad
p[:] -= g
delta[:] = rho * delta + (1 - rho) * g * g
%matplotlib inline
from d2l import torch as d2l
import torch
def init_adadelta_states(feature_dim):
s_w, s_b = d2l.zeros((feature_dim, 1)), d2l.zeros(1)
delta_w, delta_b = d2l.zeros((feature_dim, 1)), d2l.zeros(1)
return ((s_w, delta_w), (s_b, delta_b))
def adadelta(params, states, hyperparams):
rho, eps = hyperparams['rho'], 1e-5
for p, (s, delta) in zip(params, states):
with torch.no_grad():
# In-place updates via [:]
s[:] = rho * s + (1 - rho) * torch.square(p.grad)
g = (torch.sqrt(delta + eps) / torch.sqrt(s + eps)) * p.grad
p[:] -= g
delta[:] = rho * delta + (1 - rho) * g * g
p.grad.data.zero_()
%matplotlib inline
from d2l import tensorflow as d2l
import tensorflow as tf
def init_adadelta_states(feature_dim):
s_w = tf.Variable(d2l.zeros((feature_dim, 1)))
s_b = tf.Variable(d2l.zeros(1))
delta_w = tf.Variable(d2l.zeros((feature_dim, 1)))
delta_b = tf.Variable(d2l.zeros(1))
return ((s_w, delta_w), (s_b, delta_b))
def adadelta(params, grads, states, hyperparams):
rho, eps = hyperparams['rho'], 1e-5
for p, (s, delta), grad in zip(params, states, grads):
s[:].assign(rho * s + (1 - rho) * tf.math.square(grad))
g = (tf.math.sqrt(delta + eps) / tf.math.sqrt(s + eps)) * grad
p[:].assign(p - g)
delta[:].assign(rho * delta + (1 - rho) * g * g)
Pasirinkus , kiekvieno parametro atnaujinimo pusėjimo trukmė yra 10. Tai paprastai veikia gana gerai. Gauname tokį elgesį.
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
d2l.train_ch11(adadelta, init_adadelta_states(feature_dim),
{'rho': 0.9}, data_iter, feature_dim);
Glaustam įgyvendinimui tiesiog naudojame Adadelta algoritmą iš aukšto lygio API. Taip gauname šią vienos eilutės komandą daug kompaktiškesniam iškvietimui.
d2l.train_concise_ch11('adadelta', {'rho': 0.9}, data_iter)
trainer = torch.optim.Adadelta
d2l.train_concise_ch11(trainer, {'rho': 0.9}, data_iter)
# adadelta is not converging at default learning rate
# but it is converging at lr = 5.0
trainer = tf.keras.optimizers.Adadelta
d2l.train_concise_ch11(trainer, {'learning_rate':5.0, 'rho': 0.9}, data_iter)
12.9.3 Santrauka
- Adadelta neturi mokymosi greičio parametro. Vietoj to mokymosi greičiui adaptuoti jis naudoja paties parametrų pokyčio spartą.
- Adadelta reikia dviejų būsenos kintamųjų gradiento antriesiems momentams ir parametrų pokyčiui saugoti.
- Adadelta naudoja nutekėjusiu vidurkius, kad palaikytų einamąjį atitinkamos statistikos įvertį.
12.9.4 Pratimai
- Keiskite reikšmę. Kas nutinka?
- Parodykite, kaip įgyvendinti algoritmą nenaudojant . Kodėl tai galėtų būti gera idėja?
- Ar Adadelta tikrai neturi mokymosi greičio? Ar galite rasti optimizavimo uždavinių, kurie sugadina Adadelta?
- Palyginkite Adadelta su Adagrad ir RMSProp ir aptarkite jų konvergavimo elgesį.
