我们可以把预训练的神经网络看作一个接收输入并生成输出的程序,该程序的行为是由神经网络的结构以及它在训练过程中所看到的样本所决定的,即期望的输入-输出对,或者期望输出应该满足的特性。我们可以在Pytorch中加载和运行这些预训练好的模型。
TorchVision项目中包含一些表现优异的神经网络架构,如AlexNet、ResNet等。在torchvison.models中可以找到预定义的模型。
form torchvision import models
print(dir(models))
输出结果
['AlexNet', 'DenseNet', 'GoogLeNet',...'resnet', 'resnet101', 'resnet152', 'resnet18'...]
首字母大写的名称指的是实现了许多流行模型的Python类,它们的体系结构不同,即输入和输出之间操作的编排不同。首字母小写的名称指的是一些便捷函数,它们返回这些类实例化的模型,有时使用不同的参数集。例如,resnet101表示返回一个有101层网络的ResNet实例,resnet18表示返回一个有18层网络的ResNet实例。
为了使用AlexNet模型产生一个输出图片,我们可以创建一个AlexNet类的实例。
alexnet=models.AlexNet()
此时,alexnet是一个可以运行AlexNet架构的对象。通过向alexnet提供一些精确的输入数据,我们将在网络中运行一个正向传播(forward pass)。也就是说,输入将经过一组神经元,其输出将被传递给下一组神经元,直到得到最后的输出。
实际上,如果我们有一个真实类型的input对象,我们可以使用output=alexnet(input)
运行正向传播。但这样做产生的知识一些垃圾数据!因为网络没有初始化,它的权重还没有经过任何训练。网络本身就是一块白板,或者是随机的白板,我们要做的就是要么从头训练它,要么加载之前训练好的网络。
使用resnet101来实例化一个具有101层的卷积神经网络。传递一个参数,指示函数下载resnet101在ImageNet数据集上训练好的权重
resnet=models.resnet101(pretrained=True)
可以像调用函数一样调用resnet变量,将一幅或多幅图像作为输入,并为1000个ImageNet类生成对等数量的分数。然而,在此之前我们必须对输入的图像进行预处理,使其大小合适,使其颜色大致处于相同的数值范围。为此,TorchVision模块提供了transforms模块,它允许我们快速定义具有基本预处理功能的管道。
from torchvision import transforms
preprocess=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]
)])
我们定义了一个预处理函数,将输入图像缩放到256×256个像素,围绕中心将图像裁剪为224×224个像素,并将其转换为一个张量,对其RGB分量进行归一化处理,使其具有定义的均值和标准差。
现在从网上下载一张狗的图片,对其进行预处理,然后就可以运行模型了。
from PIL import Image
img=Image.open("/home/user1/QinRui/learn-dataset/dog.jpg")
img_t=preprocess(img)
import torch
batch_t=torch.unsqueeze(img_t,0)
在深度学习中,在新数据上运行训练过的模型的过程被称为推理(inference)。为了进行推理,我们需要将网络置于eval模式。
resnet.eval()
如果不这么做,那么一些预训练的过的模型,如批量归一化(Batch Normalization)和丢弃法(Dropout)将不会产生有意义的答案,仅仅是因为它们内部工作的方式。现在进行推理。
out=resnet(batch_t)
print(out)
最终产生了一个拥有1000个分数的向量,每个类对应一个分数,现在我们需要找到得分高的类的标签,这将告诉我们模型从图像中得到了什么。
要查看预测标签的列表,我们需要加载一个文本文件,按照训练中呈现给网络的顺序列出标签,然后我们从网络中产生最高得分的索引出挑选出标签。
# 加载一个包含1000个标签的文件
with open('/home/user1/QinRui/learn-dataset/imagenet_classes.txt') as f:
labels=[line.strip() for line in f.readlines()]
# 确定out张量中最高得分对应的索引
_, index=torch.max(out,1)
# 使用index[0]获得实际的数字作为标签列表的索引,并用softmax使输出归一化
percentage=torch.nn.functional.softmax(out,dim=1)[0]*100
print(labels[index[0]],percentage[index[0]].item())
# 输出结果
Pembroke, Pembroke Welsh corgi 75.87240600585938
在本例中,模型有约75%的把握认为它看到的是彭布罗克威尔士柯基。