吳恩達《神經網絡與深度學習》課程筆記(3)-- 神經網絡基礎之Python與向量化

本筆記參考了黃海廣博士和紅色石頭的筆記內容。

本課程對應的作業,本人已翻譯,放在github上,地址如下:

https://github.com/fuhuaxu/deeplearning-ai-assignment/tree/master/lesson1

 

上節課我們主要介紹了邏輯迴歸,以輸出概率的形式來處理二分類問題。我們介紹了邏輯迴歸的Cost function表達式,並使用梯度下降算法來計算最小化Cost function時對應的參數w和b。通過計算圖的方式來講述了神經網絡的正向傳播和反向傳播兩個過程。本節課我們將來探討Python和向量化的相關知識。

這裏說的矩陣運算,實際用的都是np.array(),並沒有用np.matrix(),因爲np.matrix是np.array的特例,array更靈活,速度更快。

1. Vectorization

深度學習算法中,數據量很大,在程序中應該儘量減少使用loop循環語句,而可以使用向量運算來提高程序運行速度。

向量化(Vectorization)就是利用矩陣運算的思想,大大提高運算速度。例如下面所示在Python中使用向量化要比使用循環計算速度快得多。

import numpy as np
import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

tic = time.time()
c = np.dot(a,b)
toc = time.time()

print(c)
print("Vectorized version:" + str(1000*(toc-tic)) + "ms")

c = 0
tic = time.time()
for i in range(1000000):
	c += a[i]*b[i]
toc = time.time()

print(c)
print("for loop:" + str(1000*(toc-tic)) + "ms")

輸出結果類似於:

250286.989866
Vectorized version:1.5027523040771484ms
250286.989866
For loop:474.29513931274414ms

從程序運行結果上來看,該例子使用for循環運行時間是使用向量運算運行時間的約300倍。因此,深度學習算法中,使用向量化矩陣運算的效率要高得多。

爲了加快深度學習神經網絡運算速度,可以使用比CPU運算能力更強大的GPU。事實上,GPU和CPU都有並行指令(parallelization instructions),稱爲Single Instruction Multiple Data(SIMD)。SIMD是單指令多數據流,能夠複製多個操作數,並把它們打包在大型寄存器的一組指令集。SIMD能夠大大提高程序運行速度,例如python的numpy庫中的內建函數(built-in function)就是使用了SIMD指令。相比而言,GPU的SIMD要比CPU更強大一些。

 

2. More Vectorization Examples

上一部分我們講了應該儘量避免使用for循環而使用向量化矩陣運算。在python的numpy庫中,我們通常使用np.dot()函數來進行矩陣運算。

我們將向量化的思想使用在邏輯迴歸算法上,儘可能減少for循環,而只使用矩陣運算。值得注意的是,算法最頂層的迭代訓練的for循環是不能替換的。而每次迭代過程對J,dw,b的計算是可以直接使用矩陣運算。

上面是我們邏輯迴歸的求導代碼,有兩層循環,第一層是對每個樣本的循環,第二層是針對每個樣本的nx 個特徵的循環。也就是需要循環 dw1  、dw2  、dw3  等等。j  的實際值是1、2 和 nx 。通過下圖的推導過程,將這層循環去掉。

我們僅僅使用了一個向量操作 dw=dw+x(i)dz(i)  。最後,我們得到 dw=dw/m  。現在我們通過將兩層循環轉成一層循環,我們仍然還有這個循環訓練樣本。

 

3. Vectorizing Logistic Regression

在《神經網絡與深度學習》課程筆記(2)中我們介紹過,整個訓練樣本構成的輸入矩陣X的維度是(nx , m),權重矩陣w的維度是(nx , 1),b是一個常數值,而整個訓練樣本構成的輸出矩陣Y的維度爲(1, m)。

利用向量化的思想,所有m個樣本的線性輸出Z可以用矩陣表示:

在python的numpy庫中可以表示爲:

Z = np.dot(w.T, X) + b
A = sigmoid(Z)
其中,w.T表示w的轉置。

這樣,我們就能夠使用向量化矩陣運算代替for循環,對所有m個樣本同時運算,大大提高了運算速度。

4. Vectorizing Logistic Regression’s Gradient Output

前面的章節,對於邏輯迴歸的梯度下降算法已經去掉了一個for循環。

下面再看剩下部分如何轉化爲向量化的矩陣形式。

  1. Dz向量化

之前我們在講梯度計算的時候,列舉過幾個例子, dz(1)=a(1)-y(1) ,dz(2)=a(2)-y(2)  ……等等一系列類似公式。現在,對 m 個訓練數據做同樣的運算,我們可以定義一個新的變量 dZ=[dz(1),dz(2)...dz(m)]  ,所有的 dz  變量橫向排列,因此,dZ  是一個 1×m  的矩陣,或者說,一個 m  維行向量。在之前的幻燈片中,我們已經知道如何計算A ,即 [a(1),a(2)...a(m)] ,我們需要找到這樣的一個行向量 Y=[y(1)y(2)...y(m)]  ,由此,我們可以這樣計算 dZ=A-Y=[a(1)-y(1)a(2)-y(2)...a(m)-y(m)] ,不難發現第一個元素就是 dz(1) ,第二個元素就是 dz(2)  ……我們現在僅需一行代碼,就可以同時完成這所有的計算。

