思考一下,神經(jīng)網(wǎng)絡是靠什么來判斷得到的結果是好還是壞呢?
答案是通過比較神經(jīng)網(wǎng)絡自己預測的輸出與真實標簽的差距,也就是Loss函數(shù)。從數(shù)學上推導loss函數(shù)可以看這里。
為了找到最小的loss,通常采用的是梯度下降(Gradient Descent)的方法。
記loss為 , M 是樣本的數(shù)量。
一、梯度下降 Gradient Descent
梯度下降的思想是計算loss的梯度, 并取當前點的梯度值的負數(shù),由梯度的定義可以直到,負的梯度指向區(qū)域最小值,如果是正值就是區(qū)域最大值。步長由學習率決定,k+1次的權重值就是第k次的權重減去學習率乘梯度:

1. 批梯度下降 Batch gradient descent
上面的公式使用了數(shù)據(jù)集里的所有的樣本來計算梯度,這種方法被稱為批梯度下降(Batch gradient descent)。
如果我們每次迭代只計算一次梯度,那整體梯度下降的就太慢了,并且可能因為數(shù)據(jù)量太大,內(nèi)存放不下。不過對于凸誤差面,批梯度下降可以保證收斂到全局最小值,對于非凸面,可以保證收斂到局部最小值。
2. 隨機梯度下降 Stochastic gradient descent
隨機梯度下降每次只用一個樣本更新參數(shù),因此梯度下降的非常快,但不是很穩(wěn)定。SGD不會像批梯度下降一樣向最優(yōu)點逼近,可能會在最優(yōu)點附近震蕩。不過也有人說如果逐漸降低學習率,SGD也會想BGD一樣收斂到全局最小值或者局部最小值。
3. Mini-batch gradient descent
Mini-batch gradient descent是每次用B個樣本來更新參數(shù),B=1的時候是SGD,B=M的時候就是BGD。這樣做可以得到一個更加穩(wěn)定的梯度下降,同時也減少了需要計算的參數(shù),提高了優(yōu)化效率。一般來說B會取2的冪,比如2,4,8,16,32,64,128等,有利于GPU的加速。
Mini-batch gradient descent 是現(xiàn)在最常用的方法,通常說的SGD指的也就是Mini-batch gradient descent。SGD 的缺點是選擇合適的學習率可能很困難。學習率太小會導致收斂緩慢,而學習率太大會阻礙收斂,并導致?lián)p失函數(shù)在最小值附近波動甚至發(fā)散。
二、 動量 Gradient Descent With Momentum
1. 動量 Momentum
上面提到了SGD的一個缺點,就是在每個更新參數(shù)的時候,不一定是朝著梯度下降的方向,比如下面左邊的圖,我們更希望在水平方向上下降的快一點,而在垂直方向上的變化量小一點。Momentum的作用就是在相關方向上加速SGD并且抑制震蕩。
如果我們增加一個變量來儲存上一步的更新向量:
通常取

接下來詳細講一下momentum的作用:

從圖上可以看到藍色的箭頭是不加動量時參數(shù)要指向的方向, 紅色箭頭是上一次的梯度下降指向的方向,如果是區(qū)域最小值在水平方向的右邊,那么綠色箭頭會比藍色箭頭更快到達區(qū)域最小值。
Momentum的優(yōu)點在于可以抑制震蕩,加速收斂,缺點是需要調(diào)整學習率。
2. Nesterov Accelerated Gradient
Nesterov Accelerated Gradient 在momentum上做了一些改變, 計算了下一次參數(shù)的loss,計算了梯度的二階梯度,所以比SGD+momentum收斂地更快[5]。
這塊數(shù)學沒怎么懂,總之它收斂比momentum更快。
3. AdaGrad
上面的優(yōu)化方法都用的是固定的學習率,缺點就是需要自己調(diào)參數(shù)找最適合的學習率,所以我們要想辦法,讓學習率在優(yōu)化過程中一起優(yōu)化了。
AdaGrad 全稱Adpative Gradient,方法如下, 這里的代表的是矩陣元素間的乘法:
可以看到與SGD的更新規(guī)則相比,上面公式里與學習率相同作用的,是一個基于梯度和上一次迭代里學習率的值。
Adagrad的主要好處之一是,它無需手動調(diào)整學習速度。 大多數(shù)實現(xiàn)使用默認值0.01并將其保留為默認值。缺點就是學習率下降的太快了。
4. RMSprop
通常取
RMSprop的優(yōu)點是不會讓學習率單調(diào)變小。
5. Adam
Adaptive Moment Estimation
通常
Adam 看起來是RMSprop和 momentum的結合版, 一般推薦使用Adam來訓練。
6. AMSGrad
Adam 有時候被觀察到不能收斂到最優(yōu)解,于是就有人提出了解決方案:
是不是比Adam更好還不確定。
小結
最常用的兩種優(yōu)化方法是SGD+momentum 和Adam,兩種方法各有優(yōu)缺點:
- SGD + Nesterov momentum + 學習率衰減
優(yōu)點: 可以穩(wěn)定的收斂,現(xiàn)在依舊被許多paper使用
缺點:需要調(diào)整學習率衰減 - Adam
優(yōu)點:自適應的學習率
缺點:loss曲線很難解釋
三、Pytorch實現(xiàn)
pytorch實現(xiàn)SGD和Adam
import torch.optim as optim
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# optimizer = optim.Adam(model.parameters(), lr=learning_rate)
for input, target in dataset:
# set zero gradient
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
# take optimization step
optimizer.step()
如果想只優(yōu)化特定的一些參數(shù):
params_to_update = []
for name, param in self.model.named_parameters():
if param.requires_grad == True:
params_to_update.append(param)
為不同參數(shù)設置不同的學習率
optimizer = torch.optim.SGD([
{'params': model.parameters()},
{'params': model.s, 'lr':1e-3}
], lr=learning_rate)
為不同的參數(shù)設置不同的優(yōu)化器:
class MultipleOptimizer(object):
def __init__(self, *op):
self.optimizers = op
def zero_grad(self):
for op in self.optimizers:
op.zero_grad()
def step(self):
for op in self.optimizers:
op.step()
optimizer = MultipleOptimizer(optim.SGD([model.s], lr=0.01),
optim.Adam(model.parameters(), lr=learning_rate))
optimizer.zero_grad()
loss.backward()
optimizer.step()
如果想要根據(jù)訓練的表現(xiàn)調(diào)節(jié)學習率,可以使用torch.optim.lr_scheduler里的函數(shù),可以根據(jù)各種條件調(diào)節(jié)學習率的變化。