續(xù)前一節(jié) 1.2 神經(jīng)網(wǎng)絡(luò)基礎(chǔ)2
7. 計(jì)算圖(Computation Graph)
神經(jīng)網(wǎng)絡(luò)的計(jì)算都是按照前向傳播過(guò)程計(jì)算出神經(jīng)網(wǎng)絡(luò)的輸出,緊接著用反向傳播過(guò)程來(lái)計(jì)算出對(duì)應(yīng)的梯度或者導(dǎo)數(shù)。計(jì)算圖就解釋了為什么神經(jīng)網(wǎng)絡(luò)是這樣的一種組織形式。通過(guò)舉例來(lái)闡釋計(jì)算圖,即計(jì)算過(guò)程。舉一個(gè)比logistic回歸更簡(jiǎn)單、非正式的例子來(lái)說(shuō)明:計(jì)算J(a,b,c)=3(a+bc)這個(gè)函數(shù)實(shí)際上有三個(gè)步驟:
第一步:u = bc
第二步:v = a + u
第三步:J = 3v
通過(guò)上述步驟,可以計(jì)算出J(a,b,c)的值,將這個(gè)計(jì)算過(guò)程反向執(zhí)行,即為梯度(導(dǎo)數(shù))計(jì)算過(guò)程。

8. 計(jì)算圖的導(dǎo)數(shù)計(jì)算(Derivatives with a Computation Graph)
本節(jié)課主要介紹如何利用計(jì)算圖進(jìn)行函數(shù)J的導(dǎo)數(shù)計(jì)算。
在反向傳播算法的術(shù)語(yǔ)中,如果你想計(jì)算最后輸出變量的導(dǎo)數(shù),這個(gè)變量就是你最關(guān)心的變量,在圖2中可以看到,這個(gè)變量就是J,這個(gè)計(jì)算函數(shù)J關(guān)于變量v的導(dǎo)數(shù)的過(guò)程(dJ/dv=?)就是一步反向傳播的過(guò)程。在流程圖中就體現(xiàn)為一個(gè)反向步。


那么,我們可以繼續(xù)思考,如果對(duì)a增加一定數(shù)值,函數(shù)J的數(shù)值會(huì)發(fā)生什么變化呢?

修改a的值會(huì)根據(jù)計(jì)算流程圖將改變值傳遞到最右邊,即a的數(shù)值變化,最終會(huì)反應(yīng)到函數(shù)J的結(jié)果中。這個(gè)計(jì)算過(guò)程可以理解為:a->v->J,這個(gè)微分傳導(dǎo)的過(guò)程在微積分中稱(chēng)為鏈?zhǔn)椒▌t(Chain rule)。

計(jì)算最終輸出變量的導(dǎo)數(shù)就是計(jì)算d輸出變量關(guān)于某個(gè)變量的導(dǎo)數(shù)。那么這個(gè)導(dǎo)數(shù)的公式在代碼中應(yīng)該用什么樣的變量名來(lái)表示呢?Andrew給出了一種命名方案:根據(jù)函數(shù)關(guān)于哪個(gè)變量進(jìn)行求導(dǎo)來(lái)命名,如:求最終輸出變量J關(guān)于變量v的導(dǎo)數(shù),在代碼中我們可以用dv來(lái)表示,在本例中,dv=3;同理,求最終輸出變量J關(guān)于變量a的導(dǎo)數(shù),在代碼中我們可以用da來(lái)表示,在本例中,da=3,其他情況以此類(lèi)推。

本節(jié)課的核心要點(diǎn)是:當(dāng)計(jì)算所有這些導(dǎo)數(shù)時(shí),最有效的方法是根據(jù)計(jì)算流程圖從右到左計(jì)算,如下圖中的紅色箭頭的方向:

9. logistic回歸中的梯度下降法(Logistic Regression Gradient Descent)
本節(jié)課主要介紹怎樣計(jì)算偏導(dǎo)數(shù)來(lái)實(shí)現(xiàn)logistic回歸的梯度下降法,它的核心關(guān)鍵點(diǎn)是用來(lái)實(shí)現(xiàn)logistic回歸的梯度下降法中的幾個(gè)重要公式。但在本節(jié)視頻中,將使用計(jì)算流程圖來(lái)計(jì)算導(dǎo)數(shù)。用計(jì)算流程圖來(lái)推導(dǎo)logistic回歸的梯度下降算法有點(diǎn)大材小用了,但為了后面能夠更加深入的了解神經(jīng)網(wǎng)絡(luò)算法,這里采用了計(jì)算流程圖的方式來(lái)分析logistic回歸的梯度下降法執(zhí)行過(guò)程。

要想計(jì)算損失函數(shù)L的偏導(dǎo)數(shù),首先需要從圖6中的計(jì)算流程圖最右側(cè)的節(jié)點(diǎn)往回退一步,計(jì)算最終結(jié)果損失函數(shù)L關(guān)于變量a的導(dǎo)數(shù),得到結(jié)果da后,再回退一步,計(jì)算L關(guān)于z的導(dǎo)數(shù)dz,最后回退到初始變量,計(jì)算L關(guān)于w1的導(dǎo)數(shù)dw1、L關(guān)于w2的導(dǎo)數(shù)dw2和L關(guān)于b的導(dǎo)數(shù)b。

