Pytorch使用预训练模型进行图像分类

在本文中,我们将介绍一些使用预训练网络的实际例子,这些网络出现在TorchVision模块的图像分类中。

Torchvision包包括流行的数据集,模型体系结构,和通用的图像转换为计算机视觉。基本上,如果你进入计算机视觉并使用PyTorch, Torchvision将会有很大的帮助!

1. Pre-trained Models for Image Classification

预训练模型是在大型 benchmark数据集(如ImageNet)上训练的神经网络模型。深度学习社区从这些开源模式中获益匪浅。此外,预先训练的模型是计算机视觉研究快速发展的一个主要因素。其他研究人员和从业人员可以使用这些最先进的模型,而不是重新发明一切从零开始。

下面给出了一个粗略的时间轴,说明了这些先进的模型是如何随着时间的推移而改进的。我们只包括那些模型是在Torchvision包。
在这里插入图片描述
在详细介绍如何使用预先训练的模型进行图像分类之前,让我们看看有哪些预先训练的模型。我们将在这里讨论AlexNet和ResNet101作为两个主要的例子。这两个网络都接受过ImageNet数据集的训练。

ImageNet数据集拥有超过1400万张由斯坦福大学维护的图像。它被广泛用于各种图像相关的深度学习项目。这些图像属于不同的类别或标签。像AlexNet和ResNet101这样的预训练模型的目的是将图像作为输入并预测它的类别。

这里的“预训练”指的是深度学习架构,例如AlexNet和ResNet101,已经在一些(巨大的)数据集上进行了训练,因此产生了权重和偏差。架构与权重和偏差之间的区别应该非常清楚,因为我们将在下一节中看到,TorchVision既有架构,又有预训练的模型。

1.1. 模型推理过程

由于我们将关注如何使用预先训练的模型来预测输入的类(标签),所以让我们也讨论其中涉及的过程。这个过程被称为模型推理。整个过程由以下主要步骤组成。

  • 1.读取输入图像
  • 2.在图像上执行变换。例如,调整大小,中央裁剪,正规化等等。
  • 3.前向传递:使用预先训练的权值找出输出向量。这个输出向量中的每个元素描述模型预测输入图像属于某个特定类的置信度。
  • 4.根据得到的分数(我们在步骤3中提到的输出向量的元素),显示预测。

1.2 使用TorchVision加载预训练网络

现在,我们已经具备了模型推理的知识,并了解了预训练模型的含义,让我们看看如何在TorchVision模块的帮助下使用它们。

首先,让我们使用下面给出的命令安装TorchVision模块。

pip install torchvision

接下来,让我们从torchvision模块导入模型,看看我们有哪些不同的模型和架构可用。

from torchvision import models
import torch

dir(models)

仔细观察我们得到的输出

['AlexNet',
 'DenseNet',
 'GoogLeNet',
 'Inception3',
 'MobileNetV2',
 'ResNet',
 'ShuffleNetV2',
 'SqueezeNet',
 'VGG',
...
 'alexnet',
 'densenet',
 'densenet121',
 'densenet161',
 'densenet169',
 'densenet201',
 'detection',
 'googlenet',
 'inception',
 'inception_v3',
...
]

注意,有一个条目叫AlexNet,另一个叫AlexNet。大写的名称指的是Python类(AlexNet),而AlexNet是一个方便的函数,它返回从AlexNet类实例化的模型。这些方便的函数也可能有不同的参数集。例如,densenet121densenet161densenet169densenet201都是DenseNet类的实例,但层数不同——分别为121,161,169和201

1.3. 利用AlexNet进行图像分类

让我们先从AlexNet开始。它是图像识别领域早期的突破性网络之一。如果你有兴趣了解AlexNet的架构,你可以看看我们在理解AlexNet上的帖子。
在这里插入图片描述
AlexNet架构
步骤1:加载预训练模型
在第一步中,我们将创建一个网络实例。我们还将传递一个参数,以便函数可以https://github.com/spmallick/learnopencv/tree/master/Inference-for-PyTorch-Models/ONNX-Caffe2d模型的权重。

alexnet = models.alexnet(pretrained=True)

# You will see a similar output as below
# Downloading: "https://download.pytorch.org/models/alexnet-owt- 4df8aa71.pth" to /home/hp/.cache/torch/checkpoints/alexnet-owt-4df8aa71.pth

