PyTorch构建与部署深度学习模型(1)简单应用

PyTorch是最受欢迎的深度学习Python库之一,它被人工智能研究社区广泛使用。许多开发者和研究人员使用PyTorch来加速深度学习研究实验和原型设计。

1.为什么使用PyTorch

如果你正在学习机器学习,进行深度学习研究,或构建人工智能系统,你可能需要使用深度学习框架。深度学习框架可以很容易地完成数据加载、预处理、模型设计、训练和部署等常见任务。PyTorch由于其简单、灵活和Python接口,已经在学术和研究团体中非常受欢迎。
以下是学习和使用PyTorch的一些原因:

  • PyTorch很受欢迎
  • PyTorch得到所有主流云平台的支持,如Amazon Web Services (AWS)、谷歌云平台(GCP)、微软Azure、阿里云等
  • PyTorch得到Google Colaboratory和Kaggle Kernels支持
  • PyTorch成熟稳定
  • PyTorch支持CPU、GPU、TPU和并行处理
  • PyTorch支持分布式训练:您可以在多台机器上的多个gpu上训练神经网络。
  • PyTorch支持部署到生产环境:使用新的TorchScript和TorchServe特性,您可以轻松地将模型部署到包括云服务器在内的生产环境中。
  • PyTorch开始支持移动端部署:虽然目前还处于试验阶段,但你现在可以将模型部署到iOS和Android设备上。
  • PyTorch拥有一个庞大的生态系统和一组开源库:Torchvision、fastai和PyTorch Lightning等库扩展了功能,并支持自然语言处理(NLP)和计算机视觉等特定领域。
  • PyTorch也有一个c++前端:虽然在本书中我将重点关注Python接口,PyTorch还支持前端c++接口。如果您需要构建高性能、低延迟应用程序,您可以使用与Python API相同的设计和架构,用c++编写它们。
  • PyTorch本身支持ONNX格式:你可以很容易地将你的模型导出为ONNX格式,并在与ONNX兼容的平台、运行时或可视化工具中使用它们。
  • PyTorch拥有一个庞大的开发者社区和用户论坛:https://pytorch.tips/discuss

2.小试牛刀

在实践中,您将在代码的开头导入所有必要的库。但是,在本例中,我们将在使用库时导入它们,这样您就可以看到每个任务需要哪些库。

首先,让我们选择一个我们想分类的图像。在这个例子中,我们会选择一杯新鲜、热的咖啡。使用以下代码下载咖啡映像到您的本地环境:

import urllib.request
url = 'https://upload.wikimedia.org/wikipedia/commons/4/45/A_small_cup_of_coffee.JPG'
fpath = 'coffee.jpg'
urllib.request.urlretrieve(url, fpath)

注意,代码使用了urllib库的urlretrieve()函数从web获取图像。通过指定fpath,将文件重命名为coffee.jpg

接下来,我们使用PIL读取我们的本地图像:

import matplotlib.pyplot as plt
from PIL import Image
img = Image.open('coffee.jpg')
plt.imshow(img)

PyTorch构建与部署深度学习模型(1)简单应用
注意,我们还没有使用PyTorch。接下来,我们将把图像传递给一个经过预处理的图像分类神经网络(NN),但在此之前,我们需要对图像进行预处理。预处理数据在机器学习中很常见,因为神经网络期望输入满足一定的要求。

在我们的示例中,图像数据是RGB 1600 × 1200像素JPEG格式。我们需要应用一系列被称为transforms的预处理步骤,将图像转换成适合NN的格式。我们在以下代码中使用Torchvision实现了这一点:

import torch
from torchvision import transforms
transform = transforms.Compose([
 	 transforms.Resize(256),
	 transforms.CenterCrop(224),
	 transforms.ToTensor(),
	 transforms.Normalize(
	 mean=[0.485, 0.456, 0.406],
	 std=[0.229, 0.224, 0.225])])
img_tensor = transform(img)
print(type(img_tensor), img_tensor.shape)
# <class 'torch.tensor'> torch.Size([3, 224, 224])

我们使用Compose()变换来定义一系列对图像进行预处理的变换。首先,我们需要调整和裁剪图像以适应NN。图像目前是PIL格式,因为这是我们之前读取它的方式。但是我们的神经网络需要一个张量输入,所以我们把PIL图像转换成一个张量。

张量是PyTorch中最基本的数据对象,我们将在下一章中详细介绍它们。你可以考虑像NumPy数组或数字数组这样的张量,它们有一些额外的特性。现在,我们只需要把图像转换成一个数字张量数组就可以了。将像素值的范围缩放到0到1之间。

我们再应用一个称为Normalize()的变换,将[0,1]范围内的像素值进行标准化。平均值和标准差(std)的值是根据用来训练模型的数据预先计算的。对图像进行归一化可以提高分类器的精度。

最后,我们调用transform(img)对图像应用所有的变换。正如你所看到的,img_tensor是一个3 × 224 × 224torch.Tensor,代表224 × 224像素的3通道图像的张量。

高效的机器学习是批量处理数据的,我们的模型期望得到一批数据。然而,我们只有一个图像,所以我们需要创建一个大小为1的批处理,如下所示的代码:

