PyTorch 教程

Pytorch 教程摘要

在本 pytorch 教程中,您将从头开始学习所有概念。本教程涵盖从基础到高级的主题,如 pytorch 定义、pytorch 的优缺点、比较、安装、pytorch 框架、回归和图像分类。本 pytorch 教程完全免费。

什么是 PyTorch?

PyTorch 是一个基于 Torch 的开源机器学习库,用于自然语言处理 Python。它与 NumPy 类似,但具有强大的 GPU 支持。它提供动态计算图,您可以在 autograd 的帮助下随时修改。PyTorch 也比其他一些框架更快。它由 Facebook 的 AI 研究小组于 2016 年开发。

PyTorch 的优点和缺点

以下是 PyTorch 的优点和缺点:

PyTorch 的优势

  1. 简单库
    PyTorch 代码很简单。它很容易理解,你可以立即使用该库。例如,看看下面的代码片段:
class Net(torch.nn.Module):
   def __init__(self):
       super(Net, self).__init__()
       self.layer = torch.nn.Linear(1, 1)

   def forward(self, x):
       x = self.layer(x)      
       return x

如上所述,您可以轻松定义网络模型,并且无需太多训练即可快速理解代码。

  1. 动态计算图

动态计算图

图片来源:使用 PyTorch 探索深度学习

Pytorch 提供动态计算图 (DAG)。计算图是一种在图形模型或理论中表达数学表达式的方式,例如节点和边。节点将执行数学运算,而边是一个张量,将被输入到节点中并以张量形式承载节点的输出。

DAG 是一种具有任意形状的图,能够在不同的输入图之间进行操作。每次迭代都会创建一个新图。因此,可以具有相同的图结构,也可以创建具有不同操作的新图,或者我们可以将其称为动态图。

  1. 更好的性能

社区和研究人员对框架进行基准测试和比较,看看哪一个更快。GitHub 存储库 深度学习框架和 GPU 的基准测试 报道称,PyTorch 在每秒处理图像方面比其他框架更快。

如下图所示,与 vgg16 和 resnet152 的比较图

PyTorch 的优势

PyTorch 的优势

  1. 本地人 Python

PyTorch 更基于 Python。例如,如果你想训练一个模型,你可以使用原生控制流(如循环和递归),而无需添加更多特殊变量或会话即可运行它们。这对训练过程非常有帮助。

Pytorch 还实现了命令式编程,而且它绝对更灵活。因此,可以在计算过程中打印出张量值。

PyTorch 的缺点

PyTorch 需要第三方应用程序来实现可视化。它还需要一个 API 服务器来实现生产。

接下来在本 PyTorch 教程中,我们将了解 PyTorch 和 TensorFlow 之间的区别。

PyTorch 与 Tensorflow

产品型号 PyTorch Tensorflow
模型定义 该模型在子类中定义,并提供易于使用的包 该模型定义很多,你需要了解语法
GPU支持
图形类型 动态 静止
工具 没有可视化工具 您可以使用 Tensorboard 可视化工具
社区 社区仍在不断壮大 大型活跃社区

安装 PyTorch

Linux

在 Linux 中安装它很简单。您可以选择使用虚拟环境,也可以直接使用 root 权限安装。在终端中输入此命令

pip3 install --upgrade torch torchvision

AWS Sagemaker

Sagemaker 是 Amazon 网络服务 它提供强大的机器学习引擎,并预装了深度学习配置,供数据科学家或开发人员构建、训练和部署任何规模的模型。

首先打开 Amazon Sagemaker 控制台并单击创建笔记本实例并填写笔记本的所有详细信息。

AWS Sagemaker

下一步,单击“打开”以启动您的笔记本实例。

AWS Sagemaker

最后, Jupyter,单击新建并选择 conda_pytorch_p36,您就可以使用安装了 Pytorch 的笔记本实例了。

接下来在本 PyTorch 教程中,我们将学习 PyTorch 框架基础知识。

PyTorch 框架基础

在深入研究之前,让我们先了解一下 PyTorch 的基本概念。PyTorch 对每个变量都使用 Tensor,类似于 numpy 的 ndarray,但支持 GPU 计算。在这里我们将解释网络模型、损失函数、反向传播和优化器。

网络模型

可以通过子类化 torch.nn 来构建网络。主要有 2 个部分,

  1. 第一部分是定义你将使用的参数和层
  2. 第二部分是主要任务,称为前向过程,它将接受输入并预测输出。
