赞
踩
本文内容将讲述如何利用已经训练好的VGG-16模型(基于ImageNet数据集)来自动识别图像类别,其中模型测试将使用GPU主机而非GPU主机实现;并介绍如何下载利用PyTorch框架、什么是VGG-16以及实现对图像的尺寸与颜色的变换。
ImageNet是斯坦福大学从互联网上收集的大量图片后,对其分类整理后所形成的数据集。在PyTorch中可以轻松使用ImageNet数据集中的ILSVRC2012数据集,该数据集有1000种分类数,包含大多数日常所见到的物品(如玩具、零食与动物等),共120万张图片作为训练集,5万张作为验证集,10万张作为测试集;在PyTorch中还可以很方便使用各种已经训练好的或者是学习好的参数与神经网络模型。
VGG-16是2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG19最为著名。
VGG网络被广泛应用于图像分类、目标检测、语义分割等计算机视觉任务中,并且其网络结构的简单性和易实现性使得VGG成为了深度学习领域的经典模型之一。
首先进入Pytorch官网,根据自己的电脑配置好对应的torch版本以及torchvision软件包,下图第一行红色底色为稳定版本(推荐),第二行为操作系统(一般为Windows系统),第三行为安装方式(Conda与Pip都行),第五行要根据自己的GPU以及NVIDIA下载对应的CUDA版本(torch官网会自动检测电脑所适应的版本),如果电脑没有GPU或者是A卡,则可以选择CPU下载方式,最后复制最后一行的代码在cmd命定窗(其他地方也行,如jupyter)运行即可。(这里建议读者去根据专门的教程下载torch)
首先导入对应的软件包,并确认Pytorch版本号
# 导入软件包
import numpy as np
import json
from PIL import Image
import matplotlib.pyplot as plt
import torch
import torchvision
from torchvision import models, transforms
%matplotlib inline
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
#主要解决jupyter notebook“内核似乎挂掉了,它很快将自动重启”的问题
print("PyTorch Version: ",torch.__version__)
print("Torchvision Version: ",torchvision.__version__)
第一次执行该代码将会耗费较长时间,需要下载对应的训练参数。
#VGG-16已完成训练模型的载入
# 第一次执行时,由于需要从网络下载学习好的参数数据,因此执行时间会稍微长一些
#生成VGG-16模型的实例
use_pretrained=True
# 使用已经训练好的参数
net=models.vgg16(pretrained=use_pretrained)
net.eval() # 设置为推测模式,也就是测试模式,能够直接进行预测
# 输出模型的网络结构
print(net)
加载好后,打印输出网络模型,可以看到,VGG-16主要采用3*3的卷积结构,relu激活函数以及最大池化层,通道数由64个开始翻倍增长(网格输入的图像尺寸为颜色通道数为3的RGB格式,图像高宽均为224像素 [批次,3,224,224])
,这样子使得模型”窄而深“的同时,参数量也不会过多,最后连接三层全连接网络层,由于有1000个类别,故输出神经元为1000。
图片为在网络上随机寻找的金毛犬图片(1300,1100,3),为了方便输入到模型中,需要对图片进行一定的预处理操作,首先将尺寸转换为224*224大小,并对颜色信息进行标准化,对每个RGB值用平均值与标准偏差进行归一化处理(根据ILSVRC2012数据集计算得到的)。
# 对输入图片进行预处理的类
class BaseTransform():
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)
#确认图像预处理的结果 # 读取图片 image_file_path='./data/R-C.jpg' #该图片保存在当前路径下data文件夹下,命名为R-C.jpg img=Image.open(image_file_path) # [高度][宽度][颜色RGB] plt.imshow(img) plt.show() 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)) #转换为[长,宽,通道]方便imshow img_transformed=np.clip(img_transformed, 0, 1) plt.imshow(img_transformed) plt.show()
首先需要下载模型所预测得到1000个结果类别的json文件imagenet_class_index.json
#·文件夹“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)
再载入分类标签信息,保存为字典形式
#根据ILSVRC数据,从模型的输出结果计算出分类标签
ILSVRC_class_index=json.load(open('./data/imagenet_class_index.json', 'r'))
ILSVRC_class_index
根据ILSVRC数据,从模型的输出结果计算出分类标签,具体首先细节可查看下方代码:
# 根据输出结果对标签进行预测的后处理类 class ILSVRCPredictor(): """ ---------- 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()) #detach将结果从网格分离出来,并转为numpy数组 predicted_label_name=self.class_index[str(maxid)][1] #得到预测类别名 return predicted_label_name
将已经处理好的图片后,可以很方便的使用已训练VGG-16模型来对图片进行预测,模型预测的1000个类别经过前面定义的ILSVRCPredictor函数处理后,将返回预测概率最高的分类类别标签,具体代码如下,由于将图片传入到Pytorch网络中,需要采用批次处理([批次,通道,长,宽]类似这种格式),所以这里采用小批次对图片进行处理后,再输入到网络中。
# 载入ILSVRC的标签信息,并生成字典型变量 ILSVRC_class_index=json.load(open('./data/imagenet_class_index.json', 'r')) predictor=ILSVRCPredictor(ILSVRC_class_index)# 生成ILSVRCPredictor的实例 # 读取输入的图像 image_file_path='./data/R-C.jpg' img=Image.open(image_file_path) # [ 高度 ][ 宽度 ][ 颜色RGB] # 完成预处理后,添加批次尺寸的维度 transform=BaseTransform(resize, mean, std) #创建预处理类 img_transformed = transform(img) inputs=img_transformed.unsqueeze_(0) # torch.Size([3, 224, 224])(0) # torch.Size([1, 3, 224, 224]) 小批次 out=net(inputs) #输出结果1000维 result =predictor.predict_max(out)# 输入数据到模型中,并将模型的输出转换为标签.predict_max# torch.Size([1, 1000])(out)(概率最大) # 输出预测结果 print("输入图像的预测结果:", result)
可以看到,模型成功的将图片预测为金毛犬(金毛寻回犬)。接下来,我们再随机找一张图片,看看模型的预测结果是否正确:
image_file_path='./data/R-C2.jpg' #甲壳虫图片
img=Image.open(image_file_path) # [高度][宽度][颜色RGB]
plt.imshow(img)
plt.show()
resize=224# 3. 同时显示预处理前后的图片
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()
首先对图片进行同样的预处理后,得到的结果如下:
接着还是相同的步骤,对图片进行小批次处理后,将图片输入到VGG-16模型中,可以看到,模型同样正确的预测出图片的类别:叶甲虫
# 读取输入的图像
image_file_path='./data/R-C2.jpg'
img=Image.open(image_file_path) # [ 高度 ][ 宽度 ][ 颜色RGB]
# 完成预处理后,添加批次尺寸的维度
transform=BaseTransform(resize, mean, std)
#创建预处理类
img_transformed = transform(img)
inputs=img_transformed.unsqueeze_(0) # torch.Size([3, 224, 224])(0) # torch.Size([1, 3, 224, 224]) 小批次
out=net(inputs)
result =predictor.predict_max(out)
# 输出预测结果
print("输入图像的预测结果:", result)
本章内容主要讲述如何利用已学习好的VGG-16模型进行图片的自动分类预测,可以发现利用迁移学习可以很方便的进行我们所需要的研究,而且结果也相当不错,对于VGG-16模型,还有VGG-19,读者如果感兴趣可以自己去练习实践。对于VGG网络模型的原理不是本文重点,如果对VGG模型感兴趣可以去找相关资料学习。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。