⚡終于!!!
⚡終于又有時間學習Deep Learning了⚡!
30天ML計劃,一起加油!!!
https://blog.csdn.net/weixin_44333889/category_11271153.html《專欄》
在訓練NN的時候,有哪些Optimizers可以優化更快的找到global Minima?
下面我們來看下有哪些方法可以優化求解。
Background
在訓練神經網路的時候,最開始我們是用的Gradient Descent(梯度下降法,GD)來求解,但是會出現很多問題,面臨大量的資料的時候,GD會出現local Minima,而且求解速度會下降。
關于GD+Momentum,可以看這個介紹簡單易懂。
整個技術的發展路線如下:
SGD 【Cauchy,1847】
SGD with momentum 【Rumelhart,et al.,Nature’1986】
上面兩個是遠古時期的優化求解方法,其實放到現在來看,依舊還是很有效果。
如下面這些就是SGDM訓練出來的,

目前比較常用的是下面三個Optimizers:
Adagrad 【Duchi,et al. JMLR’11 2011】
RMSProp 【Hinton,et al. Lecture slides, 2013】
Adam 【kingma,et al. ICLR’15 2014】
借用一下李老師(台大,李宏毅)的PPT。
SGD,stochastic gradient descent。也就是最普通的方法,如下圖所示
Adagrad
Adagrad(自适應梯度算法)。其基本思想是,對每個參數theta自适應的調節它的學習率,自适應的方法就是對每個參數乘以不同的系數,并且這個系數是通過之前累積的梯度大小的平方和決定的,也就是說,對于之前更新很多的,相對就可以慢一點,而對那些沒怎麼更新過的,就可以給一個大一些的學習率。
Adagrad算法:
以上就為Adagrad算法的内容。
Python實作代碼:
import numpy as np
class Adagrad:
def __init__(self, learning_rate=0.01):
self.learning_rate = learning_rate # 學習率設定為0.01
self.fg = None
self.delta = 1e-07 # 設定1e-07微小值避免分母為0
def update(self, params, grads): # 更新操作
if self.fg is None:
self.fg = {} # 設為空清單
for key, value in params.items():
self.fg[key] = np.zeros_like(value) # 構造一個矩陣
for key in params.keys(): # 循環疊代
self.fg[key] += grads[key] * grads[key]
params[key] -= self.learning_rate * grads[key] / (np.sqrt(self.fg[key]) + self.delta)
RMSProp
RMSProp算法實則為對Adagrad的一個改進,也就是把Adagrad對曆史梯度加和變成了對曆史梯度求均值,再利用這個均值代替Adagrad累加的梯度和對目前梯度進行權重,并用來update更新。
用均值代替求和是為了解決Adagrad的學習率逐漸消失的問題。
圖檔源自網絡)
有位大佬的解釋更加清晰,可跳轉
此處。
def RMSprop(x, y, step=0.01, iter_count=500, batch_size=4, alpha=0.9, beta=0.9):
length, features = x.shape
data = np.column_stack((x, np.ones((length, 1))))
w = np.zeros((features + 1, 1))
Sdw, v, eta = 0, 0, 10e-7
start, end = 0, batch_size
# 開始疊代
for i in range(iter_count):
# 計算臨時更新參數
w_temp = w - step * v
# 計算梯度
dw = np.sum((np.dot(data[start:end], w_temp) - y[start:end]) * data[start:end], axis=0).reshape((features + 1, 1)) / length
# 計算累積梯度平方
Sdw = beta * Sdw + (1 - beta) * np.dot(dw.T, dw)
# 計算速度更新量、
v = alpha * v + (1 - alpha) * dw
# 更新參數
w = w - (step / np.sqrt(eta + Sdw)) * v
start = (start + batch_size) % length
if start > length:
start -= length
end = (end + batch_size) % length
if end > length:
end -= length
return w
Adam
最後講講Adam(自适應矩估計 Adaptive moment estimation),因為目前是比較強的,下面這些都是由Adam訓練出來的,
看一下Adam和SGDM的準确率對比(源自論文)
由于Adam的提出的地方有一些突兀,并非在論文或會議,能找到的最原始的出處也隻有下面了,看一下他的更新方式吧,相當于一個優化參數的更新子產品。
Adam 的Python代碼有大佬已經開源了:
https://github.com/yzy1996/Python-Code/blob/master/Algorithm/Optimization-Algorithm/Adam.py https://github.com/sagarvegad/Adam-optimizer/blob/master/Adam.py如果不想轉連結,這裡直接附上了:
import math
alpha = 0.01
beta_1 = 0.9
beta_2 = 0.999 # 初始化參數的值
epsilon = 1e-8
def func(x):
return x*x -4*x + 4
def grad_func(x): # 計算梯度
return 2*x - 4
theta_0 = 0 # 初始化向量
m_t = 0
v_t = 0
t = 0
while (1): # 循環直到它收斂
t+=1
g_t = grad_func(theta_0) # 計算随機函數的梯度
m_t = beta_1*m_t + (1-beta_1)*g_t # 更新梯度的移動平均線
v_t = beta_2*v_t + (1-beta_2)*(g_t*g_t) # 更新平方梯度的移動平均線
m_cap = m_t/(1-(beta_1**t)) # 計算偏差校正後的估計
v_cap = v_t/(1-(beta_2**t)) # 計算偏差校正後的估計
theta_0_prev = theta_0
theta_0 = theta_0 - (alpha*m_cap)/(math.sqrt(v_cap)+epsilon) # 更新參數
if(theta_0 == theta_0_prev): # 檢查是否收斂
break
總而言之,這個優化器目前是處于機器學習中最強的優化地位。
其實,對于不同的資料集或許會有所偏差,在不同的優化時間段,前中後期,各個優化器的準确率會有所波動,如下(源自論文)準确率測試圖:
是以,不經感歎道,搞優化求解,真的是一門玄學啊,老的方法不一定在現在沒有用,新的方法不一定适用于是以場景,找到最适合的方法才是真的有效的。相信在科技如此發達的現在及以後,會有更多的優化求解算法,推進人類進步,而不僅僅是從硬體上提升運算速度。