注意,通常PyTorch模型的扩展名为.pt或.pth
一旦下载了权重,我们就可以继续其他步骤。我们还可以检查网络架构的一些细节,如下所示。

print(alexnet)

步骤2:图像变换

一旦我们有了模型,下一步就是变换输入图像,使它们具有正确的形状和其他特征,如平均值和标准差。这些值应该与训练模型时使用的值一样。这确保了网络将产生有意义的答案。

我们可以利用TochVision模块中的变换对输入图像进行预处理。在这种情况下,我们可以对AlexNet和ResNet使用以下转换。

from torchvision import transforms
transform = transforms.Compose([            #[1]
 transforms.Resize(256),                    #[2]
 transforms.CenterCrop(224),                #[3]
 transforms.ToTensor(),                     #[4]
 transforms.Normalize(                      #[5]
 mean=[0.485, 0.456, 0.406],                #[6]
 std=[0.229, 0.224, 0.225]                  #[7]
 )])

让我们试着理解上面的代码片段中发生了什么。

  • 行[1]:在这里,我们定义了一个transform,它是对输入图像进行的所有图像变换的组合。
  • 行[2]:调整图像的大小为256×256像素。
  • 行[3]:裁切图像到224×224像素左右的中心。
  • 行[4]:将图像转换为PyTorch张量数据类型。
  • 行[5-7]:对图像进行归一化,将其平均值和标准差设置为规定值。

第三步:加载输入图像并进行预处理
接下来,让我们加载输入图像并执行上面指定的图像转换。请注意,我们将在TorchVision中广泛使用Pillow (PIL)模块,因为它是TorchVision支持的默认图像后端。

# Import Pillow
from PIL import Image
img = Image.open("dog.jpg")

在这里插入图片描述
接下来,对图像进行预处理,并准备批处理以通过网络。

img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

步骤4:模型推理
最后,是时候使用预先训练的模型来查看模型认为图像是什么。
首先,我们需要将模型置于eval模式

alexnet.eval()

接下来,让我们执行推论。

out = alexnet(batch_t)
print(out.shape)

这一切都很好,但我们如何处理这个输出向量,其中包含1000个元素?我们仍然没有得到图像的类(或标签)。为此,我们将首先从一个包含所有1000个标签列表的文本文件中读取和存储标签。注意,行号指定了类号,所以确保不改变顺序是非常重要的。

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

因为AlexNetResNet已经在相同的ImageNet数据集上进行了训练,所以我们可以对两个模型使用相同的Class列表。
现在,我们需要找出输出向量out中最大分数出现的索引。我们将使用这个指标来找出预测。

_, index = torch.max(out, 1)

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100

print(labels[index[0]], percentage[index[0]].item())

该模型预测的图像是拉布拉多犬有41.58%的置信度。
但这听起来太低了。让我们看看模型认为图像还属于什么类别。
这里是输出:

[('Labrador retriever', 41.585166931152344),
 ('golden retriever', 16.59166145324707),
 ('Saluki, gazelle hound', 16.286880493164062),
 ('whippet', 2.8539133071899414),
 ('Ibizan hound, Ibizan Podenco', 2.3924720287323)]

这个模型成功地预测出这是一只狗,但它对狗的品种不是很确定。

让我们对草莓和汽车的图像做同样的尝试,看看我们得到的输出。
在这里插入图片描述
这是上述草莓图像得到的输出。我们可以看到,得分最高得分是“草莓”,得分接近99.99%。

[('strawberry', 99.99365997314453),
 ('custard apple', 0.001047826954163611),
 ('banana', 0.0008201944874599576),
 ('orange', 0.0007371827960014343),
 ('confectionery, confectionary, candy store', 0.0005758354091085494)]

在这里插入图片描述
类似地,对于上面给出的汽车图像,输出如下。

[('cab, hack, taxi, taxicab', 33.30569839477539),
 ('sports car, sport car', 14.424001693725586),
 ('racer, race car, racing car', 10.685123443603516),
 ('beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon',
  7.846532821655273),
 ('passenger car, coach, carriage', 6.985556125640869)]

就是这样!通过这4个步骤,就可以使用预先训练好的模型进行图像分类。
我们在ResNet上试试同样的方法怎么样?

1.4. 使用ResNet进行图像分类

我们将使用resnet101 - 101层卷积神经网络。Resnet101在训练过程中调整了大约4450万个参数。这是巨大的!

让我们快速浏览一下使用resnet101进行图像分类所需的步骤。

