隨機梯度下降法(SGD)是訓練深度學習模型最常用的優化方法。在前期文章中我們講了梯度是如何計算的,主要采用BP算法,或者說利用鏈式法則。但是深度學習模型是復雜多樣的,你不大可能每次都要自己使用鏈式法則去計算梯度,然后采用硬編程的方式實現。
而目前的深度學習框架其都是實現了自動求梯度的功能,你只關注模型架構的設計,而不必關注模型背后的梯度是如何計算的。不過,我們還是想說一說自動求導是如何實現的。
這里我們會講幾種常見的方法,包括數值微分(Numerical Differentiation),符號微分(Symbolic Differentiation),前向模式(Forward Mode)和反向模式(Reverse Mode)
數值微分
數值微分方式應該是最直接而且簡單的一種自動求導方式。從導數的定義中,我們可以直觀看到:
當h接近0時,導數是可以近似計算出來的。可以看到上面的計算式幾乎適用所有情況,除非該點不可導。可是數值微分卻有兩個問題,第一個就是求出的導數可能不准確,這畢竟是近似表示,比如要求f(x)=x^2在零點附近的導數,如果h選取不當,你可能會得到符號相反的結果,此時誤差就比較大了。第二個問題是對於參數比較多時,對深度學習模型來說,上面的計算是不夠高效的,因為每計算一個參數的導數,你都需要重新計算f(x+h)。但是數值運算有一個特殊的用武之地就是在於可以做梯度檢查(Gradient check),你可以用這種不高效但簡單的方法去檢查其他方法得到的梯度是否正確。
符號模式
符號微分適合符號表達式的自動求導,符號微分技術廣泛應用在數學軟件如Matlab、Maple及Mathematica等。符號微分的原理是基於下面的簡單求導規則:
當我們將符號表達式用表達式樹表示時,可以利用加法規則和乘法規則進行自動求導。比如我們要求符號表達式f(x)=2x+x^2,可以展開成如下圖的表達式樹:
利用求導規則,可以求出:
基於表達式樹和求導規則,我們可以得到最終的導數。有一點要注意的是,符號微分不一定會得到簡化的導數,因為計算機可能並不能進行智能的簡化。所以,如果表達式樹結構較復雜時,得到的導數表達式會相當復雜,也許出現表達式爆炸現象。
前向模式
前向模式最簡單明了,其基於的是二元數(dual numbers)。我們先來講解一下二元數,其基本格式如下所示:
其中a和b都是實數,而
是無窮小量,你可以認為其無限接近0,但是並不等於0,並且
,這是借鑒了微積分中的概念。所以,你可以認為
是一個接近5的數。對於二元數,其滿足簡單的加法和乘法規則:
對於二元數,其更重要的一個特性是:
這意味着,我們只需要計算出
,就可以得到
以及其對應的導數
。所以,一個前向計算過程可以同時得到函數值與其導數,這就是前向模式的原理。舉例來說,如果要計算f(x)=2x+x^2在x=2處的函數值與導數,其計算過程如下所示:
反向模式
最后要說的就是反向模式,反向模式就是我們常說的BP算法,其基於的原理是鏈式法則。我們僅需要一個前向過程和反向過程就可以計算所有參數的導數或者梯度,這對於擁有大量訓練參數的神經網絡模型梯度的計算特別適合,所以常用的深度學習框架如Tensorflow其自動求導就是基於反向模式。方向模式具體的實現細節可以參考之前的文章。
參考資料
1. Automatic Differentiation in Machine Learning: a Survey, https://arxiv.org/pdf/1502.05767.pdf
2. Hands-On Machine Learning with Scikit-Learn and TensorFlow, Aurélien Géron, 2017.