58.3_使用已训练的VGG16

58.3 使用已训练的VGG16

接下来使用已训练的VGG16进行图像识别。首先要做的是加载样本图像。

importdezero   
from PIL import Image   
url  $=$  'https://github.com/oreilly-japan/deep-learning-from-scratch-3/' raw/images/zebra.jpg   
img_path  $\equiv$ dezero.util.get_file(url)   
img  $=$  Image.open(img_path)   
img.show()

上面的代码使用前面介绍的dezero.utils.get_file函数下载图像文件,然后使用 PIL包读取已下载的图像。执行上述代码,会显示图58-3中的图像。


图58-3 使用PIL读取的样本图像

PIL(Python Image Library)是一个图像处理库,针对图像提供了读取、保存、转换等功能。我们可以通过pip install pillow来安装PIL。

前面代码中的img = Image.open(img_path)用于读取图像,img的类型是 PIL.Image。但是DeZero处理的数据是ndarray类型,因此我们需要使用执行转换处理的函数。我们在DeZero的VGG16类中准备一个静态方法preprocess。该方法可按以下方式使用。

from models import VGG16  
x = VGG16 preprocess(img)  
print(type(x), x.shape)

运行结果

<class 'numpy.ndarray'> (3, 224, 224)

preprocess是静态方法,它可以从类调用,无须通过实例。它接收的参数是PIL.Image类型的数据。内部所做的处理是将数据调整为高224、宽224的大小,然后将其转换为ndarray实例。这里的大小(224,224)是VGG16的输入图像的大小。VGG16.preprocess方法也做了一些其他的预处理,如按照BGR的顺序排列颜色通道、减去固定值等。这些是用VGG16训练ImageNet时要做的预处理。

在使用已训练的权重数据推断未知数据时,需要做与训练模型时相同的预处理,否则输入到模型的数据将是不同的,模型无法正确进行识别。

准备工作已经完成。下面使用已训练的VGG16进行分类。以下是step/step58.py中的所有代码。

steps/step58.py

import numpy as np  
from PIL import Image  
importdezero  
fromdezero.models import VGG16
url = 'https://github.com/oreilly-japan/deep-learning-from-scratch-3/'\  
'raw/images/zebra.jpg'  
img_path =dezero.utils.get_file(url)  
img = Image.open(img_path)  
x = VGG16.preprocess(img)  
x = x[np.newaxis] #增加用于小批量处理的轴  
model = VGG16(pretrained=True)  
withdezero.test_mode():  
    y = model(x)  
predict_id = np.argmax(y.data)  
model.plot(x, to_file='vgg.pdf') #计算图的可视化  
labels =dezerodatasets.ImageNet.labels() #ImageNet的标签  
print(labels[predict_id])

运行结果

zebra

上面的代码首先读取图像,进行预处理,然后在数据的前面添加用于小批量的轴。这会使 xx 的形状由 (3, 224, 224) 变为 (1, 3, 224, 224)。之后将数据传给 VGG16,让它进行推理。输出层 (1000 个类别) 中数值最大的索引就是模型分类的结果。

另外,dezero/datasets.py中还准备了ImageNet的标签(键为对象ID、值为标签名的字典)。使用它可以从对象ID中取出标签名称。结果zebra(斑马)表明图像被正确识别了出来。到这里就完成了VGG16的实现。

除VGG16之外,dezero/models.py中还有其他著名的模型,如ResNet(参考文献[37])和SqueezeNet(参考文献[38])。感兴趣的读者可以参考。

步骤59

使用 RNN 处理时间序列数据

我们此前见到的神经网络是具有前馈(feed forward)结构的网络。前馈指信号向一个方向前进,它的特点是输出只取决于输入。而RNN(循环神经网络)是具有如图59-1所示的循环结构的网络。


图59-1 RNN的结构

图59-1中的循环结构使RNN的输出前馈到自身。所以,RNN网络拥有“状态”。也就是说,当数据输入到RNN时,状态被更新,输出由状态决定。

本步骤的主题是RNN。RNN在计算上比前馈网络更复杂。但有了DeZero,如此复杂的计算也能简单地实现。在本步骤,笔者将结合RNN的实现来介绍RNN的原理。