Deep Learning with PyTorch: A 60 Minute Blitz 自学笔记
Tensor
张量是一种特殊的数据结构,与数组和矩阵非常相似。在PyTorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码
张量类似于NumPy的ndarray,除了张量可以在GPU或其他专用硬件上运行以加速计算
1 | import torch |
Tensor Initialization
- 张量可以通过多种方式初始化
- 张量可以直接从数据中创建。数据类型是自动推断的。torch.tensor(data)
1
2data = [[1, 2], [3, 4]]
x_data = torch.tensor(data) - 张量可以从NumPy中的arrays创建,反之亦然。torch.from_numpy(np_array)
1
2np_array = np.array(data)
x_np = torch.from_numpy(np_array) - 从另一个张量,新张量将保留参数张量的属性(形状、数据类型)。torch.ones_like(tensor,type) & torch.rand_like(tensor,type)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22x_ones = torch.ones_like(x_data)
# retains the properties of x_data
# torch.ones_like 是 PyTorch 中的一个函数
# 它根据给定的张量(tensor)创建一个与其形状、数据类型相同的新张量
# 并且所有元素的值都为1
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float)
# overrides the datatype of x_data
# torch.rand_like 是 PyTorch 中的一个函数
# 它根据给定的张量(tensor)创建一个与其形状和数据类型相同的新张量
# 其中元素是从均匀分布([0, 1))中随机采样的浮点数
print(f"Random Tensor: \n {x_rand} \n")
out:
Ones Tensor:
tensor([[1, 1],
[1, 1]])
Random Tensor:
tensor([[0.8823, 0.9150],
[0.3829, 0.9593]]) - 随机或恒定值,用shape决定输出张量的维数。(shape)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")
out:
Random Tensor:
tensor([[0.3904, 0.6009, 0.2566],
[0.7936, 0.9408, 0.1332]])
Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
- 张量可以直接从数据中创建。数据类型是自动推断的。torch.tensor(data)
Tensor Attributes
- 张量属性描述了它们的形状、数据类型以及存储它们的设备。tensor.shape() & tensor.dtype() & tensor.device()
1 | tensor = torch.rand(3, 4) |
Tensor Operations
- 张量操作包括转置、索引、切片、数学运算、线性代数、随机采样等。每一个都可以在GPU上运行(通常比在CPU上运行速度更快)。torch.cuda.is_available() & tensor.to(‘cuda’)
1 | # We move our tensor to the GPU if available |
- 标准numpy类索引和切片:tensor[:,n] & tensor[n,:]
1 | tensor = torch.ones(4, 4) |
- 连接张量:使用torch.cat沿给定维度连接一系列张量。另请参见torch.stack,与torch.cat略有不同
1 | t1 = torch.cat([tensor, tensor, tensor], dim=1) |
- 乘以张量:* & @ & tensor.mul(tensor) & torch.matmul(tensor1, tensor2)
1 | # This computes the element-wise product |
- In-place operation(““):x.copy(y), x.t_(), x.add(n) will change x.
1 | print(tensor, "\n") |
- In-place operation 可以节省一些内存,但在计算导数时可能会出现问题,因为会立即丢失历史记录。因此,不鼓励使用它们
Bridge with NumPy
- CPU上的tensor和NumPy数组上的张量可以共享它们的底层内存位置,改变一个就会改变另一个
Tensor to NumPy array
- t.numpy()
1 | t = torch.ones(5) |
NumPy array to Tensor
- torch.from_numpy(n)
1 | n = np.ones(5) |
A Gentle Introduction to torch.autograd
- torch.autograd是PyTorch的自动微分引擎,为神经网络训练提供动力
Background
神经网络(NN)是对某些输入数据执行的嵌套函数的集合。这些函数由参数(由权重和偏差组成)定义,这些参数在PyTorch中存储在张量中
训练神经网络分为两个步骤:
- 正向传播:在正向传播中,神经网络对正确的输出做出最佳预测。它通过每个函数运行输入数据来进行猜测
- 反向传播:在反向传播中,神经网络根据其猜测的误差按比例调整其参数。它通过从输出向后遍历,收集误差相对于函数参数(梯度)的导数,并使用梯度下降优化参数来实现这一点
Usage in PyTorch
- 例子:我们从torchvision加载一个预训练的resnet18模型。我们创建了一个随机数据张量来表示具有3个通道、高度和宽度为64的单个图像,并将其相应的标签初始化为一些随机值。预训练模型中的标签具有形状(1,1000)
1 | import torch |
Differentiation in Autograd
- autograd如何收集梯度?
1 | import torch |
1 | # 调用.backward()时,autograd会计算这些梯度并将其存储在相应张量的.grad属性中 |
Optional Reading - Vector Calculus using autograd
Computational Graph
autograd在由Function对象组成的有向无环图(DAG)中记录数据(张量)和所有执行的操作(以及由此产生的新张量)。在这个DAG中,叶子是输入张量,根是输出张量。通过从根到叶跟踪此图,您可以使用链式规则自动计算梯度
In a forward pass, autograd does two things simultaneously:
- 运行所请求的操作以计算结果张量
- 在DAG中保持操作的梯度函数
The backward pass kicks off when .backward() is called on the DAG root. autograd then:
- 根据每个.grad_fn计算梯度
- 将它们累积在各自张量的.grad属性中
- 使用链式规则,一直传播到叶张量
DAG的可视化表示。在图中,箭头指向正向传递的方向。节点表示正向传递中每个操作的反向函数。蓝色的叶节点表示我们的叶张量a和b
DAGs在PyTorch中是动态的。每次.backward()调用后,autograd都会开始填充一个新的图
torch.autograd跟踪所有requires_grad标志设置为True的张量上的操作。对于不需要梯度的张量,将此属性设置为False会将其从梯度计算DAG中排除
1 | x = torch.rand(5, 5) |
- 在神经网络中,不计算梯度的参数通常被称为冻结参数。在微调中,我们冻结了大部分模型,通常只修改分类器层以对新标签进行预测
1 | from torch import nn, optim |