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