pytorch 深度學習之線性代數
標量
包含一個數值的叫標量(scalar)。標量由只有一個元素的張量表示:
import torch
x = torch.tensor(3.0)
y = torch.tensor(2.0)
x + y,x * y,x / y,x ** y
(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))
向量
將向量視為標量值組成的列表。 我們將這些標量值稱為向量的元素(element)或分量(component)。通過一維張量處理向量。一般來說,張量可以具有任意長度,取決於機器的記憶體限制,可以使用下標來引用向量的任一元素。
\[\mathbf{A}=\left[\begin{array}{c}\mathbf{a}_{1}^{\top} \\ \mathbf{a}_{2}^{\top} \\ \vdots \\ \mathbf{a}_{m}^{\top}\end{array}\right] \]x = torch.arange(4) x,x[3]
(tensor([0, 1, 2, 3]), tensor(3))
長度,維度和形狀
向量的長度通常稱為向量的維度,可以通過呼叫 Python 的內建 len()函式來訪問張量的長度。當用張量表示一個向量(只有一個軸)時,我們也可以通過.shape屬性訪問向量的長度。 形狀(shape)是一個元素組,列出了張量沿每個軸的長度(維數)。 對於只有一個軸的張量,形狀只有一個元素:
len(x),x.shape
(4, torch.Size([4]))
矩陣
正如向量將標量從零階推廣到一階,矩陣將向量從一階推廣到二階。
\[\mathbf{A}=\left[\begin{array}{cccc}a_{11} & a_{12} & \cdots & a_{1 n} \\ a_{21} & a_{22} & \cdots & a_{2 n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m 1} & a_{m 2} & \cdots & a_{m n}\end{array}\right] \]A = torch.arange(20).reshape(5, 4) A,A[-1],A[2][3]
(tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]]),
tensor([16, 17, 18, 19]),
tensor(11))
當我們交換矩陣的行和列時,結果稱為矩陣的轉置(transpose):
A.T
tensor([[ 0, 4, 8, 12, 16], [ 1, 5, 9, 13, 17], [ 2, 6, 10, 14, 18], [ 3, 7, 11, 15, 19]])
作為方陣的一種特殊型別,對稱矩陣(symmetric matrix)\(\mathbf{A}\) 等於其轉置:\(\mathbf{A}=\mathbf{A}^{\top}\),定義一個對稱矩陣:
B = torch.tensor([[1,2,3],[2,0,4],[3,4,5]])
B,B == B.T
(tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]]),
tensor([[True, True, True],
[True, True, True],
[True, True, True]]))
張量
就像向量是標量的推廣,矩陣是向量的推廣一樣,我們可以構建具有更多軸的資料結構。 張量為我們提供了描述具有任意數量軸的 n 維陣列的通用方法:
X = torch.arange(24).reshape(2,3,4)
X
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
張量演算法的基本性質
給定具有相同形狀的任意兩個張量,任何按元素二元運算的結果都將是相同形狀的張量:
A = torch.arange(20,dtype=torch.float32).reshape(5,4)
B = A.clone()
A,A + B
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
將張量乘以或加上一個標量不會改變張量的形狀,其中張量的每個元素都將與標量相加或相乘:
a = 2
X = torch.arange(24).reshape(2,3,4)
a + X,(a * X).shape
(tensor([[[ 2, 3, 4, 5],
[ 6, 7, 8, 9],
[10, 11, 12, 13]],
[[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]]),
torch.Size([2, 3, 4]))
降維
計算張量元素的和:
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
(tensor([0., 1., 2., 3.]), tensor(6.))
預設情況下,呼叫求和函式會沿所有的軸降低張量的維度,使它變為一個標量。 我們還可以指定張量沿哪一個軸來通過求和降低維度。 以矩陣為例,為了通過求和所有行的元素來降維(軸0),我們可以在呼叫函式時指定 axis=0。 由於輸入矩陣沿0軸降維以生成輸出向量,因此輸入軸0的維數在輸出形狀中消失:
A = torch.arange(20,dtype=torch.float32).reshape(5,4)
A_sum_axis0 = A.sum(axis=0)
A,A_sum_axis0,A_sum_axis0.shape
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([40., 45., 50., 55.]),
torch.Size([4]))
指定 axis=1 將通過彙總所有列的元素降維(軸1)。因此,輸入軸1的維數在輸出形狀中消失:
A = torch.arange(20,dtype=torch.float32).reshape(5,4)
A_sum_axis1 = A.sum(axis=1)
A,A_sum_axis1,A_sum_axis1.shape
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([ 6., 22., 38., 54., 70.]),
torch.Size([5]))
沿著行和列對矩陣求和,等價於對矩陣的所有元素進行求和:
A.sum(axis=[0, 1]) # A.sum()
tensor(190.)
呼叫 mean 函式可以求平均值:
A.mean(),A.sum()/A.numel(),A.mean(axis=0),A.sum(axis=0)/A.shape[0]
(tensor(9.5000),
tensor(9.5000),
tensor([ 8., 9., 10., 11.]),
tensor([ 8., 9., 10., 11.]))
有時在呼叫函式來計算總和或均值時保持軸數不變會很有用:
sum_A = A.sum(axis=1, keepdims=True)
sum_A,A/sum_A
(tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]]),
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]]))
點積
給定兩個向量:\(\mathbf{x}, \mathbf{y} \in \mathbb{R}^{d}\),它們的點積(dot product):\(\mathbf{x}^{\top} \mathbf{y}\),或者記為:\(\langle\mathbf{x}, \mathbf{y}\rangle\),相同位置的按元素乘積的和:\(\mathbf{x}^{\top} \mathbf{y}=\sum_{i=1}^{d} x_{i} y_{i}\):
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
矩陣-向量積
為矩陣 A 和向量 x 呼叫 torch.mv(A, x) 時,會執行矩陣-向量積。 注意,A 的列維數(沿軸1的長度)必須與 x 的維數(其長度)相同:
\[\mathbf{A}=\left[\begin{array}{c}\mathbf{a}_{1}^{\top} \\ \mathbf{a}_{2}^{\top} \\ \vdots \\ \mathbf{a}_{m}^{\top}\end{array}\right] \] \[\mathbf{A}=\left[\begin{array}{cccc}a_{11} & a_{12} & \cdots & a_{1 n} \\ a_{21} & a_{22} & \cdots & a_{2 n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m 1} & a_{m 2} & \cdots & a_{m n}\end{array}\right] \] \[\mathbf{A} \mathbf{x}=\left[\begin{array}{c}\mathbf{a}_{1}^{\top} \\ \mathbf{a}_{2}^{\top} \\ \vdots \\ \mathbf{a}_{m}^{\top}\end{array}\right] \mathbf{x}=\left[\begin{array}{c}\mathbf{a}_{1}^{\top} \mathbf{x} \\ \mathbf{a}_{2}^{\top} \mathbf{x} \\ \vdots \\ \mathbf{a}_{m}^{\top} \mathbf{x}\end{array}\right] \]A.shape,x.shape,torch.mv(A,x)
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))
矩陣-矩陣乘法
假設有兩個矩陣:\(\mathbf{A} \in \mathbb{R}^{n \times k}\),\(\mathbf{B} \in \mathbb{R}^{k \times m}\):
\[\mathbf{A}=\left[\begin{array}{cccc}a_{11} & a_{12} & \cdots & a_{1 k} \\ a_{21} & a_{22} & \cdots & a_{2 k} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n 1} & a_{n 2} & \cdots & a_{n k}\end{array}\right], \quad \mathbf{B}=\left[\begin{array}{cccc}b_{11} & b_{12} & \cdots & b_{1 m} \\ b_{21} & b_{22} & \cdots & b_{2 m} \\ \vdots & \vdots & \ddots & \vdots \\ b_{k 1} & b_{k 2} & \cdots & b_{k m}\end{array}\right] \]則計算結果 \(\mathbf{C} \in \mathbb{R}^{n \times m}\):
\[\mathbf{C}=\mathbf{A B}=\left[\begin{array}{c}\mathbf{a}_{1}^{\top} \\ \mathbf{a}_{2}^{\top} \\ \vdots \\ \mathbf{a}_{n}^{\top}\end{array}\right]\left[\begin{array}{llll}\mathbf{b}_{1} & \mathbf{b}_{2} & \cdots & \mathbf{b}_{m}\end{array}\right]=\left[\begin{array}{cccc}\mathbf{a}_{1}^{\top} \mathbf{b}_{1} & \mathbf{a}_{1}^{\top} \mathbf{b}_{2} & \cdots & \mathbf{a}_{1}^{\top} \mathbf{b}_{m} \\ \mathbf{a}_{2}^{\top} \mathbf{b}_{1} & \mathbf{a}_{2}^{\top} \mathbf{b}_{2} & \cdots & \mathbf{a}_{2}^{\top} \mathbf{b}_{m} \\ \vdots & \vdots & \ddots & \vdots \\ \mathbf{a}_{n}^{\top} \mathbf{b}_{1} & \mathbf{a}_{n}^{\top} \mathbf{b}_{2} & \cdots & \mathbf{a}_{n}^{\top} \mathbf{b}_{m}\end{array}\right] \]B = torch.ones(4,3)
torch.mm(A,B)
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
範數
一個向量的範數告訴我們一個向量有多大。 這裡考慮的大小(size)概念不涉及維度,而是分量的大小。
線上性代數中,向量範數是將向量對映到標量的函式 \(f\) 。給定任意向量 \(\mathbf{X}\),向量範數要滿足一些屬性:
- 第一個性質:如果我們按常數因子 \(Q\) 縮放向量的所有元素, 其範數也會按相同常數因子的絕對值縮放:\(f(\alpha \mathbf{x})=|\alpha| f(\mathbf{x})\)
- 第二個性質:三角不等式:\(f(\mathbf{x}+\mathbf{y}) \leq f(\mathbf{x})+f(\mathbf{y})\)
- 第三個性質:範數必須是非負的:\(f(\mathbf{x}) \geq 0\)
- 最後一個性質要求範數最小為0,當且僅當向量全由0組成:\(\forall i,[\mathbf{x}]_{i}=0 \Leftrightarrow f(\mathbf{x})=0\)
歐幾里得距離是一個 \(L_{2}\) 範數:
\[\|\mathbf{x}\|_{2}=\sqrt{\sum_{i=1}^{n} x_{i}^{2}} \]u = torch.tensor([3.0,-4.0])
torch.norm(u)
tensor(5.)
\(L_{1}\) 範數,表示為向量元素的絕對值之和:
\[\|\mathbf{x}\|_{1}=\sum_{i=1}^{n}\left|x_{i}\right| \]與 \(L_{2}\) 範數相比,\(L_{1}\) 範數受異常值的影響較小。
torch.abs(u).sum()
tensor(7.)
\(L_{2}\) 範數和 \(L_{1}\) 範數都是更一般的範數的特例:
\[\|\mathbf{x}\|_{p}=\left(\sum_{i=1}^{n}\left|x_{i}\right|^{p}\right)^{1 / p} \]類似於向量的 \(L_{2}\) 範數,矩陣 \(\mathbf{X} \in \mathbb{R}^{m \times n}\) 的Frobenius範數(Frobenius norm)是矩陣元素平方和的平方根:
\[\|\mathbf{X}\|_{F}=\sqrt{\sum_{i=1}^{m} \sum_{j=1}^{n} x_{i j}^{2}} \]Frobenius 範數滿足向量範數的所有性質,它就像是矩陣形向量的 \(L_{2}\) 範數。 呼叫以下函式將計算矩陣的 Frobenius 範數。
torch.norm(torch.ones(4,9))
tensor(6.)
範數和目標
經常試圖解決優化問題: 最大化分配給觀測資料的概率; 最小化預測和真實觀測之間的距離。目標,或許是深度學習演算法最重要的組成部分(除了資料),通常被表達為範數。