自动微分方法(auto diff)
學(xué)習(xí)機(jī)器學(xué)習(xí)的同學(xué)在學(xué)習(xí)過程中會經(jīng)常遇到一個問題,那就是對目標(biāo)函數(shù)進(jìn)行求微分,線性回歸這類簡單的就不說、復(fù)雜的如神經(jīng)網(wǎng)絡(luò)類那些求導(dǎo)過程的酸爽。像我還是那種比較粗心的人往往有十導(dǎo)九錯,所以說自動求導(dǎo)就十分有必要了,本文主要介紹幾種求導(dǎo)的方式。假設(shè)我們的函數(shù)為(f(x,y)=x^2y+y+2),目標(biāo)是求出偏導(dǎo)(frac{partial{f}}{partial{x}})和(frac{partial{f}}{partial{y}})。求導(dǎo)的方式主要分為以下幾種
手動求導(dǎo)法(Manual Differentiation)###
首先準(zhǔn)備一張紙和一支筆,根據(jù)上學(xué)時候?qū)W到的求導(dǎo)法則,開始計(jì)算。最終得到的結(jié)果
(frac{partial{f}}{partial{x}}=2xy)
(frac{partial{f}}{partial{y}}=x^2+1)
上面這個小例子比較簡單,口算即可得到答案,但如果方程比較復(fù)雜那就難說了。幸好有自動求導(dǎo)的方法,例如符號求導(dǎo)方法。
符號求解法(Symbolic Differentiation)###
符號求導(dǎo)是根據(jù)一些求導(dǎo)法則,進(jìn)行求導(dǎo)。例如我們大學(xué)高數(shù)學(xué)習(xí)的((uv)prime=u'v+v'u),((u+v)'=u'+v'),((frac{u}{v})'=frac{u'v-v'u}{v^2})等等,下圖是(g(x,y)=5+xy)的符號求導(dǎo)工作流程。
原公式在圖的左邊,求導(dǎo)公式在圖的右半部分,求導(dǎo)的過程是先求葉子節(jié)點(diǎn),自下向上。最終對節(jié)點(diǎn)進(jìn)行見之得到求導(dǎo)結(jié)果(frac{partial{g}}{partial{x}}=y),這個例子固然簡單,但是對于一個更復(fù)雜的公式,那么求導(dǎo)符號圖將會十分的龐大(表達(dá)式膨脹),另外對于一些變化的公式(硬代碼)這種方法就無能為力了:
def fun(a,b):
z=0
for i in range(100):
z = a * np.cos(z + i) + z * np.sin(b - i)
return z
數(shù)值求導(dǎo)法(Numerical Differentiation)###
導(dǎo)數(shù)的定義是當(dāng)自變量的增量趨于零時,因變量的增量與自變量的增量之商的極限。
其中(varepsilon)是一個無窮小的數(shù),所以我們可以計(jì)算在x=3,y=4這一點(diǎn)對x的偏導(dǎo)數(shù),(f'(x=3,y)=frac{f(3+varepsilon,4)-f(3,4)}{varepsilon}),對應(yīng)的代碼如下:
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)
10.000000000331966
通過上面的結(jié)果我們發(fā)現(xiàn),得出的結(jié)果不是十分的精確,并且在對x和y求偏導(dǎo)的整個過程中,至少需要計(jì)算3次(f()),也就是說如果有1000個參數(shù),那么至少需要計(jì)算1001次(f()),在神經(jīng)網(wǎng)絡(luò)中,參數(shù)巨多,這樣計(jì)算效率會比較差。不過這種方法常被用到進(jìn)行檢驗(yàn)得到的求導(dǎo)結(jié)果是否正確。
前向自動求導(dǎo)法(Forward-Mode Autodiff)###
前向求導(dǎo)是依賴于數(shù)值求導(dǎo)和符號求導(dǎo)的一種求解方法,給定公式(a+{varepsilon}b),這種被稱作dual number,其中a和b是實(shí)數(shù),(varepsilon)是一個無窮小的數(shù),并且({varepsilon}^2=0),舉個栗子,(42 + 24varepsilon),我們可以把它看成42.00000000...24的數(shù)值.我們可以通過這種方法(42.0,24.0)來表示,dual number滿足以下的運(yùn)算法則:
1.(lambda(a+bvarepsilon) = avarepsilon + b{lambda}varepsilon)
2.((a+bvarepsilon)+(c+dvarepsilon) = (a+c)+(b+d)varepsilon)
3.((a+bvarepsilon) imes(c+dvarepsilon) = ac+(ad+bc)varepsilon+(bd){varepsilon}^2=ac+(ad+bc)varepsilon)
還有一點(diǎn)就是(h(a+bvarepsilon)=h(a)+b{ imes}h'(a)varepsilon)。
上圖給出了使用前向求導(dǎo)方法計(jì)算出(f(x,y))在x=3,y=4這一點(diǎn)(frac{partial{f}}{partial{x}}(3,4))的偏導(dǎo),同理求出(frac{partial{f}}{partial{y}}(3,4)),圖中的思路很清晰就不贅述。前向求導(dǎo)方法相對數(shù)值求導(dǎo)來說準(zhǔn)確率較高,當(dāng)和數(shù)值求導(dǎo)方法一樣如果參數(shù)過多的時候效率會比較差,因?yàn)檫@種方法需要遍歷整個圖。
逆向自動求導(dǎo)法(Reverse-Mode Atuodiff)###
TensorFlow采用的是逆向自動求導(dǎo)方法,該方法首先正向遍歷整個圖,計(jì)算出每個節(jié)點(diǎn)的值;然后逆向(從上到下)遍歷整個圖,計(jì)算出節(jié)點(diǎn)的偏導(dǎo)值,步驟如下圖所示;節(jié)點(diǎn)內(nèi)藍(lán)色的數(shù)值表示正向計(jì)算出的結(jié)果,為了方便表達(dá),我們從下到上,從左到右依次標(biāo)注為(n_1)到(n_7),可以看到最后的值(n_7)(頂部節(jié)點(diǎn))為42。
在逆向求導(dǎo)過程中使用鏈?zhǔn)角髮?dǎo)方法:
(frac{partial{f}}{partial{x}}=frac{partial{f}}{partial{n_i}}{ imes}frac{partial{n_i}}{partial{x}})
先看節(jié)點(diǎn)(n_7),作為輸出節(jié)點(diǎn)(f=n_7),所以導(dǎo)數(shù)值為(frac{partial{f}}{partial{n_7}}=1),
接著向下計(jì)算(n_5),(frac{partial{f}}{partial{n_5}}=frac{partial{f}}{partial{n_7}}{ imes}frac{partial{n_7}}{partial{n_5}}),上一步計(jì)算出(frac{partial{f}}{partial{n_7}}=1),現(xiàn)在我們只需要計(jì)算(frac{partial{n_7}}{partial{n_5}}),從圖中我們知道(n_7=n_5+n_6),可以得出(frac{partial{f}}{partial{x}}=1)。所以(frac{partial{f}}{partial{n_5}}=1),接下來的步驟可以看上面的圖,這里就不贅述了。
逆向自動求導(dǎo)法這種方法十分強(qiáng)大且準(zhǔn)確率較高,尤其是有卻多的輸入。這種發(fā)方法僅需要正向和逆向遍歷一次即可,這種方法更強(qiáng)大的地方在于能夠解決符號求解法中硬代碼的問題。
總結(jié)
以上是生活随笔為你收集整理的自动微分方法(auto diff)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信小程序走出国门,国际化将指日可待?
- 下一篇: Windows CE是什么(downlo