PyTorch 简介:构建识别手写数字的神经网络

作者选择了 代码 2040作为 写给捐赠计划的一部分接受捐赠。

介绍

机器学习是计算机科学的一个领域,它在数据中找到模式。从2021年开始,机器学习实践者将这些模式用于 检测自动驾驶汽车的轨道;训练 机器人手解决鲁比克立方体;或 产生有疑问的艺术品味的图像.随着机器学习模型变得更加准确和性能,我们看到主流应用和产品越来越多。

深度学习是一个机器学习的子集,专注于特别复杂的模型,称为神经网络。在后来的先进的DigitalOcean文章中(如这篇关于构建一个Atari机器人的教程(https://andsky.com/tech/tutorials/how-to-build-atari-bot-with-openai-gym)),我们将正式定义复杂是什么意思。神经网络是您听到的高精度和催眠的现代模型,在各种任务中应用。在本教程中,您将专注于一个特定任务,称为对象识别或图像分类。

您将在 PyTorch中构建、训练和评估深度神经网络,该框架由 Facebook AI Research开发用于深度学习。与其他深度学习框架(如Tensorflow)相比,PyTorch是一个初学者友好的框架,具有缓解功能,可帮助构建过程。它对于先进的用户也非常可自定义,研究人员和实践者在Facebook和Tesla等公司中使用它。

  • 在 PyTorch 中构建、训练和评估深度神经网络
  • 了解应用深度学习的风险

虽然您不需要在实践深度学习或PyTorch方面的经验来跟随本教程,但我们将假定您熟悉机器学习术语和概念,如培训和测试,功能和标签,优化和评估。

前提条件

要完成本教程,您将需要Python 3的本地开发环境,至少具有1GB的RAM,您可以遵循 如何安装和设置Python 3的本地编程环境来配置您所需的一切。

步骤 1 – 创建您的项目和安装依赖

让我们为这个项目创建一个工作区,并安装您需要的依赖,您将把工作区称为pytorch:

1mkdir ~/pytorch

导航到pytorch目录:

1cd ~/pytorch

然后为项目创建一个新的虚拟环境:

1python3 -m venv pytorch

激活你的环境:

1source pytorch/bin/activate

然后安装 PyTorch。在 macOS 上,使用以下命令安装 PyTorch:

1python -m pip install torch==1.4.0 torchvision==0.5.0

在 Linux 和 Windows 上,使用以下命令为仅 CPU 构建:

1pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
2pip install torchvision

随着依赖的安装,您现在将建立您的第一个神经网络。

步骤2:构建一个你好世界神经网络

在这个步骤中,你将建立你的第一个神经网络并训练它. 你将了解在Pytorch的两个子库,torch.nn用于神经网络操作和torch.optim用于神经网络优化器。 为了了解什么是优化器,你还将了解一个名为 gradient descent 的算法。 在本教程中,你将使用以下五步来构建和训练模型:

  1. 建立计算图表
  2. 设置优化器
  3. 设置标准
  4. 设置数据
  5. 训练模型

在本教程的第一个部分中,您将建立一个小型模型,具有可管理的数据集,开始创建一个新的文件 step_2_helloworld.py,使用 nano 或您最喜欢的文本编辑器:

1nano step_2_helloworld.py

现在你将写一个短的18行片段,训练一个小型模型. 开始通过导入几个PyTorch实用程序:

1[label step_2_helloworld.py]
2import torch
3import torch.nn as nn
4import torch.optim as optim

在这里,您将 PyTorch 库代替为几个常见的捷径:

  • torch 包含所有 PyTorch 实用程序. 然而,常规 PyTorch 代码包括一些额外的导入。 我们遵循相同的惯例,这样你就可以在网上理解 PyTorch 教程和随机代码片段
  • torch.nn 包含用于构建神经网络的实用程序。 这通常被称为 nn.
  • torch.optim 包含培训实用程序。

接下来,定义神经网络、培训工具和数据集:

1[label step_2_helloworld.py]
2. . .
3net = nn.Linear(1, 1)  # 1. Build a computation graph (a line!)
4optimizer = optim.SGD(net.parameters(), lr=0.1)  # 2. Setup optimizers
5criterion = nn.MSELoss()  # 3. Setup criterion
6x, target = torch.randn((1,)), torch.tensor([0.])  # 4. Setup data
7. . .

在这里,您可以定义任何深度学习培训脚本的几个必要部分:

*'net =.'定义"神经网络". 在这种情况下,模型是"y = m * x"的正线;参数"nn.Linear(1,1)"是您的正线斜线. 这个_模型参数_nn.Linear(1,1)'将在培训期间更新。 注意torch.nn'(用nn'来取用)包括许多深层学习操作,例如此处使用的完全连接的地层(nn.Linear')和进取地层(nn.Conv2d')。 (- *优化者=.'界定了优化者。 这个优化器决定神经网络如何学习. 在写出几行代码后,我们将更详细地讨论优化者. 请注意,torch.optim'(被取名为optim')包括许多你能够使用的优化器。 (_) ) *标准=.'界定了损失。 简言之,损失定义了_什么_ 您的模型试图最小化 。 对于一行的基本模型,目标是将您一行预测的y-值与训练集中的实际y-值之间的相差最小. 注意torch.nn'(用`nn'来取用) 包括您可以使用的许多其他损失函数。

  • x,目标=.' 定义您的"数据集". 现在,数据集只是一个坐标——一个x值和一个y值。 在此情况下, " torch " 包本身提供[tensor' (https://pytorch.org/docs/stable/tensors.html),以创建新的收音机,而`randn'则以随机值创建收取机。 ( (英语)

最后,通过对数据集进行十次迭代来训练模型,每次调整模型的参数:

 1[label step_2_helloworld.py]
 2. . .
 3# 5. Train the model
 4for i in range(10):
 5    output = net(x)
 6    loss = criterion(output, target)
 7    print(round(loss.item(), 2))
 8
 9    net.zero_grad()
10    loss.backward()
11    optimizer.step()

你的总体目标是通过调整线的斜坡来最大限度地减少损失。 为了实现这一目标,本培训代码实施了一个名为 gradient descent 的算法。 降级降级的直觉是这样的: 想象一下你正向下看碗。 碗上有许多点,每个点都与不同的参数值相匹配。 碗本身就是损失表面: 碗的中间――最低点――表示有最低损失的最佳模型。

找到最低损失的最佳模型:

  1. 使用 net = nn.Linear(1, 1) 初始化一个随机模型. 这相当于在碗上选择一个随机点
  2. for i in range(10) 循环中,你开始训练。 这相当于向碗的中心迈进
  3. 每个步骤的方向是由梯度指定的。 您将在这里跳过正式证据,但总而言之,负梯度指向碗中最低点
  4. optimizer =... 中,您指定了 step 尺寸。 这决定了每个步骤的尺寸

只需十个步骤,你可以到达碗的中心,最好的可能的模型与最低可能的损失. 对于降级下降的可视化,请参阅Distill的 为什么动力真的工作,页面顶部的第一个数字。

这个代码的最后三行也很重要:

  • net.zero_grad 清除从上一步迭代中可能剩下的所有梯度
  • loss.backward 计算新的梯度
  • optimizer.step 使用这些梯度来采取步骤。 请注意,您没有自己计算梯度。

這現在結束了你的「Hello world」神經網絡. 保存並關閉你的檔案。

重复检查你的脚本是否匹配 step_2_helloworld.py

1python step_2_helloworld.py

你的脚本将产生如下:

 1[secondary_label Output]
 20.33
 30.19
 40.11
 50.07
 60.04
 70.02
 80.01
 90.01
100.0
110.0

请注意,您的损失不断减少,这表明您的模型正在学习,在使用 PyTorch 时还需要注意两个其他实施细节:

  1. PyTorch 使用torch.Tensor 来存储所有数据和参数. 在这里,torch.randn 会生成随机值的 tensor,以提供的形状。例如,torch.randn(1, 2)) 会创建 1x2 tensor 或 2 维的行 vector
  2. PyTorch 支持各种优化器。 此功能为torch.optim.SGD,也被称为stochastic gradient descent (SGD)。 简而言之,这是本教程中描述的算法,您在其中采取了步骤,以达到最佳值。 有更多参与的优化器在 SGD 上添加额外的功能。 也有许多损失,而torch.nn.MSELoss 只是其中之一。

在下一步,您将用神经网络替换这个小型模型,玩具数据集将用常用的机器学习基准。

步骤3 – 在手写数字上训练你的神经网络

然而,为了更好地了解 PyTorch 的优势,您现在将使用torch.nn.functional构建一个深度神经网络,其中包含更多的神经网络操作,以及torchvision.datasets,支持您可以使用的许多数据集。

您将使用 convolutions,这些是模式寻找器. 对于图像,convolutions 会寻找意义的不同级别的 2D 模式:直接应用于图像的 Convolutions 正在寻找较低级别的功能,如边缘。

现在,您将通过定义一个稍微更复杂的模型来扩展您所建造的第一个 PyTorch 模型,您的神经网络现在将包含两个转换和一个完全连接的层,以处理图像输入。

开始创建一个新的文件 step_3_mnist.py,使用你的文本编辑器:

1nano step_3_mnist.py

您将遵循与之前相同的五步算法:

  1. 建立计算图表
  2. 设置优化器
  3. 设置标准
  4. 设置数据
  5. 训练模型

首先,定义你的深度神经网络. 请注意,这是你可能在MNIST上发现的其他神经网络的平行版本,这是故意的,所以你可以在笔记本电脑上训练你的神经网络:

 1[label step_3_mnist.py]
 2import torch
 3import torch.nn as nn
 4import torch.optim as optim
 5import torch.nn.functional as F
 6
 7from torchvision import datasets, transforms
 8from torch.optim.lr_scheduler import StepLR
 9
10# 1. Build a computation graph
11class Net(nn.Module):
12    def __init__(self):
13        super(Net, self).__init__()
14        self.conv1 = nn.Conv2d(1, 32, 3, 1)
15        self.conv2 = nn.Conv2d(32, 64, 3, 1)
16        self.fc = nn.Linear(1024, 10)
17
18    def forward(self, x):
19        x = F.relu(self.conv1(x))
20        x = F.relu(self.conv2(x))
21        x = F.max_pool2d(x, 1)
22        x = torch.flatten(x, 1)
23        x = self.fc(x)
24        output = F.log_softmax(x, dim=1)
25        return output
26net = Net()
27. . .

在这里,你定义了一个神经网络类,继承从nn.Module。神经网络中的所有操作(包括神经网络本身)必须继承从nn.Module

  1. 在构建器中,定义你的网络所需的任何操作,在这种情况下,你有两个汇率和一个完全连接的层。(一个提示:构建器总是从super().__init__()开始) PyTorch 预计在将模块(例如nn.Conv2d)分配到实例属性(self.conv1)之前将母类类进行初始化。 2 在前进方法中,运行初始化的操作。

这种神经网络使用几种不同的操作:

  • nn.Conv2d: A convolution. Convolutions search for patterns in the image. Earlier convolutions look for "low-level" patterns like edges. Later convolutions in the network look for "high-level" patterns like legs on a dog, or ears.
  • nn.Linear: A fully connected layer. Fully connected layers relate all input features to all output dimensions.
  • F.relu, F.max_pool2d:这些是非线性类型。 (非线性是任何非线性函数)。 relu是函数 f(x) = max(x, 0max_pool在每个值中占据最大值。 在这种情况

其次,就像之前一样,定义优化器。这次,您将使用不同的优化器和不同的 hyper-parameter 设置。 超级参数配置培训,而培训调整模型参数。 这些超级参数设置是从 PyTorch MNIST 示例中取出的:

1[label step_3_mnist.py]
2. . .
3optimizer = optim.Adadelta(net.parameters(), lr=1.)  # 2. Setup optimizer
4. . .

第三,与以往不同,你现在将使用不同的损失. 此损失用于 classification 问题,其中您的模型的输出是类索引. 在此特定示例中,模型将输出输入图像中包含的数字(可能有 0 至 9 之间的任何数字):

1[label step_3_mnist.py]
2. . .
3criterion = nn.NLLLoss()  # 3. Setup criterion
4. . .

第四,设置数据. 在这种情况下,您将设置一个名为 MNIST的数据集,其中包含手写数字。深度学习101教程通常使用此数据集。

 1[label step_3_mnist.py]
 2. . .
 3# 4. Setup data
 4transform = transforms.Compose([
 5    transforms.Resize((8, 8)),
 6    transforms.ToTensor(),
 7    transforms.Normalize((0.1307,), (0.3081,))
 8])
 9train_dataset = datasets.MNIST(
10    'data', train=True, download=True, transform=transform)
11train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=512)
12. . .

在这里,您通过重新调整图像,将图像转换为 PyTorch 压缩器,并将压缩器正常化为平均值 0 和差异值 1。

在接下来的两个行中,您将设置train=True,因为这是训练数据集和download=True,以便您下载数据集,如果它还没有。

batch_size=512决定了网络一次训练的图像数目;除非大批量(例如,数十万),更大的批量更适合大约更快的训练。

第五,训练模型 在下面的代码块中,你会做出最小的修改,而不是在相同的样本上运行十次,你现在会对所提供的数据集中的所有样本进行一次迭代。

 1[label step_3_mnist.py]
 2. . .
 3# 5. Train the model
 4for inputs, target in train_loader:
 5    output = net(inputs)
 6    loss = criterion(output, target)
 7    print(round(loss.item(), 2))
 8
 9    net.zero_grad()
10    loss.backward()
11    optimizer.step()
12. . .

保存并关闭您的文件。

检查你的脚本是否匹配 step_3_mnist.py

1python step_3_mnist.py

你的脚本将产生如下:

 1[secondary_label Output]
 22.31
 32.18
 42.03
 51.78
 61.52
 71.35
 81.3
 91.35
101.07
111.0
12...
130.21
140.2
150.23
160.12
170.12
180.12

请注意,最终损失低于初始损失值的10%,这意味着您的神经网络正在正确训练。

然而,对于0.12的损失很难推理:我们不知道0.12是否是。 为了评估您的模型的性能,您接下来计算这个分类模型的准确性。

步骤4:评估你的神经网络

以前,您计算了数据集的 train 分割值,但是,保持数据集的单独 validation 分割是很好的做法。您使用此验证分割来计算您的模型的准确性,但是,您不能用它来进行培训。接下来,您将设置验证数据集并评估您的模型。

首先,將你的「step_3_mnist.py」檔案複製為「step_4_eval.py」。

1cp step_3_mnist.py step_4_eval.py
2nano step_4_eval.py

首先,设置验证数据集:

1[label step_4_eval.py]
2. . .
3train_loader = ...
4val_dataset = datasets.MNIST(
5    'data', train=False, download=True, transform=transform)
6val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=512)
7. . .