batch = img_tensor.unsqueeze(0)
print(batch.shape)
# out: torch.Size([1, 3, 224, 224])

我们使用PyTorch的unsqueeze()函数向张量添加一个维度,并创建一个大小为1的批。现在我们有一个大小为1 × 3 × 224 × 224的张量。

现在我们的图像已经为分类器NN准备好了!我们将使用一个名为AlexNet的著名图像分类器。AlexNet赢得了2012ImageNet大型视觉识别挑战赛。使用Torchvision加载这个模型很容易,如下所示的代码:

from torchvision import models
model = models.alexnet(pretrained=True)

我们将使用一个预先训练过的模型,所以我们不需要训练它。AlexNet模型已经用数百万张图像进行了预训练,在对图像进行分类方面做得很好。让我们传入我们的图像,看看它是如何做到的:

device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)
# out(results will vary): cpu
model.eval()
model.to(device)
y = model(batch.to(device))
print(y.shape)
# out: torch.Size([1, 1000])

GPU加速是PyTorch的一个关键优势。在第一行中,我们使用PyTorch的cuda.is_available()函数来查看我们的机器是否有GPU。我们只对一张图像进行分类,所以我们不需要GPU,但如果我们有大量的图像,那么GPU可能会帮助我们加快速度。

model.eval()函数配置我们的AlexNet模型进行推断或预测(而不是训练)。模型的某些组成部分只在训练中使用,我们不想在这里使用它们。使用model.to(device)batch.to(device)将我们的模型和输入数据发送给GPU(如果可用的话),并执行model(batch.to(device))运行我们的分类器。

输出y1,000个输出组成。因为我们的批处理只包含一个图像,第一个维度是1,而类的数量是1000,每个类一个值。值越高,图像包含该类的可能性越大。下面的代码找到获胜的类:

y_max, index = torch.max(y,1)
print(index, y_max)
# out: tensor([967]) tensor([22.3059],
# grad_fn=<MaxBackward0>)

使用PyTorchmax()函数,我们看到index967的值最大,为22.3059,因此是优胜者。然而,我们不知道967类代表什么。让我们用类名加载这个文件,并找出答案:

import urllib.request
url = "https://raw.githubusercontent.com/joe-papa/pytorch-book/main/files/imagenet_class_labels.txt"
fpath = 'imagenet_class_labels.txt'
urllib.request.urlretrieve(url, fpath)

with open('imagenet_class_labels.txt') as f:
  classes = [line.strip() for line in f.readlines()]

print(classes[967])
# out: 967: 'espresso',

与前面一样,我们使用urlretrieve()下载包含每个类描述的文本文件。然后,我们使用readlines()读取文件,并创建一个包含类名的列表。当我们print(classes[967])时,它告诉我们967类是浓缩咖啡!

使用PyTorchsoftmax()函数,我们可以将输出值转换为概率:

prob = torch.nn.functional.softmax(y, dim=1)[0] * 100
print(classes[index[0]], prob[index[0]].item())
#967: 'espresso', 87.85208892822266

要打印索引处的概率,我们使用PyTorchtensor.item()方法。item()方法经常被使用,它返回一个张量中包含的数值。实验结果表明,该模型对该图像的确定度为87.85%。

我们可以使用PyTorchsort()函数对输出概率进行排序,看看前5个:

_, indices = torch.sort(y, descending=True)
for idx in indices[0][:5]:
 print(classes[idx], prob[idx].item())
# out:
# 967: 'espresso', 87.85208892822266
# 968: 'cup', 7.28359317779541
# 504: 'coffee mug', 4.33521032333374
# 925: 'consomme', 0.36686763167381287
# 960: 'chocolate sauce, chocolate syrup',
# 0.09037172049283981

我们看到模型预测图像是87.85%的浓缩咖啡,7.28%的杯子和4.3%的咖啡杯的概率,但它似乎相当确信图像是浓缩咖啡。

3.完整代码

你可能觉得你现在就需要一杯浓缩咖啡。在那个例子中我们已经讨论了很多!完成所有事情的核心代码实际上要短得多。假设你已经下载了这些文件,你只需要运行以下代码来使用AlexNet对图像进行分类:

import torch
from torchvision import transforms, models
transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(
    mean=[0.485, 0.456, 0.406],
    std=[0.229, 0.224, 0.225])])
img_tensor = transform(img)
batch = img_tensor.unsqueeze(0)
model = models.alexnet(pretrained=True)
device = "cuda" if torch.cuda.is_available() else "cpu"
model.eval()
model.to(device)
y = model(batch.to(device))
prob = torch.nn.functional.softmax(y, dim=1)[0] * 100
_, indices = torch.sort(y, descending=True)
for idx in indices[0][:5]:
    print(classes[idx], prob[idx].item())

这就是如何用PyTorch构建一个图像分类器。试着在模型中运行您自己的图像,看看它是如何对它们进行分类的。

上一篇:防止过拟合之提前终止(Early Stopping)


下一篇:支付宝手机网站支付接口 FOR ECShop