标量、向量、矩阵
矩阵把空间进行扭曲
矩阵的范数:F范数:所有元素的平方加和再开根号
特征向量:不被矩阵改变方向的向量
向量是标量的推广,矩阵是向量的推广,张量(多维)是矩阵的推广
线性代数的实现
import torch
# 标量由只有一个元素的张量表示
x = torch.tensor([3.0])
# 向量:由标量值组成的列表
x = torch.arange(4)
print(x) # tensor([0, 1, 2, 3])
# 通过张量的索引访问任一元素
print(x[3]) # tensor(3)
# 访问张量的长度
print(len(x)) # 4
# 张量的形状,只有一个轴的张量,形状只有一个元素
print(x.shape) # torch.Size([4])
# 创建一个形状为(2,3)的矩阵,并将其转置
A = torch.arange(6).reshape((2,3))
print(A.T)
# 对称矩阵等于其转置后的矩阵
B = torch.tensor([[1,2,3],[2,0,4],[3,4,5]])
print(B == B.T)
# tensor([[True, True, True],
# [True, True, True],
# [True, True, True]])
# 创建更多轴的数据结构
X = torch.arange(24).reshape((2,3,4))
print(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]]]) 在一个三维张量中,有2个二维矩阵,每个二维矩阵中有3个向量,每个向量有4个标量
# 矩阵相加
A = torch.arange(20,dtype=torch.float32).reshape(5,4)
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
# 两个矩阵按元素相乘,称为哈达玛积
print(A * B)
# tensor([[ 0., 1., 4., 9.],
# [ 16., 25., 36., 49.],
# [ 64., 81., 100., 121.],
# [144., 169., 196., 225.],
# [256., 289., 324., 361.]])
# 标量与矩阵的运算,即为与矩阵中每个元素的运算,形状不变
a = 2
X = torch.arange(24).reshape(2,3,4)
print(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]]])
print(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])
print(a*X,(a*X).shape)
# tensor([[[ 0, 2, 4, 6],
# [ 8, 10, 12, 14],
# [16, 18, 20, 22]],
#
# [[24, 26, 28, 30],
# [32, 34, 36, 38],
# [40, 42, 44, 46]]]) torch.Size([2, 3, 4])
# 矩阵求和:按指定张量维度求和
# 按哪个维度求和,哪个维度消失 把哪个维度压扁
A = torch.arange(24).reshape(2,3,4)
print(A)
# 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]]])
print(A.sum(axis=0),A.sum(axis=0).shape)
# tensor([[12, 14, 16, 18],
# [20, 22, 24, 26],
# [28, 30, 32, 34]]) torch.Size([3, 4])
print(A.sum(axis=1),A.sum(axis=1).shape)
# tensor([[12, 15, 18, 21],
# [48, 51, 54, 57]]) torch.Size([2, 4])
print(A.sum(axis=2),A.sum(axis=2).shape)
# tensor([[ 6, 22, 38],
# [54, 70, 86]]) torch.Size([2, 3])
print(A.sum(axis=[0,1]),A.sum(axis=[0,1]).shape) # 按两个维度求和
# tensor([60, 66, 72, 78]) torch.Size([4])
# 平均值mean mean()要求矩阵是浮点型
A = torch.arange(12,dtype=torch.float32).reshape(3,4)
print(A)
# tensor([[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]])
print(A.mean()) # tensor(5.5000)
print(A.sum()/A.numel()) # tensor(5.5000)
print(A.mean(axis=0)) # tensor([4., 5., 6., 7.])
print(A.sum(axis=0)/A.shape[0]) # tensor([4., 5., 6., 7.])
# 计算总和或均值是保持轴数不变,即不要丢掉维数,将求和维度的值变为1
sum_A = A.sum(axis=0,keepdims=True)
print(sum_A,sum_A.shape) # tensor([[12., 15., 18., 21.]]) torch.Size([1, 4])
# 这样就可以保证A与sum_A的维度一致,可以通过广播机制进行计算
print(A/sum_A)
# 某个轴计算A元素的累计求和
print(A.cumsum(axis=0))
# tensor([[ 0., 1., 2., 3.],
# [ 4., 6., 8., 10.],
# [12., 15., 18., 21.]])
# 点积:相同位置的按元素乘积的和 (向量-向量)
x = torch.arange(4,dtype=torch.float32)
y = torch.ones(4,dtype=torch.float32)
print(torch.dot(x,y)) # tensor(6.)
print(torch.sum(x*y)) # tensor(6.) 也可以通过执行按元素乘法,再求和表示
# 矩阵-向量积
print(A.shape) # torch.Size([3, 4])
print(x.shape) # torch.Size([4])
print(torch.mv(A,x),torch.mv(A,x).shape) # tensor([14., 38., 62.]) torch.Size([3])
# 矩阵-矩阵乘法
B = torch.ones(2,3)
print(A.shape) # torch.Size([3, 4])
print(B.shape) # torch.Size([2, 3])
print(torch.mm(B,A),torch.mm(B,A).shape)
# tensor([[12., 15., 18., 21.],
# [12., 15., 18., 21.]]) torch.Size([2, 4])
# L2范数是向量元素平方和的平方根
u = torch.tensor([3.0,-4.0])
print(torch.norm(u)) # tensor(5.)
# L1范数是向量元素的绝对值之和
print(torch.abs(u).sum()) # tensor(7.)
# 矩阵的范数:是矩阵元素的平方和的平方根
print(torch.norm(torch.ones((4,9)))) # tensor(6.)
QA互动
Q1:torch不区分行向量和列向量吗?
向量就是一维的,在计算机里是一维数组,没有行列之分。要想区分行列向量,就要按矩阵来看。