.. _sec_momentum:
Momentum
========
:numref:`sec_sgd` içinde, rasgele gradyan inişini gerçekleştirirken,
yani, gradyanın yalnızca gürültülü bir sürümünün mevcut olduğu
optimizasyonu gerçekleştirirken neler olduğunu inceledik. Özellikle,
gürültülü gradyanlar için gürültü karşısında öğrenme oranını seçmek söz
konusu olduğunda aşırı temkinli olmamız gerektiğini fark ettik. Eğer çok
hızlı azaltırsak yakınsama durur. Eğer çok hoşgörülü olursak, gürültü
bizi eniyi cevaptan uzaklaştırmaya devam ettiğinden, yeterince iyi bir
çözüme yaklaşmayı başaramayız.
Temel Bilgiler
--------------
Bu bölümde, özellikle uygulamada yaygın olan belirli optimizasyon
problemleri türleri için daha etkili optimizasyon algoritmaları
araştıracağız.
Sızdıran Ortalamalar
~~~~~~~~~~~~~~~~~~~~
Önceki bölümde, hesaplamayı hızlandırmak için bir araç olarak minigrup
SGD tartışmamızı gördünüz. Ayrıca, gradyanların ortalama varyans
miktarını azalttığı güzel yan etkisi de vardı. Minigrup rasgele gradyan
inişi şu şekilde hesaplanabilir:
.. math::
\mathbf{g}_{t, t-1} = \partial_{\mathbf{w}} \frac{1}{|\mathcal{B}_t|} \sum_{i \in \mathcal{B}_t} f(\mathbf{x}_{i}, \mathbf{w}_{t-1}) = \frac{1}{|\mathcal{B}_t|} \sum_{i \in \mathcal{B}_t} \mathbf{h}_{i, t-1}.
Notasyonu basit tutmak için, :math:`t-1` zamanında güncellenen
ağırlıkları kullanarak :math:`i` örneğinin rasgele gradyan inişi olarak
:math:`\mathbf{h}_{i, t-1} = \partial_{\mathbf{w}} f(\mathbf{x}_i, \mathbf{w}_{t-1})`
kullandık. Bir minigrup üzerindeki gradyanların ortalamasının ötesinde
bile varyans azaltmanın etkisinden faydalanabilsek güzel olurdu. Bu
görevi yerine getirmek için bir seçenek gradyan hesaplamayı “sızıntılı
ortalama” ile değiştirmektir:
.. math:: \mathbf{v}_t = \beta \mathbf{v}_{t-1} + \mathbf{g}_{t, t-1}
bazı :math:`\beta \in (0, 1)` için geçerlidir. Bu, anlık gradyanı birden
çok *geçmiş* gradyan üzerinden ortalama alınmış bir gradyan ile etkili
bir şekilde değiştirir. :math:`\mathbf{v}` *momentum* olarak
adlandırılır. Amaç fonksiyonu yokuştan aşağı yuvarlanan ağır bir topun
geçmiş kuvvetler üzerinde integral alması benzer şekilde geçmiş
gradyanları biriktirir. Daha ayrıntılı olarak neler olup bittiğini
görmek için :math:`\mathbf{v}_t`'i özyinelemeli olarak aşağıdaki gibi
açalım:
.. math::
\begin{aligned}
\mathbf{v}_t = \beta^2 \mathbf{v}_{t-2} + \beta \mathbf{g}_{t-1, t-2} + \mathbf{g}_{t, t-1}
= \ldots, = \sum_{\tau = 0}^{t-1} \beta^{\tau} \mathbf{g}_{t-\tau, t-\tau-1}.
\end{aligned}
Büyük :math:`\beta`, uzun menzilli ortalamaya karşılık gelirken, küçük
:math:`\beta` ise gradyan yöntemine göre yalnızca hafif bir düzeltme
anlamına gelir. Yeni gradyan değişimi artık belirli bir örnekte en dik
iniş yönünü değil, geçmiş gradyanların ağırlıklı ortalamasını işaret
ediyor. Bu, üzerinde gradyanları hesaplama maliyeti olmadan bir toplu iş
üzerinde ortalamanın faydalarının çoğunu gerçekleştirmemize olanak
tanır. Bu ortalama yordamını daha sonra daha ayrıntılı olarak tekrar
gözden geçireceğiz.
Yukarıdaki akıl yürütme, şimdi momentumlu gradyanlar gibi
*hızlandırılmış* gradyan yöntemleri olarak bilinen şeyin temelini
oluşturmuştur. Optimizasyon probleminin kötü koşullu olduğu durumlarda
(yani ilerlemenin diğerlerinden çok daha yavaş olduğu, dar bir kanyona
benzeyen bazı yönlerin olduğu yerlerde) çok daha etkili olmanın ek
avantajından yararlanırlar. Ayrıca, daha kararlı iniş yönleri elde etmek
için sonraki gradyanlar üzerinde ortalama yapmamıza izin verirlar.
Gerçekten de, gürültüsüz dışbükey problemler için bile ivmenin yönü,
momentumun neden çalıştığı ve neden bu kadar iyi çalıştığının temel
nedenlerinden biridir.
Beklendiği gibi, etkinliği nedeniyle ivme derin öğrenme ve ötesinde
optimizasyonda iyi çalışılmış bir konudur. Örneğin, ayrıntılı bir analiz
ve etkileşimli animasyon için güzel `açıklayıcı
makale `__'ye :cite:`Goh.2017`
bakın. Bu :cite:`Polyak.1964` tarafından önerilmiştir.
:cite:`Nesterov.2018` dışbükey optimizasyon bağlamında ayrıntılı bir
teorik tartışma sunar. Derin öğrenmede momentumun uzun zamandır faydalı
olduğu bilinmektedir. Ayrıntılar için örneğin
:cite:`Sutskever.Martens.Dahl.ea.2013` çalışmasındaki tartışmalarına
bakın.
Kötü Koşullu Bir Problem
~~~~~~~~~~~~~~~~~~~~~~~~
Momentum yönteminin geometrik özelliklerini daha iyi anlamak için,
önemli ölçüde daha az hoş bir amaç fonksiyonu ile de olsa, gradyan
inişini tekrar gözden geçiriyoruz. :numref:`sec_gd` içinde
:math:`f(\mathbf{x}) = x_1^2 + 2 x_2^2`'i, yani orta miktarda çarpık
elipsoid bir amaç kullandığımızı hatırlayın. Bu işlevi :math:`x_1`
yönünde uzatarak daha da bozuyoruz
.. math:: f(\mathbf{x}) = 0.1 x_1^2 + 2 x_2^2.
Daha önce olduğu gibi :math:`f` :math:`(0, 0)`'da minimum seviyeye
sahiptir. Bu fonksiyon :math:`x_1` yönünde *çok* düzdür. Bu yeni işlevde
daha önce olduğu gibi gradyan inişi gerçekleştirdiğimizde ne olacağını
görelim. Öğrenme oranını :math:`0.4` seçiyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()
eta = 0.4
def f_2d(x1, x2):
return 0.1 * x1 ** 2 + 2 * x2 ** 2
def gd_2d(x1, x2, s1, s2):
return (x1 - eta * 0.2 * x1, x2 - eta * 4 * x2, 0, 0)
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.943467, x2: -0.000073
.. figure:: output_momentum_e3683f_3_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
import torch
from d2l import torch as d2l
eta = 0.4
def f_2d(x1, x2):
return 0.1 * x1 ** 2 + 2 * x2 ** 2
def gd_2d(x1, x2, s1, s2):
return (x1 - eta * 0.2 * x1, x2 - eta * 4 * x2, 0, 0)
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.943467, x2: -0.000073
/home/d2l-worker/miniconda3/envs/d2l-tr-release-0/lib/python3.9/site-packages/torch/functional.py:478: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at ../aten/src/ATen/native/TensorShape.cpp:2895.)
return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined]
.. figure:: output_momentum_e3683f_6_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
import tensorflow as tf
from d2l import tensorflow as d2l
eta = 0.4
def f_2d(x1, x2):
return 0.1 * x1 ** 2 + 2 * x2 ** 2
def gd_2d(x1, x2, s1, s2):
return (x1 - eta * 0.2 * x1, x2 - eta * 4 * x2, 0, 0)
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.943467, x2: -0.000073
.. figure:: output_momentum_e3683f_9_1.svg
.. raw:: html
.. raw:: html
Yapı gereği, :math:`x_2` yönündeki gradyan *çok daha* yüksek ve yatay
:math:`x_1` yönünden çok daha hızlı değişiyor. Böylece iki istenmeyen
seçenek arasında sıkışmış olduk: Küçük bir öğrenme oranı seçersek,
çözümün :math:`x_2` yönünde ıraksamamasını sağlarız, ancak :math:`x_1`
yönünde yavaş yakınsama ile eyerleniriz. Tersine, büyük bir öğrenme
oranı ile :math:`x_1` yönünde hızla ilerliyoruz ancak :math:`x_2`'te
ıraksıyoruz. Aşağıdaki örnek, :math:`0.4`'ten :math:`0.6`'ya kadar
öğrenme hızında hafif bir artıştan sonra bile neler olduğunu
göstermektedir. :math:`x_1` yönündeki yakınsama gelişir ancak genel
çözüm kalitesi çok daha kötüdür.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta = 0.6
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.387814, x2: -1673.365109
.. figure:: output_momentum_e3683f_15_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta = 0.6
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.387814, x2: -1673.365109
.. figure:: output_momentum_e3683f_18_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta = 0.6
d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.387814, x2: -1673.365109
.. figure:: output_momentum_e3683f_21_1.svg
.. raw:: html
.. raw:: html
Momentum Yöntemi
~~~~~~~~~~~~~~~~
Momentum yöntemi, yukarıda açıklanan gradyan inişi problemini çözmemizi
sağlar. Yukarıdaki optimizasyon izine baktığımızda geçmişteki
gradyanların ortalama işe yarayacağını düşünebiliriz. Sonuçta,
:math:`x_1` yönünde bu, iyi hizalanmış gradyanları bir araya getirecek
ve böylece her adımda kapladığımız mesafeyi artıracaktır. Tersine,
gradyanların salınım yaptığı :math:`x_2` yönünde, bir toplam gradyan
birbirini iptal eden salınımlar nedeniyle adım boyutunu azaltacaktır.
:math:`\mathbf{g}_t` gradyan yerine :math:`\mathbf{v}_t` kullanarak
aşağıdaki güncelleştirme denklemlerini verir:
.. math::
\begin{aligned}
\mathbf{v}_t &\leftarrow \beta \mathbf{v}_{t-1} + \mathbf{g}_{t, t-1}, \\
\mathbf{x}_t &\leftarrow \mathbf{x}_{t-1} - \eta_t \mathbf{v}_t.
\end{aligned}
:math:`\beta = 0` için düzenli gradyan inişini kurtardığımızı unutmayın.
Matematiksel özellikleri derinlemesine incelemeden önce, algoritmanın
pratikte nasıl davrandığına hızlı bir göz atalım.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def momentum_2d(x1, x2, v1, v2):
v1 = beta * v1 + 0.2 * x1
v2 = beta * v2 + 4 * x2
return x1 - eta * v1, x2 - eta * v2, v1, v2
eta, beta = 0.6, 0.5
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: 0.007188, x2: 0.002553
.. figure:: output_momentum_e3683f_27_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def momentum_2d(x1, x2, v1, v2):
v1 = beta * v1 + 0.2 * x1
v2 = beta * v2 + 4 * x2
return x1 - eta * v1, x2 - eta * v2, v1, v2
eta, beta = 0.6, 0.5
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: 0.007188, x2: 0.002553
.. figure:: output_momentum_e3683f_30_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def momentum_2d(x1, x2, v1, v2):
v1 = beta * v1 + 0.2 * x1
v2 = beta * v2 + 4 * x2
return x1 - eta * v1, x2 - eta * v2, v1, v2
eta, beta = 0.6, 0.5
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: 0.007188, x2: 0.002553
.. figure:: output_momentum_e3683f_33_1.svg
.. raw:: html
.. raw:: html
Gördüğümüz gibi, daha önce kullandığımız aynı öğrenme oranıyla bile,
momentum hala iyi bir şekilde yakınsıyor. Momentum parametresini
azalttığımızda neler olacağını görelim. :math:`\beta = 0.25`'e kadar
yarıya indirmek, neredeyse hiç yakınsamayan bir yörüngeye yol açar.
Bununla birlikte, momentumsuz halinden çok daha iyidir (çözüm ıraksadığı
zaman).
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta, beta = 0.6, 0.25
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.126340, x2: -0.186632
.. figure:: output_momentum_e3683f_39_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta, beta = 0.6, 0.25
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.126340, x2: -0.186632
.. figure:: output_momentum_e3683f_42_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
eta, beta = 0.6, 0.25
d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 20, x1: -0.126340, x2: -0.186632
.. figure:: output_momentum_e3683f_45_1.svg
.. raw:: html
.. raw:: html
Rasgele gradyan inişi, özellikle minigrup rasgele gradyan inişi ile
momentumu birleştirebileceğinizi unutmayın. Tek değişiklik, bu durumda
:math:`\mathbf{g}_{t, t-1}` gradyanlarını :math:`\mathbf{g}_t` ile
değiştirmemizdir. Son olarak, kolaylık sağlamak için
:math:`\mathbf{v}_0 = 0`'ı :math:`t=0`'da ilklettik. Sızdıran
ortalamaların güncellemelere ne yaptığına bakalım.
Etkili Örneklem Ağırlığı
~~~~~~~~~~~~~~~~~~~~~~~~
Hatırlayalım
:math:`\mathbf{v}_t = \sum_{\tau = 0}^{t-1} \beta^{\tau} \mathbf{g}_{t-\tau, t-\tau-1}`.
Limitte terimler
:math:`\sum_{\tau=0}^\infty \beta^\tau = \frac{1}{1-\beta}`'ye toplanır.
Başka bir deyişle, gradyan inişte veya rasgele gradyan inişte
:math:`\eta` boyutunda bir adım atmak yerine,
:math:`\frac{\eta}{1-\beta}` boyutunda bir adım atıyoruz ve aynı zamanda
potansiyel olarak çok daha iyi davranan bir iniş yönüyle uğraşıyoruz.
Bunlar ikisi bir arada faydalardır. :math:`\beta`'yı farklı seçenekler
için ağırlıklandırmanın nasıl davrandığını göstermek için aşağıdaki
diyagramı göz önünde bulundurun.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.set_figsize()
betas = [0.95, 0.9, 0.6, 0]
for beta in betas:
x = np.arange(40).asnumpy()
d2l.plt.plot(x, beta ** x, label=f'beta = {beta:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_51_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.set_figsize()
betas = [0.95, 0.9, 0.6, 0]
for beta in betas:
x = torch.arange(40).detach().numpy()
d2l.plt.plot(x, beta ** x, label=f'beta = {beta:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_54_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.set_figsize()
betas = [0.95, 0.9, 0.6, 0]
for beta in betas:
x = tf.range(40).numpy()
d2l.plt.plot(x, beta ** x, label=f'beta = {beta:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_57_0.svg
.. raw:: html
.. raw:: html
Pratik Deneyler
---------------
Momentumun pratikte nasıl çalıştığını görelim, yani, uygun bir
iyileştirici bağlamında kullanıldığında. Bunun için biraz daha
ölçeklenebilir bir uygulamaya ihtiyacımız var.
Sıfırdan Uygulama
~~~~~~~~~~~~~~~~~
(Minigrup) rasgele gradyan inişi ile karşılaştırıldığında, momentum
yönteminin bir dizi yardımcı değişken muhafaza etmesi gerekir, mesela
hız. Gradyanlar (ve en iyileştirme probleminin değişkenleri) ile aynı
şekle sahiptir. Aşağıdaki uygulamada bu değişkenleri ``states`` olarak
adlandırıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def init_momentum_states(feature_dim):
v_w = np.zeros((feature_dim, 1))
v_b = np.zeros(1)
return (v_w, v_b)
def sgd_momentum(params, states, hyperparams):
for p, v in zip(params, states):
v[:] = hyperparams['momentum'] * v + p.grad
p[:] -= hyperparams['lr'] * v
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def init_momentum_states(feature_dim):
v_w = torch.zeros((feature_dim, 1))
v_b = torch.zeros(1)
return (v_w, v_b)
def sgd_momentum(params, states, hyperparams):
for p, v in zip(params, states):
with torch.no_grad():
v[:] = hyperparams['momentum'] * v + p.grad
p[:] -= hyperparams['lr'] * v
p.grad.data.zero_()
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def init_momentum_states(features_dim):
v_w = tf.Variable(tf.zeros((features_dim, 1)))
v_b = tf.Variable(tf.zeros(1))
return (v_w, v_b)
def sgd_momentum(params, grads, states, hyperparams):
for p, v, g in zip(params, states, grads):
v[:].assign(hyperparams['momentum'] * v + g)
p[:].assign(p - hyperparams['lr'] * v)
.. raw:: html
.. raw:: html
Bunun pratikte nasıl çalıştığını görelim.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train_momentum(lr, momentum, num_epochs=2):
d2l.train_ch11(sgd_momentum, init_momentum_states(feature_dim),
{'lr': lr, 'momentum': momentum}, data_iter,
feature_dim, num_epochs)
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
train_momentum(0.02, 0.5)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.242, 0.179 sec/epoch
.. figure:: output_momentum_e3683f_75_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train_momentum(lr, momentum, num_epochs=2):
d2l.train_ch11(sgd_momentum, init_momentum_states(feature_dim),
{'lr': lr, 'momentum': momentum}, data_iter,
feature_dim, num_epochs)
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
train_momentum(0.02, 0.5)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.244, 0.014 sec/epoch
.. figure:: output_momentum_e3683f_78_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train_momentum(lr, momentum, num_epochs=2):
d2l.train_ch11(sgd_momentum, init_momentum_states(feature_dim),
{'lr': lr, 'momentum': momentum}, data_iter,
feature_dim, num_epochs)
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
train_momentum(0.02, 0.5)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.242, 0.106 sec/epoch
.. figure:: output_momentum_e3683f_81_1.svg
.. raw:: html
.. raw:: html
Momentum hiper parametresi ``momentum``'u 0.9'a yükselttiğimizde, bu,
:math:`\frac{1}{1 - 0.9} = 10` gibi önemli ölçüde daha büyük bir etkin
örneklem boyutu anlamına gelir. Sorunları kontrol altında tutmak için
öğrenme oranını azar azar :math:`0.01`'a indiriyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.01, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.243, 0.194 sec/epoch
.. figure:: output_momentum_e3683f_87_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.01, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.246, 0.013 sec/epoch
.. figure:: output_momentum_e3683f_90_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.01, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.252, 0.103 sec/epoch
.. figure:: output_momentum_e3683f_93_1.svg
.. raw:: html
.. raw:: html
Öğrenme oranını azaltmak, pürüzsüz olmayan optimizasyon problemleriyle
ilgili her türlü sorunu daha da giderir. :math:`0.005` olarak ayarlamak
iyi yakınsama özellikleri sağlar.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.005, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.243, 0.219 sec/epoch
.. figure:: output_momentum_e3683f_99_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.005, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.246, 0.014 sec/epoch
.. figure:: output_momentum_e3683f_102_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_momentum(0.005, 0.9)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.243, 0.102 sec/epoch
.. figure:: output_momentum_e3683f_105_1.svg
.. raw:: html
.. raw:: html
Özlü Uygulama
~~~~~~~~~~~~~
Standart ``sgd`` çözücüde momentum zaten yerleşik olduğundan Gluon'da
yapılacak çok az şey var. Eşleşen parametrelerin ayarlanması çok benzer
bir yörünge oluşturur.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
d2l.train_concise_ch11('sgd', {'learning_rate': 0.005, 'momentum': 0.9},
data_iter)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.251, 0.190 sec/epoch
.. figure:: output_momentum_e3683f_111_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
trainer = torch.optim.SGD
d2l.train_concise_ch11(trainer, {'lr': 0.005, 'momentum': 0.9}, data_iter)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.270, 0.013 sec/epoch
.. figure:: output_momentum_e3683f_114_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
trainer = tf.keras.optimizers.SGD
d2l.train_concise_ch11(trainer, {'learning_rate': 0.005, 'momentum': 0.9},
data_iter)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
loss: 0.260, 0.101 sec/epoch
.. figure:: output_momentum_e3683f_117_1.svg
.. raw:: html
.. raw:: html
Kuramsal Analiz
---------------
Şimdiye kadar :math:`f(x) = 0.1 x_1^2 + 2 x_2^2`'nin 2D örneği oldukça
yapılandırılmış görünüyordu. Şimdi bunun, en azından dışbükey ikinci
dereceden amaç fonksiyonlarının en aza indirilmesi durumunda
karşılaşabileceği problem türlerinin açık bir temsilcisi olduğunu
göreceğiz.
İkinci Dereceden Dışbükey Fonksiyonlar
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Aşağıdaki işlevi düşünün:
.. math:: h(\mathbf{x}) = \frac{1}{2} \mathbf{x}^\top \mathbf{Q} \mathbf{x} + \mathbf{x}^\top \mathbf{c} + b.
Bu genel bir ikinci dereceden fonksiyondur. Pozitif kesin matrisler
:math:`\mathbf{Q} \succ 0` için, yani, pozitif özdeğerlere sahip
matrisler için, bu minimum değer
:math:`b - \frac{1}{2} \mathbf{c}^\top \mathbf{Q}^{-1} \mathbf{c}` ile
:math:`\mathbf{x}^* = -\mathbf{Q}^{-1} \mathbf{c}` değerinde bir en
küçük değer bulucuya sahiptir. Bu nedenle :math:`h`'yi yeniden
yazabiliriz
.. math:: h(\mathbf{x}) = \frac{1}{2} (\mathbf{x} - \mathbf{Q}^{-1} \mathbf{c})^\top \mathbf{Q} (\mathbf{x} - \mathbf{Q}^{-1} \mathbf{c}) + b - \frac{1}{2} \mathbf{c}^\top \mathbf{Q}^{-1} \mathbf{c}.
Gradyan
:math:`\partial_{\mathbf{x}} f(\mathbf{x}) = \mathbf{Q} (\mathbf{x} - \mathbf{Q}^{-1} \mathbf{c})`
ile verilir. Yani, :math:`\mathbf{x}` ile :math:`\mathbf{Q}` ile
çarpılan en küçük değer bulucu arasındaki mesafe ile verilir. Sonuç
olarak da momentum
:math:`\mathbf{Q} (\mathbf{x}_t - \mathbf{Q}^{-1} \mathbf{c})`
terimlerinin doğrusal bir kombinasyonudur.
:math:`\mathbf{Q}` pozitif kesin olduğundan
:math:`\mathbf{Q} = \mathbf{O}^\top \boldsymbol{\Lambda} \mathbf{O}`
üzerinden bir dikey (çevirme) matrisi :math:`\mathbf{O}` ve köşegen
matrisi :math:`\boldsymbol{\Lambda}` için pozitif özdeğerlerine
ayrıştırılabilir. Bu, çok basitleştirilmiş bir ifade elde etmek için
:math:`\mathbf{x}`'den
:math:`\mathbf{z} := \mathbf{O} (\mathbf{x} - \mathbf{Q}^{-1} \mathbf{c})`'ye
değişken değişikliği yapmamıza olanak tanır:
.. math:: h(\mathbf{z}) = \frac{1}{2} \mathbf{z}^\top \boldsymbol{\Lambda} \mathbf{z} + b'.
Burada
:math:`b' = b - \frac{1}{2} \mathbf{c}^\top \mathbf{Q}^{-1} \mathbf{c}`.
:math:`\mathbf{O}` sadece bir dikey matris olduğundan bu durum
gradyanları anlamlı bir şekilde bozmaz. :math:`\mathbf{z}` ile ifade
edilirse gradyan inişi aşağıdaki ifadeye dönüşür:
.. math:: \mathbf{z}_t = \mathbf{z}_{t-1} - \boldsymbol{\Lambda} \mathbf{z}_{t-1} = (\mathbf{I} - \boldsymbol{\Lambda}) \mathbf{z}_{t-1}.
Bu ifadedeki önemli gerçek gradyan inişinin farklı özuzaylar arasında
*karışmadığıdır*. Yani, :math:`\mathbf{Q}`'nun özsistemi açısından ifade
edildiğinde optimizasyon problemi koordinat-yönlü bir şekilde
ilerlemektedir. Bu aynı zamanda momentum için de geçerlidir.
.. math::
\begin{aligned}
\mathbf{v}_t & = \beta \mathbf{v}_{t-1} + \boldsymbol{\Lambda} \mathbf{z}_{t-1} \\
\mathbf{z}_t & = \mathbf{z}_{t-1} - \eta \left(\beta \mathbf{v}_{t-1} + \boldsymbol{\Lambda} \mathbf{z}_{t-1}\right) \\
& = (\mathbf{I} - \eta \boldsymbol{\Lambda}) \mathbf{z}_{t-1} - \eta \beta \mathbf{v}_{t-1}.
\end{aligned}
Bunu yaparken ayrıca şu teoremi kanıtladık: Dışbükey bir ikinci derece
fonksiyon için ivmeli ve ivmesiz gradyan inişi, ikinci dereceden
matrisin özvektörleri yönünde koordinat yönlü optimizasyonuna ayrışır.
Skaler Fonksiyonlar
~~~~~~~~~~~~~~~~~~~
Yukarıdaki sonuç göz önüne alındığında,
:math:`f(x) = \frac{\lambda}{2} x^2` işlevini en aza indirdiğimizde
neler olduğunu görelim. Gradyan inişi için
.. math:: x_{t+1} = x_t - \eta \lambda x_t = (1 - \eta \lambda) x_t.
:math:`|1 - \eta \lambda| < 1` olduğunda bu optimizasyon üstel bir
oranda yakınsar çünkü :math:`t` adımdan sonra
:math:`x_t = (1 - \eta \lambda)^t x_0` olur. Bu,
:math:`\eta \lambda = 1`'e kadar :math:`\eta` öğrenme oranını artırdıkça
yakınsama oranının başlangıçta nasıl arttığını gösterir. Bunun ötesinde
ıraksar ve :math:`\eta \lambda > 2` için optimizasyon problemi
ıraksıyor.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
lambdas = [0.1, 1, 10, 19]
eta = 0.1
d2l.set_figsize((6, 4))
for lam in lambdas:
t = np.arange(20).asnumpy()
d2l.plt.plot(t, (1 - eta * lam) ** t, label=f'lambda = {lam:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_123_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
lambdas = [0.1, 1, 10, 19]
eta = 0.1
d2l.set_figsize((6, 4))
for lam in lambdas:
t = torch.arange(20).detach().numpy()
d2l.plt.plot(t, (1 - eta * lam) ** t, label=f'lambda = {lam:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_126_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
lambdas = [0.1, 1, 10, 19]
eta = 0.1
d2l.set_figsize((6, 4))
for lam in lambdas:
t = tf.range(20).numpy()
d2l.plt.plot(t, (1 - eta * lam) ** t, label=f'lambda = {lam:.2f}')
d2l.plt.xlabel('time')
d2l.plt.legend();
.. figure:: output_momentum_e3683f_129_0.svg
.. raw:: html
.. raw:: html
Momentum durumunda yakınsaklığı analiz etmek için güncelleme
denklemlerini iki skaler açısından yeniden yazarak başlıyoruz: Biri
:math:`x` ve diğeri momentum :math:`v` için. Bu şuna yol açar:
.. math::
\begin{bmatrix} v_{t+1} \\ x_{t+1} \end{bmatrix} =
\begin{bmatrix} \beta & \lambda \\ -\eta \beta & (1 - \eta \lambda) \end{bmatrix}
\begin{bmatrix} v_{t} \\ x_{t} \end{bmatrix} = \mathbf{R}(\beta, \eta, \lambda) \begin{bmatrix} v_{t} \\ x_{t} \end{bmatrix}.
:math:`\mathbf{R}`'ı, yakınsama davranışını yöneten
:math:`2 \times 2`'yi göstermek için kullandık. :math:`t` adımdan sonra
ilk tercih :math:`[v_0, x_0]`,
:math:`\mathbf{R}(\beta, \eta, \lambda)^t [v_0, x_0]` olur. Bu nedenle,
yakınsama hızını belirlemek :math:`\mathbf{R}`'nin özdeğerlerine
kalmıştır. Harika bir animasyon için :cite:`Goh.2017` `Distill
post `__\ una ve ayrıntılı analiz
için :cite:`Flammarion.Bach.2015` bölümüne bakın.
:math:`0 < \eta \lambda < 2 + 2 \beta` olduğunda momentumun
yakınsadığını gösterilebilir. Bu, gradyan inişi için
:math:`0 < \eta \lambda < 2` ile karşılaştırıldığında daha geniş bir
uygulanabilir parametre aralığıdır. Ayrıca, genel olarak
:math:`\beta`'nin büyük değerlerinin arzu edildiğini de göstermektedir.
Daha fazla ayrıntı, makul miktarda teknik detay gerektirir ve ilgilenen
okuyucunun orijinal yayınlara başvurmasını öneririz.
Özet
----
- Momentum, geçmiş gradyanlara göre sızan bir ortalama ile gradyanların
yerini alır. Bu, yakınsamayı önemli ölçüde hızlandırır.
- Hem gürültüsüz gradyan inişi hem de (gürültülü) rasgele gradyan inişi
için arzu edilir.
- Momentum, rasgele gradyan inişi için ortaya çıkma olasılığı çok daha
yüksek olan optimizasyon sürecinin durdurulmasını önler.
- Geçmiş verilerin katlanarak azaltılması nedeniyle etkin gradyan
sayısı :math:`\frac{1}{1-\beta}` ile verilir.
- Dışbükey ikinci derece problemler durumunda bu ayrıntılı olarak
açıkça analiz edilebilir.
- Uygulama oldukça basittir ancak ek bir durum vektörü (momentum
:math:`\mathbf{v}`) saklamamızı gerektirir.
Alıştırmalar
------------
1. Momentum hiper parametrelerinin ve öğrenme oranlarının diğer
kombinasyonlarını kullanın ve farklı deneysel sonuçları gözlemleyip
analiz edin.
2. Birden fazla özdeğeriniz olduğu, yani
:math:`f(x) = \frac{1}{2} \sum_i \lambda_i x_i^2`, örn.
:math:`\lambda_i = 2^{-i}` gibi bir ikinci derece polinom problem
için GD ve momentum deneyin. :math:`x` değerlerinin ilk
:math:`x_i = 1` için nasıl azaldığını çizdirin.
3. :math:`h(\mathbf{x}) = \frac{1}{2} \mathbf{x}^\top \mathbf{Q} \mathbf{x} + \mathbf{x}^\top \mathbf{c} + b`
için minimum değeri ve küçültücüyü türetin.
4. Biz momentumlu rasgele gradyan inişi gerçekleştirdiğinizde ne
değişir? Momentumlu minigrup rasgele gradyan inişi kullandığımızda ne
olur? Ya parametrelerle deney yaparsak ne olur?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html