前言
本章我們主要講解一下深度學(xué)習中的一些優(yōu)化算法。
一、優(yōu)化和深度學(xué)習
1.1 優(yōu)化的目標
優(yōu)化和深度學(xué)習的目標是根本不同的。前者主要關(guān)注的是最小化目標,后者則關(guān)注在給定有限數(shù)據(jù)量的情況下尋找合適的模型。
例如,訓(xùn)練誤差和泛化誤差通常不同:由于優(yōu)化算法的目標函數(shù)通常是基于訓(xùn)練數(shù)據(jù)集的損失函數(shù),因此優(yōu)化的目標是減少訓(xùn)練誤差。但是,深度學(xué)習(或更廣義地說,統(tǒng)計推斷)的目標是減少泛化誤差。為了實現(xiàn)后者,除了使用優(yōu)化算法來減少訓(xùn)練誤差之外,我們還需要注意過擬合。
1.2 深度學(xué)習中的優(yōu)化挑戰(zhàn)
1.2.1 局部最小值
隨著目標函數(shù)中的參數(shù)不斷的迭代,目標函數(shù)的值可能陷入一個矩陣最小值,導(dǎo)致找不到目標函數(shù)的全局最小值。
在這種情況下,小批量上梯度的自然變化能夠?qū)?shù)從局部極小值中跳出。
1.2.2 鞍點
除了局部最小值之外,鞍點是梯度消失的另一個原因。鞍點(saddle point)是指函數(shù)的所有梯度都消失但既不是全局最小值也不是局部最小值的任何位置。
在二維情況下:
在三維情況下:
可以看到中間那個點是x方向的最小值,是y方向的最大值。
對于多維函數(shù)來說,判斷一個該點是否是局部最小值、局部最大值還是鞍點。通常是通過海森矩陣的正定性來進行判斷的。
一個多元函數(shù)的二階泰勒展開式為:
f
(
x
)
=
f
(
a
)
+
∑
i
=
1
n
f
x
i
(
a
)
(
x
i
?
a
i
)
+
1
2
∑
i
=
1
n
∑
j
=
1
n
(
x
i
?
a
i
)
(
x
j
?
a
j
)
f
x
i
x
j
(
a
)
]
f(\mathbf{x}) = f(\mathbf{a}) + \sum_{i=1}^{n} f_{x_i}(\mathbf{a})(x_i - a_i) + \frac{1}{2} \sum_{i=1}^{n} \sum_{j=1}^{n} (x_i - a_i)(x_j - a_j) f_{x_i x_j}(\mathbf{a}) ]
f(x)=f(a)+i=1∑n?fxi??(a)(xi??ai?)+21?i=1∑n?j=1∑n?(xi??ai?)(xj??aj?)fxi?xj??(a)]
改寫成矩陣形式:
f
(
x
)
=
f
(
a
)
+
(
x
?
a
)
T
▽
f
(
a
)
+
1
2
(
x
?
a
)
T
H
(
x
?
a
)
f(\mathbf{x}) = f(\mathbf{a}) + (\mathbf{x} - \mathbf{a})^T \bigtriangledown f(\mathbf{a}) + \frac{1}{2} (\mathbf{x} - \mathbf{a})^T \mathbf{H} (\mathbf{x} - \mathbf{a})
f(x)=f(a)+(x?a)T▽f(a)+21?(x?a)TH(x?a)
其中H被稱為海森矩陣。由于需要判斷的點肯定是每個分量上的導(dǎo)數(shù)為0,所以上式可改寫為:
f
(
x
)
=
f
(
a
)
+
1
2
(
x
?
a
)
T
H
(
x
?
a
)
f(\mathbf{x}) = f(\mathbf{a}) + \frac{1}{2} (\mathbf{x} - \mathbf{a})^T \mathbf{H} (\mathbf{x} - \mathbf{a})
f(x)=f(a)+21?(x?a)TH(x?a)
所以H的正定性決定了該點是什么樣的點:
-
當函數(shù)在零梯度位置處的Hessian矩陣的特征值全部為正值時,我們有該函數(shù)的局部最小值;
-
當函數(shù)在零梯度位置處的Hessian矩陣的特征值全部為負值時,我們有該函數(shù)的局部最大值;
-
當函數(shù)在零梯度位置處的Hessian矩陣的特征值為負值和正值時,我們有該函數(shù)的一個鞍點。
對于高維度問題,至少部分特征值為負的可能性相當高。這使得鞍點比局部最小值更有可能出現(xiàn)。
1.2.3 梯度消失
可能遇到的最隱蔽問題是梯度消失。導(dǎo)致梯度消失的一個經(jīng)典原因就是激活函數(shù)的選擇問題。例如tanh激活函數(shù)在兩端的梯度接近于哦,導(dǎo)致優(yōu)化將會停滯很長一段時間。
正如我們所看到的那樣,深度學(xué)習的優(yōu)化充滿挑戰(zhàn)。幸運的是,有一系列強大的算法表現(xiàn)良好,即使對于初學(xué)者也很容易使用。此外,沒有必要找到最優(yōu)解。局部最優(yōu)解或其近似解仍然非常有用。
二、梯度下降
2.1 一維梯度下降
為什么梯度下降算法可以優(yōu)化目標函數(shù)呢?我們可以先從一維梯度下降中觀察。
首先一元函數(shù)在x點處的泰勒展開式為:
f
(
x
+
?
)
=
f
(
x
)
+
?
f
′
(
x
)
+
O
(
?
2
)
.
f(x + \epsilon) = f(x) + \epsilon f'(x) + \mathcal{O}(\epsilon^2).
f(x+?)=f(x)+?f′(x)+O(?2).
假設(shè)我們已知往負梯度方向可以減少f的值(這個可以去看梯度的推導(dǎo)),我們選擇固定步長
η
>
0
\eta > 0
η>0,然后取
?
=
?
η
f
′
(
x
)
\epsilon = -\eta f'(x)
?=?ηf′(x)??傻锰├照归_式:
f
(
x
?
η
f
′
(
x
)
)
=
f
(
x
)
?
η
f
′
2
(
x
)
+
O
(
η
2
f
′
2
(
x
)
)
.
f(x - \eta f'(x)) = f(x) - \eta f'^2(x) + \mathcal{O}(\eta^2 f'^2(x)).
f(x?ηf′(x))=f(x)?ηf′2(x)+O(η2f′2(x)).
我們總可以找到足夠小的
η
\eta
η使得高階項變得無關(guān),因此
f
(
x
?
η
f
′
(
x
)
)
?
f
(
x
)
.
f(x - \eta f'(x)) \lessapprox f(x).
f(x?ηf′(x))?f(x).
這時,我們使用
x
←
x
?
η
f
′
(
x
)
x \leftarrow x - \eta f'(x)
x←x?ηf′(x)來進行迭代x就能讓f的值越來越小。
2.1.1 學(xué)習率
學(xué)習率(learning rate)決定目標函數(shù)能否收斂到局部最小值,以及何時收斂到最小值。這個學(xué)習率 η \eta η可由我們自己設(shè)定。
- 如果設(shè)置過小,將導(dǎo)致x的更新非常慢,需要多次迭代。
- 如果設(shè)置的過大,泰勒展開式的高階項可能會變大,導(dǎo)致函數(shù)的結(jié)果不來回波動,或者陷入局部最小值。
2.2 多元梯度下降
對于多元函數(shù)來說,它的在
x
=
[
x
1
,
x
2
,
…
,
x
d
]
?
\mathbf{x} = [x_1, x_2, \ldots, x_d]^\top
x=[x1?,x2?,…,xd?]?的泰勒展開可以寫為:
f
(
x
+
?
)
=
f
(
x
)
+
?
?
?
f
(
x
)
+
O
(
∥
?
∥
2
)
.
f(\mathbf{x} + \boldsymbol{\epsilon}) = f(\mathbf{x}) + \mathbf{\boldsymbol{\epsilon}}^\top \nabla f(\mathbf{x}) + \mathcal{O}(\|\boldsymbol{\epsilon}\|^2).
f(x+?)=f(x)+???f(x)+O(∥?∥2).
其中梯度為:
?
f
(
x
)
=
[
?
f
(
x
)
?
x
1
,
?
f
(
x
)
?
x
2
,
…
,
?
f
(
x
)
?
x
d
]
?
.
\nabla f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_d}\bigg]^\top.
?f(x)=[?x1??f(x)?,?x2??f(x)?,…,?xd??f(x)?]?.
我們同樣可以使用 x ← x ? η ? f ( x ) . \mathbf{x} \leftarrow \mathbf{x} - \eta \nabla f(\mathbf{x}). x←x?η?f(x).來進行迭代。
等高圖觀察如下:
2.3 自適應(yīng)方法
選擇“恰到好處”的學(xué)習率
η
\eta
η是很棘手的。 如果我們把它選得太小,就沒有什么進展;如果太大,得到的解就會振蕩,甚至可能發(fā)散。
因此,我們可以考慮目標函數(shù)的值以及梯度和曲率的二階方法,幫助我們自適應(yīng)這個學(xué)習率。
2.3.1 牛頓法
一個多元函數(shù)f在x點
?
\epsilon
?領(lǐng)域內(nèi)的泰勒展開:
f
(
x
+
?
)
=
f
(
x
)
+
?
?
?
f
(
x
)
+
1
2
?
?
?
2
f
(
x
)
?
+
O
(
∥
?
∥
3
)
.
f(\mathbf{x} + \boldsymbol{\epsilon}) = f(\mathbf{x}) + \boldsymbol{\epsilon}^\top \nabla f(\mathbf{x}) + \frac{1}{2} \boldsymbol{\epsilon}^\top \nabla^2 f(\mathbf{x}) \boldsymbol{\epsilon} + \mathcal{O}(\|\boldsymbol{\epsilon}\|^3).
f(x+?)=f(x)+???f(x)+21????2f(x)?+O(∥?∥3).
我們令
H
=
d
e
f
?
2
f
(
x
)
\mathbf{H} \stackrel{\mathrm{def}}{=} \nabla^2 f(\mathbf{x})
H=def?2f(x),其中
H
\mathbf{H}
H也被稱為海森矩陣或者黑塞矩陣。
為了使得函數(shù)在這個領(lǐng)域內(nèi)最小,我們需要令f的梯度為0,兩邊對
?
\epsilon
?求導(dǎo),并忽略掉高階項,得:
?
f
(
x
)
+
H
?
=
0
?and?hence?
?
=
?
H
?
1
?
f
(
x
)
.
\nabla f(\mathbf{x}) + \mathbf{H} \boldsymbol{\epsilon} = 0 \text{ and hence } \boldsymbol{\epsilon} = -\mathbf{H}^{-1} \nabla f(\mathbf{x}).
?f(x)+H?=0?and?hence??=?H?1?f(x).
所以我們迭代的時候直接令
x
←
x
?
H
?
1
?
f
(
x
)
x \leftarrow x -\mathbf{H}^{-1} \nabla f(\mathbf{x})
x←x?H?1?f(x)
但是我們需要注意一下,如果二階導(dǎo)數(shù)為負值,即逼近曲線開頭向下,f的值可能會增加。這是這個算法的致命缺陷!
這發(fā)生了驚人的錯誤。我們怎樣才能修正它? 一種方法是用取Hessian的絕對值來修正,另一個策略是重新引入學(xué)習率。 這似乎違背了初衷,但不完全是——擁有二階信息可以使我們在曲率較大時保持謹慎,而在目標函數(shù)較平坦時則采用較大的學(xué)習率。
2.3.2 其他自適應(yīng)方法
比如預(yù)處理、線搜索等。
三、隨機梯度下降
3.1 隨機梯度更新
在深度學(xué)習中,目標函數(shù)通常是訓(xùn)練數(shù)據(jù)集中每個樣本的損失函數(shù)的平均值。給定n個樣本的訓(xùn)練數(shù)據(jù)集,我們假設(shè)
f
i
(
x
)
f_i(\mathbf{x})
fi?(x)是關(guān)于索
i
i
i
的訓(xùn)練樣本的損失函數(shù),其中
x
\mathbf{x}
x是參數(shù)向量。然后我們得到目標函數(shù):
f
(
x
)
=
1
n
∑
i
=
1
n
f
i
(
x
)
.
f(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n f_i(\mathbf{x}).
f(x)=n1?i=1∑n?fi?(x).
可以看出反向傳播的計算代價隨著n線性增長,因此,當訓(xùn)練數(shù)據(jù)集較大時,反向傳播代價高。
為了解決上述問題,我們提出了隨機梯度下降(SGD)(注:我們常常把小批量梯度下降算法也稱為SGD)。
隨機梯度下降算法,不再計算完所有樣本的損失函數(shù)再反向傳播進行迭代了,而是隨機抽取所有樣本中的一個樣本計算損失并反向傳播更新參數(shù)。
3.2 動態(tài)學(xué)習率
在隨機梯度下降中,對學(xué)習率敏感,因此,我們可以采用動態(tài)調(diào)節(jié)學(xué)習率的方式改變學(xué)習率。以下是根據(jù)時間動態(tài)調(diào)整學(xué)習率的策略:
η
(
t
)
=
η
i
?if?
t
i
≤
t
≤
t
i
+
1
分段常數(shù)
η
(
t
)
=
η
0
?
e
?
λ
t
指數(shù)衰減
η
(
t
)
=
η
0
?
(
β
t
+
1
)
?
α
多項式衰減
\begin{split}\begin{aligned} \eta(t) & = \eta_i \text{ if } t_i \leq t \leq t_{i+1} && \text{分段常數(shù)} \\ \eta(t) & = \eta_0 \cdot e^{-\lambda t} && \text{指數(shù)衰減} \\ \eta(t) & = \eta_0 \cdot (\beta t + 1)^{-\alpha} && \text{多項式衰減} \end{aligned}\end{split}
η(t)η(t)η(t)?=ηi??if?ti?≤t≤ti+1?=η0??e?λt=η0??(βt+1)?α??分段常數(shù)指數(shù)衰減多項式衰減??
四、小批量隨機梯度下降
隨機梯度下降使用完整數(shù)據(jù)集來計算梯度并更新參數(shù), 隨機梯度下降算法一次處理一個訓(xùn)練樣本來取得進展。 二者各有利弊:每當數(shù)據(jù)非常相似時,梯度下降并不是非?!皵?shù)據(jù)高效”。 而由于CPU和GPU無法充分利用向量化,隨機梯度下降并不特別“計算高效”。 這暗示了兩者之間可能有折中方案,這便涉及到小批量隨機梯度下降(minibatch gradient descent)。
加入損失函數(shù)的最終全貌圖像如下:
假設(shè)我們當前參數(shù)所在位置在紅點:
如果我們考慮了所有樣本的損失函數(shù)的梯度變化情況,那么它就會找到當前點的最優(yōu)梯度下降方向,最終情況可能如下:
每次方向找的是最優(yōu)的,但是計算損失函數(shù)以及計算梯度太慢。
而如果隨機找一個樣本就更新參數(shù),雖然迭代速度很快,但是過于隨機可能需要很多次迭代才能降低。
而小批量梯度下降算法就是他們的折中,可參考下面代碼:
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y) # X和y的小批量損失
# 因為l形狀是(batch_size,1),而不是一個標量。l中的所有元素被加到一起,
# 并以此計算關(guān)于[w,b]的梯度
l.sum().backward()
sgd([w, b], lr, batch_size) # 使用參數(shù)的梯度更新參數(shù)
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
其中 l l l是一個向量,每個元素都是小批量中每個樣本的損失,在本代碼中我們使用了sum累加所有損失并反向傳播,那么它會對每個樣本的損失函數(shù)中的每一個參數(shù)求偏導(dǎo)并對應(yīng)加到一起,當然我們除了使用sum也可以使用平均損失函數(shù),pytorch中的MSELoss用的就是平均損失。在迭代器中,我們還需要去除batch_size對梯度的影響。如:
def sgd(params, lr, batch_size): #@save
"""小批量隨機梯度下降"""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()
五、動量法
之前我們都是把所有維度的梯度同時考慮并優(yōu)化,那么我們能不能在每個維度上分別做不同程度的優(yōu)化呢?答案是可行的,這就是我們要講的動量法,考慮一種“慣性”。
我們可以先考慮兩個參數(shù)的梯度下降優(yōu)化。
我們可以看到它一方向的梯度大體是對的,而另一個軸的方向波動很大。
我們可以用當前點的梯度方向加上上個點的梯度方向,如果當前點的一個梯度分量與上個點的對應(yīng)梯度分量方向相同,就會促進這個方向的變化,如果相反則會抑制它。
而動量法這是利用了這個特性,只不過動量法是考慮了前面所有的梯度并進行加權(quán)求和,而不是僅僅考慮上一個點。
這里的加權(quán)是用了指數(shù)加權(quán)平均法,這個我們在批量歸一化那里也有說過。舉個例子:
六、AdaGrad–自適應(yīng)學(xué)習率
AdaGrad是一種優(yōu)化算法,用于訓(xùn)練機器學(xué)習模型。它是基于梯度下降的一種自適應(yīng)學(xué)習率方法,旨在解決傳統(tǒng)梯度下降算法中學(xué)習率難以選擇的問題。
AdaGrad通過自適應(yīng)地調(diào)整學(xué)習率,可以在訓(xùn)練過程中逐漸減小對稀疏特征的學(xué)習率,而對頻繁出現(xiàn)特征的學(xué)習率保持較大。具體而言,它會根據(jù)每個參數(shù)的歷史梯度大小來動態(tài)地調(diào)整學(xué)習率。
公式如下:
Adagrad優(yōu)化算法就是在每次使用一個 batch size 的數(shù)據(jù)進行參數(shù)更新的時候,算法計算所有參數(shù)的梯度,那么其想法就是對于每個參數(shù),初始化一個變量 s 為 0,然后每次將該參數(shù)的梯度平方求和累加到這個變量 s 上。
Adagrad特別適合稀疏數(shù)據(jù),所謂的稀疏數(shù)據(jù)更多的是指某個特征有或者沒有,而稠密數(shù)據(jù)是指都有這些特征,具體區(qū)別是特征數(shù)值的大小。
有這樣一個規(guī)律,隨著維度的增加,你遇到稀疏數(shù)據(jù)的可能性越高。
AdaGrad也有一個缺點,就是它會考慮前面所有的歷史梯度,這樣的話可能會對當前學(xué)習率的調(diào)整不夠準確。改進的方法就是使用指數(shù)加權(quán)只考慮最近的一些歷史梯度。----------此方法就叫做RMSprop方法
七、Adam
我們可以結(jié)合動量法與RMSprop方法,修正動量的同時,自適應(yīng)學(xué)習率。文章來源:http://www.zghlxwxcb.cn/news/detail-634773.html
具體公式如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-634773.html
總結(jié)
附錄–參考資料
- 各種優(yōu)化算法總結(jié)
- 可視化軟件
到了這里,關(guān)于深度學(xué)習中的優(yōu)化算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!