图像分类(VGG)(1)


已完成训练的VGG模型的使用方法

使用ImageNet数据集中已经提前训练好网络参数的VGG-16模型来实现对未知图片进行自动分类处理的程序。
ImageNet是斯坦福大学从互联网上收集的已分类的图像数据集,ILSVRC竞赛常用(ImageNet Large Scale Visual Recognition Challenge)
Torch中可以轻松使用ImageNet数据集中的ILSVRC2012数据集(分类数:1000种;训练用数据:120万张;验证用数据:5万张;测试用数据:10万张)

文件夹准备

import os
import urllib.request
import zipfile



#·文件夹“data”不存在时制作
data_dir = "./data/"
if not os.path.exists(data_dir):
    os.mkdir(data_dir)



#下载ImageNet的class_index
#是在Keras准备的。
# https://github.com/fchollet/deep-learning-models/blob/master/imagenet_utils.py

url = "https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json"
save_path = os.path.join(data_dir, "imagenet_class_index.json")

if not os.path.exists(save_path):
    urllib.request.urlretrieve(url, save_path)



#1.3下载并解压缩你要用到的蚂蚁和蜜蜂的图像数据
# 是在PyTorch指南课程中准备的。
# https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html

url = "https://download.pytorch.org/tutorial/hymenoptera_data.zip"
save_path = os.path.join(data_dir, "hymenoptera_data.zip")

if not os.path.exists(save_path):
    urllib.request.urlretrieve(url, save_path)

    # 读取ZIP文件
    zip = zipfile.ZipFile(save_path)
    zip.extractall(data_dir)  # 解压缩ZIP
    zip.close()  # 盗取ZIP文件

    #删除ZIP文件
    os.remove(save_path)





【※(实施完)】

手动下载金毛寻回犬的图像

https://pixabay.com/ja/photos/goldenretriever-%E7%8A%AC-3724972/
640x426尺寸的图像
(图片版权信息:CCO Creative Commons,免费商业使用,无需标注归属)

将其直接放在文件夹“data”的下方。

Code

导入软件包

# 导入软件包
import numpy as np
import json
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline

import torch
import torchvision
from torchvision import models, transforms

VGG-16已完成训练模型的载入

#VGG-16已完成训练模型的载入
# 第一次执行时,由于需要从网络下载学习好的参数数据,因此执行时间会稍微长一些

#生成VGG-16模型的实例
use_pretrained = True  # 使用已经训练好的参数
net = models.vgg16(pretrained=use_pretrained)
net.eval()  # 设置为推测模式

#  输出模型的网络结构
print(net)

实现一个对输入图片进行预处理的类BaseTransform()
注意:这里的__call__()作用是,如果不指定函数名而直接调用实例的变量名,call()函数内的代码直接会被执行。这里等于说就是直接返回一个被预处理过后的一个图片。

# 对输入图片进行预处理的类
class BaseTransform():
    """
    调整图片的尺寸,并对颜色进行规范化。

    Attributes
    ----------
    resize : int
       指定调整尺寸后图片的大小
    mean : (R, G, B)
       各个颜色通道的平均值
    std : (R, G, B)
       各个颜色通道的标准偏差
    """

    def __init__(self, resize, mean, std):
        self.base_transform = transforms.Compose([
            transforms.Resize(resize),  #将较短边的长度作为resize的大小
            transforms.CenterCrop(resize),  #从图片中央截取resize × resize大小的区域
            transforms.ToTensor(),  #转换为Torch张量
            transforms.Normalize(mean, std)  #颜色信息的正规化
        ])

    def __call__(self, img):
        return self.base_transform(img)

plt.show()一下预处理的效果,可省略.

注意:由于tentor即张量为( 颜色、高度、宽度 ),转换成np后需要转换为 ( 高度、宽度、颜色 )img_transformed = img_transformed.numpy().transpose((1, 2, 0)),如何限制范围为0~1,img_transformed = np.clip(img_transformed, 0, 1)

#确认图像预处理的结果

