使用PyTorch中的预训练模型进行图像分类

PyTorch的TorchVision模块中包含多个用于图像分类的预训练模型,TorchVision包由流行的数据集、模型结构和用于计算机视觉的通用图像转换函数组成。一般来讲,如果你进入计算机视觉和使用PyTorch,TorchVision可以提供还多便利的操作!

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

预训练模型是在像ImageNet这样的大型基准数据集上训练得到的神经网络模型。深度学习社区从这些开源模型中获益良多,这也是计算机视觉研究迅速发展的主要原因之一。其他研究人员和实践者可以使用这些最先进的模型,而不是从零开始训练。

下面是一个粗略的时间表,说明最先进的模型是如何随着时间的推移而改进的。我们只包括了TorchVision中的那些模型。

在我们关注如何使用预训练模型进行图像分类的细节之前,让我们看看各种预训练模型是什么。我们将以AlexNet和ResNet50为两个主要例子。这两个网络都在ImageNet数据集上进行了训练。ImageNet数据集拥有斯坦福大学维护的1400多万张图像,广泛用于各种与图像相关的深度学习项目。图像属于各种标签。即使可以互换使用这两个术语,我们在此统一使用类这个术语。像AlexNet和ResNet101这样预先训练过的模型的目的是以图像作为输入并预测它的类。

这里预先训练的含义是像AlexNet和ResNet50这样的深度学习结构,已经在一些(巨大的)数据集上进行了训练,从而携带了由此训练所产生的权重和偏差。'网络架构'与‘权重和偏差’之间的这种区别应该是非常清楚的,TorchVision既有网络架构,也有预训练模型。

1.1.模型推断过程

由于我们将重点讨论如何使用预训练模型来预测输入的类(标签),所以我们也讨论一下与此相关的过程。这个过程被称为模型推断。整个过程由以下主要步骤组成.

1、读取输入图像

2、在图像上执行转换,例如调整大小、中心裁剪、正则化等,这些都属于图像的预处理,为了是输入图像符合模型的要求。

3、正向传递:这一步使用预先训练的权重来找出输出向量(二维数组),此输出向量中的每个元素描述该模型预测输入图像属于某个类的置信度。例如是狗的可能性为0.2、猫的可能性为0.5、老虎的可能性为0.1等。 

4、根据所获得的置信度(步骤3中我们提到的输出向量的元素),显示预测结果。

我们先要为接下来的实验准备材料,下载如下资源:

wget https://upload.wikimedia.org/wikipedia/commons/2/26/YellowLabradorLooking_new.jpg -O dog.jpg
wget https://raw.githubusercontent.com/Lasagne/Recipes/master/examples/resnet50/imagenet_classes.txt

1.2.使用TorchVision加载预先训练网络

既然我们已经具备了模型推理的知识,以及预训练模型意味着什么,让我们看看如何在TorchVision模块的帮助下使用它们。

首先,让我们安装TorchVision模块。使用

pip3 install torchvision

或者

python3 -m pip install torchvision

接下来,让我们从torchvison模块导入models模块,看看我们可以使用哪些不同的模型和网络结构。

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类实例化的模型。这些功能函数也可能有不同的版本,例如,densenet121, densenet161, densenet169, densenet201都返回DenseNet 类的实例,但层数不同-分别为121、161、169和201。

1.3.利用AlexNet进行图像分类

让我们首先从AlexNet开始,它是图像识别中早期突破性的网络之一。 其网络结构如下:

AlexNet Architecture

第一步:加载预先训练好的模型

在第一步中,我们将创建一个网络实例。我们需要传递一个参数,以便函数可以下载模型的权重。。

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/frank/.cache/torch/checkpoints/alexnet-owt-4df8aa71.pth

模型下载需要10分钟左右,模型文件会缓存在用户的相应目录中,下次加载就不需要下载了。

注:我的电脑上缓存在了/home/frank/.cache/torch/checkpoints/alexnet-owt-4df8aa71.pth

请注意,通常PyTorch模型的扩展为.pt或.pt, 一旦权重被下载,我们就可以接着继续其他步骤。我们还可以查看网络结构的一些细节如下。

