【DL-CV】正則化,Dropout<前篇---後篇>【DL-CV】淺談GoogLeNet(咕咕net)segmentfault
原味版的SGD(如下稱SGD)是經過死跟負梯度方向來對參數進行更新的,也就是走一步、停下肯定方向、再走一步,如此循環。很是簡單,很是老實的走法不是麼?可是SGD這個相對簡單的算法在實際使用中仍是會產生很多的問題,下面咱們來看看最主要的幾個數組
1️⃣SGD 一旦陷入損失的局部最小值或鞍點(既不是最大值也不是最小值的臨界點)訓練將變得緩慢:
網絡
做爲問題的引入咱們先考慮參數只有一個的狀況下損失關於該參數的圖(如上,x軸是該參數,y軸是損失)函數
這是一維的狀況,在高維的狀況下(上千上萬個參數),局部最小值意味着全部參數不管往哪一個方向走損失都會增大,這實際上是很是罕見的事情。而高維狀況下的鞍點能夠這樣理解,即在該點下某些方向會使損失增大,某些方向會使損失減小;因此在高維狀況下遇到鞍點將會是很是常見的事情,在鞍點附近訓練速度將會變得緩慢。學習
2️⃣SGD 對全部參數更新時應用一樣的學習率:
梯度由許多偏導數組成,對應着各個參數的更新。對於偏導數大的,咱們但願配個小的學習率給他;對於偏導數小的,咱們但願配個大的學習率給他,這樣各個參數都能得到大體相同的更新幅度,提升網絡的健壯性。惋惜SGD固定死的學習率不能知足咱們的要求優化
3️⃣SGD 在遇到噪聲時,訓練將變得緩慢:
SGD 是經過隨機抽取小批量樣本進行訓練的,是對每次損失和梯度的估計(不像批量學習同樣所有訓練樣本全往裏塞得到真實的損失和估計),當估計中存在噪音,參數更新的方向會受到影響而偏離,致使訓練時間延長spa
綜上,使用原版的SGD進行參數更新帶來的體驗並非那麼好(須要更新換代啦)。還好的是,偉大的研究人員,或是對原版SGD進行了各類各樣的魔改,或是靈光一閃提出新的更新算法,如今已經有多種更高級的參數更新的方法啦,下面就來看一下3d
該方法的關鍵是引入一個速度的概念。速度這個量將對歷次求得的梯度進行累加,在每次累加時會有一參數$\gamma$對原速度進行衰減處理後再進行累加。參數更新時,咱們不在根據當前的負梯度方向進行更新,而是根據當前速度方向更新。這樣引入速度以後 SGD卡在局部最小值和鞍點的問題 會獲得有效解決,從而加速訓練。blog
上面的說明不懂不要緊,看了下面的比喻你便會豁然開朗
懂了下面就放公式,順便比較SGD和魔改後的SGD,公式中的t表明第t次迭代更新
SGD | SGD + 動量 | |
---|---|---|
公式(x是待更新參數) | $$x_{t+1}=x_t-\alpha\nabla_xL(x_t)$$ | $$v_{t+1}=\gamma v_t+\alpha\nabla_xL(x_t)$$$$x_{t+1}=x_t-v_{t+1}$$ |
代碼實現 |
至於參數$\gamma$,其存在至關於摩擦力,可以使使速度衰減。若是沒有$\gamma$,小球到達最後的「U型」山底就不會停下來,訓練時參數可能就收斂不了。$\gamma$常爲[0.5,0.9,0.95,0.99]中的一個,而且一般爲0.9。$\gamma$也能夠隨着訓練的進行而逐漸上升,如剛開始將$\gamma$設爲0.5而在後面的多個epoch中慢慢提高到0.99
Nesterov動量與普通動量原理上有些許不一樣(Nesterov動量能夠說是普通動量的小升級)。在理論上對於凸函數Nesterov動量能獲得更好的收斂,在實踐中也確實比普通動量表現更好一些。
使用Nesterov動量時,不會計算當前點的梯度,而是先往速度方向步進到下一點,計算這「下一點」的梯度,而後回到原點把這「下一點」的梯度加到速度上,再用累加後的速度在原點上進行步進。這個看似畫蛇添足的操做並非無心義的,計算「下一點」的梯度能夠看做是對將來位置梯度的預測從而提早對速度方向進行修正,從而進一步加快訓練速度。下面來對比一下普通動量和Nesterov動量:
普通動量 | Nesterov動量 | |
---|---|---|
圖示 | ||
公式 | $$v_{t+1}=\gamma v_t+\alpha\nabla_xL(x_t)$$$$x_{t+1}=x_t-v_{t+1}$$ | $$v_{t+1}=\gamma v_t + \alpha \nabla_xL(x_t - \gamma v_t)$$$$x_{t+1} = x_t-v_{t+1}$$ |
這兩個動量更新方法都有效解決了SGD的問題1️⃣