Import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
 def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(3, 20, 5)
        self.conv2 = nn.Conv2d(20, 40, 5)
self.fc1 = nn.Linear(320, 10)

def forward(self, x):
       x = F.relu(self.conv1(x))
       x = F.relu(self.conv2(x))
       x = x.view(-1, 320)
       x = F.relu(self.fc1(x))
       return F.log_softmax(x)

net = Model()

如上所示,您创建了一个名为 Model 的 nn.Module 类。它包含 2 个 Conv2d 层和一个线性层。第一个 conv2d 层的输入为 3,输出形状为 20。第二层将接受 20 的输入,并将产生 40 的输出形状。最后一层是形状为 320 的完全连接层,将产生 10 的输出。

前向过程将接受 X 的输入并将其馈送到 conv1 层并执行 ReLU 函数,

类似地,它还将馈送 conv2 层。之后,x 将被重塑为 (-1, 320) 并馈送至最后的 FC 层。在发送输出之前,您将使用 softmax 激活函数。

后向过程由 autograd 自动定义,因此您只需定义前向过程。

损失函数

损失函数用于衡量预测模型预测预期结果的能力。PyTorch 在 torch.nn 模块中已经有许多标准损失函数。例如,您可以使用交叉熵损失来解决多类 PyTorch 分类问题。定义损失函数和计算损失很容易:

loss_fn = nn.CrossEntropyLoss()

#training process
loss = loss_fn(out, target)

使用 PyTorch 可以轻松使用自己的损失函数计算。

反向传播

要执行反向传播,只需调用 los.backward()。将计算误差,但请记住使用 zero_grad() 清除现有梯度

net.zero_grad() # to clear the existing gradient
loss.backward() # to perform backpropragation

优化

torch.optim 提供了常用的优化算法,你可以用一个简单的步骤来定义一个优化器:

optimizer = torch.optim.SGD(net.parameters(), lr = 0.01, momentum=0.9)

你需要传递网络模型参数和学习率,以便在每次迭代后反向传播过程之后更新参数。

使用 PyTorch 进行简单回归

让我们通过 PyTorch 示例学习简单的回归:

步骤1)创建我们的网络模型

我们的网络模型是一个简单的线性层,其输入和输出形状为 1。

from __future__ import print_function

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable

class Net(nn.Module):
   def __init__(self):
       super(Net, self).__init__()
       self.layer = torch.nn.Linear(1, 1)

   def forward(self, x):
       x = self.layer(x)      
       return x

net = Net()
print(net)

网络输出应该是这样的

Net(
  (hidden): Linear(in_features=1, out_features=1, bias=True)
)

步骤2)测试数据

在开始训练过程之前,你需要了解我们的数据。你创建一个随机函数来测试我们的模型。Y = x3 sin(x)+ 3x+0.8 rand(100)

# Visualize our data
import matplotlib.pyplot as plt
import numpy as np

x = np.random.rand(100)
y = np.sin(x) * np.power(x,3) + 3*x + np.random.rand(100)*0.8

plt.scatter(x, y)
plt.show()

以下是我们的函数的散点图:

使用 PyTorch 绘制简单回归的散点图

在开始训练过程之前,您需要将 numpy 数组转换为 Torch 和 autograd 支持的变量,如下面的 PyTorch 回归示例所示。

# convert numpy array to tensor in shape of input size
x = torch.from_numpy(x.reshape(-1,1)).float()
y = torch.from_numpy(y.reshape(-1,1)).float()
print(x, y)

步骤 3)优化器和损失

接下来,您应该为我们的训练过程定义优化器和损失函数。

# Define Optimizer and Loss Function
optimizer = torch.optim.SGD(net.parameters(), lr=0.2)
loss_func = torch.nn.MSELoss()

步骤4)训练

现在让我们开始训练过程。在 250 个周期内,您将迭代我们的数据以找到超参数的最佳值。

inputs = Variable(x)
outputs = Variable(y)
for i in range(250):
   prediction = net(inputs)
   loss = loss_func(prediction, outputs) 
   optimizer.zero_grad()
   loss.backward()        
   optimizer.step()       

   if i % 10 == 0:
       # plot and show learning process
       plt.cla()
       plt.scatter(x.data.numpy(), y.data.numpy())
       plt.plot(x.data.numpy(), prediction.data.numpy(), 'r-', lw=2)
       plt.text(0.5, 0, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 10, 'color':  'red'})
       plt.pause(0.1)

plt.show()

