梯度降低法能夠分爲三種,批量梯度降低法(BGD)、小批量梯度降低(MBGD)、隨機梯度降低法(SGD),這三種方法是優化時對數據所採起的的策略,但所運用的思想是一致的,都是梯度降低,如今先講解下梯度降低。html
假設有一目標函數y =x2,對這一凸函數但願尋找到其最小值,這裏能夠輕鬆獲得梯度爲2x,咱們假設學習率eta=0.1,每次自變量的變化爲eta*2x,既然是梯度降低,那麼可獲得x = x-eta*2x,代碼以下:算法
import numpy as np import math import matplotlib.pyplot as plt %matplotlib inline #y=x**2 def gd(eta): x =10 res = [x] for i in range(10): x -= eta*2*x res.append(x) return res res = gd(0.1) def show_trace(res): n = max(abs(min(res)), abs(max(res)), 10) f_line = np.arange(-n, n, 0.1) # plt.set_figsize() plt.plot(f_line, [x * x for x in f_line]) plt.plot(res, [x * x for x in res], '-o') plt.xlabel('x') plt.ylabel('f(x)') show_trace(res)
迭代10次後結果入下圖:網絡
可見y隨着梯度一步步向最小值優化,這個就是梯度降低的核心,對於多元的也是如此,例如y=x12+2x22,見下圖,其餘形式的變種也是在這個的基礎上進行改進,下面開始介紹三種降低方法。app
爲便於理解,咱們假定進行線性迴歸擬合,設函數爲ide
hθ (x(i)) = θ1x(i) + θ0 其中i = 1,2,3,...m 表明樣本數函數
對應的損失函數爲學習
BGD是指每次迭代時用所用樣本數據計算梯度,優化
優勢:atom
1.每次計算運用全部數據進行運算,可用矩陣實現並行計算spa
2.經過全部數據求梯度在全局範圍進行搜索,當目標函數爲凸函數時,必定能達到全局最優
缺點:
1.每次求梯度用所有數據會致使訓練速度緩慢
隨機梯度降低與批量梯度降低最大的不一樣在於前者每次計算梯度只採用一個隨機樣本,即m=1,公式中無求和符號
優勢:
1.因爲不是在所有訓練數據上的損失函數,而是在每輪迭代中,隨機優化某一條訓練數據上的損失函數,這樣每一輪參數的更新速度大大加快。
缺點:
1.準確度降低。因爲即便在目標函數爲強凸函數的狀況下,SGD仍舊沒法作到線性收斂。
2.可能會收斂到局部最優,因爲單個樣本並不能表明全體樣本的趨勢。
3.不易於並行實現。
解釋下爲何SGD比BGD迭代更快,假若有100w條數據,BGD一次迭代須要計算100w個樣本,可能迭代10次後才能達到全局最優,那麼就計算了1000w次梯度;要換成SGD每次隨機一個樣本,100w條數據迭代完後就可能找到了最優解,此時的計算時間是遠小於BGD的。
結合BGD和SGD的優缺點,從而衍生出了小批量梯度降低法,跟批量梯度降低很類似,他們的差異在於m=batch,每次隨機更新batch個樣本數據的梯度,當batch爲1時就爲SGD,當batch爲樣本數總數N時即爲BGD
優勢:
1.經過矩陣運算,每次在一個batch上優化神經網絡參數並不會比單個數據慢太多。
2.每次使用一個batch能夠大大減少收斂所須要的迭代次數,同時可使收斂到的結果更加接近梯度降低的效果。(好比上例中的100W,設置batch_size=100時,須要迭代1w次,遠小於SGD的100w次)
3.可實現並行化。
缺點:
1.batch_size的不當選擇可能會帶來一些問題。
batch_size的選擇帶來的影響:
(1)在合理地範圍內,增大batch_size的好處:
a. 內存利用率提升了,大矩陣乘法的並行化效率提升。
b. 跑完一次 epoch(全數據集)所需的迭代次數減小,對於相同數據量的處理速度進一步加快。
c. 在必定範圍內,通常來講 Batch_Size 越大,其肯定的降低方向越準,引發訓練震盪越小。
(2)盲目增大batch_size的壞處:
a. 內存利用率提升了,可是內存容量可能撐不住了。
b. 跑完一次 epoch(全數據集)所需的迭代次數減小,要想達到相同的精度,其所花費的時間大大增長了,從而對參數的修正也就顯得更加緩慢。
c. Batch_Size 增大到必定程度,其肯定的降低方向已經基本再也不變化。
下圖爲三種迭代策略下目標函數的收斂過程
動量法又稱衝量算法,其核心思想可當作指數平均,每次求得梯度後都跟前面的梯度進行指數平滑,讓梯度更加平滑去防止梯度變化過大,公式以下:
dw是咱們計算出來的原始梯度,v則是用指數加權平均計算出來的梯度,α爲學習率。這至關於對原始梯度作了一個平滑,而後再用來作梯度降低,對於二元函數迭代代碼以下:
def momentum_2d(x1, x2, v1, v2): v1 = gamma * v1 + (1-gamma)*0.2 * x1 v2 = gamma * v2 + (1-gamma)*4 * x2 return x1 - eta * v1, x2 - eta * v2, v1, v2
AdaGrad算法會使用一個小批量隨機梯度gt按元素平方的累加變量st,而後更新的梯度爲gt除以st+ε的開方,η爲學習率,ϵ是爲了維持數值穩定性而添加的常數,如10-6,具體公式以下:
因爲st會一直累積增大(公式中分母變大),實際能夠當作學習率η隨機訓練而減少,當學習率在迭代早期降得較快且當前解依然不佳時,AdaGrad算法在迭代後期因爲學習率太小,自變量的迭代軌跡較平滑,可能較難找到一個有用的解,對於二元函數迭代代碼以下:
def adagrad_2d(x1, x2, s1, s2): g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6 # 前兩項爲自變量梯度 s1 += g1 ** 2 s2 += g2 ** 2 x1 -= eta / math.sqrt(s1 + eps) * g1 x2 -= eta / math.sqrt(s2 + eps) * g2 return x1, x2, s1, s2
RMSProP算法能夠當作AdaGrad算法的改進,在AdaGrad的基礎上加上Momentum法,第一步再也不是直接加和,而是引入指數平滑,對每一次的平方和進行平滑,RMSprop迭代更新公式以下:
β的典型值是0.999。公式中還有一個ϵ,這是一個很小的數,典型值是10-8。對於二元函數迭代代碼以下:
def rmsprop_2d(x1, x2, s1, s2): g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6 s1 = gamma * s1 + (1 - gamma) * g1 ** 2 s2 = gamma * s2 + (1 - gamma) * g2 ** 2 x1 -= eta / math.sqrt(s1 + eps) * g1 x2 -= eta / math.sqrt(s2 + eps) * g2 return x1, x2, s1, s2
AdaDelta算法一樣是在AdaGrad算法進行改進,有意思的是,AdaDelta算法沒有學習率這一超參數,
(1)梯度平方求和並加入指數平滑
(2)AdaDelta算法還維護一個額外的狀態變量Δxt,其元素一樣在時間步0時被初始化爲0。咱們使用Δxt-1來計算自變量的變化量
(3)其中ϵ是爲了維持數值穩定性而添加的常數,如10-5。接着更新自變量
(4)最後,咱們使用Δxt來記錄自變量變化量g′t按元素平方的指數加權移動平均
能夠看到,如不考慮ϵ的影響,AdaDelta算法與RMSProp算法的不一樣之處在於使用√Δxt−1來替代超參數η。
Adam算法則是RMSProP算法和Momentum法的結合。先看迭代更新公式:
分母部分取的是RMSProP算法,分子部分取的是Momentum法,典型值:β1=0.9,β2=0.999,ϵ=10−8◂,▸β1=0.9,β2=0.999,ϵ=10−8。Adam算法至關於先把原始梯度作一個指數加權平均,再作一次歸一化處理,而後再更新梯度值。
引用及參考
http://zh.gluon.ai/chapter_optimization/optimization-intro.html