2020-5-1 吳恩達-NN&DL-w2 NN基礎(2.11 向量化 Vectorization,2.12 向量化的更多例子)

1.視頻網站:mooc慕課https://mooc.study.163.com/university/deeplearning_ai#/c
2.詳細筆記網站(中文):http://www.ai-start.com/dl2017/
3.github課件+作業+答案:https://github.com/stormstone/deeplearning.ai

2.11 向量化 Vectorization-加速計算

向量化是非常基礎的去除代碼中for循環的藝術。在深度學習領域,運行向量化是一個關鍵的技巧。

在邏輯迴歸中你需要去計算z=wTx+bz=w^Tx+b,在第一節中已經介紹過,這裏的w,x都是列向量。如果你有很多的特徵那麼就會有一個非常大的向量,wRnxw \in R^{n_x}xRnxx \in R^{n_x}
在這裏插入圖片描述
如果你想使用非向量化方法去計算wTxw^Tx,代碼如下

z=0

for i in range(n_x)
    z+=w[i]*x[i]
z+=b

如果改用向量化方式,代碼如下

z=np.dot(w,x)+b

你將會發現這個方法非常快。

讓我們用下面這個小例子說明一下。

import numpy as np #導入numpy庫

a = np.array([1,2,3,4]) #創建一個數組a

print(a)

# [1 2 3 4]

import time #導入時間庫

a = np.random.rand(1000000)

b = np.random.rand(1000000) #通過round隨機得到兩個一百萬維度的數組

tic = time.time() #現在測量一下當前時間

#向量化的版本

c = np.dot(a,b)

toc = time.time()

print("c=",c)

print("Vectorized version:" + str(10000*(toc-tic)) +"ms") #打印一下向量化的版本的時間

#繼續增加非向量化的版本

c = 0

tic = time.time()

for i in range(1000000):

    c += a[i]*b[i]

toc = time.time()

print("c=",c)

print("For loop:" + str(10000*(toc-tic)) + "ms")#打印for循環的版本的時間

在python中運行結果如下

[1 2 3 4]
c= 249939.826271
Vectorized version:99.10821914672852ms
c= 249939.826271
For loop:8998.942375183105ms

在兩個方法中,向量化和非向量化計算了相同的c值,如你所見,非向量化版本多花費了90倍時間。

所以說,向量化後運行速度會大幅提升。

CPU和GPU都有並行化指令,有時候會叫SIMD指令,意思是單指令多維數據。SIMD指令的意義是,如果你使用了內置函數,例如:np.function或者其他能讓你去掉顯示for循環的函數,此時python的numpy能夠充分利用並行化,去更快的計算。這一點,在CPU和GPU上計算都是成立的。

GPU更加擅長SIMD計算,事實上CPU也不是太差,可能沒有GPU那麼擅長吧。

2.12 向量化的更多例子 More vectorization examples

上一節我們瞭解了通過numpy內置函數和避開顯式的for循環的方式進行向量化,從而有效提高代碼速度。

經驗法則:當我們在寫神經網絡程序時,或者在寫邏輯迴歸,或者其他神經網絡模型時,應該避免寫循環語句。

再來看一些例子。

例1
如果你想計算向量u=Avu=Av,根據矩陣乘法的定義,ui=jAijvju_i=\sum_jA_{ij}v_j
如果用非向量化計算

u=np.zeros((n,1)) #初始化
for i...
	for j...
		u[i]+=A[i][j]*v[j]

這是一個雙重循環。

改用向量化計算

u=np.dot(A,v)

這裏消除了2個循環,速度會更加快。

例2
假設有向量v=[v1...vn]v=\begin{bmatrix} v_1 \\ ... \\ v_n \\ \end{bmatrix},現在要對向量v的每個元素做指數操作,u=[ev1...evn]u=\begin{bmatrix} e^{v_1} \\ ... \\ e^{v_n} \\ \end{bmatrix}
先使用非向量化方式

u=np.zeros((n,1)) #初始化向量u
for i in range(n): #通過循環依次計算每個元素
	u[i]=math.exp(v[i])  #一次計算一個元素

向量化方式,利用內置函數替換了上面的顯示for循環。

import numpy as np
u=np.exp(v)

向量化代碼執行的效率會快很多。

numpy有很多內置函數,例如:np.log()計算log,np.abs()計算絕對值,np.maximum()計算最大值。

所以當你想寫循環時候,先檢查numpy是否存在類似的內置函數,從而避免使用循環方式。

在第10節中,我們實現邏輯迴歸中的梯度下降算法中曾經說過會有2個for循環。
其中第二個for循環是因爲如果樣本的特徵值非常多,需要對每個特徵值進行循環遍歷。
這裏我們可以用向量化方法來替換
step1.替換初始化過程
不用初始化 dw1,dw2…dwn 都等於0。改用dw=np.zeros((n,1)),定義了n*1維向量。

step2.替換dw1,dw2…dwn循環計算

dw1 += x1(i)dz(i);#導數,參數w1變化對J的影響。注意:這裏沒有上標i,是累加整個訓練集合上的和。
dw2 += x2(i)dz(i);#導數,參數w2變化對J的影響。注意:這裏沒有上標i,是累加整個訓練集合上的和。
...
dwn += xn(i)dz(i);

替換爲dw+=x(i)dz(i)

step3.替換最後的求平均值dw=dw/m
在這裏插入圖片描述

上面的圖詳細說明了第二個for循環被替換過程。
在下一節,我們將進一步的講解邏輯迴歸,你將會看到更好的監督學習結果。在訓練中將不需要使用任何 for 循環,你也可以寫出代碼去運行整個訓練集。

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