1.Pytorch介绍
PyTorch 是由 Facebook 创建和发布的用于深度学习计算的 Python 库。它起源于早期的库 Torch 7,但完全重写。
它是两个最受欢迎的深度学习库之一。PyTorch 是一个完整的库,能够训练深度学习模型以及在推理模式下运行模型,并支持使用 GPU 进行更快的训练和推理。这是一个我们不能忽视的平台。
您可以使用 pip
安装 PyTorch 。在撰写本文时,PyTorch 的最新版本是 2.0。每个平台(包括 Windows、Linux 和 macOS)都有预构建的 PyTorch。在有效的 Python 环境中,应该照顾好这一点, pip
以便在您的平台中为您提供最新版本。
除了 PyTorch 之外,还有通常与 PyTorch 一起使用的 torchvision
库。它提供了许多有用的功能来帮助计算机视觉项目。
sudo pip install torch torchvision
这样安装可能默认安装最新版本,也可以通过pip自定义进行安装 Previous PyTorch Versions | PyTorch
可选cuda版本或者使用cpu还有平台版本(windows、linux、mac)
使用示例
# Example of PyTorch library
import torch
# declare two symbolic floating-point scalars
a = torch.tensor(1.5)
b = torch.tensor(2.5)
# create a simple symbolic expression using the add function
c = torch.add(a, b)
print(c)
查看torch版本
import torch
print(torch.__version__)
2.构建第一个多层感知机模型
深度学习是关于构建大规模神经网络。神经网络最简单的形式称为多层感知器模型。神经网络的构建块是人工神经元或感知器。这些是简单的计算单元,具有加权输入信号并使用激活函数产生输出信号。
感知器被排列成网络。一排感知器称为一层,一个网络可以有多个层。网络中感知器的架构通常称为网络拓扑。配置完成后,需要在数据集上训练神经网络。神经网络的经典且仍然首选的训练算法称为随机梯度下降。
PyTorch 允许您在极少的代码行中开发和评估深度学习模型。
在下文中,您的目标是使用 PyTorch 开发您的第一个神经网络。使用 UCI 机器学习存储库中的标准二进制(两类)分类数据集,例如 Pima Indians 数据集。
为了简单起见,网络模型只是几层完全连接的感知器。在此特定模型中,数据集有 12 个输入或预测变量,输出是 0 或 1 的单个值。因此,网络模型应有 12 个输入(第一层)和 1 个输出(最后一层)。您的第一个模型将按如下方式构建:
import torch.nn as nnmodel = nn.Sequential(nn.Linear(8, 12),nn.ReLU(),nn.Linear(12, 8),nn.ReLU(),nn.Linear(8, 1),nn.Sigmoid()
)
print(model)
这是一个具有 3 个全连接层的网络。每个层都是使用以下 nn.Linear(x, y)
语法在 PyTorch 中创建的,第一个参数是该层的输入数,第二个参数是输出数。在每层之间,使用整流线性激活,但在输出端,应用 Sigmoid 激活,使输出值介于 0 和 1 之间。这是一个典型的网络。深度学习模型就是在模型中有很多这样的层。
3.训练Pytorch模型
在 PyTorch 中构建神经网络并不能说明应该如何为特定作业训练模型。事实上,正如超参数所描述的那样,这方面有许多变化。在 PyTorch 或所有深度学习模型中,您需要决定以下有关如何训练模型:
- 什么是数据集,特别是输入和目标的外观
- 什么是损失函数来评估模型与数据的拟合优度
- 训练模型的优化算法是什么,优化算法的参数,如学习率和学习次数
使用了皮马印第安人数据集,所有输入都是数字。这将是最简单的情况,因为您不需要对数据进行任何预处理,因为神经网络可以轻松处理数字。
由于是二元分类问题,损失函数应为二元交叉熵。这意味着模型输出的目标值为分类结果的 0 或 1。但实际上,该模型可能会输出介于两者之间的任何内容。它越接近目标值越好(即损耗越低)。
梯度下降是优化神经网络的算法。梯度下降有许多变化,亚当是最常用的一种。
实现上述所有内容,以及上一课中构建的模型,以下是训练过程的代码:
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optimdataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',')
X = dataset[:,0:8]
y = dataset[:,8]
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)loss_fn = nn.BCELoss() # binary cross-entropy
optimizer = optim.Adam(model.parameters(), lr=0.001)n_epochs = 100
batch_size = 10
for epoch in range(n_epochs):for i in range(0, len(X), batch_size):Xbatch = X[i:i+batch_size]y_pred = model(Xbatch)ybatch = y[i:i+batch_size]loss = loss_fn(y_pred, ybatch)optimizer.zero_grad()loss.backward()optimizer.step()print(f'Finished epoch {epoch}, latest loss {loss}')
上面的for循环是获取一批数据并馈入模型。然后观察模型的输出并计算损失函数。基于损失函数,优化器将对模型进行一步微调,使其能够更好地匹配训练数据。经过多个更新步骤后,模型应该足够接近训练数据,以便能够高精度地预测目标。
运行上面的训练循环,观察随着训练循环的进行,损失如何减少。
4.使用Pytorch模型推理
经过训练的神经网络模型是一种记住输入和目标如何相关的模型。然后,该模型可以在给定另一个输入的情况下预测目标。
在 PyTorch 中,经过训练的模型可以像函数一样运行。假设您在上一课中训练了模型,您可以按如下方式简单地使用它:
i = 5
X_sample = X[i:i+1]
y_pred = model(X_sample)
print(f"{X_sample[0]} -> {y_pred[0]}")
但实际上,运行推理的更好方法如下:
i = 5
X_sample = X[i:i+1]
model.eval()
with torch.no_grad():y_pred = model(X_sample)
print(f"{X_sample[0]} -> {y_pred[0]}")
某些模型在训练和推理之间会有不同的行为。的 model.eval()
表示模型的目的是运行模型进行推理。该行 with torch.no_grad()
用于创建运行模型的上下文,以便 PyTorch 知道不需要计算梯度。这样可以消耗更少的资源。
这也是评估模型的方式。该模型输出一个介于 0 和 1 之间的 sigmoid 值。您可以通过将值四舍五入到最接近的整数(即布尔标签)来解释该值。比较舍入后的预测与目标匹配的频率,可以为模型分配准确率百分比,如下所示:
model.eval()
with torch.no_grad():y_pred = model(X)
accuracy = (y_pred.round() == y).float().mean()
print(f"Accuracy {accuracy}")
运行上面的代码,看看你得到的准确性是多少。您应该达到大约 75%。
5.使用Torchvision加载数据
Torchvision 是 PyTorch 的姊妹库。在这个库中,有专门用于图像和计算机视觉的函数。如您所料,有一些功能可以帮助您读取图像或调整对比度。但可能最重要的是提供一个简单的接口来获取一些图像数据集。
您将构建一个深度学习模型来对小图像进行分类。这是一个模型,允许您的计算机查看图像上的内容。正如您在前面的课程中所看到的,拥有数据集来训练模型非常重要。您将使用的数据集是 CIFAR-10。它是 10 个不同对象的数据集。还有一个更大的数据集,称为CIFAR-100。
CIFAR-10数据集可以从互联网上下载。但是,如果您安装了torchvision,则只需执行以下操作:
import matplotlib.pyplot as plt
import torchvisiontrainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True)fig, ax = plt.subplots(4, 6, sharex=True, sharey=True, figsize=(12,8))
for i in range(0, 24):row, col = i//6, i%6ax[row][col].imshow(trainset.data[i])
plt.show()
该 torchvision.datasets.CIFAR10
函数可帮助您将 CIFAR-10 数据集下载到本地目录。数据集分为训练集和测试集。因此,上面的两行就是要得到它们。然后,从下载的数据集中绘制前 24 张图像。数据集中的每张图像都是以下之一的 32×32 像素图片:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船或卡车。
6.使用Pytorch的DataLoader
上一课的 CIFAR-10 图像确实是 numpy 数组的格式。但对于 PyTorch 模型的使用,它需要位于 PyTorch 张量中。将 numpy 数组转换为 PyTorch 张量并不难,但在训练循环中,仍然需要将数据集分批划分。PyTorch DataLoader 可以帮助您使此过程更加顺畅。
回到上一课中加载的 CIFAR-10 数据集,您可以执行以下操作以获得相同的效果:
import matplotlib.pyplot as plt
import torchvision
import torch
from torchvision.datasets import CIFAR10transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
trainset = CIFAR10(root='./data', train=True, download=True, transform=transform)
testset = CIFAR10(root='./data', train=False, download=True, transform=transform)batch_size = 24
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=True)fig, ax = plt.subplots(4, 6, sharex=True, sharey=True, figsize=(12,8))
for images, labels in trainloader:for i in range(batch_size):row, col = i//6, i%6ax[row][col].imshow(images[i].numpy().transpose([1,2,0]))break # take only the first batch
plt.show()
在此代码中,使用 transform
参数创建, trainset
以便在提取数据时将数据转换为 PyTorch 张量。这是在它后面的几行中 DataLoader
执行的。该 DataLoader
对象是一个 Python 可迭代对象,您可以提取输入(图像)和目标(整数类标签)。在本例中,将批处理大小设置为 24,并迭代第一个批处理。然后,显示批处理中的每个图像。
7.卷积神经网络
图像是 2D 结构。您可以通过扁平化它们轻松地将它们转换为一维向量,并构建神经网络模型来对它们进行分类。但众所周知,保留 2D 结构会更合适,因为分类是关于图像中的内容,即平移不变的。
图像处理神经网络的标准方法是使用卷积层。使用卷积层的神经网络称为卷积神经网络。示例如下:
import torch.nn as nnmodel = nn.Sequential(nn.Conv2d(3, 32, kernel_size=(3,3), stride=1, padding=1),nn.ReLU(),nn.Dropout(0.3),nn.Conv2d(32, 32, kernel_size=(3,3), stride=1, padding=1),nn.ReLU(),nn.MaxPool2d(kernel_size=(2, 2)),nn.Flatten(),nn.Linear(8192, 512),nn.ReLU(),nn.Dropout(0.5),nn.Linear(512, 10)
)
print(model)
在上面,我们多次使用了 Conv2d
图层,以及 ReLU
激活。卷积层用于从图像中学习和提取特征。您添加的卷积层越多,网络可以学习更多高级特征。最终,您将使用池化层( MaxPool2d
如上图)对提取的特征进行分组,将它们展平为向量,然后将其传递到多层感知器网络进行最终分类。这是图像分类模型的通常结构。
8.训练图像分类器
结合为 CIFAR-10 数据集创建的 DataLoader,您可以使用以下训练循环来训练上一课中的卷积神经网络:
import torch.nn as nn
import torch.optim as optimloss_fn = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)n_epochs = 20
for epoch in range(n_epochs):model.train()for inputs, labels in trainloader:y_pred = model(inputs)loss = loss_fn(y_pred, labels)optimizer.zero_grad()loss.backward()optimizer.step()acc = 0count = 0model.eval()with torch.no_grad():for inputs, labels in testloader:y_pred = model(inputs)acc += (torch.argmax(y_pred, 1) == labels).float().sum()count += len(labels)acc /= countprint("Epoch %d: model accuracy %.2f%%" % (epoch, acc*100))
这将需要一段时间才能运行,您应该看到生成的模型可以达到不低于 70% 的准确率。
该模型是一个多分类网络。输出不是一个,而是许多分数,每个类一个。我们认为分数越高,模型认为图像属于某个类的置信度就越高。因此,使用的损失函数是交叉熵,即二元交叉熵的多类版本。
在上面的训练循环中,您应该会看到在前面的课程中学到的相当多的元素。包括在模型中的训练模式和推理模式之间切换、使用 torch.no_grad()
上下文以及计算准确性。
9.使用GPU训练
在 PyTorch 中使用 GPU 的方法是在执行之前将模型和数据发送到 GPU。然后,您可以选择从 GPU 发回结果,或直接在 GPU 中执行评估。
修改上一课中的代码以使用 GPU 并不难。以下是应该做的:
import torch.nn as nn
import torch.optim as optimdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)loss_fn = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)n_epochs = 20
for epoch in range(n_epochs):model.train()for inputs, labels in trainloader:y_pred = model(inputs.to(device))loss = loss_fn(y_pred, labels.to(device))optimizer.zero_grad()loss.backward()optimizer.step()acc = 0count = 0model.eval()with torch.no_grad():for inputs, labels in testloader:y_pred = model(inputs.to(device))acc += (torch.argmax(y_pred, 1) == labels.to(device)).float().sum()count += len(labels)acc /= countprint("Epoch %d: model accuracy %.2f%%" % (epoch, acc*100))
所做的更改如下: 您检查 GPU 是否可用并相应地设置。 device
然后将模型发送到设备。当输入(即一批图像)传递到模型时,应首先将其发送到相应的设备。由于模型输出也将在那里,因此损失计算或精度计算也应首先将目标发送到 GPU。
参考链接
Deep Learning with PyTorch (9-Day Mini-Course) - MachineLearningMastery.com