Week2:神經網路的程式設計基礎(Basics of Neural Network programming)
Pre:本章基本字母含義
2.1 Binary Classification(二分法)
邏輯迴歸模型一般用來解決二分類(Binary Classification)問題。
- 二分類就是輸出y只有{0,1}兩個離散值(也有{-1,1}的情況)。
- 以一個影象識別問題爲例,判斷圖片中是否有貓存在,0代表no cat,1代表cat。
- 彩色圖片包含RGB三個通道。例如該cat圖片的尺寸爲(64,64,3)。在神經網路模型中,我們首先要將圖片輸入x(維度是(64,64,3))轉化爲一維的特徵向量(feature vector)。方法是每個通道一行一行取,再連線起來。由於64x64x3=12288,則轉化後的輸入特徵向量維度爲(12288,1)。此特徵向量x是列向量,維度一般記爲nx。
- 如果訓練樣本共有m張圖片,那麼整個訓練樣本X組成了矩陣,維度是(nx,m)。注意,這裏矩陣X的行nx代表了每個樣本x(i)特徵個數,列m代表了樣本個數。
- Python實現的時候,你會看到
X.shape
,這是一條Python命令,用於顯示矩陣的規模,即X.shape
等於(nx,m)
2.2 Logistic Regression(邏輯迴歸)
2.3 Logistic Regression Cost Function(邏輯迴歸的損失函數)
參照吳恩達《機器學習》Week3的邏輯迴歸和代價/損失函數。
2.4 Gradient Descent(邏輯迴歸的梯度下降法)
- 問題提出
對單個數據(x,y)邏輯迴歸的損失函數是:L(y^,y)=−ylog(y^)−(1−y)log(1−y^),m個樣本的損失函數是:
J(w,b)=m1i=1∑mL(y^(i),y(i))=m1i=1∑m(−y(i)logy^(i)−(1−y(i))log(1−y^(i)))
所以在訓練邏輯迴歸模型時候,我們需要找到合適的w和b,來讓代價函數 J 的總代價降到最低。其中:y^=σ(wTx+b),σ(z)=1+e−z1
- 梯度下降法
- 由於J(w,b)是convex function,梯度下降演算法是先隨機選擇一組參數w和b值,然後每次迭代的過程中分別沿着w和b的梯度(偏導數)的反方向前進一小步,不斷修正w和b。每次迭代更新w和b後,都能讓J(w,b)更接近全域性最小值。梯度下降的過程如下圖所示:
- 梯度下降演算法每次迭代更新,w和b的修正表達式爲:
w:=w−α∂w∂J(w,b)
b:=b−α∂b∂J(w,b)
- 上式中,α是學習因子(learning rate),表示梯度下降的步進長度。
- α越大,w和b每次更新的「步伐」更大一些;
- α越小,w和b每次更新的「步伐」更小一些。
- 在程式程式碼中,我們通常使用dw來表示∂w∂J(w,b),用db來表示∂b∂J(w,b)。
微積分裡,dxdf表示對單一變數求導數,∂x∂f表示對多個變數中某個變數求偏導數。
2.5 Derivatives(求導)
2.6 More Derivative Examples
這兩節是求導和求導的例子。
2.7 Computation graph(計算圖)
整個神經網路的訓練過程實際上包含了兩個過程:正向傳播(Forward Propagation) 和 反向傳播(Back Propagation)。
- 正向傳播是從輸入到輸出,由神經網路計算得到預測輸出的過程;
- 反向傳播是從輸出到輸入,對參數w和b計算梯度的過程。
- 用計算圖(Computation graph)的形式來理解這兩個過程。舉個簡單的例子,假如Cost function爲J(a,b,c)=3(a+bc),包含a,b,c三個變數。我們用u表示bc,v表示a+u,則J=3v。它的計算圖可以寫成如下圖所示:
- 令a=5,b=3,c=2,則 u=bc=6,v=a+u=11,J=3v=33。計算圖中,這種從左到右,從輸入到輸出的過程就對應着神經網路或者邏輯迴歸中輸入與權重經過運算計算得到Cost function的正向過程。
2.8 Derivatives with a Computation Graph(計算圖的求導)
上一節介紹了計算圖的正向傳播(Forward Propagation),下面 下麪來介紹計算圖的反向傳播(Back Propagation),即計算輸出對輸入的偏導數。
還是上個計算圖的例子,輸入參數有3個,分別是a,b,c。
- 首先計算J對參數a的偏導數。從計算圖上來看,從右到左,J是v的函數,v是a的函數。則利用求導技巧,可以得到:
∂a∂J=∂v∂J⋅∂a∂v=3⋅1=3
- 根據這種思想,然後計算J對參數b的偏導數。從計算圖上來看,從右到左,J是v的函數,v是u的函數,u是b的函數。可以推導:
∂b∂J=∂v∂J⋅∂u∂v⋅∂b∂u=3⋅1⋅c=3⋅1⋅2=6
- 最後計算J對參數c的偏導數。仍從計算圖上來看,從右到左,J是v的函數,v是u的函數,u是c的函數。可以推導:
∂c∂J=∂v∂J⋅∂u∂v⋅∂c∂u=3⋅1⋅b=3⋅1⋅3=9
2.9 Logistic Regression Gradient Descent(邏輯迴歸的梯度下降法)
將對邏輯迴歸進行梯度計算。對單個樣本而言,邏輯迴歸Loss function表達式如下:
z=wTx+by^=a=σ(z)L(a,y)=−(ylog(a)+(1−y)log(1−a))
-
首先是正向傳播過程。根據上述公式,例如輸入樣本x有兩個特徵(x1,x2),相應的權重w維度也是2,即(w1,w2)。則z=w1x1+w2x2+b,Loss function的計算圖如上圖。
-
然後,計算該邏輯迴歸的反向傳播過程,即由Loss function計算參數w和b的偏導數。推導過程如下:
da=∂a∂L=−ay+1−a1−ydz=∂z∂L=∂a∂L⋅∂z∂a=(−ay+1−a1−y)⋅a(1−a)=a−y
知道了dz之後,就可以直接對w_1,w_2和b進行求導了。
dw1=∂w1∂L=∂z∂L⋅∂w1∂z=x1⋅dz=x1(a−y)dw2=∂w2∂L=∂z∂L⋅∂w2∂z=x2⋅dz=x2(a−y)db=∂b∂L=∂z∂L⋅∂b∂z=1⋅dz=a−y
則梯度下降演算法可表示爲:
w1:=w1−α dw1w2:=w2−α dw2b:=b−α db
2.10 Gradient descent on m examples(m個樣本的梯度下降法)
在之前的視訊中,你已經看到如何計算導數,以及應用梯度下降在邏輯迴歸的一個訓練樣本上。現在我們想要把它應用在m個訓練樣本上。m個樣本,其Cost function表達式如下:
z(i)=wTx(i)+by^(i)=a(i)=σ(z(i))J(w,b)=m1∑i=1mL(y^(i),y(i))=−m1∑i=1m[y(i)log y^(i)+(1−y(i))log (1−y^(i))]
2.11 向量化(Vectorization)
向量化是非常基礎的去除程式碼中for回圈的藝術,在深度學習安全領域、深度學習實踐中,你會經常發現自己訓練大數據集,因爲深度學習演算法處理大數據集效果很棒,所以你的程式碼執行速度非常重要。
- 以python爲例子,向量化來加速運算(np.function),遍歷m遍的for回圈可以寫成:
z=np.dot(w, x) + b
import numpy as np
a = np.array([1,2,3,4])
print(a)
import time
a = np.random.rand(1000000)
b = np.random.rand(1000000)
tic = time.time()
c = np.dot(a,b)
toc = time.time()
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
Python安裝Jupyter Notebook設定使用教學
- 爲了加快深度學習神經網路運算速度,可以使用比CPU運算能力更強大的GPU。事實上,GPU和CPU都有並行指令(parallelization instructions),稱爲Single Instruction Multiple Data(SIMD)。SIMD是單指令多數據流,能夠複製多個運算元,並把它們打包在大型暫存器的一組指令集。SIMD能夠大大提高程式執行速度。
- python的numpy庫中的內建函數(built-in function)就是使用了SIMD指令。
- 相比而言,GPU的SIMD要比CPU更強大一些。
2.12 向量化的更多例子(More Examples of Vectorization)
- 在python的numpy庫中,我們通常使用np.dot()函數來進行矩陣運算。當你想寫回圈時候,檢查numpy是否存在類似的內建函數,從而避免使用回圈(loop)方式。
- numpy庫有很多向量函數。比如
u=np.log
是計算對數函數(log)、 np.abs()
計算數據的絕對值、np.maximum(v, 0)
按元素計算v中每個元素和和0相比的最大值,v**2
代表獲得元素 v 每個值的平方、 1/v
獲取 v 中每個元素的倒數等等。
2.13 向量化邏輯迴歸(Vectorizing Logistic Regression)
- 常規回圈
首先我們回顧一下邏輯迴歸的前向傳播步驟。如果有 m 個訓練樣本,然後對第一個樣本進行預測,你需要這樣計算。
- 計算 z,我正在使用這個熟悉的公式 z(1)=wTx(1)+b 。然後計算啓用函數 a(1)=σ(z(1)) ,計算第一個樣本的預測值 y 。
- 然後對第二個樣本進行預測,你需要計算 z(2)=wTx(2)+b , a(2)=σ(z(2)) 。
- 然後對第三個樣本進行預測,你需要計算 z(3)=wTx(3)+b , a(3)=σ(z(3)) ,依次類推。
- 如果你有 m 個訓練樣本,你可能需要這樣做 m 次。
- 向量表示
- 定義了一個矩陣 X 作爲訓練輸入,每個x樣本是nx,將不同的列中堆積在一起。這是一個 nx 行 m 列的矩陣。我現在將它寫爲Python numpy的形式 (nx,m) ,這只是表示 X 是一個 nx 乘以 m 的矩陣 Rnx×m。
- z(1), z(2) ……一直到 z(m) ,所有值都是在同一時間內完成。
[z(1)z(2)...z(m)]=wTX+[b,b...b]
[b,b...b] 是一個 1×m 的向量或者 1×m 的矩陣或者是一個 m 維的行向量。所以希望你熟悉矩陣乘法,你會發現的 w 轉置乘以 x(1) , x(2) 一直到 x(m) 。繼續簡化可以寫成:
Z=[z(1)z(2)...z(m)]=wTX+[b,b...b]=[wTx(1)+b,wTx(2)+b...wTx(m)+b]
其中大寫的 Z表示爲 [z(1)z(2)...z(m)] ,wTx(1)+b 這是第一個元素,wTx(2)+b 這是第二個元素, wTx(m)+b 這是第 m 個元素。
- Python表示
- numpy命令是
Z=np.dot(w.T,X)+b
;最後再進行sigmoid函數,一次性表示出A=[a(1),a(2)...a(m)]。
- 這裏在Python中有一個巧妙的地方,這裏 b 是一個實數,或者你可以說是一個 1×1 矩陣。但是當你將這個向量加上這個實數時,Python自動把這個實數 b 擴充套件成一個 1×m 的行向量。在Python中被稱作廣播(brosdcasting),後邊會具體介紹。
2.14 向量化 logistic 迴歸的梯度輸出(Vectorizing Logistic Regression’s Gradient)
注:本節中大寫字母代表向量,小寫字母代表元素
- 在本節2.10中,已經給出了邏輯迴歸中梯度下降法的一般表示形式:
dzj=aj−yjdwj=m1∑i=1mxj(i)(aj(i)−yj(i))db=m1∑i=1m(aj(i)−yj(i))
- 接下來看看邏輯迴歸中的梯度下降演算法如何轉化爲向量化的矩陣形式,對於所有m個樣本。
2.15 Python 中的廣播(Broadcasting in Python)
- numpy廣播機制 機製
- 定義:對於四則運算及其混合形式,如果兩個陣列的後緣維度的軸長度相符或其中一方的軸長度爲1,則認爲它們是廣播相容的。廣播會在缺失維度和軸長度爲1的維度上進行。 python中的廣播機制 機製可由下面 下麪四條表示:
- 對於Matlab/Octave 有類似功能的函數
bsxfun
。
- numpy中的axis
import numpy as np
A = np.array([[56.0, 0.0, 4.4, 68.0],
[1.2, 104.0, 52.0, 8.0],
[1.8, 135.0, 99.0, 0.9]])
print(A)
cal = A.sum(axis= 0)
print(cal)
A.sum(axis = 0)
中的參數axis
。axis用來指明將要進行的運算是沿着哪個軸執行,在numpy中,0軸是垂直的,也就是列,而1軸是水平的,也就是行。
2.16 關於 python _ numpy 向量的說明(A note on python or numpy vectors)
本講Python中的numpy一維陣列的特性,以及與行向量或列向量的區別。並介紹在實際應用中的一些小技巧,去避免在coding中由於這些特性而導致的bug。
- 秩1:
a = np.random.randn(5)
這條語句生成的a的維度是(5,)。它既不是行向量也不是列向量,我們把a叫做rank 1 array(秩1)。這種定義會帶來一些問題。例如我們對a進行轉置,還是會得到a本身。
- 定義向量:
2.17 Jupyter/iPython Notebooks快速入門(Quick tour of Jupyter/iPython Notebooks)
Python安裝Jupyter Notebook設定使用教學
2.18 (選修)logistic 損失函數的解釋(Explanation of logistic regression cost function)
我們介紹過邏輯迴歸的Cost function。接下來我們將簡要解釋這個Cost function是怎麼來的。
-
預測輸出y^的表達式可以寫成:
y^=σ(wTx+b)
其中,σ(z)=1+exp(−z)1。y^可以看成是預測輸出爲正類(+1)的概率:y^=P(y=1∣x)
- 當y=1時:p(y∣x)=y^
- 當y=0時:p(y∣x)=1−y^
-
把上面兩個式子整合到一個式子中,得到:
P(y∣x)=y^y(1−y^)(1−y)
由於log函數的單調性,可以對上式P(y∣x)進行log處理:
log P(y∣x)=log y^y(1−y^)(1−y)=y log y^+(1−y)log(1−y^)
上述概率P(y∣x)越大越好,對上式加上負號,則轉化成了單個樣本的Loss function,越小越好,也就得到了我們之前介紹的邏輯迴歸的Loss function形式。
L=−(y log y^+(1−y)log(1−y^))
-
如果對於所有m個訓練樣本,假設樣本之間是獨立同分佈的(iid),我們希望總的概率越大越好:
max i=1∏m P(y(i)∣x(i))
引入log函數,加上負號,將上式轉化爲Cost function:
J(w,b)=−m1i=1∑mL(y^(i),y(i))=−m1i=1∑my(i) log y^(i)+(1−y(i))log(1−y^(i))
上式中,m1表示對所有m個樣本的Cost function求平均,是縮放因子。
本章總結
本節主要介紹了神經網路基礎——python和向量化。使用向量化和矩陣運算的方法能夠大大提高執行速度,節省時間。以邏輯迴歸爲例,我們將其演算法流程包括梯度下降轉換爲向量化的形式。
-
左上:
logistic 迴歸主要用於二分類問題,如圖中所示,logistic 迴歸可以求解一張影象是不是貓的問題,其中影象是輸入(x),貓(1)或非貓(0)是輸出。我們可以將 logistic 迴歸看成將兩組數據點分離的問題,如果僅有線性迴歸(啓用函數爲線性),則對於非線性邊界的數據點(例如,一組數據點被另一組包圍)是無法有效分離的,因此在這裏需要用非線性啓用函數替換線性啓用函數。在這個案例中,我們使用的是 sigmoid 啓用函數,它是值域爲(0, 1)的平滑函數,可以使神經網路的輸出得到連續、歸一(概率值)的結果。
-
左下: 神經網路的訓練目標是確定最合適的權重 w 和偏置項 b,那這個過程是怎麼樣的呢?
這個分類其實就是一個優化問題,優化過程的目的是使預測值 y^ 和真實值 y 之間的差距最小,形式上可以通過尋找目標函數的最小值來實現。所以我們首先確定目標函數(損失函數、代價函數)的形式,然後用梯度下降逐步更新 w、b,當損失函數達到最小值或者足夠小時,我們就能獲得很好的預測結果。
-
右上:
損失函數值在參數曲面上變化的簡圖,使用梯度可以找到最快的下降路徑,學習率的大小可以決定收斂的速度和最終結果。學習率較大時,初期收斂很快,不易停留在區域性極小值,但後期難以收斂到穩定的值;學習率較小時,情況剛好相反。一般而言,我們希望訓練初期學習率較大,後期學習率較小,之後會介紹變化學習率的訓練方法。
-
右下: 總結整個訓練過程,從輸入節點 x開始,通過前向傳播得到預測輸出 y^,用 y^ 和y得到損失函數值,開始執行反向傳播,更新w和b,重複迭代該過程,直到收斂。