# First, load the model
resnet = models.resnet101(pretrained=True)

# Second, put the network in eval mode
resnet.eval()

# Third, carry out model inference
out = resnet(batch_t)

# Forth, print the top 5 classes predicted by the model
_, indices = torch.sort(out, descending=True)
percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
[(labels[idx], percentage[idx].item()) for idx in indices[0][:5]]

这是resnet101的预测。

[('Labrador retriever', 48.25556945800781),
 ('dingo, warrigal, warragal, Canis dingo', 7.900787353515625),
 ('golden retriever', 6.916920185089111),
 ('Eskimo dog, husky', 3.6434383392333984),
 ('bull mastiff', 3.0461232662200928)]

就像AlexNet一样,ResNet成功地预测出这是一只狗,并以48.25%的自信预测出这是一只拉布拉多寻回犬。

2. 模型比较

到目前为止,我们已经讨论了如何使用预先训练的模型来执行图像分类,但我们还没有回答的一个问题是,我们如何决定为特定的任务选择哪个模型。在本节中,我们将根据以下标准比较预训练模型:

  • Top-1误差:如果最有把握的模型预测的类与真实的类不一样,就会出现Top-1误差。
    -top-5错误:当真实的类不在模型预测的前5个类中(根据置信度排序),就会出现top-5错误。
  • CPU上的推理时间:推理时间是模型推理步骤所花费的时间。
  • GPU上的推理时间
    模型大小:这里的大小表示PyTorch提供的预训练模型的.pth文件所占用的物理空间

一个好的模型会有较低的Top-1错误,较低的Top-5错误,较低的CPUGPU推理时间和较低的模型尺寸。
所有的实验都是在相同的输入图像上进行的,并进行多次,以便对特定模型的所有结果进行平均,以便进行分析。实验是在谷歌Colab上进行的。现在,让我们看看所获得的结果。

2.1. 模型精度比较

我们要讨论的第一个标准包括Top-1和Top-5错误。top -1误差是指top预测类与真实情况不同时的误差。由于这是一个相当困难的问题,有另一个误差测量称为Top-5误差。如果前5个预测类别中没有一个是正确的,那么该预测将被归类为错误。
在这里插入图片描述
从图中可以看出,这两个error遵循相似的趋势。AlexNet是基于深度学习的第一次尝试,从那时起在错误方面有了改进。值得一提的是GoogLeNet, ResNet, VGGNet, ResNext。

2.2. 推理时间比较

接下来,我们将基于模型推理所花费的时间来比较模型。一个图像被多次提供给每个模型,所有迭代的推理时间被平均。在谷歌Colab上对CPUGPU执行了类似的过程。即使在顺序上有一些变化,我们可以看到SqueezeNet, ShuffleNetResNet-18的推断时间非常低,这正是我们想要的。
在这里插入图片描述
在这里插入图片描述

2.3. 模型的大小比较

很多时候,当我们在android或iOS设备上使用深度学习模型时,模型大小成为一个决定性因素,有时甚至比准确性更重要。SqueezeNet的模型尺寸最小(5 MB),其次是ShuffleNet V2 (6 MB)和MobileNet V2 (14 MB)。很明显,这些模型在使用深度学习的移动应用中更受欢迎。
在这里插入图片描述
2.4. 整体比较
我们讨论了在特定标准的基础上哪个模型表现得更好。我们可以将所有这些重要的细节压缩到一个气泡图中,然后根据我们的需求来决定使用哪个模型。
我们使用的x坐标是Top-1误差(越低越好)。y坐标是GPU上的推断时间,以毫秒为单位(越低越好)。气泡大小代表模型大小(越小越好)。

注意:

  • 较小的气泡在模型尺寸方面更好。
  • 靠近原点的气泡在精度和速度方面都更好。

在这里插入图片描述

3.结论
从上图可以看出,ResNet50在所有三个参数上都是最好的模型(尺寸小,更接近原点)

  • DenseNetsResNext101在推理时间上是昂贵的。
  • AlexNetSqueezeNet的错误率都很高。

好了,就到这里吧!在这篇文章中,我们介绍了如何使用Torchvison模块进行图像分类,使用预训练的模型-只有4个步骤的过程。我们也进行了模型比较,根据我们的项目需求来决定选择什么样的模型。在下一篇文章中,我们将介绍如何使用迁移学习来使用PyTorch训练自定义数据集上的模型。

源代码地址下载


版权声明:本文为weixin_38346042原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。