print(alexnet)

上面这条语句只显示AlexNet网络结构中的各种操作和层,不显示具体的权重和偏差。

步骤2:设置图像转换

一旦我们有了模型,下一步就是转换输入图像,使它们具有正确的形状和其他特征,如均值和标准差。这些值应该类似于在训练模型时使用的值。这确保了网络将产生有正确的推断结果。 我们可以借助TochVision模块中存在的transforms对输入图像进行预处理。本例中,我们可以对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]行:这里我们定义了一个变量,它是对输入图像进行的所有图像转换的组合。

第[2]行:将图像调整为256×256像素。

第[3]行:将图像中心裁剪出来,大小为224×224像素。

第[4]行:将图像转换为PyTorch张量(tensor)数据类型。

行[5-7]:通过将图像的平均值和标准差设置为指定的值来正则化图像。

步骤3:加载输入图像并对其进行预处理

接下来,让我们加载输入图像并执行上面指定的图像转换。请注意,我们将广泛使用pillow(PIL)模块,因为它是torchvision支持的默认的图像后端(引擎)。

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

Sample test image

注:一只黄色的拉布拉多狗

接下来,对图像进行预处理,并将图像tensor增加一个维度,因为一张图像只有3个维度,但模型要求输入是4纬张量,也就是默认是输入一批图像,而不是一张。经过处理后,我们的batch_t也代表一批图像,不过其中只有一张图像而已。

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

步骤4:模型推断

最后,是时候使用预训练模型来看看模型认为图像是什么了。 首先,我们需要将我们的模型置于eval模式。然后进行推断。

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

out为一个二维向量,行为1,列为1000。前面我们提到,模型输入要求是一批图像,如果我们输入5张图像,则out的行为5,列为1000,列表示1000个类,每个类的置信度,行代表每个图像。故每一行中的1000个元素,分别表示该行对应图像为每个类的可能性。

我们如何处理out这个二维向量呢?我们还没有得到图像的类(或标签)。为此,我们将首先从一个包含所有1000个标签的列表的文本文件中读取和存储标签。请注意,行号确定了类号,因此确保不更改该顺序是非常重要的。

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

classes为含有1000个类名称字符串的列表(ImageNet数据集共包含1000个类)。

由于AlexNet和ResNet已经在相同的Image Net数据集上进行了训练,我们可以对这两种模型使用相同的类列表。 现在,我们需要找出输出向量out中的最大置信度发生在哪个位置。我们将用这个位置的下标来得出预测。

_, index = torch.max(out, 1)
 
percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
 
print(classes[index[0]], percentage[index[0]].item())

_, index = torch.max(out, 1) 的功能是,取出二维向量out中每一行的最大值及下标。index为每行最大值的下标组成的列表。

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100 的功能是,对二维向量out中的每一行进行归一化(softmax是常用的归一化指数函数),然后取出第一行并使每个元素乘以100,得到本例中拉布拉多狗对应的每种类型的可能性(即置信度)。

print(classes[index[0]], percentage[index[0]].item())的功能是,打印类名及其置信度。classes[index[0]]中,index[0]是第一行最大值的下标,即第一张图片的最大置信度的下标,index[1]为第二张图片的,index[2]是第三张图片的,以此类推。classes[index[0]]即是最大置信度对应的类名称。所以classes列表的元素顺序不可更改。percentage[index[0]].item()中,index[0]的含义同上,percentage[index[0]]代表最大置信度那一项,.item()取出该项的值。

好了!该模型预测图像是一只拉布拉多猎犬,置信度为41.58%。

但这听起来太低了。让我们看看模型认为图像属于其他类的置信度。

_, indices = torch.sort(out, descending=True)
[(classes[idx], percentage[idx].item()) for idx in indices[0][:5]]

torch.sort将out进行排序,默认对每一行排序,这里我们指定以递减的方式排序。

[(classes[idx], percentage[idx].item()) for idx in indices[0][:5]]中,indices[0][:5]产生一个临时的一维列表,包含indices的第一行前5个元素,也就是置信度最高的5个元素的下标值。

