m 個樣本的梯度下降(Gradient Descent on m Examples)
在之前的筆記中,已經講述了如何計算導數,以及應用梯度下降在邏輯回歸的一個訓練樣本上。現在我們想要把它應用在m個訓練樣本上。
首先,讓我們時刻記住有關於損失函數就J(w,b) 的定義。
當你的算法輸出關於樣本y 的 a(i), a(i)是訓練樣本的預測值,即:
所以我們在前面展示的是對於任意單個訓練樣本,如何計算微分當你只有一個訓練樣本。
因此dw_1,dw_2和db 添上上標i表示你求得的相應的值。
如果你面對的是我們在之前演示的那種情況,但只使用了一個訓練樣本(x^(i),y^(i)) 。
現在你知道帶有求和的全局代價函數,實際上是1到m項各個損失的平均。
所以它表明全局代價函數對w1的微分,w1的微分也同樣是各項損失對w1微分的平均。
但之前我們已經演示了如何計算這項,即之前幻燈中演示的如何對單個訓練樣本進行計算。
所以你真正需要做的是計算這些微分,如我們在之前的訓練樣本上做的。並且求平均,這會給你全局梯度值,你能夠把它直接應用到梯度下降算法中。
所以這裡有很多細節,但讓我們把這些裝進一個具體的算法。同時你需要一起應用的就是邏輯回歸和梯度下降。
我們初始化 J=0,dw_1=0,dw_2=0,db=0
代碼流程:
J=0;dw1=0;dw2=0;db=0; for i = 1 to m: z(i) = wx(i)+b a(i) = sigmoid(z(i)) J += -[y(i)log(a(i))+(1-y(i))log(1-a(i)) dz(i) = a(i)-y(i) dw1 += x1(i)dz(i) dw2 += x2(i)dz(i) db += dz(i) J/= m dw1/= m dw2/= m db/= m w=w-alpha*dw b=b-alpha*db
筆記上只應用了一步梯度下降。因此你需要重複以上內容很多次,以應用多次梯度下降。看起來這些細節似乎很複雜,但目前不要擔心太多。
但這種計算中有兩個缺點,也就是說應用此方法在邏輯回歸上你需要編寫兩個for循環。
第一個for循環是一個小循環遍歷m個訓練樣本,
第二個for循環是一個遍歷所有特徵的for循環。
這個例子中我們只有2個特徵,所以n等於2並且n_x 等於2。 但如果你有更多特徵,你開始編寫你的因此dw_1,dw_2,你有相似的計算從dw_3一直下去到dw_n。所以看來你需要一個for循環遍歷所有n個特徵
當你應用深度學習算法,你會發現在代碼中顯式地使用for循環使你的算法很低效,同時在深度學習領域會有越來越大的數據集。所以能夠應用你的算法且沒有顯式的for循環會是重要的,並且會幫助你適用於更大的數據集。所以這裡有一些叫做向量化技術,它可以允許你的代碼擺脫這些顯式的for循環。
我想在先於深度學習的時代,也就是深度學習興起之前,向量化是很棒的。
可以使你有時候加速你的運算,但有時候也未必能夠。
但是在深度學習時代向量化,擺脫for循環已經變得相當重要。
因為我們越來越多地訓練非常大的數據集,因此你真的需要你的代碼變得非常高效。
所以在接下來的幾個筆記中,我們會談到向量化,以及如何應用向量化而連一個for循環都不使用。
所以學習了這些,我希望你有關於如何應用邏輯回歸,或是用於邏輯回歸的梯度下降,事情會變得更加清晰。
向量化(Vectorization)
向量化是非常基礎的去除代碼中for循環的藝術,在深度學習安全領域、深度學習實踐中,你會經常發現自己訓練大數據集,因為深度學習算法處理大數據集效果很棒,所以你的代碼運行速度非常重要,否則如果在大數據集上,你的代碼可能花費很長時間去運行,你將要等待非常長的時間去得到結果。所以在深度學習領域,運行向量化是一個關鍵的技巧,讓我們舉個慄子說明什麼是向量化。
在邏輯回歸中你需要去計算z=w^T x+b,w、x都是列向量。如果你有很多的特徵那麼就會有一個非常大的向量,所以w∈R^(n_x ) , x∈R^(n_x ),所以如果你想使用非向量化方法去計算w^T x,你需要用如下方式(python)
z=0for i in range(n_x)z+=w[i]*x[i]z+=b
這是一個非向量化的實現,你會發現這真的很慢,作為一個對比,向量化實現將會非常直接計算w^T x,代碼如下(其中使用了numpy函數,這個有點重要,需要記得哦!):
z=np.dot(w,x)+b
這是向量化計算w^T x的方法,你將會發現這個非常快
讓我們用一個小例子說明一下(以下為在Jupyter notebook上寫的Python代碼):
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(「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」)#列印for循環的版本的時間
返回值見圖。
在兩個方法中,向量化和非向量化計算了相同的值,如你所見,
向量化版本花費了1.5毫秒,非向量化版本的for循環花費了大約幾乎500毫秒,非向量化版本多花費了300倍時間。
所以在這個例子中,僅僅是向量化你的代碼,就會運行300倍快。這意味著如果向量化方法需要花費一分鐘去運行的數據,for循環將會花費5個小時去運行。
一句話總結,以上都是在說和for循環相比,向量化可以快速得到結果。
你可能聽過很多類似如下的話,「大規模的深度學習使用了GPU或者圖像處理單元實現」,但是以上做的案例都是在jupyter notebook上面實現,這裡只有CPU,CPU和GPU都有並行化的指令,他們有時候會叫做SIMD指令,這個代表了一個單獨指令多維數據,這個的基礎意義是,如果你使用了built-in函數,像np.function或者並不要求你實現循環的函數,它可以讓python的充分利用並行化計算,這是事實在GPU和CPU上面計算,GPU更加擅長SIMD計算,但是CPU事實上也不是太差,可能沒有GPU那麼擅長吧。
接下來的筆記中,你將看到向量化怎麼能夠加速你的代碼,經驗法則是,無論什麼時候,避免使用明確的for循環。