對比普通實作方法與使用Numpy科學計算子產品實作的差别,展現使用Numpy的優勢在哪裡。
-
- 1、Sigmoid函數,np.exp()
- 2、Sigmoid 梯度
- 3、重塑矩陣(Reshaping arrays)
- 4、規範化
- 5、廣播(broadcasting)和Softmax函數
- 6、矢量化(向量化)
- 7、L1 和 L2 損失函數
1、Sigmoid函數,np.exp()
np.exp():e的多少次幂,即 ex e x
我們分别使用 math.exp()、np.exp() 來實作 sigmoid中的指數函數的建構。
 Sigmoid函數公式為: Sigmoid=11+e−x S i g m o i d = 1 1 + e − x
首先使用普通的數學方式來實作:
import math
def basic_sigmoid(x):
'''
計算輸入為 x 的sigmoid函數
Arguments: x: 實數
Return:s--sigmoid(x)
'''
s = / ( + math.exp(-x))
return s
但是事實上,深度學習中很少用 ’math‘ 子產品,因為它的輸入必須是一個實數,而在深度學習中,輸入經常為矩陣或是向量。
import numpy as np
x = np.array([,,])
print(np.exp(x))
>> [ ]
結果是将輸入矩陣的每個元素都對應的做了 ex e x 運算。
x = np.array([,,])
print(x+)
輸出結果為矩陣的每一個元素都做相同的運算。
注:
這裡輸入的作為運算的矩陣必須是 np.array([ , , ]) 生成的, nimpy array,否則無法執行這些運算。
我們可以建構一個輸入為矩陣的 Sigmoid S i g m o i d 函數:
sigmoid(x)=sigmoid⎛⎝⎜x1x2x3⎞⎠⎟=⎛⎝⎜⎜⎜11+e−x111+e−x211+e−x3⎞⎠⎟⎟⎟,For x∈Rn s i g m o i d ( x ) = s i g m o i d ( x 1 x 2 x 3 ) = ( 1 1 + e − x 1 1 1 + e − x 2 1 1 + e − x 3 ) , F o r x ∈ R n
import numpy as np
def sigmoid(x):
s = / ( + np.exp(-x))
return s
x = np.array([,,])
sigmoid(x)
>> [ ]
對每一個輸入矩陣的元素做了 11+e−x 1 1 + e − x 運算,然後傳回了同樣形狀的矩陣。
2、Sigmoid 梯度
我們需要使用反向傳播來計算優化損失函數的梯度,梯度也就是導數。
首先我們對 Sigmiod S i g m i o d 函數求導:
Sigmoid′=11+e−x−1(1+e−x)2 S i g m o i d ′ = 1 1 + e − x − 1 ( 1 + e − x ) 2
令 Sigmoid S i g m o i d 函數表示為 σ(x) σ ( x ) 即梯度函數可以寫為:
sigmoid_derivative(x)=σ′(x)=σ(x)(1−σ(x)) s i g m o i d _ d e r i v a t i v e ( x ) = σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) )
簡化即計算:
σ′(x)=s(1−s) σ ′ ( x ) = s ( 1 − s )
def sigmoid_derivative(x):
s = sigmoid(x)
ds = s * ( - s)
return ds
x = np.array([,,])
print('Sigmoid_derivative')
>> [ ]
同樣是對每個元素應用了 Sigmoid 求導公式。
3、重塑矩陣(Reshaping arrays)
X.shape():可以得到矩陣 / 向量 X 的形狀
X.reshape():用于将 X 改變成其他的形狀
例如,在科學計算的時候,輸入一張圖檔是一個3D形狀的矩陣 (length,height,depth=3) ( l e n g t h , h e i g h t , d e p t h = 3 ) ,然而,當把這張圖檔作為一個算法的輸入的時候,要将它轉換為一個向量的形狀 (length∗height∗3,1) ( l e n g t h ∗ h e i g h t ∗ 3 , 1 ) ,即将3D矩陣轉換為了1D的向量。
def image2vector(image):
v = image.reshape(image.shape[] * image.shape[] * image.shape[], )
return v
# 這是3*3*2的矩陣,典型的圖檔其實應該是(x * y * 3)的,因為對應RGB三層
image = np.array([[[ , ],
[ , ],
[ , ]],
[[ , ],
[ , ],
[ , ]],
[[ , ],
[ , ],
[ , ]]])
>> image2vector(image) = [[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]
[ ]]
reshape 3*3*2 轉化為了 (3*3*2)*1 即 18*1 維的矩陣。
shape:
image 尺寸為 3×3×2 3 × 3 × 2
則:
image.shape[0]=3image.shape[1]=3image.shape[2]=2 i m a g e . s h a p e [ 0 ] = 3 i m a g e . s h a p e [ 1 ] = 3 i m a g e . s h a p e [ 2 ] = 2
4、規範化
深度學習中另一個常用的技術是規範化資料,規範化後由于梯度下降收斂的更加迅速,是以往往能得到更好的性能。規範化即将輸入 x 的每一行的元素改變為 x||x|| x | | x | |
例如:
x=[023644] x = [ 0 3 4 2 6 4 ]
接下來:
||x||=np.linalg.norm(x,axis=1,keepdims=True)=[556−−√] | | x | | = n p . l i n a l g . n o r m ( x , a x i s = 1 , k e e p d i m s = T r u e ) = [ 5 56 ]
是以:
x_normalized=x||x||=[0256√35656√45456√] x _ n o r m a l i z e d = x | | x | | = [ 0 3 5 4 5 2 56 6 56 4 56 ]
即:
将 x 的每一行元素都除以 ||x|| | | x | | 對應行的元素。
規範化後,輸入矩陣 x 的每一行會變為一個機關長度的向量(即長度為1)
def normalizeRows(x):
x_norm = np.linalg.norm(x, axis = , keepdims = True)
x = x / norm
return x
Input:
x = np.array([
[, , ],
[, , ]])
Output:
[[ ]
[ ]]
注意:
在這個過程中,如果輸出 x_norm 的形狀以及 x 的形狀,你會發現他們的形狀并不相同。
x_norm 有同樣的行數,但隻有一列
是以,當使用 x_norm 分割 x 的時候是如何進行的呢?這就是 Numpy 中的廣播(broadcasting)。
5、廣播(broadcasting)和Softmax函數
廣播是 Numpy 中一個概念,它在執行不同形狀之間矩陣的數學運算時非常的有用。
例如:
使用 Numpy 實作一個 Softmax 函數,當你的算法需要二分類或者分更多的類的時候,你可以将 softmax 函數作為一個規範化函數使用。
- 對于 x∈R1×n 對 于 x ∈ R 1 × n
softmax(x)=softmax([x1 x2 ⋅⋅⋅ xn])=[ex1∑jexj ex2∑jexj ⋅⋅⋅ exn∑jexj] s o f t m a x ( x ) = s o f t m a x ( [ x 1 x 2 · · · x n ] ) = [ e x 1 ∑ j e x j e x 2 ∑ j e x j · · · e x n ∑ j e x j ]
-
對于矩陣 x∈Rm×n, xij 映射到輸入x的第 i 行和第 j 列,即: 對 于 矩 陣 x ∈ R m × n , x i j 映 射 到 輸 入 x 的 第 i 行 和 第 j 列 , 即 :
softmax(x)=softmax⎡⎣⎢⎢⎢⎢⎢x11x21⋮xm1x12x22⋮xm2x13x23⋮xm3⋯⋯⋱⋯x1nx2n⋮xmn⎤⎦⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢ex11∑jex1jex21∑jex2j⋮exm1∑jexmjex12∑jex1jex22∑jex2j⋮exm2∑jexmjex13∑jex1jex23∑jex2j⋮exm3∑jexmj⋯⋯⋱⋯ex1n∑jex1jex2n∑jex2j⋮exmn∑jexmj⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥ s o f t m a x ( x ) = s o f t m a x [ x 11 x 12 x 13 ⋯ x 1 n x 21 x 22 x 23 ⋯ x 2 n ⋮ ⋮ ⋮ ⋱ ⋮ x m 1 x m 2 x m 3 ⋯ x m n ] = [ e x 11 ∑ j e x 1 j e x 12 ∑ j e x 1 j e x 13 ∑ j e x 1 j ⋯ e x 1 n ∑ j e x 1 j e x 21 ∑ j e x 2 j e x 22 ∑ j e x 2 j e x 23 ∑ j e x 2 j ⋯ e x 2 n ∑ j e x 2 j ⋮ ⋮ ⋮ ⋱ ⋮ e x m 1 ∑ j e x m j e x m 2 ∑ j e x m j e x m 3 ∑ j e x m j ⋯ e x m n ∑ j e x m j ]
即輸入 x 矩陣的每個元素除以該行元素所有的和( 新的 x11=x11x11+x12+⋯+x1n 新 的 x 11 = x 11 x 11 + x 12 + ⋯ + x 1 n )
def sotfmax(x):
x_exp = np.exp(x)
x_sum = np.sum(x_exp, axis = , keepdims = True)
s = x_exp / x_sum
return s
np.sum⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪axiskeepdims=None=1=True否則對所有元素求和對每一行求和保留原格式,同等維數降維 n p . s u m { a x i s = N o n e 對所有元素求和 = 1 對每一行求和 k e e p d i m s = T r u e 保留原格式,同等維數 否 則 降維
np.exp() 對任意 np.array 數組 x 的每個位置的元素應用了指數函數。
6、矢量化(向量化)
在深度學習處理大量資料的時候,非計算上最優的函數會成為你的算法中的一個巨大的瓶頸,并導緻模型的運作花費巨大的時間。為了確定你的代碼計算的效率,我們需要使用矢量化;
下面,将對 向量點積(dot)、外積(outer)、元素逐個相乘(elementwise)以及矩陣點積(gdot)分别用經典方法和 Numpy 來實作。
首先,令:
x1=[9,2,5,0,0,7,5,0,0,0,9,2,5,0,0]x2=[9,2,2,9,0,9,2,5,0,0,9,2,5,0,0] x 1 = [ 9 , 2 , 5 , 0 , 0 , 7 , 5 , 0 , 0 , 0 , 9 , 2 , 5 , 0 , 0 ] x 2 = [ 9 , 2 , 2 , 9 , 0 , 9 , 2 , 5 , 0 , 0 , 9 , 2 , 5 , 0 , 0 ]
time.process_time()用來計時,tic 記下程式運作前時刻計數值,toc 記下程式運作結束後時刻的計數值,相減 ×1000 × 1000 即為 ms。
- 向量點積:
# 經典方法實作
tic = time.process_time()
dot =
for i in range(len(x1)):
dot += x1[i] * x2[i]
toc = time.process_time() # tic toc用來計時
print(dot)
# Numpy方法實作
dot = np.dot(x1, x2)
- 外積:
# 經典方法實作
outer = np.zeros(len(x1), len(x2)) #建立一個(15×15)的全0矩陣
for i in range(len(x1)):
for j in range(len(x2)):
outer[i, j] = x1[i] * x2[j]
# Numpy方法實作
outer = np.outer(x1, x2)
生成一個 len(x1)*len(x2) 的矩陣。
- 逐個元素相乘:
# 經典方法實作
mul = np.zeros(len(x1))
for i in range(len(x1)):
mul[i] = x1[i] * x2[j]
# Numpy方法實作
mul = np.multiply(x1, x2)
生成的仍為同型矩陣,每位的元素為x1, x2相應位元素的乘積。
- 矩陣點積:
# 經典方法實作
W = np.random.rand(,len(x1))
gdot = np.zeros(W.shape[]) # 即3個[···],[···],[···]一維矩陣,每個矩陣内有15個元素
for i in range(W.shape[]):
for j in range(len(x1)):
gdot[i] += W[i,j] * x1[j]
# Numpy方法實作
gdot = np.dot(W, x1)
先随機生成一個 3×len(x1) 3 × l e n ( x 1 ) 即 (3×15) ( 3 × 15 ) 的 Numpy 矩陣 W
然後周遊這三個矩陣
再周遊每個矩陣内的元素
每個矩陣内的每個元素和x1相應位置的元素做乘法,再加和。
最後得到 [x x x] 這樣 3×1 的矩陣
注意:
np.dot() 是矩陣-矩陣或矩陣-向量 相乘(帶求和)
np.multiply() 是元素間的相乘
7、L1 和 L2 損失函數
定義損失來評估模型的性能。預測值 y^ y ^ 和真實值 y y 之間的內插補點即為損失值。
在深度學習中,使用類似梯度下降優化算法來最小化損失值。
L1損失函數:
L1(y^,y)=∑i=0m|y(i)−y^(i)|L1(y^,y)=∑i=0m|y(i)−y^(i)|
定義 L1 損失函數:
def L1(yhat, y):
loss = np.sum(np.abs(y - yhat))
return loss
yhat = np.array([, , , , ])
y = np.array([, , , , ])
L1 = L1(yhat, y)
>> L1 =
定義 L2 損失函數:
L2(y^,y)=∑i=0m(y(i)−y^(i))2 L 2 ( y ^ , y ) = ∑ i = 0 m ( y ( i ) − y ^ ( i ) ) 2
def L2(yhat, y):
loss = np.dot((y - yhat), (y - yhat))
return loss
L1:內插補點的絕對值之和;
L2:內插補點的平方之和;
注:
1. (y - yhat).T :即轉置,如果矩陣維數為1,則傳回自身;
2. 如果 x=[x1,x2,…,xn] x = [ x 1 , x 2 , … , x n ] ,那麼
np.dot(x,x)=∑j=0nx2j n p . d o t ( x , x ) = ∑ j = 0 n x j 2