所以,對於所有m個樣本,dZ的維度是(1,m),可表示爲:

2、db向量化

在上面的代碼中,仍然需要一個循環來遍歷所有樣本,對於db部分僞代碼如下:

db=0

db+=dz(1)

db+=dz(2)

………….

db+=dz(m)

db=dbm

 

2. dw向量化

接下來看dw 的僞代碼,

所以dw可表示爲:

對應的程序爲:

dw = 1/m*np.dot(X,dZ.T)
這樣,我們把整個邏輯迴歸中的for循環儘可能用矩陣運算代替,對於單次迭代epoch,梯度下降算法流程如下所示:
Z = np.dot(w.T,X) + b
A = sigmoid(Z)
dZ = A-Y
dw = 1/m*np.dot(X,dZ.T)
db = 1/m*np.sum(dZ)

w = w - alpha*dw
b = b - alpha*db

其中,alpha是學習因子,決定w和b的更新速度。上述代碼只是對單次訓練更新而言的,外層還需要一個for循環,表示迭代次數。

 

5. Broadcasting in Python

下面介紹使用python的另一種技巧:廣播(Broadcasting)。python中的廣播機制可由下面四條表示:

  • 讓所有輸入數組都向其中shape最長的數組看齊,shape中不足的部分都通過在前面加1補齊
  • 輸出數組的shape是輸入數組shape的各個軸上的最大值
  • 如果輸入數組的某個軸和輸出數組的對應軸的長度相同或者其長度爲1時,這個數組能夠用來計算,否則出錯
  • 當輸入數組的某個軸的長度爲1時,沿着此軸運算時都用此軸上的第一組值

簡而言之,就是python中可以對不同維度的矩陣進行四則混合運算,但至少保證有一個維度是相同的。下面給出幾個廣播的例子,具體細節可參閱python的相關手冊,這裏就不贅述了。

值得一提的是,在python程序中爲了保證矩陣運算正確,可以使用reshape()函數來對矩陣設定所需的維度。這是一個很好且有用的習慣。

6. A note on python/numpy vectors

接下來我們將總結一些python的小技巧,避免不必要的code bug。

python中,如果我們用下列語句來定義一個向量:

a = np.random.randn(5)

 

這條語句生成的a的維度是(5,)。它既不是行向量也不是列向量,我們把a叫做rank 1 array。這種定義會帶來一些問題。例如我們對a進行轉置,還是會得到a本身。所以,如果我們要定義(5,1)的列向量或者(1,5)的行向量,最好使用下來標準語句,避免使用rank 1 array。

a = np.random.randn(5,1)
b = np.random.randn(1,5)

除此之外,我們還可以使用assert語句對向量或數組的維度進行判斷,例如:

assert(a.shape == (5,1))

assert會對內嵌語句進行判斷,即判斷a的維度是不是(5,1)的。如果不是,則程序在此處停止。使用assert語句也是一種很好的習慣,能夠幫助我們及時檢查、發現語句是否正確。

另外,還可以使用reshape函數對數組設定所需的維度:

a.reshape((5,1))

7. Quick tour of Jupyter/iPython Notebooks

Jupyter notebook(又稱IPython notebook)是一個交互式的筆記本,支持運行超過40種編程語言。本課程所有的編程練習題都將在Jupyter notebook上進行,使用的語言是python。

 

8. Explanation of logistic regression cost function(optional)

在上一節課的筆記中,我們介紹過邏輯迴歸的Cost function。接下來我們將簡要解釋這個Cost function是怎麼來的。

我們希望上述概率P(y|x)越大越好,對上式加上負號,則轉化成了單個樣本的Loss function,越小越好,也就得到了我們之前介紹的邏輯迴歸的Loss function形式。

如果對於所有m個訓練樣本,假設樣本之間是獨立同分布的(iid),我們希望總的概率越大越好:

同樣引入log函數,加上負號,將上式轉化爲Cost function:

9. Summary

本節課我們主要介紹了神經網絡基礎——python和向量化。在深度學習程序中,使用向量化和矩陣運算的方法能夠大大提高運行速度,節省時間。以邏輯迴歸爲例,我們將其算法流程包括梯度下降轉換爲向量化的形式。同時,我們也介紹了python的相關編程方法和技巧。

本課程對應的作業,本人已翻譯,放在github上,地址如下:

https://github.com/fuhuaxu/deeplearning-ai-assignment/tree/master/lesson1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章