步骤5)结果

如下所示,您已成功使用神经网络执行了 PyTorch 回归。实际上,在每次迭代中,图中的红线都会更新并改变其位置以适应数据。但在这张图片中,它仅向您显示最终结果,如下面的 PyTorch 示例所示:

简单回归结果的散点图

PyTorch 图像分类示例

学习基础知识的流行方法之一 深入学习 是MNIST数据集,是深度学习中的“Hello World”,数据集包含0-9的手写数字,共有60,000个训练样本和10,000个测试样本,这些样本已经标注,大小为28×28像素。

使用 PyTorch 进行图像分类

步骤1)预处理数据

在此 PyTorch 分类示例的第一步中,您将使用 torchvision 模块加载数据集。

在开始训练过程之前,您需要了解数据。Torchvision 将加载数据集并根据网络的适当要求(例如形状和规范化图像)转换图像。

import torch
import torchvision
import numpy as np
from torchvision import datasets, models, transforms

# This is used to transform the images to Tensor and normalize it
transform = transforms.Compose(
   [transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

training = torchvision.datasets.MNIST(root='./data', train=True,
                                       download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(training, batch_size=4,
                                         shuffle=True, num_workers=2)

testing = torchvision.datasets.MNIST(root='./data', train=False,
                                      download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(testing, batch_size=4,
                                        shuffle=False, num_workers=2)

classes = ('0', '1', '2', '3',
          '4', '5', '6', '7', '8', '9')
         
import matplotlib.pyplot as plt
import numpy as np

#create an iterator for train_loader
# get random training images
data_iterator = iter(train_loader)
images, labels = data_iterator.next()

#plot 4 images to visualize the data
rows = 2
columns = 2
fig=plt.figure()
for i in range(4):
   fig.add_subplot(rows, columns, i+1)
   plt.title(classes[labels[i]])
   img = images[i] / 2 + 0.5     # this is for unnormalize the image
   img = torchvision.transforms.ToPILImage()(img)
   plt.imshow(img)
plt.show()

转换函数将图像转换为张量并规范化该值。函数 torchvision.transforms.MNIST 将下载目录中的数据集(如果不可用),必要时设置数据集进行训练并执行转换过程。

要可视化数据集,您可以使用 data_iterator 获取下一批图像和标签。您可以使用 matplot 绘制这些图像及其相应的标签。正如您在下方看到的我们的图像及其标签。

PyTorch 图像分类示例

步骤2)网络模型配置

现在在这个 PyTorch 示例中,您将为 PyTorch 图像分类创建一个简单的神经网络。

这里我们介绍在 PyTorch 中创建网络模型的另一种方法。我们将使用 nn.Sequential 来创建序列模型,而不是创建 nn.Module 的子类。

import torch.nn as nn

# flatten the tensor into 
class Flatten(nn.Module):
   def forward(self, input):
       return input.view(input.size(0), -1)

#sequential based model
seq_model = nn.Sequential(
           nn.Conv2d(1, 10, kernel_size=5),
           nn.MaxPool2d(2),
           nn.ReLU(),
           nn.Dropout2d(),
           nn.Conv2d(10, 20, kernel_size=5),
           nn.MaxPool2d(2),
           nn.ReLU(),
           Flatten(),
           nn.Linear(320, 50),
           nn.ReLU(),
           nn.Linear(50, 10),
           nn.Softmax(),
         )

net = seq_model
print(net)

这是我们的网络模型的输出

Sequential(
  (0): Conv2d(1, 10, kernel_size=(5, 5), stride=(1, 1))
  (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (2): ReLU()
  (3): Dropout2d(p=0.5)
  (4): Conv2d(10, 20, kernel_size=(5, 5), stride=(1, 1))
  (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (6): ReLU()
  (7): Flatten()
  (8): Linear(in_features=320, out_features=50, bias=True)
  (9): ReLU()
  (10): Linear(in_features=50, out_features=10, bias=True)
  (11): Softmax()
)

网络解释

  1. 顺序为:第一层为 Conv2D 层,输入形状为 1,输出形状为 10,内核大小为 5
  2. 接下来,你有一个 MaxPool2D 层
  3. ReLU 激活函数
  4. 一个 Dropout 层来删除低概率值。
  5. 然后是第二个 Conv2d,其输入形状为最后一层的 10,输出形状为 20,内核大小为 5
  6. 接下来是 MaxPool2d 层
  7. ReLU 激活函数。
  8. 之后,你需要将张量压平,然后再将其输入到线性层
  9. 线性层将使用 softmax 激活函数将我们的输出映射到第二个线性层

步骤3)训练模型

在开始训练过程之前,需要设置标准和优化函数。

对于标准,您将使用 CrossEntropyLoss。对于优化器,您将使用学习率为 0.001 且动量为 0.9 的 SGD,如下面的 PyTorch 示例所示。

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

前向过程将获取输入形状并将其传递到第一个 conv2d 层。然后从那里,它将被输入到 maxpool2d 中,最后放入 ReLU 激活函数中。第二个 conv2d 层中将发生相同的过程。之后,输入将被重塑为 (-1,320) 并输入到 fc 层以预测输出。

现在,您将开始训练过程。您将迭代我们的数据集 2 次或以 2 个时期为一个时期,并打印出每 2000 个批次的当前损失。

for epoch in range(2): 

#set the running loss at each epoch to zero
   running_loss = 0.0
# we will enumerate the train loader with starting index of 0
# for each iteration (i) and the data (tuple of input and labels)
   for i, data in enumerate(train_loader, 0):
       inputs, labels = data

# clear the gradient
       optimizer.zero_grad()

#feed the input and acquire the output from network
       outputs = net(inputs)

#calculating the predicted and the expected loss
       loss = criterion(outputs, labels)

#compute the gradient
       loss.backward()

#update the parameters
       optimizer.step()

       # print statistics
       running_loss += loss.item()
       if i % 1000 == 0:
           print('[%d, %5d] loss: %.3f' %
                 (epoch + 1, i + 1, running_loss / 1000))
           running_loss = 0.0

在每个时期,枚举器将获得下一个输入元组和相应的标签。在将输入馈送到网络模型之前,我们需要清除之前的梯度。这是必需的,因为在后向过程(反向传播过程)之后,梯度将被累积而不是被替换。然后,我们将计算预测输出与预期输出之间的损失。之后,我们将进行反向传播来计算梯度,最后,我们将更新参数。

以下是训练过程的输出

[1, 	1] loss: 0.002
[1,  1001] loss: 2.302
[1,  2001] loss: 2.295
[1,  3001] loss: 2.204
[1,  4001] loss: 1.930
[1,  5001] loss: 1.791
[1,  6001] loss: 1.756
[1,  7001] loss: 1.744
[1,  8001] loss: 1.696
[1,  9001] loss: 1.650
[1, 10001] loss: 1.640
[1, 11001] loss: 1.631
[1, 12001] loss: 1.631
[1, 13001] loss: 1.624
[1, 14001] loss: 1.616
[2, 	1] loss: 0.001
[2,  1001] loss: 1.604
[2,  2001] loss: 1.607
[2,  3001] loss: 1.602
[2,  4001] loss: 1.596
[2,  5001] loss: 1.608
[2,  6001] loss: 1.589
[2,  7001] loss: 1.610
[2,  8001] loss: 1.596
[2,  9001] loss: 1.598
[2, 10001] loss: 1.603
[2, 11001] loss: 1.596
[2, 12001] loss: 1.587
[2, 13001] loss: 1.596
[2, 14001] loss: 1.603

步骤4)测试模型

在训练我们的模型后,您需要使用其他图像集进行测试或评估。

我们将为 test_loader 使用一个迭代器,它将生成一批图像和标签,并传递给训练好的模型。预测输出将显示并与预期输出进行比较。

#make an iterator from test_loader
#Get a batch of training images
test_iterator = iter(test_loader)
images, labels = test_iterator.next()

results = net(images)
_, predicted = torch.max(results, 1)

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

fig2 = plt.figure()
for i in range(4):
   fig2.add_subplot(rows, columns, i+1)
   plt.title('truth ' + classes[labels[i]] + ': predict ' + classes[predicted[i]])
   img = images[i] / 2 + 0.5     # this is to unnormalize the image
   img = torchvision.transforms.ToPILImage()(img)
   plt.imshow(img)
plt.show()

PyTorch 图像分类示例

结语

  • PyTorch 是一个基于 Torch 的开源 机器学习 图书馆 自然语言处理 运用 Python.
  • PyTorch 的优点:1)简单的库,2)动态计算图,3)更好的性能,4)原生 Python
  • PyTorch 对每个变量使用 Tensor,类似于 numpy 的 ndarray,但具有 GPU 计算支持。
  • 学习深度学习基础知识的流行方法之一是使用 MNIST 数据集。