在第 12.4 節中,我們回顧了在執行隨機梯度下降時會發生什么,即,在只有梯度的噪聲變體可用的情況下執行優化時。特別是,我們注意到對于噪聲梯度,我們在選擇面對噪聲的學習率時需要格外謹慎。如果我們將它降低得太快,收斂就會停滯。如果我們過于寬容,我們將無法收斂到一個足夠好的解決方案,因為噪聲會不斷驅使我們遠離最優解。
12.6.1。基本
在本節中,我們將探索更有效的優化算法,尤其是針對實踐中常見的某些類型的優化問題。
12.6.1.1。漏平均值
在上一節中,我們討論了小批量 SGD 作為加速計算的一種方法。它還有一個很好的副作用,即平均梯度減少了方差量。小批量隨機梯度下降可以通過以下方式計算:
(12.6.1)gt,t?1=?w1|Bt|∑i∈Btf(xi,wt?1)=1|Bt|∑i∈Bthi,t?1.
為了保持符號簡單,我們在這里使用 hi,t?1=?wf(xi,wt?1) 作為樣本的隨機梯度下降i使用及時更新的權重t?1. 如果我們能夠從方差減少的效果中受益,甚至超越小批量的平均梯度,那就太好了。完成此任務的一個選擇是用“leaky average”代替梯度計算:
(12.6.2)vt=βvt?1+gt,t?1
對于一些β∈(0,1). 這有效地將瞬時梯度替換為對多個過去梯度進行平均的梯度 。v稱為速度。它積累了過去的梯度,類似于一個重球從目標函數景觀上滾下來如何對過去的力進行積分。為了更詳細地了解發生了什么,讓我們展開vt遞歸地進入
(12.6.3)vt=β2vt?2+βgt?1,t?2+gt,t?1=…,=∑τ=0t?1βτgt?τ,t?τ?1.
大的β相當于長期平均水平,而小 β僅相當于相對于梯度法的輕微修正。新的梯度替換不再指向特定實例上最速下降的方向,而是指向過去梯度的加權平均值的方向。這使我們能夠實現批量平均的大部分好處,而無需實際計算其梯度的成本。稍后我們將更詳細地重新討論這個平均過程。
上述推理構成了現在所謂的 加速梯度方法的基礎,例如動量梯度。他們享有額外的好處,即在優化問題是病態的情況下更有效(即,在某些方向上進展比其他方向慢得多,類似于狹窄的峽谷)。此外,它們允許我們對后續梯度進行平均以獲得更穩定的下降方向。事實上,即使對于無噪聲凸問題,加速方面也是動量起作用的關鍵原因之一。
正如人們所預料的那樣,由于其功效,勢頭是深度學習及其他領域優化的一個深入研究的課題。例如,請參閱Goh(2017 年)撰寫的 精美說明文章,以獲取深入分析和交互式動畫。它是由Polyak ( 1964 )提出的。Nesterov(2018)在凸優化的背景下進行了詳細的理論討論。長期以來,眾所周知,深度學習的勢頭是有益的。參見例如Sutskever等人的討論 。( 2013 )了解詳情。
12.6.1.2。病態問題
為了更好地理解動量法的幾何特性,我們重新審視了梯度下降法,盡管它的目標函數明顯不太令人滿意。回想一下我們在12.3 節中使用的f(x)=x12+2x22,即適度扭曲的橢球物鏡。我們通過在x1方向通過
(12.6.4)f(x)=0.1x12+2x22.
像之前一樣f有它的最小值(0,0). 這個函數 在方向上非常平坦x1. 讓我們看看當我們像以前一樣對這個新函數執行梯度下降時會發生什么。我們選擇一個學習率0.4.
%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))
epoch 20, x1: -0.943467, x2: -0.000073
%matplotlib inline from mxnet import np, npx from d2l import mxnet as d2l 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))
epoch 20, x1: -0.943467, x2: -0.000073
%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))
epoch 20, x1: -0.943467, x2: -0.000073
通過構造,梯度在x2方向比水平方向高得多 ,變化也快得多x1 方向。因此,我們陷入了兩個不受歡迎的選擇之間:如果我們選擇一個小的學習率,我們確保解決方案不會在x2方向,但我們背負著緩慢收斂x1方向。相反,隨著學習率的提高,我們在x1方向但分歧 x2. 下面的例子說明了即使在學習率略有增加之后會發生什么0.4到0.6. 趨同于x1方向有所改善,但整體解決方案質量更差。
eta = 0.6 d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
epoch 20, x1: -0.387814, x2: -1673.365109
eta = 0.6 d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
epoch 20, x1: -0.387814, x2: -1673.365109
eta = 0.6 d2l.show_trace_2d(f_2d, d2l.train_2d(gd_2d))
epoch 20, x1: -0.387814, x2: -1673.365109
12.6.1.3。動量法
動量法使我們能夠解決上述梯度下降問題。看看上面的優化軌跡,我們可能會憑直覺認為對過去的梯度進行平均會很有效。畢竟,在x1direction 這將聚合良好對齊的梯度,從而增加我們每一步覆蓋的距離。相反,在x2梯度振蕩的方向,聚合梯度將由于相互抵消的振蕩而減小步長。使用vt而不是漸變 gt產生以下更新方程:
(12.6.5)vt←βvt?1+gt,t?1,xt←xt?1?ηtvt.
請注意,對于β=0我們恢復常規梯度下降。在深入研究數學屬性之前,讓我們快速了解一下該算法在實踐中的表現。
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))
epoch 20, x1: 0.007188, x2: 0.002553
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))
epoch 20, x1: 0.007188, x2: 0.002553
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))
epoch 20, x1: 0.007188, x2: 0.002553
正如我們所看到的,即使使用我們之前使用的相同學習率,動量仍然收斂得很好。讓我們看看當我們減少動量參數時會發生什么。減半到β=0.25導致幾乎不收斂的軌跡。盡管如此,它比沒有動量(當解決方案發散時)要好得多。
eta, beta = 0.6, 0.25 d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
epoch 20, x1: -0.126340, x2: -0.186632
eta, beta = 0.6, 0.25 d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
epoch 20, x1: -0.126340, x2: -0.186632
eta, beta = 0.6, 0.25 d2l.show_trace_2d(f_2d, d2l.train_2d(momentum_2d))
epoch 20, x1: -0.126340, x2: -0.186632
請注意,我們可以將動量與隨機梯度下降結合起來,特別是小批量隨機梯度下降。唯一的變化是在那種情況下我們替換梯度gt,t?1 和gt. 最后,為了方便我們初始化 v0=0在時間t=0. 讓我們看看泄漏平均實際上對更新做了什么。
12.6.1.4。有效樣品重量
回想起那個 vt=∑τ=0t?1βτgt?τ,t?τ?1. 在極限條件下,項加起來為 ∑τ=0∞βτ=11?β. 換句話說,而不是邁出一大步η在梯度下降或隨機梯度下降中,我們采取一個大小的步驟 η1?β同時,處理可能表現更好的下降方向。這是二合一的好處。為了說明加權如何針對不同的選擇β考慮下圖。
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();
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();
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();
12.6.2。實踐實驗
讓我們看看動量在實踐中是如何工作的,即,當在適當的優化器的上下文中使用時。為此,我們需要一個更具可擴展性的實現。
12.6.2.1。從零開始實施
與(minibatch)隨機梯度下降相比,動量法需要維護一組輔助變量,即速度。它與梯度(和優化問題的變量)具有相同的形狀。在下面的實現中,我們稱這些變量為states。
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_()
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
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)
讓我們看看這在實踐中是如何工作的。
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)
loss: 0.248, 0.133 sec/epoch
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)
loss: 0.243, 29.702 sec/epoch
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)
loss: 0.243, 1.087 sec/epoch
當我們將動量超參數增加到momentum0.9 時,它相當于一個顯著更大的有效樣本量 11?0.9=10. 我們稍微降低學習率 0.01以控制事情。
train_momentum(0.01, 0.9)
loss: 0.259, 0.156 sec/epoch
train_momentum(0.01, 0.9)
loss: 0.245, 28.885 sec/epoch
train_momentum(0.01, 0.9)
loss: 0.253, 1.084 sec/epoch
降低學習率進一步解決了非平滑優化問題的任何問題。將其設置為0.005產生良好的收斂特性。
train_momentum(0.005, 0.9)
loss: 0.243, 0.141 sec/epoch
train_momentum(0.005, 0.9)
loss: 0.248, 22.937 sec/epoch
train_momentum(0.005, 0.9)
loss: 0.243, 1.088 sec/epoch
12.6.2.2。簡潔的實現
在 Gluon 中幾乎不需要做任何事情,因為標準sgd求解器已經內置了動量。設置匹配參數會產生非常相似的軌跡。
trainer = torch.optim.SGD d2l.train_concise_ch11(trainer, {'lr': 0.005, 'momentum': 0.9}, data_iter)
loss: 0.250, 0.141 sec/epoch
d2l.train_concise_ch11('sgd', {'learning_rate': 0.005, 'momentum': 0.9}, data_iter)
loss: 0.245, 21.439 sec/epoch
trainer = tf.keras.optimizers.SGD d2l.train_concise_ch11(trainer, {'learning_rate': 0.005, 'momentum': 0.9}, data_iter)
loss: 0.259, 1.141 sec/epoch
12.6.3。理論分析
到目前為止的二維示例f(x)=0.1x12+2x22似乎很做作。我們現在將看到,這實際上非常具有代表性,至少在最小化凸二次目標函數的情況下可能遇到的問題類型。
12.6.3.1。二次凸函數
考慮函數
(12.6.6)h(x)=12x?Qx+x?c+b.
這是一個一般的二次函數。對于正定矩陣 Q?0,即,對于具有正特征值的矩陣,它有一個最小值 x?=?Q?1c最小值 b?12c?Q?1c. 因此我們可以重寫h作為
(12.6.7)h(x)=12(x?Q?1c)?Q(x?Q?1c)+b?12c?Q?1c.
梯度由下式給出 ?xh(x)=Q(x?Q?1c). 也就是說,它由之間的距離給出x和最小化器,乘以Q. 因此,速度也是項的線性組合 Q(xt?Q?1c).
自從Q是正定的,它可以分解成它的特征系統通過 Q=O?ΛO對于正交(旋轉)矩陣O和一個對角矩陣 Λ正特征值。這允許我們執行變量的更改x到 z=defO(x?Q?1c) 獲得一個更簡化的表達式:
(12.6.8)h(z)=12z?Λz+b′.
這里 b′=b?12c?Q?1c. 自從O只是一個正交矩陣,它不會以有意義的方式擾亂梯度。表示為 z梯度下降變成
(12.6.9)zt=zt?1?Λzt?1=(I?Λ)zt?1.
這個表達式中的重要事實是梯度下降不會在不同的特征空間之間混合。也就是說,當用以下的特征系統表示時Q優化問題以坐標方式進行。這也適用于
(12.6.10)vt=βvt?1+Λzt?1zt=zt?1?η(βvt?1+Λzt?1)=(I?ηΛ)zt?1?ηβvt?1.
在這樣做時,我們只是證明了以下定理:凸二次函數有和沒有動量的梯度下降分解為二次矩陣特征向量方向上的坐標優化。
12.6.3.2。標量函數
鑒于上述結果,讓我們看看當我們最小化函數時會發生什么f(x)=λ2x2. 對于梯度下降,我們有
(12.6.11)xt+1=xt?ηλxt=(1?ηλ)xt.
每當|1?ηλ|<1這種優化以指數速率收斂,因為之后t我們的步驟 xt=(1?ηλ)tx0. 這顯示了收斂速度最初是如何隨著我們增加學習率而提高的 η直到ηλ=1. 除此之外,事情有所不同ηλ>2優化問題發散。
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();
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();
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();
為了分析動量情況下的收斂性,我們首先根據兩個標量重寫更新方程:一個用于x和一個速度v. 這產生:
(12.6.12)[vt+1xt+1]=[βλ?ηβ(1?ηλ)][vtxt]=R(β,η,λ)[vtxt].
我們用了R表示2×2治理收斂行為。后t步驟初始選擇 [v0,x0]成為 R(β,η,λ)t[v0,x0]. 因此,這取決于特征值R來確定收斂速度。有關精彩動畫,請參閱Goh ( 2017 )的Distill 帖子,以及有關詳細分析的Flammarion 和 Bach ( 2015 ) 。可以證明0<ηλ<2+2β 速度收斂。與相比,這是更大范圍的可行參數0<ηλ<2用于梯度下降。它還表明,一般來說,大值β是可取的。進一步的細節需要相當多的技術細節,我們建議有興趣的讀者查閱原始出版物。
12.6.4。概括
動量用過去梯度的泄漏平均值代替梯度。這顯著加快了收斂速度。
無噪聲梯度下降和(噪聲)隨機梯度下降都是可取的。
動量可防止優化過程停滯,而隨機梯度下降更可能發生這種情況。
梯度的有效數量由下式給出 11?β由于過去數據的指數下降。
在凸二次問題的情況下,這可以明確地詳細分析。
實現非常簡單,但它需要我們存儲一個額外的狀態向量(速度v).
12.6.5。練習
使用動量超參數和學習率的其他組合,觀察和分析不同的實驗結果。
對具有多個特征值的二次問題嘗試梯度下降和動量,即 f(x)=12∑iλixi2,例如, λi=2?i. 繪制值如何x減少初始化xi=1.
導出最小值和最小值 h(x)=12x?Qx+x?c+b.
當我們使用動量執行隨機梯度下降時會發生什么變化?當我們使用帶動量的小批量隨機梯度下降時會發生什么?試驗參數?
-
pytorch
+關注
關注
2文章
808瀏覽量
13239
發布評論請先 登錄
相關推薦
評論