自動微分原理與示例


自動微分原理與示例
機器學習的同學在學習過程中會經常遇到一個問題,那就是對目標函數進行求微分,線性回歸這類簡單的就不說、復雜的如神經網絡類那些求導過程。
本文介紹了五種微分方式,最后兩種才是自動微分。
前兩種方法求出了原函數對應的導函數,后三種方法只是求出了某一點的導數。
假設原函數是f(x,y)=x2y+y+2,需要求其偏導數 ,以便應用於梯度下降等算法。

1、手工求導
首先准備一張紙和一支筆,根據上學時候學到的求導法則,開始計算。最終得到的結果。

 缺點是對於復雜函數容易出錯。這一計算過程可由計算機幫完成,這就是符號微分。

這個小例子比較簡單,口算即可得到答案,但如果方程比較復雜那就難說了。幸好有自動求導的方法,例如符號求導方法。
2、符號微分(Symbolic Differentiation)
如圖1所示,使用符號微分的方法,計算函數g(x,y)=5+xy的偏導數。圖左側代表函數g(x,y),右側代表g(x,y)關於x的偏導數

 (同樣的,可以求得)。

 圖1. 符號微分

算法首先求葉子節點關於x的偏導數,然后沿着樹向上,求得其他節點關於自變量的偏導數。這與手工求導所使用的規則是一樣的。
如果函數復雜,算法生成的樹將十分龐大,性能不高。而且無法對很隨意的代碼求導,例如:
def my_func(a, b):
z = 0
for i in range(100):
z = a * np.cos(z + i) + z * np.sin(b - i)
return z

3、數值微分(Numerical Differentiation)
這是根據導數的定義來求解的。函數h(x)h(x)在x0x0點的導數為:

 

 取一個很小的ε,帶入公式進行計算即可。方法所得結果不夠精確,參數過多時計算量也比較大。但是計算起來很簡單,可用於校驗手工算出的導數是否正確。

如果有1000個參數,至少需要調用h(x)1001詞,來求得所有偏導數。
導數的定義是當自變量的增量趨於零時,因變量的增量與自變量的增量之商的極限。
其中εε是一個無窮小的數,所以我們可以計算在x=3,y=4這一點對x的偏導數,,對應的代碼如下:

def f(x, y):
return x**2*y + y + 2
def derivative(f, x, y, x_eps, y_eps):
return (f(x + x_eps, y + y_eps) - f(x, y)) / (x_eps + y_eps)
df_dx = derivative(f, 3, 4, 0.00001, 0)
df_dy = derivative(f, 3, 4, 0, 0.00001)
>>print(df_dx)
24.000039999805264
>>print(df_dy)
4、前向自動微分(Forward-Mode Autodiff)
算法依賴一個虛數(dual numbers,這讓我想起來oracle的虛表。難度dual可以表示虛無的意思?) ε,滿足,但ε≠0(姑且理解為一階無窮小吧)。

由於ε是無窮小,因此滿足h(a+bε)=h(a)+b×h′(a)ε。因此,算出h(a+ε)可以同時得到h(a)和h′(a),如圖2所示。

 

 圖2. 前向自動微分

上圖值計算了,同樣的方法可以算的

如果有1000個參數,需要遍歷上圖1000次,來求得所有偏導數。
5、反向自動微分(Reverse-Mode Autodiff)
這是TensorFlow所采用的自動微分算法。如圖3所示,算法首先前向(也就是從輸入到輸出)計算每個節點的值,然后反向(從輸出到輸入)計算所有的偏導數。

 圖3. 反向自動微分

反向計算時應用鏈式求導法則:

 由於n7n7就是輸出節點,f=n7,因此

算法強大且精確,尤其是輸入很多,輸出很少時。假如函數有10個輸出(不管輸入是1千,2萬還是更多),求得所有偏導數需要對上圖遍歷11次。
各個算法比較:

 

 



參考鏈接:
https://www.cnblogs.com/royhoo/p/Autodiff.html
https://www.cnblogs.com/wxshi/p/8007106.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM