2.3.1. 标量
import torch
x = torch.tensor(3.0)
y = torch.tensor(2.0)
x + y, x * y, x / y, x**y
2.3.2向量
可以被视为标量值组成的列表
x = torch.arange(4)
x
通过张量的索引来访问任意元素
x = torch.arange(4)
x
访问张量的长度
len(x)
对于只有一个轴的张量,形状只有一个元素
x.shape
2.3.3. 矩阵
创建矩阵
A = torch.arange(20).reshape(5, 4)
A
转置
A.T
2.3.4张量
就像向量是标量的推广,矩阵是向量的推广一样,我们可以构建具有更多轴的数据结构
X = torch.arange(24).reshape(2, 3, 4)
X
2.3.5张量算法的基本性质
任何按元素的一元运算都不会改变其操作数的形状。 同样,给定具有相同形状的任意两个张量,任何按元素二元运算的结果都将是相同形状的张量
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
A, A + B
B=A 区别:只是简单的做复制,不会做内存的分配,只是把A的索引给B。
当然这并不影响本次算法的A+B的操作,
将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘:
如下:
a = 2
X = torch.arange(24).reshape(2, 3, 4)
X,a + X, (a * X).shape
2.3.6. 降维
我们可以表示任意形状张量的元素和
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
默认情况下,调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量。 我们还可以指定张量沿哪一个轴来通过求和降低维度。 以矩阵为例,为了通过求和所有行的元素来降维(轴0),可以在调用函数时指定axis=0
。 由于输入矩阵沿0轴降维以生成输出向量,因此输入轴0的维数在输出形状中消失。
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
指定axis=1
将通过汇总所有列的元素降维(轴1)。因此,输入轴1的维数在输出形状中消失。
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
沿着行和列对矩阵求和,等价于对矩阵的所有元素进行求和。
A.sum(axis=[0, 1]) # 结果和A.sum()相同
一个与求和相关的量是平均值(mean或average)。 我们通过将总和除以元素总数来计算平均值。 在代码中,我们可以调用函数来计算任意形状张量的平均值。
A.mean(), A.sum() / A.numel()
同样,计算平均值的函数也可以沿指定轴降低张量的维度。
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
以上是二维度,下面尝试三维的一些求和操作
A = torch.arange(40).reshape(2, 5, 4)
print(A, "\n")
print(A.sum(), "\n")
A_sum0 = A.sum(axis=0)
A_sum1 = A.sum(axis=1)
print(A_sum0, "\n")
print(A_sum1, "\n")
A_sum02= A.sum(axis=[0, 2])
print(A_sum02, "\n")
结果;
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],
[24, 25, 26, 27],
[28, 29, 30, 31],
[32, 33, 34, 35],
[36, 37, 38, 39]]])
tensor(780)
tensor([[20, 22, 24, 26],
[28, 30, 32, 34],
[36, 38, 40, 42],
[44, 46, 48, 50],
[52, 54, 56, 58]])
tensor([[ 40, 45, 50, 55],
[140, 145, 150, 155]])
tensor([ 92, 124, 156, 188, 220])
那么我们可以这么理解:
sum(axis= x)顾名思义是求和函数, 但是注意函数的返回值是张量而不是数值;
如果括号里什么都不写则是返回一个标量, 值是所有元素的和
如果axis=0即对A的第一个维度也就是2这个维度进行求和, 返回值就是一个大小为5x4的张量
如果axis=1即对A的第二个维度也就是5这个维度进行求和, 返回值就是一个大小为2x4的张量
如果axis=[0, 2]即对A的第一和第三个维度进行求和, 返回值就是一个大小为5的张量
可以理解为对哪些维度求和就要消除哪些维度
但是,广播机制需要不损失维度,这时候需要我们保留维度,如果说不想损失维度的话可以加上keepdims=True,
sum_A = A.sum(axis=1, keepdims=True)
sum_A
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
例如,由于sum_A
在对每行进行求和后仍保持两个轴,我们可以通过广播将A
除以sum_A
A / sum_A
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]])
同理的三维操作:例如A_sum0T就是一个1x5x4的张量, 保留了第一个维度。如下
A = torch.arange(40).reshape(2, 5, 4)
A_sum0T = A.sum(axis=0, keepdims=True)
print(A_sum0T, "\n")
print(A_sum0T.shape)
tensor([[[20., 22., 24., 26.],
[28., 30., 32., 34.],
[36., 38., 40., 42.],
[44., 46., 48., 50.],
[52., 54., 56., 58.]]])
torch.Size([1, 5, 4])
2.3.7广播机制
广播机制是一种补全机制, 现给定两个矩阵进行运算, 在特定情况下两个矩阵会扩充为相同维度且各个维度大小相等的两个矩阵
特定情况如下: 对于矩阵的维度我们从后往前看, 如果相同则往前看; 如果不同且其中一个为1, 则把1扩展为另一个矩阵当前维度的大小;
如果两个矩阵的维度不同, 且从后往前一直都满足特定情况, 那么对于维度小的矩阵会自动补全为另一个矩阵的维度
A = torch.ones(4, 3, 2)
B = torch.ones(4, 1, 2) # B的1扩充为3
print((A+B).shape)
torch.Size([4, 3, 2])
A = torch.ones(4, 1, 3, 2) # A的1扩充为5
B = torch.ones(5, 1, 2) # B的1扩充为3, 并补全了4这个维度
print((A+B).shape)
torch.Size([4, 5, 3, 2])
A = torch.ones(4, 1, 3, 3)
B = torch.ones(5, 1, 2)
print((A+B).shape) # 2!=3, 不满足特定情况, 报错
注意: 广播机制只是在运算过程中改变了原矩阵的维度, 运算结束后矩阵的维度还是原来的样子
2.3.8求平均值
A = torch.arange(40, dtype=torch.float32).reshape(2, 5, 4)
print(A.mean())
print(A.sum()/A.numel(), "\n")
print(A.mean(axis=0))
print(A.sum(axis=0)/A.shape[0], "\n")
tensor(19.5000)
tensor(19.5000)
tensor([[10., 11., 12., 13.],
[14., 15., 16., 17.],
[18., 19., 20., 21.],
[22., 23., 24., 25.],
[26., 27., 28., 29.]])
tensor([[10., 11., 12., 13.],
[14., 15., 16., 17.],
[18., 19., 20., 21.],
[22., 23., 24., 25.],
[26., 27., 28., 29.]])
和sum()相似, 对于求平均值函数mean()来说也是如此, 返回值也是张量
求平均值除了用mean()函数外还可以用sum()/个数, 这样的返回值依旧是张量; (求单独某一维的元素个数要用shape[])
注意求平均值的前提是张量的数值类型是float
2.3.8求累加值
A = torch.arange(20).reshape(5, 4)
print(A)
print(A.cumsum(axis=0))
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
tensor([[ 0, 1, 2, 3],
[ 4, 6, 8, 10],
[12, 15, 18, 21],
[24, 28, 32, 36],
[40, 45, 50, 55]])
cumsum(axis= x): 累加求和, 与sum()不同, cumsum的返回值维度不变, 和原张量相同; 元素的值类似于第x维上的前缀和
备注:cumsum函数的解释:
cumsum()
是PyTorch张量的一个方法,用于计算累积和。在这个例子中,axis=0
表示沿着第一个维度(即行)进行累积求和。
具体来说,A.cumsum(axis=0)
将对张量A的每一列进行累积求和,生成一个新的张量。新张量的第一行与原始张量A的第一行相同,第二行是原始张量A的第一行和第二行的和,以此类推。最终的结果将被打印出来。
例如,如果A是一个2行3列的张量,那么A.cumsum(axis=0)
将生成一个2行3列的新张量,其中第一行与A的第一行相同,第二行是A的第一行和第二行的和。
请注意,axis=0
是可选的,默认情况下是对整个张量进行累积求和。如果你想在其他维度上进行累积求和,可以通过修改axis
参数来实现。
2.3.9求点积
x = torch.arange(4, dtype=torch.float32)
y = torch.ones(4, dtype=torch.float32)
print(x)
print(y)
print(torch.dot(x, y))
print(torch.sum(x*y))
tensor([0., 1., 2., 3.])
tensor([1., 1., 1., 1.])
tensor(6.)
tensor(6.)
dot(x, y): 求两个向量的点积, 也就是相同位置元素乘积的和; 效果等同于sum(x*y)
2.3.10矩阵乘法
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = torch.ones(4, 3)
print(torch.mm(A, B))
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
mm(A, B): 指的就是矩阵乘法, 而之前的A*B只是点乘
2.3.11求范数#
A = torch.tensor([3.0, -4.0])
print(A)
print(torch.abs(A).sum())
print(torch.norm(A),"\n")
A = torch.ones(4, 9)
print(A)
print(torch.norm(A))
tensor([ 3., -4.])
tensor(7.)
tensor(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., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1.]])
tensor(6.)
abs(向量).sum(): 求向量的L1范数, 就是把所有元素的绝对值加起来
norm(向量): 求向量的L2范数, 就是把所有元素的平方加起来再开根号, 可以理解为向量的模
norm(矩阵): 求矩阵的F范数, 也是把所有元素的平方加起来再开根号