前言

本文章是来自于动手学深度学习v2的学习笔记

预备知识

张量(tensor)指的是n维数组,只有一个轴上的张量对应数学上的向量(vector),具有两个轴的张量对应数学上的矩阵(martix).

在Pytorch中有关张量的读写操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch
# 创建一个一维张量
x = torch.arange(12)

# 访问张量的形状
x.shape

# 张量中元素的总数
x.numel()

# 改变张量的形状, 使用-1可以自动计算出另一个维度,如 x.reshape(-1, 4)
x.reshape(3, 4)

# 创建值全为0的张量
torch.zeros((2, 3, 4))

# 创建值全为1的张量
torch.ones((2, 3, 4))

# 以下代码创建一个形状为(3,4)的张量。 其中的每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样
torch.randn(3, 4)

# 创建一个确定值的张量
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

在Pytorch中有关张量的运算操作

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
import torch

x = torch.sensor([1, 2, 4, 8])
y = torch.sensor([2, 2, 2, 2])

# 加 减 乘 除 求幂
x+y, x-y, x*y, x/y, x**y

# e的x幂运算
torch.exp(x)

# 所有元素求和
x.sum()

# 张量的连接
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

# dim=0 按照形状第一个维度连接
torch.cat((X, Y), dim=0)
# (tensor([[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.],
# [ 2., 1., 4., 3.],
# [ 1., 2., 3., 4.],
# [ 4., 3., 2., 1.]]),

# dim=1 形状的第二个维度连接
torch.cat((X, Y), dim=1)

# tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
# [ 4., 5., 6., 7., 1., 2., 3., 4.],
# [ 8., 9., 10., 11., 4., 3., 2., 1.]]))

X == Y

# tensor([[False, True, False, True],
# [False, False, False, False],
# [False, False, False, False]])

广播机制

在某些情况下及时两个张量的形状不同,我们也可以通过调用广播机制来执行元素操作。这种机制为:

  1. 通过适当的复制元素来扩展一个或者两个数组,使得两个张量具有相同的形状
  2. 对新生成的数组执行按元素操作

可广播的一对张量需要满足以下规则

  1. 每个张量至少有一个维度
  2. 从尾部的维度开始,维度尺寸
    • 或者相等
    • 或者其中一个张量的维度尺寸为1
    • 或者一个张量不存在这个维度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 不可广播( a 不满足第一条规则)。
a = torch.empty((0,))
b = torch.empty(2, 2)


# m 和 n 可广播
# 倒数第一个维度:两者的尺寸均为1
# 倒数第二个维度:n尺寸为1
# 倒数第三个维度:两者尺寸相同
# 倒数第四个维度:n该维度不存在
m = torch.empty(5, 3, 4, 1)
n = torch.empty( 3, 1, 1)


# 不可广播,因为倒数第三个维度:2 != 3
p = torch.empty(5, 2, 4, 1)
q = torch.empty( 3, 1, 1)
1
2
3
4
5
6
7
8
9
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))

# 由于a和b的形状不相同,所以在相加时会先通过广播机制将两个张量扩大到3x2的张量之后,
# 再进行运算, 扩展的行或者列使用默认值0来代替
a + b
# tensor([[0, 1],
# [1, 2],
# [2, 3]])

索引和切片

1
2
3
4
5
6
7
8
9
10
X = torch.arange(12, dtype=torch.float32).reshape((3,4))

# 获取最后一个元素
X[-1]

# 指定索引更改张量中数据
X[1, 2] = 9

# 获取第一行和第二行的所有元素
X[0:2, :]