深度學習線性代數簡明教程

深度學習線性代數簡明教程

來自專欄論智28 人贊了文章

作者:Vihar Kurama

編譯:weakish

深度學習(Deep Learning)是機器學習的子領域。而線性代數(linear algebra)是有關連續值的數學。許多計算機科學家在此方面經驗不足(傳統上計算機科學更偏重離散數學)。想要理解和使用許多機器學習演算法,特別是深度學習演算法,對線性代數的良好理解是不可或缺的。

為什麼要學數學?

線性代數、概率論和微積分是確切地表達機器學習的「語言」。學習這些主題有助於形成對機器學習演算法底層機制的深入理解,也有助於開發新的演算法。

如果我們查看的尺度足夠小,那麼深度學習背後的一切都是數學。所以在開始深度學習之前,有必要理解基本的線性代數。

標量、向量、矩陣、張量;圖片來源:hadrienj.github.io

深度學習背後的核心數據結構是標量(Scalar)向量(Vector)矩陣(Matrix)張量(Tensor)。讓我們通過編程,使用這些數據結構求解基本的線性代數問題。

標量

標量是單個數字,或者說,0階(0th-order)張量。x ∈ ?表示x是一個屬於實數集?的標量。

在深度學習中,有不同的數字集合。?表示正整數集(1,2,3,…)。?表示整數集,包括正數、負數和零。?表示有理數集(可以表達為兩個整數之比的數)。

在Python中有幾個內置的標量類型:intfloatcomplexbytesUnicode。Numpy又增加了二十多個新的標量類型。

import numpy as npnp.ScalarType

返回:

(int, float, complex, int, bool, bytes, str, memoryview, numpy.bool_, numpy.int8, numpy.uint8, numpy.int16, numpy.uint16, numpy.int32, numpy.uint32, numpy.int64, numpy.uint64, numpy.int64, numpy.uint64, numpy.float16, numpy.float32, numpy.float64, numpy.float128, numpy.complex64, numpy.complex128, numpy.complex256, numpy.object_, numpy.bytes_, numpy.str_, numpy.void, numpy.datetime64, numpy.timedelta64)

其中,以下劃線(_)結尾的數據類型和對應的Python內置類型基本上是等價的。

在Python中定義標量和一些運算

下面的代碼演示了一些張量的算術運算。

a = 5b = 7.5print(type(a))print(type(b))print(a + b)print(a - b)print(a * b)print(a / b)

輸出:

<class int><class float>12.5-2.537.50.6666666666666666

下面的代碼段檢查給定的變數是否是標量:

import numpy as npdef isscalar(num): if isinstance(num, generic): return True else: return Falseprint(np.isscalar(3.1))print(np.isscalar([3.1]))print(np.isscalar(False))

輸出:

TrueFalseTrue

向量

向量是由單個數字組成的有序數組,或者說,1階張量。向量是向量空間這一對象的組成部分。向量空間是特定長度(又叫維度)的所有可能的向量的整個集合。三維實數向量空間(?3)常用於表示現實世界中的三維空間。

為了指明向量的分量(component),向量的第i個標量元素記為x[i]

在深度學習中,向量通常用來表示特徵向量。

在Python中定義向量和一些運算

聲明向量:

x = [1, 2, 3]y = [4, 5, 6]print(type(x))

輸出:

<class list>

+並不表示向量的加法,而是列表的連接:

print(x + y)

輸出:

[1, 2, 3, 4, 5, 6]

需要使用Numpy進行向量加法:

z = np.add(x, y)print(z)print(type(z))

輸出:

[5 7 9]<class numpy.ndarray>

向量的叉積(cross product)

兩個向量的叉積向量,大小等於以這兩個向量為鄰邊的平行四邊形面積,方向與這兩個向量所在平面垂直:

圖片來源:維基百科

np.cross(x, y)

返回:

[-3 6 -3]

向量的點積(dot product)

向量的點積為標量,對於給定長度但方向不同的兩個向量而言,方向差異越大,點積越小。

圖片來源:betterexplained.com

np.dot(x, y)

返回:

32

矩陣

矩陣是由數字組成的矩形數組,或者說,2階張量。如果m和n為正整數,即,m, n ∈ ?,那麼,一個m x n矩陣包含m * n個數字,m行n列。

m x n可表示為以下形式:

有時簡寫為:

在Python中定義矩陣和一些運算

在Python中,我們使用numpy庫創建n維數組,也就是矩陣。我們將列表傳入matrix方法,以定義矩陣。

x = np.matrix([[1,2],[3,4]])x

返回:

matrix([[1, 2], [3, 4]])

矩陣第0軸的元素均值:

x.mean(0)

返回:

matrix([[2., 3.]]) # (1+3)/2, (3+4)/2

矩陣第1軸的元素均值:

x.mean(1)

返回:

z = x.mean(1)z

返回:

