Pytorch基础复习
Pytorch基础复习
Pytorch简单入门
- 安装以后进行简单测试:
- 验证GPU是否可以使用:
1 |
|
- 张量:Pytorch 的一大作用就是可以代替 Numpy 库,Tensors张量,它相当于 Numpy 的多维数组(ndarrays)。
两者的区别就是 Tensors 可以应用到 GPU 上加快计算速度
。 - Pytorch当中的张量是圆括号套中括号。中括号才是数组,外部一定是有一个圆括号的。
张量的声明和定义- 声明:
- torch.empty(): 声明一个未初始化的矩阵。
- torch.rand():随机初始化一个矩阵
- torch.zeros():创建数值皆为 0 的矩阵
- torch.tensor():直接传递 tensor 数值来创建
- tensor.new_ones():new_*() 方法需要输入尺寸大小。
- torch.randn_like(old_tensor):保留相同的尺寸大小
- 获取tensor的size:tensor.size()
- torch.Size 实际上是元组(tuple)类型,所以支持所有的元组操作。和上面的不一样,注意。
- 声明:
1 |
|
加法操作。
- 加号运算符
- torch.add(tensor1, tensor2, [out=tensor3])
- tensor1.add_(tensor2):直接修改 tensor 变量
可以改变 tensor 变量的操作都带有一个后缀 _, 例如 x.copy_(y), x.t_() 都可以改变 x 变量
1 |
|
访问某一维数据。
对于 Tensor 的访问,和 Numpy 对数组类似,可以使用索引来访问某一维的数据,如下所示:
1 |
|
Tensor的尺寸修改。
对 Tensor 的尺寸修改,可以采用 torch.view() ,如下所示:
1 |
|
如果 tensor 仅有一个元素,可以采用 .item() 来获取类似 Python 中整数类型的数值:
1 |
|
如果我想把Tensor里面的元素变成标量数组,需要用到numpy
1 |
|
Tensor 转换为 Numpy 数组.
- Tensor是向量,是多维向量组合。
- Numpy是向量,但是Numpy没有逗号,可以看做是标量
1 |
|
Numpy 数组转换为 Tensor。
1 |
|
CUDA张量。
Tensors 可以通过 .to 方法转换到不同的设备上,即 CPU 或者 GPU 上。例子如下所示:
1 |
|
autograd
autograd库:要是提供了对 Tensors 上所有运算操作的自动微分功能,也就是计算梯度的功能。它属于 define-by-run 类型框架,即反向传播操作的定义是根据代码的运行方式,因此每次迭代都可以是不同的。
- 设置torch.Tensor的属性:
.requires_grad=True
,那么就会开始追踪在该变量上的所有操作。 - 而完成计算后,可以调用
.backward() 并自动计算所有的梯度
。 - 得到的梯度都保存在属性
.grad
中。 .detach()
方法分离出计算的历史,可以停止一个 tensor 变量继续追踪其历史信息 ,同时也防止未来的计算会被追踪。- 防止跟踪历史(以及使用内存),可以将代码块放在
with torch.no_grad():
内,因为模型会包含一些带有 requires_grad=True 的训练参数,但实际上并不需要它们的梯度信息。
1 |
|
算出上面梯度的原因:
Function类:
- Tensor 和 Function 两个类是有关联并建立了一个非循环的图,可以编码一个完整的计算记录。
- 每个 tensor 变量都带有属性 .grad_fn ,该属性引用了创建了这个变量的 Function (除了由用户创建的 Tensors,它们的 grad_fn=None)。
- 如果要进行求导运算,可以调用一个 Tensor 变量的方法 .backward() 。如果该变量是一个标量,即仅有一个元素,那么不需要传递任何参数给方法
.backward(),当包含多个元素的时候,就必须指定一个 gradient 参数
,表示匹配尺寸大小的 tensor
神经网络
在 PyTorch 中 torch.nn 专门用于实现神经网络。其中 nn.Module 包含了网络层的搭建,以及一个方法– forward(input) ,并返回网络的输出 output.
对于神经网络来说,一个标准的训练流程是这样的:
- 定义一个多层的神经网络
- 对数据集的预处理并准备作为网络的输入
- 将数据输入到网络
- 计算网络的损失
- 反向传播,计算梯度
- 更新网络的梯度,一个简单的更新规则是 weight = weight - learning_rate * gradient
首先定义一个神经网络,包含两层卷积层和三层全连接层:
1 |
|
定义的神经网络:
- 必须实现forward 函数
- 而 backward 函数在采用 autograd 时就自动定义好了
- 在 forward 方法可以采用任何的张量操作
- net.parameters() 可以返回网络的训练参数
- 反向传播需要先清空梯度缓存,并反向传播随机梯度。
1 |
|
torch.nn 只支持小批量(mini-batches)数据,也就是输入不能是单个样本,比如对于 nn.Conv2d 接收的输入是一个 4 维张量–nSamples * nChannels * Height * Width 。
所以,如果你输入的是单个样本,需要采用 input.unsqueeze(0) 来扩充一个假的 batch 维度,即从 3 维变为 4 维。
第一个维度是Batch维度。
损失函数
损失函数的输入是 (output, target) ,即网络输出和真实标签对的数据,然后返回一个数值表示网络输出和真实标签的差距。
1 |
|
反向传播
反向传播的实现只需要调用 loss.backward() 即可,当然首先需要清空当前梯度缓存,即.zero_grad() 方法,否则之前的梯度会累加到当前的梯度,这样会影响权值参数的更新。
1 |
|
更新权重
采用随机梯度下降(Stochastic Gradient Descent, SGD)方法的最简单的更新权重规则如下:
- weight = weight - learning_rate * gradient
1 |
|
但是这只是最简单的规则,深度学习有很多的优化算法,不仅仅是 SGD,还有 Nesterov-SGD, Adam, RMSProp 等等.采用 torch.optim 库,使用例子如下所示:
1 |
|
训练分类器
通常在处理如图片、文本、语音或者视频数据的时候,一般都采用标准的 Python 库将其加载并转成 Numpy 数组,然后再转回为 PyTorch 的张量
。
PyTorch 对于计算机视觉,特别创建了一个torchvision
的库,它包含一个数据加载器(data loader),可以加载比较常见的数据集,比如 Imagenet, CIFAR10, MNIST 等等,然后还有一个用于图像的数据转换器(data transformers),调用的库是 torchvision.datasets 和 torch.utils.data.DataLoader。
训练CIFAR10 数据集:
- 通过调用 torchvision 加载和归一化 CIFAR10 训练集和测试集;
- 构建一个卷积神经网络;
- 定义一个损失函数;
- 在训练集上训练网络;
- 在测试集上测试网络性能。
1 |
|
可视化部分训练图片:
1 |
|
构建一个神经网络:
1 |
|
训练网络:指定需要迭代的 epoch,然后输入数据,指定次数打印当前网络的信息,比如 loss 或者准确率等性能评价标准。
1 |
|
测试网络性能:测试集进行测试,检验网络模型的泛化能力。对于图像分类任务来说,一般就是用准确率作为评价标准。
先用一个小的batch做测试:
1 |
|
在GPU上训练
1 |
|
DataParallel会自动分割数据集并发送任务给多个 GPUs 上的多个模型。然后等待每个模型都完成各自的工作后,它又会收集并融合结果,然后返回。