.. _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