從零實(shí)現(xiàn)深度學(xué)習(xí)框架(二)常見(jiàn)運(yùn)算的計(jì)算圖

引言
本著“凡我不能創(chuàng)造的,我就不能理解”的思想,本系列文章會(huì)基于純Python以及NumPy從零創(chuàng)建自己的深度學(xué)習(xí)框架,該框架類(lèi)似PyTorch能實(shí)現(xiàn)自動(dòng)求導(dǎo)。
要深入理解深度學(xué)習(xí),從零開(kāi)始創(chuàng)建的經(jīng)驗(yàn)非常重要,從自己可以理解的角度出發(fā),盡量不適用外部完備的框架前提下,實(shí)現(xiàn)我們想要的模型。本系列文章的宗旨就是通過(guò)這樣的過(guò)程,讓大家切實(shí)掌握深度學(xué)習(xí)底層實(shí)現(xiàn),而不是僅做一個(gè)調(diào)包俠。
本文介紹常見(jiàn)運(yùn)算的計(jì)算圖。
計(jì)算圖直觀地表示了計(jì)算過(guò)程。通過(guò)觀察反向傳播的梯度流動(dòng),可以幫助我們理解反向傳播的推導(dǎo)過(guò)程。
我們會(huì)利用計(jì)算圖來(lái)實(shí)現(xiàn)自動(dòng)求導(dǎo)工具。首先我們看一下常見(jiàn)運(yùn)算操作的計(jì)算圖。
加法

求這個(gè)運(yùn)算的梯度比較簡(jiǎn)單,易得
為經(jīng)過(guò)反向傳播傳遞到節(jié)點(diǎn)上的梯度。
減法

由?可得
乘法

?的梯度也比較簡(jiǎn)單,易得。
此時(shí),反向傳播時(shí)會(huì)將上游傳來(lái)的梯度乘以當(dāng)前路徑上計(jì)算出來(lái)的梯度。
除法

的梯度稍微有點(diǎn)復(fù)雜,。
我們現(xiàn)在看到的都是單變量,其實(shí)也可以是多變量(向量、張量或矩陣)。在多變量時(shí),只需要獨(dú)立計(jì)算向量中各個(gè)元素,即,向量的各個(gè)元素獨(dú)立于其他元素進(jìn)行對(duì)應(yīng)元素的計(jì)算。在下文的矩陣乘法時(shí)會(huì)詳細(xì)介紹。
分支
嚴(yán)格來(lái)說(shuō),分支并不是我們常見(jiàn)運(yùn)算的一種。但是有些情況下很有用,比如進(jìn)行廣播操作時(shí)。

分支是最簡(jiǎn)單的復(fù)制形式,它的反向傳播是上游傳來(lái)的梯度之和。
Repeat
上面的分支操作有兩個(gè)副本(或者分支),也可以擴(kuò)展為個(gè)副本,此時(shí)稱(chēng)為復(fù)制(Repeat)。

如上圖,將長(zhǎng)度為的數(shù)組復(fù)制了份,這個(gè)復(fù)制操作可以看成是個(gè)分支操作,所以它的反向傳播可以通過(guò)個(gè)梯度的總和。

如果通過(guò)Numpy實(shí)現(xiàn)的化:
import?numpy?as?np
D,?N?=?8,?7
x?=?np.random.randn(1,D)
y?=?np.repeat(x,?N,?axis=0)?#?axis=0?沿著行的方向復(fù)制N份,變成了(N,D)
#?上面是正向傳播
#?下面是梯度
dy?=?np.random.randn(N,D)?#?y的梯度一定和y的維度保持一致
dx?=?np.sum(dy,?axis=0,?keepdims=True)?#?同理,x的梯度也和x保持一致,這里變成了(1,D)

上圖是簡(jiǎn)單介紹一下Numpy中axis的概念。當(dāng)數(shù)組是1D的時(shí)候,只有一個(gè)軸,所以0軸的方向和2D的不同,要注意一下。
Numpy中的廣播會(huì)復(fù)制數(shù)組的元素,可以通過(guò)這里的復(fù)制操作來(lái)表示。
Sum
Sum(求和)也是我們?cè)谏疃葘W(xué)習(xí)中常用的運(yùn)算。加法操作可以看成是求和的特殊形式。
考慮對(duì)一個(gè)對(duì)數(shù)組沿著第行的方向求和,此時(shí)正向傳播和反向傳播如下所示。