在你的文件末尾,在训练循环后,添加一个验证循环:

 1[label step_4_eval.py]
 2    . . .
 3    optimizer.step()
 4
 5correct = 0.
 6net.eval()
 7for inputs, target in val_loader:
 8    output = net(inputs)
 9    _, pred = output.max(1)
10    correct += (pred == target).sum()
11accuracy = correct / len(val_dataset) * 100.
12print(f'{accuracy:.2f}% correct')

在这里,验证循环执行几个操作来计算准确性:

  • 运行 net.eval() 确保您的神经网络处于评估模式,并准备进行验证。 若干操作在评估模式下运行不同于在训练模式下运行
  • val_loader 中对所有输入和标签进行迭代
  • 运行模型 net(inputs) 以获得每个类的概率
  • 查找具有最高概率 output.max(1) 的类别。 output 是对 n 样本和 k 类别的尺寸 (n, k) 的 tensor。 1 意味着您在指数 1 尺寸 一起计算最大值。

保存并关闭您的文件。

双重检查你的脚本是否匹配 step_4_eval.py

1python step_4_eval.py

注意具体的损失值和最终准确性可能会有所不同:

1[secondary_label Output]
22.31
32.21
4...
50.14
60.2
789% correct

您现在已经训练了您的第一个深度神经网络. 您可以通过调整训练的超级参数进行进一步的修改和改进:这包括不同数量的时代,学习率和不同的优化器。 我们包括配对超级参数的样本脚本; 这个脚本训练相同的神经网络,但为10个时代,获得97%的准确性。