# 1. 读取图片
image_file_path = './xxxxxxxxxx/xxx.jpg'
img = Image.open(image_file_path)  # [高度][宽度][颜色RGB]

# 2.  显示处理前的图片示
plt.imshow(img)
plt.show()

# 3. 同时显示预处理前后的图片
resize = 224
mean = (0.485, 0.456, 0.406)
std = (0.229, 0.224, 0.225)
transform = BaseTransform(resize, mean, std)
img_transformed = transform(img)  # torch.Size([3, 224, 224])

# 将 ( 颜色、高度、宽度 ) 转换为 ( 高度、宽度、颜色 ),并将取值范围限制在0~1
img_transformed = img_transformed.numpy().transpose((1, 2, 0))
img_transformed = np.clip(img_transformed, 0, 1)
plt.imshow(img_transformed)
plt.show()

实现一个处理输出后结果进行预测的类ILSVRCPredictor(),即实现将VGG16模型1000维的输出结果转换为分类标签的ILSVRCPredictor类。

从VGG-16模型输出的数值被保存到大小为torch.Size([1,1000])的PyTorch张量中,这里需要将其转换为NumPy变量。因此调用.debatch(),将输出结果从网路中分离出来;然后,对被debatch的张量进行.numpy()调用,将其转换为numpy变量,并用np.argmax()获取最大值的索引。

ILSVRC_class_index = json.load(open('./data/imagenet_class_index.json', 'r'))

# 根据输出结果对标签进行预测的后处理类
class ILSVRCPredictor():
    """
    根据ILSVRC数据,从模型的输出结果计算出分类标签

    Attributes
    ----------
    class_index : dictionary
           将类的index与标签名关联起来的字典型变量
    """

    def __init__(self, class_index):
        self.class_index = class_index

    def predict_max(self, out):
        """
        获得概率最大的ILSVRC分类标签名

        Parameters
        ----------
        out : torch.Size([1, 1000])
            从Net中输出结果

        Returns
        -------
        predicted_label_name : str
            预测概率最高的分类标签的名称
        """
        maxid = np.argmax(out.detach().numpy())
        #str()将数字->字符,class_index是字典,所以key是字符,故str(),再然后values是一个列表,列表第二个元素是#所分类别的名字,故[1]
        predicted_label_name = self.class_index[str(maxid)][1]

        return predicted_label_name

调用已完成学习的VGG开始预测手头的图片啦

整理一下思路,输入的图片经过BaseTransform()预处理转换后,被作为VGG-16模型的输入数据输入。模型输出的1000维数据又经过ISVRCPredicor的处理,被转换为预测概率最高的分类标签名,并作为最终的输出结果返回。

注意,在将图片输入PyTorch网络中,需一小批次的形式传递,故使用.unsqueeze_(0),(英语单词非压缩,即扩展)0代表是第一维度,作用就是扩展一个维度,在整体大小不变的情况下,且增大的维度是第一维度(确实就batch_size=1)。

# 载入ILSVRC的标签信息,并生成字典型变量
ILSVRC_class_index = json.load(open('./data/imagenet_class_index.json', 'r'))

# 生成ILSVRCPredictor的实例
predictor = ILSVRCPredictor(ILSVRC_class_index)

# 读取输入的图像
image_file_path = './xxxx/xxxx.jpg'
img = Image.open(image_file_path)  # [ 高度 ][ 宽度 ][ 颜色RGB]

# 完成预处理后,添加批次尺寸的维度
transform = BaseTransform(resize, mean, std)  #创建预处理类
img_transformed = transform(img)  # torch.Size([3, 224, 224])
inputs = img_transformed.unsqueeze_(0)  # torch.Size([1, 3, 224, 224])

# 输入数据到模型中,并将模型的输出转换为标签
out = net(inputs)  # torch.Size([1, 1000])
result = predictor.predict_max(out)

# 输出预测结果
print("输入图像的预测结果:", result)

Author: 寒风渐微凉
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source 寒风渐微凉 !
 Previous
Next 
  TOC