导读: 什么是PyTorch?我们如何用PyTorch快速实现一个完整的神经网络训练流程?首先阅读链接的官方 Pytorch 教程。然后,将完成有关张量 (Tensor)、Autograd、神经网络和分类器训练/评估的练习。有些问题会要求您实现几行代码,而其他问题会要求您猜测操作的输出是什么,或者识别代码的问题。强烈建议您在参考解决方案中查找问题之前先亲自尝试这些问题。
- 在 PyTorch 中执行张量运算。
- 了解 Autograd 背景下神经网络的后向和前向传递。
- 检测 PyTorch 训练代码中的常见问题。
方法一:colab已经自动帮我们安装好了torch库,我们可以直接使用。建议可以直接先使用在线的编译器,先快速理解知识点。
方法二:在vscode/pycharm上通过pip install 来安装torch,torchvision
我们将从最基本的张量开始。首先,浏览官方张量教程这里。
张量是一种特殊的数据结构,与数组和矩阵非常相似。在PyTorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码。张量与NumPy的 ndarray 类似,不同之处在于张量可以在GPU或其他专用硬件上运行以加速计算。如果您熟悉 ndarrays,那么您就会熟悉Tensor API。如果没有,请按照此下面的问题进行操作。最好可以不看答案操作一遍,先思考一下,再去搜索一下,最后比对一下正确的操作。这样子效果是最好的。
- 将二维列表
[[5,3], [0,9]]
转换为一个张量 - 使用区间
[0, 1)
上均匀分布的随机数创建形状(5, 4)
的张量t
- 找出张量
t
所在的设备及其数据类型。 - 创建形状
(4,4)
和(4,4)
的两个随机张量,分别称为u
和v
。将它们连接起来形成形状为(8, 4)
的张量。 - 连接
u
和v
以创建形状(2, 4, 4)
的张量。 - 连接
u
和v
形成一个张量,称为形状(4, 4, 2)
的w
。 - 索引
w
位于3, 3, 0
。将该元素称为e
。 - 会在
u
或v
的哪一个中找到w
?并核实。 - 创建一个形状为
(4, 3)
的全为1
的张量a
。对a
进行元素级别的自乘操作。 - 向
a
添加一个额外的维度(新的第0
维度)。 - 执行
a
与转置矩阵的乘法。 a.mul(a)
会产生什么结果?
神经网络(NN) 是对某些输入数据执行的嵌套函数的集合。这些函数由参数(由权重和偏差组成)定义,这些参数在PyTorch中存储在张量中。可以使用 torch.nn 包构建神经网络。
训练神经网络分两步进行:
- 前向传播:在前向传播中,神经网络对正确的输出做出最佳猜测。它通过每个函数运行输入数据来进行猜测。
- 反向传播:在反向传播中,神经网络根据其猜测的误差按比例调整其参数。它通过从输出向后遍历、收集误差相对于函数参数(梯度)的导数并使用梯度下降来优化参数来实现这一点。
更一般地,神经网络的典型训练过程如下:
- 定义具有一些可学习参数(或权重)的神经网络
- 迭代输入数据集
- 通过网络处理输入
- 计算损失(输出距离正确还有多远)
- 将梯度传播回网络参数
- 更新网络的权重,通常使用简单的更新规则:权重=权重-学习率梯度
有了这些教程,我们就可以尝试以下练习了!假设我们有以下起始代码,将下面这段代码复制到你的编辑器中:
import torch
from torchvision.models import resnet18, ResNet18_Weights
model = resnet18(weights=ResNet18_Weights.DEFAULT)
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 1000)
- 使用数据对模型进行前向传递并将其保存为
preds
。 preds
的形状应该是什么?验证你的猜测。- 将
resnet18
的conv1
属性的权重参数保存为w
。打印w
因为我们稍后需要它(请注意,我的w
不会与你的相同)。 w
的grad
属性应该是什么?请验证。- 创建一个交叉熵损失对象,并用它来使用
labels
和preds
计算损失,保存为loss
。打印loss
,因为我们稍后需要它。 - 打印最后一次产生
loss
损失的数学运算。 - 执行反向传播。
w
应该改变吗?检查 #3 的输出。w
的grad
属性会与 #4 不同吗?并验证。loss
的grad
属性应该返回什么?验证一下。loss
的requires_grad
属性应该是什么?验证一下。labels
的requires_grad
属性应该是什么?验证一下。- 如果你再次执行反向传播会发生什么?
- 创建一个学习率 (
lr=1e-2
) 和动量 (momentum=0.9
) 的 SGD 优化器对象,并执行一步。 w
是否应该改变?检查第3题的输出。loss
是否应该改变?检查第5题的输出。- 将所有可训练参数的梯度清零。
w
的grad
属性应该是什么?验证一下。- 在不运行的情况下,判断以下代码是否会成功执行。
- 判断以下代码是否会成功执行。
- 判断以下代码是否会成功执行。
- 对于不能执行的代码,你如何修改其中一个
.backward
行使其工作? - 以下代码的输出是什么?
- 以下代码的输出是什么?
- 以下代码有什么问题?
- 按正确的顺序排列训练循环的以下步骤(有多种正确答案,但你在教程中会看到一种典型的设置):以下代码的输出是什么?
- 我们将实现一个有一个隐藏层的神经网络。这个网络将接受一个32x32的灰度图像输入,展开它,通过一个有100个输出特征的仿射变换,应用
ReLU
非线性,然后映射到目标类别(10)。实现初始化和前向传递,完成以下代码。使用nn.Linear
,F.relu
,torch.flatten
- 用两行代码验证你能通过上述网络进行前向传递。
- 在不运行代码的情况下,猜测以下语句的结果是什么?
- 获取网络参数的名称
- 以下语句指的是哪个网络层?它将评估什么?
- 以下示意图包含了实现一个神经网络所需的所有信息。实现初始化和前向传递,完成以下代码。使用
nn.Conv2d
,nn.Linear
,F.max_pool2d
,F.relu
,torch.flatten
。提示:ReLU
在子采样操作后和前两个全连接层之后应用。 - 修改上述代码,使用
nn.MaxPool2d
代替F.max_pool2d
- 尝试通过将第一个卷积层的输出通道数从6增加到12来增加网络的宽度。你还需要改变什么?
接下来,我们进入教程的最后一部分:Cifar10教程。这个教程通过以下步骤来训练一个图像分类器:
- 使用torchvision加载和归一化 (normalize) CIFAR10训练和测试数据集
- 定义一个卷积神经网络
- 定义一个损失函数
- 在训练数据上训练网络
- 在测试数据上测试网络
完成上述教程后,回答以下问题:
- 以下数据集加载代码可以运行,但代码中是否有错误?这些错误的影响是什么?如何修复这些错误?
- 编写两行代码从数据加载器中获取随机的训练图像(假设上面的错误已经修复)。
- 以下训练代码可以运行,但代码中是否有错误(包括计算效率低下)?这些错误的影响是什么?如何修复这些错误?
切记以上代码可能刚开始看会有些困难,但这很正常,一定要克制住自己的好奇心直接看答案,哪怕实在想不出来,也应该先把自己的思考和尝试写下来。然后再去看答案,比对自己的输出和答案有什么区别(敏感的人可能发现了,这和前向传播和计算损失很像),确实是这样,就是需要不断训练自己的大脑。
熟悉PyTorch可能需要一些时间,这很正常!PyTorch是深度学习开发的强大工具。完成上面的练习后,可以在这里查看快速入门教程,该教程将涵盖更多方面,包括保存和加载模型以及数据集和数据加载器。在学习API的过程中,记住关键的使用模式可能会很有用;我喜欢的一个PyTorch备忘录可以在[这里](https://github.com/pytorch/tutorials/blob/master/beginner_source/PyTorch Cheat.md)找到。
这就是我们关于PyTorch基础知识的全部内容!恭喜你 - 现在你已经具备了开始解决利用PyTorch的更复杂深度学习代码的能力。