和加法一樣,反向傳播時(shí)將梯度(拷貝)分配到所有的箭頭上,Sum操作是上面介紹的復(fù)制操作的逆向操作。即Sum的正向傳播相當(dāng)于復(fù)制操作的反向傳播;Sum的反向傳播相當(dāng)于復(fù)制操作的正向傳播。
我們也看一下通過(guò)Numpy實(shí)現(xiàn)的例子。
D,?N?=?8,?7
#?正向傳播
x?=?np.random.randn(N,?D)
y?=?np.sum(x,?axis=0,?keepdims=True)?#?變成了(1,D)
#?反向傳播
dy?=?np.random.randn(1,?D)?#?維度和y保持一致
dx?=?np.repeat(dy,?N,?axis=0)?#?復(fù)制成了(N,D)
Matmul
Matmul是矩陣乘法(Matrix Multiply),比如,考慮這個(gè)運(yùn)算。的形狀分別是、和。

它的反向傳播稍微有點(diǎn)復(fù)雜。我們先來(lái)了解下雅可比矩陣(Jacobian matrix)。

用每個(gè)對(duì)每個(gè)計(jì)算偏微分,計(jì)算得到的矩陣高度是的個(gè)數(shù),寬度是的個(gè)數(shù)。
把展開(kāi)得:
這里假設(shè)我們要計(jì)算對(duì)的導(dǎo)數(shù)。
我們先計(jì)算
接著計(jì)算對(duì)的導(dǎo)數(shù),根據(jù)雅克比矩陣,有
看起來(lái)挺復(fù)雜,但是如果我們先把中第個(gè)元素的等式寫(xiě)出來(lái),就會(huì)很簡(jiǎn)單,如:
所以?,把完整的寫(xiě)出來(lái),有
所以 ,這就解釋了為什么計(jì)算矩陣乘法的反向傳播時(shí),有個(gè)參數(shù)需要轉(zhuǎn)置的。
有
的形狀是,的形狀和它保持一致,也是。
的形狀和一樣,是
的形狀是。
在推導(dǎo)上面的公式時(shí),不要被寫(xiě)法的復(fù)雜所迷惑了,只要我們展開(kāi)把等式寫(xiě)出來(lái),或者用一個(gè)簡(jiǎn)單的比如的矩陣自己去推,就可以知道規(guī)律。
上面把寫(xiě)出來(lái)后,計(jì)算就很簡(jiǎn)單了,因?yàn)榇藭r(shí)只與有關(guān),對(duì)于剩下的元素的導(dǎo)數(shù)都是0,變成了。
下面介紹幾個(gè)簡(jiǎn)單的一元操作。
Pow
計(jì)算,我們把看成是變量,看成是常數(shù)。只有一個(gè)變量,因此定義為一元操作。,一元操作比較簡(jiǎn)單,因此正向傳播和反向傳播畫(huà)到一張圖里面。

Log
取對(duì)數(shù)(Log),一般指的是以指數(shù)為底。,那么。

Exp
指數(shù)函數(shù)最簡(jiǎn)單了,,原樣返回。

Neg
Neg是取負(fù)數(shù)的意思,,,可以理解為。

最后一句:BUG,走你!


Markdown筆記神器Typora配置Gitee圖床
不會(huì)真有人覺(jué)得聊天機(jī)器人難吧(一)
Spring Cloud學(xué)習(xí)筆記(一)
沒(méi)有人比我更懂Spring Boot(一)
入門(mén)人工智能必備的線(xiàn)性代數(shù)基礎(chǔ)
1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的在看是我創(chuàng)作的動(dòng)力。
2.關(guān)注公眾號(hào),每天為您分享原創(chuàng)或精選文章!
3.特殊階段,帶好口罩,做好個(gè)人防護(hù)。