深度学习的风险

一个Gotcha是,深度学习并不总是获得最先进的结果。深度学习在功能丰富、数据丰富的场景中工作得很好,但相反,在数据稀缺、功能稀缺的模式中表现不好。

另一个Gotcha是,深度学习不被理解得很好. 没有准确性,优化或甚至融合的保证。 另一方面,经典机器学习技术被研究得很好,并且相对易于解释。 再次,有积极的研究来解决深度学习中的这种缺乏解释性。 您可以在什么解释性AI无法解释(以及我们如何修复)中阅读更多。

最重要的是,深度学习缺乏可解释性导致被忽视的偏见. 例如,来自加州大学伯克利大学的研究人员能够在标题中显示模型的性别偏见(Women also Snowboard](https://arxiv.org/abs/1803.09797))。 其他研究努力集中在机器学习中的社会问题上(公平](https://en.wikipedia.org/wiki/Fairness_(machine_learning)) 鉴于这些问题正在进行积极的研究,很难在模型中推荐处方偏见的诊断。

结论

PyTorch 是深度学习框架,适用于爱好者和研究人员,为了了解 PyTorch,您已经训练了一个深度神经网络,并学习了几种方法和技巧来定制深度学习。

您还可以使用预先构建的神经网络架构,而不是建立自己的。 以下是可选的部分链接: Google Colab 上使用现有神经网络架构,您可以尝试。

查看我们的其他文章,深入了解机器学习和相关领域:

Published At
Categories with 技术
comments powered by Disqus