结果如下:

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

不知道你注意到没有,所有这些都是狗的品种。因此,模型设法预测,这是一只狗的置信度很高,但它不是很确定的狗的品种。 就这样!你所需要的就是这4个步骤来使用预训练模型进行图像分类。 我们试试ResNet怎么样?

1.4.使用ResNet进行图像分类

我们将使用ResNet50(一个50层卷积神经网络)。 让我们快速地看一下使用ResNet50进行图像分类所需的步骤。

# First, load the model
resnet = models.resnet50(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
[(classes[idx], percentage[idx].item()) for idx in indices[0][:5]]

结果如下

[('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.26%。

2.模型比较

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

1、top-1错误:如果模型预测的置信度最高的类与真正的类不相同,则会发生top-1错误。

2、top-5错误:当真正的类不在模型预测置信度最高的前5个类中时,会发生前top-5错误(按置信度排序)。

3、CPU的推断时间:推断时间是模型推理过程所花费的时间。

4、GPU的推断时间 : 当推理运行于gpu时,所花费的推理时间

5、模型大小:这里的大小代表由PyTorch提供的预训练模型的.pth(或.pt) 文件所占用的物理空间。

一个好的模型将具有低的TOP-1错误,低的TOP-5错误,低的CPU和GPU上的推理时间和低的模型大小。 所有的实验都是在同一个输入图像上进行的,并且多次进行,这样就可以将特定模型的所有结果的平均值进行分析。实验是在GoogleColab上进行的。现在,让我们看看所获得的结果。

2.1.模型的准确性比较

我们要讨论的第一个标准是TOP-1和TOP-5错误。TOP-1错误要求较为苛刻,还有另一个错误度量称为TOP-5错误。如果前5个预测类中没有一个是正确的,则预测被归类为错误。

Accuracy Comparison of Models

 

 

从图表中注意到,这两个错误都遵循类似的趋势。AlexNet是基于深度学习的第一次尝试,此后错误率有所改善。值得一提的是GoogLeNet、ResNet、VGGNet、ResNext。

2.2.推断时间比较

接下来,我们将根据模型推理所需的时间对模型进行比较。多次向每个模型提供一幅图像,并对所有迭代的推理时间进行平均。对CPU和GoogleColab上的GPU执行了类似的过程。尽管顺序上有一些变化,但我们可以看到,SqueseNet、ShuffleNet和ResNet-18的推理时间非常低,这正是我们想要的。

Inference time on CPU comparison

Inference time on GPU comparison

2.3.模型大小比较

很多时候,当我们在Android或iOS设备上使用深度学习模型时,模型大小成为决定因素,有时甚至比准确性更重要。挤压网的最小模型大小(5MB),其次是ShuffleNetV2(6MB)和MobileNetV2(14MB)。很明显,为什么这些模型在使用深度学习的移动应用程序中是首选的。

Model size comparison

2.4.总体比较

我们讨论了哪种模型在某个特定标准上表现更好。我们可以在一个气泡图中包含所有这些重要的细节,然后我们可以参考这些细节,根据我们的需求来决定要选择哪个模型。 我们使用的x坐标是Top-1错误(较低更好)。其中y坐标是GPU上的推理时间,单位为毫秒(更低更好),气泡大小代表模型大小(较低更好)

 注: 较小的气泡在模型大小方面更好。 在原点附近的气泡在精度和速度方面都更好。

3.最终结果

从上面的图表可以清楚地看出,ResNet50是所有三个参数(尺寸小,更接近原点)的最佳模型。 在推理时间上,DenseNets和ResNext101是昂贵的。 AlexNet 和SqueezeNet 有相当高的错误率。

在这篇文章中,我们介绍了如何使用TorchVision模块来使用预先训练的模型进行图像分类,只需4步。我们还进行了模型比较,以决定选择什么样的模型,当然这取决于我们的项目需求。在下一篇文章中,我们将介绍在PyTorch中如何使用迁移学习,在自定义数据集上训练模型。

参考链接:https://www.learnopencv.com/pytorch-for-beginners-image-classification-using-pre-trained-models/

  • 20
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值