matrix([[1.5], # (1+2)/2 [3.5]]) # (3+4)/2

shape屬性返回矩陣的形狀:

z.shape

返回:

(2, 1)

所以,矩陣z有2行1列。

順便提下,向量的shape屬性返回由單個數字(向量的長度)組成的元組:

np.shape([1, 2, 3])

返回:

(3,)

而標量的shape屬性返回一個空元祖:

np.shape(1)

返回:

()

矩陣加法和乘法

矩陣可以和標量及其他矩陣相加、相乘。這些運算在數學上都有精確的定義。機器學習和深度學習經常使用這些運算,所以有必要熟悉這些運算。

對矩陣求和:

x = np.matrix([[1, 2], [4, 3]])x.sum()

返回:

10

矩陣-標量加法

在矩陣的每個元素上加上給定標量:

x = np.matrix([[1, 2], [4, 3]])x + 1

返回:

matrix([[2, 3], [5, 4]])

矩陣-標量乘法

類似地,矩陣-標量乘法就是在矩陣的每個元素上乘以給定標量:

x * 3

返回:

matrix([[ 3, 6], [12, 9]])

矩陣-矩陣加法

形狀相同的矩陣才能相加。兩個矩陣對應位置的元素之和作為新矩陣的元素,而新矩陣的形狀和原本兩個矩陣一樣。

x = np.matrix([[1, 2], [4, 3]])y = np.matrix([[3, 4], [3, 10]])

x和y的形狀均為(2, 2)

x + y

返回:

matrix([[ 4, 6], [ 7, 13]])

矩陣-矩陣乘法

形狀為m x n的矩陣與形狀為n x p的矩陣相乘,得到形狀為m x p的矩陣。

圖片來源:hadrienj.github.io

從編程的角度,矩陣乘法的一個直觀解釋是,一個矩陣是數據,另一個矩陣是即將應用於數據的函數(操作):

圖片來源:betterexplained.com

x = np.matrix([[1, 2], [3, 4], [5, 6]])y = np.matrix([[7], [13]]x * y

返回:

matrix([[ 33], [ 73], [113]])

上面的代碼中,矩陣x的形狀為(3, 2),矩陣y的形狀為(2, 1),故所得矩陣的形狀為(3, 1)。如果x的列數不等於y的行數,則x和y不能相乘,強行相乘會報錯shapes not aligned

矩陣轉置

矩陣轉置交換原矩陣的行和列(行變為列,列變為行),即:

x = np.matrix([[1, 2], [3, 4], [5, 6]])x

返回:

matrix([[1, 2], [3, 4], [5, 6]])

使用numpy提供的transpose()方法轉置矩陣:

x.transpose()

返回:

matrix([[1, 3, 5], [2, 4, 6]])

張量

比標量、向量、矩陣更通用的是張量概念。在物理科學和機器學習中,有時有必要使用超過二階的張量(還記得嗎?標量、向量、矩陣分別可以視為0、1、2階張量。)

圖片來源:refactored.ai

在Python中定義張量和一些運算

張量當然也可以用numpy表示(超過二階的張量不過是超過二維的數組):

import numpy as npt = np.array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ])t.shape

返回:

(3, 3, 3)

張量加法

s = np.array([ [[1,2,3], [4,5,6], [7,8,9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]],])s + t

返回:

array([[[ 2, 4, 6], [ 8, 10, 12], [14, 16, 18]], [[21, 23, 25], [27, 29, 31], [33, 35, 37]], [[40, 42, 44], [46, 48, 50], [52, 54, 56]]])

張量乘法

s * t得到的是阿達馬乘積(Hadamard Product),也就是分素相乘(element-wise multiplication),將張量s和t中的每個元素相乘,所得乘積為結果張量對應位置的元素。

s * t

返回:

array([[[ 1, 4, 9], [ 16, 25, 36], [ 49, 64, 81]], [[110, 132, 156], [182, 210, 240], [272, 306, 342]], [[399, 440, 483], [528, 575, 624], [675, 728, 783]]])

張量積(Tensor Product)需要使用numpy的tensordot方法計算。

圖片來源:維基百科

計算s ? t:

s = np.array([[[1, 2], [3, 4]]])t = np.array([[[5, 6], [7, 8]]])np.tensordot(s, t, 0)

返回:

array([[[[[[ 5, 6], [ 7, 8]]], [[[10, 12], [14, 16]]]], [[[[15, 18], [21, 24]]], [[[20, 24], [28, 32]]]]]])

其中,最後一個參數0表示求張量積。當該參數為1時,表示求張量的點積(tensor dot product),這一運算可以視為向量點積概念的推廣;當該參數為2時,表示求張量的縮並(tensor double contraction),這一運算可以視為矩陣乘法概念的推廣。

當然,由於張量常用於深度學習,因此我們也經常直接使用深度學習框架表達張量。比如,在PyTorch中,創建一個形狀為(5, 5)的張量,然後用浮點數1填充該張量:

torch.ones(5, 5)

返回:

tensor([[ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.]]

推薦閱讀:

EdX-Columbia機器學習課第7講筆記:kNN與貝葉斯分類器
機器學習(入門):如何用邏輯回歸分類
計算機視覺領域的一些牛人博客,超有實力的研究機構等的網站鏈接
第一屆Deep Learning for Visual SLAM Workshop觀感: 後四講
觀點:傳統機器學習尚處於因果層級底層,達成完備AI的7個工具

TAG:深度學習DeepLearning | 機器學習 | 線性代數 |