接下來(lái)根據(jù)梯度下降法算法,計(jì)算下一個(gè)能夠使損失函數(shù)更小的w1、w2和b的組合,計(jì)算公式如下:

10. m個(gè)樣本的梯度下降(Gradient Descent on m examples)
在本節(jié)課中,主要講解了如何計(jì)算m個(gè)樣本的訓(xùn)練集的整體成本函數(shù)J(w,b)的梯度下降計(jì)算過(guò)程,并使用Python偽代碼進(jìn)行說(shuō)明。
在上一節(jié)課中,我們已經(jīng)計(jì)算出了單個(gè)樣本的損失函數(shù)的導(dǎo)數(shù),而m個(gè)樣本的訓(xùn)練集整體的成本函數(shù)J(w,b)的計(jì)算公式已經(jīng)在上一篇文章第3節(jié)中給出,也就是說(shuō),成本函數(shù)J的導(dǎo)數(shù)就是所有樣本損失函數(shù)L的導(dǎo)數(shù)的平均數(shù),這個(gè)分析過(guò)程如圖7所示:

根據(jù)上述分析,可以得出圖8所示的Python偽代碼:

從偽代碼中可以看出,梯度下降法的一次迭代需要經(jīng)過(guò)兩層嵌套的循環(huán)計(jì)算才能完成,循環(huán)的時(shí)間復(fù)雜度為O(m*n),其中,m代表訓(xùn)練集中樣本個(gè)數(shù),n代表一個(gè)樣本中特征的個(gè)數(shù)。
當(dāng)實(shí)現(xiàn)深度學(xué)習(xí)算法時(shí),在代碼中顯式的使用for循環(huán)會(huì)使算法非常低效,為了解決在深度學(xué)習(xí)算法中對(duì)于大量訓(xùn)練集的學(xué)習(xí)效率問(wèn)題,引入了向量化技術(shù),該技術(shù)可以避免在深度學(xué)習(xí)算法中使用for循環(huán),進(jìn)而提高運(yùn)算效率。
注意:本節(jié)課中,每個(gè)樣本的特征個(gè)數(shù)假設(shè)為兩個(gè),在實(shí)際應(yīng)用過(guò)程中也可能是多個(gè),每個(gè)特征都會(huì)對(duì)應(yīng)一個(gè)變量w,變量b為每個(gè)樣本對(duì)應(yīng)一個(gè)。
11. 向量化(Vectorization)
本質(zhì)上,向量化是消除代碼中顯示for循環(huán)語(yǔ)句的藝術(shù)。
訓(xùn)練集數(shù)據(jù)量越大,深度學(xué)習(xí)算法才能夠更加優(yōu)越。這就需要我們的深度學(xué)習(xí)算法運(yùn)算速度足夠快,因此,在深度學(xué)習(xí)領(lǐng)域,完成向量化的能力已經(jīng)變成一個(gè)關(guān)鍵的技能。
本節(jié)課主要以?xún)蓚€(gè)1,000,000維矩陣相乘為例,在Python中用for循環(huán)和向量化的方法實(shí)現(xiàn),比較兩種方法的運(yùn)行耗時(shí),從而驗(yàn)證了使用向量化的方法要比顯示的for循環(huán)的運(yùn)算性能更好,下圖為本人根據(jù)視頻教程在Jupyter Notebook中做的實(shí)驗(yàn)截圖:

深度學(xué)習(xí)一般是在GPU(圖像處理單元,Graphics Processing Unit)中運(yùn)行的,但在本次課程中的demo是運(yùn)行在Jupyter Notebook中的,即運(yùn)行在CPU中,這就說(shuō)明GPU和CPU均有并行化的指令(也稱(chēng)為SIMD指令),也就是一條指令中可以同時(shí)處理多數(shù)據(jù)流。
我們可以通過(guò)numpy.functions來(lái)調(diào)用這些方法,避免Python代碼中顯式調(diào)用for循環(huán),從而能夠更好地利用CPU或者GPU的并行機(jī)制。
經(jīng)驗(yàn)法則:只要有其他可能,就不要使用顯示的for循環(huán)。
Whenever possible, avoid explicit for-loops. ——Andrew Ng
12. 向量化的更多例子(More Vectorization Examples)
用內(nèi)置函數(shù)或者其他方法代替顯式for循環(huán)。
本節(jié)課首先介紹了幾個(gè)numpy庫(kù)中常用的一些方法,如:矩陣的每個(gè)元素的指數(shù)計(jì)算、對(duì)數(shù)計(jì)算、絕對(duì)值計(jì)算等。具體的方法寫(xiě)法如下圖所示:

利用numpy庫(kù)中的內(nèi)置方法對(duì)第10節(jié)中編寫(xiě)的m個(gè)樣本的訓(xùn)練集的梯度下降法算法進(jìn)行優(yōu)化,最終,我們可以將兩層嵌套的循環(huán)中的內(nèi)層for循環(huán)優(yōu)化掉,即將樣本內(nèi)特征向量的遍歷被優(yōu)化了。優(yōu)化過(guò)程及結(jié)果如下圖所示:

本節(jié)課優(yōu)化完成后的算法效率得到了大大的提高,但仍然還有一層for循環(huán)用來(lái)遍歷訓(xùn)練集中的樣本,那么如何優(yōu)化這個(gè)循環(huán)呢?我們將在第14節(jié)中來(lái)見(jiàn)證這個(gè)奇跡的時(shí)刻!
13. 向量化logistic回歸(Vectorizing Logistic Regression)
本節(jié)課主要講的內(nèi)容是:向量化如何在logistic回歸中應(yīng)用,這樣就能做到在一次計(jì)算過(guò)程中同時(shí)處理整個(gè)m個(gè)樣本的訓(xùn)練集。那么在正向傳播步驟的一次迭代的向量化實(shí)現(xiàn),應(yīng)該如何做呢?
- 首先,為了達(dá)成這個(gè)目的,我們需要將m個(gè)樣本各自的特征向量x(i)作為一個(gè)個(gè)列向量合并成一個(gè)大的矩陣,記為X;
- 然后,將所有的z(i)也合并成一個(gè)行向量,記為Z,Z=[z(1) z(2) ... z(m)];
- 那么,計(jì)算m次z(i)的過(guò)程就可以轉(zhuǎn)化為一次m維的行向量wT與nxm維矩陣的乘積與1m維行向量[b b ... b]之和,即:Z=wTX+[b b ... b];
- 同理,可以將m個(gè)預(yù)測(cè)結(jié)果a(i)整合為一個(gè)m維的行向量,記為A,A=[a(1) a(2) ... a(m)]=sigma(Z);
在Python中,m維的行向量+實(shí)數(shù)b將會(huì)被自動(dòng)轉(zhuǎn)化為m維的行向量+1*m維的行向量[b b ... b]。這個(gè)操作在Python中稱(chēng)為廣播(Broadcasting)。

14. 向量化logistic回歸的梯度輸出(Vectorizing Logistic Regression's Gradient Computation)
本節(jié)課的主要內(nèi)容是:運(yùn)用向量化來(lái)計(jì)算m個(gè)樣本的訓(xùn)練數(shù)據(jù)集的梯度。
首先,根據(jù)第13節(jié)中的講解,我們可以將m個(gè)dz(i)=a(i)-y(i)合并到一次計(jì)算過(guò)程中:
dZ=A-Y=[a(1)-y(1) a(2)-y(2) ...]
這樣我們就可以將第12節(jié)中的遍歷m個(gè)樣本的for循環(huán)進(jìn)行向量化,從而去除另外一個(gè)顯式for循環(huán)。

接下來(lái),將第13節(jié)和本節(jié)內(nèi)容結(jié)合起來(lái),整體來(lái)看下logistic回歸的梯度下降法一次迭代優(yōu)化后的偽代碼:

到此為止,我們已經(jīng)對(duì)logistic回歸的梯度下降法一次迭代的計(jì)算過(guò)程全部進(jìn)行了向量化,但是,為了得到盡可能小的成本函數(shù)J,我們還是需要通過(guò)for循環(huán)來(lái)進(jìn)行多次的梯度下降法的迭代,從而得到合適的w和b的組合。
15. Python中的廣播(Broadcasting in Python)
本節(jié)課中主要講解了Python中的廣播(Broadcasting)是怎樣運(yùn)作的,這個(gè)技術(shù)同樣也是為了能夠提高代碼的效能。



16. 關(guān)于Python/numpy向量的說(shuō)明(A note on python/numpy vectors)

17. Jupyter/Ipython 筆記本的快速指南
本節(jié)課主要講解了在Coursera中的IPython的一些常用的功能。其中,
- 灰色塊表示代碼塊;
- 作業(yè)的代碼需要寫(xiě)在代碼開(kāi)始和代碼結(jié)束注釋之間才算有效;
- 執(zhí)行一個(gè)單元格內(nèi)的代碼有兩種方式:一種是右鍵選中單元格,選擇【Run Cells】;另一種方法是使用快捷鍵,在Windows操作系統(tǒng)中,默認(rèn)快捷鍵為Shift+Enter;
- 雙擊文本單元格可以查看文本單元格的Markdown源碼,運(yùn)行單元格可以恢復(fù)文本預(yù)覽模式;
- 如果出現(xiàn)斷網(wǎng)或者其他錯(cuò)誤導(dǎo)致內(nèi)核(Kernel)宕機(jī),可以通過(guò)工具欄中的重啟功能進(jìn)行重啟操作;
- 要盡可能運(yùn)行說(shuō)明文檔中的所有單元格,因?yàn)榭赡苡胁糠肿兞渴窃谏厦娴膯卧裰卸x的,而我們?cè)诤罄m(xù)的單元格執(zhí)行過(guò)程中需要用到這些變量。