TensorFlow深度学习实战(9)——构建VGG模型实现图像分类
0. 前言
VGG
模型是一种经典的深度卷积神经网络 (Convolutional Neural Network, CNN) 架构,该模型以其简单而有效的设计而著名,在图像分类任务中取得了优异成绩。VGG
模型的核心特点是采用了深层的网络结构,其中大部分层由卷积层和池化层组成,且卷积操作使用了尺寸较小的 3 x 3
卷积核,这使得网络能够捕捉到丰富的图像特征。
1. VGG 模型
1.1 VGG16 与 VGG19
VGG
是于 2014
年提出的图像识别模型,通过将网络层深度增加到 16-19
个,显著提高了网络性能。模型在 ImageNet ILSVRC-2012
数据集上对模型进行训练,数据集包含 1000
个类别的图像,分为三组:训练集 (130
万张图像)、验证集 (5
万张图像)和测试集( 10
万张图像)。每个图像为 224 x 224
像素,具有 3
个通道。VGG16
模型在 ILSVRC-2012
验证集上的 top-5
错误率为 7.5%
,在 ILSVRC-2012
测试集上的 top-5
错误率为 7.4%
。
VGG19
是 VGG16
的改进版本,具有更多的卷积和池化操作,VGG19
模型的体系结构如下:
可以看到,上示的体系结构中具有更多的网络层以及更多的参数量。需要注意的是,VGG16
和 VGG19
体系结构中的 16
和 19
代表这些网络中的网络层数。
1.2 ImageNet
ImageNet
竞赛的目标是利用一个大型手工标注的 ImageNet
数据集( 1000
万标记图像,描述了 10000
多个类别)的子集进行训练,算法需要预测图像中存在的对象的标签,以便对照片内容进行检索和自动标注。
2. 构建 VGG16 模型实现图像分类
2.1 模型构建
使用 tf.keras
能够预加载已经训练完成的 VGG
模型权重到 tf.keras
模型中使用:
import tensorflow as tf
from tensorflow.keras import layers, models
import cv2, numpy as np
import os
# define a VGG16 network
def VGG_16(weights_path=None):
model = models.Sequential()
model.add(layers.ZeroPadding2D((1,1),input_shape=(224,224, 3)))
model.add(layers.Convolution2D(64, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2), strides=(2,2)))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(128, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2), strides=(2,2)))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(256, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(256, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2), strides=(2,2)))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2), strides=(2,2)))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.ZeroPadding2D((1,1)))
model.add(layers.Convolution2D(512, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2), strides=(2,2)))
model.add(layers.Flatten())
#top layer of the VGG net
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1000, activation='softmax'))
if weights_path:
model.load_weights(weights_path)
return model
虽然我们可以使用 tf.keras.applications.vgg16
来直接获取模型及其权重,但为了展示 VGG16
的内部工作原理,我们使用 tf.keras
实现了一个 VGG16
网络,接下来,将使用该模型实现图像分类。
2.2 使用 VGG16 网络识别猫
使用预训练权重测试模型性能:
im = cv2.resize(cv2.imread('cat.jpg'), (224, 224)).astype(np.float32)
im = np.expand_dims(im, axis=0)
# Test pretrained model
path_file = os.path.join(os.path.expanduser("~"), '.keras/models/vgg16_weights_tf_dim_ordering_tf_kernels.h5')
model = VGG_16(path_file)
model.summary()
model.compile(optimizer='sgd', loss='categorical_crossentropy')
out = model.predict(im)
print(np.argmax(out))
模型返回类别 281
,对应于 tabby, tabby cat
:
可以看到,我们所实现的 VGG16
网络能够成功识别猫的图像。
3. 使用 tf.Keras 内置的 VGG16 网络模块
tf.Keras.applications
包含预构建和预训练的深度学习模型。在实例化模型时,权重会自动下载并存储在 ~/.keras/models/
中,使用模型预测小狗图像:
import tensorflow as tf
from tensorflow.keras.applications.vgg16 import VGG16
import matplotlib.pyplot as plt
import numpy as np
import cv2
# prebuild model with pre-trained weights on imagenet
model = VGG16(weights='imagenet', include_top=True)
model.compile(optimizer='sgd', loss='categorical_crossentropy')
# resize into VGG16 trained images' format
im = cv2.resize(cv2.imread('dog.jpg'), (224, 224))
im = np.expand_dims(im, axis=0)
im.astype(np.float32)
# predict
out = model.predict(im)
index = np.argmax(out)
print(index)
plt.plot(out.ravel())
plt.show()
运行代码,模型返回结果 208
,对应于 Labrador retriever
,模型返回的其它类别置信度都非常小。
4. 利用预训练模型进行特征提取
当网络学习如何将图像分类到正确类别时,每一层都学会了识别执行最终分类所必需的特征。较低层识别低阶特征,如颜色和边缘,而较高层将这些低阶特征组合成形状或物体等高阶特征。因此,中间层具有提取图像重要特征的能力,这些特征能够用于模型执行分类任务。
可以使用深度卷积神经网络进行特征提取,本节中,我们以 VGG16
为例从特定层中提取图像特征。需要注意的是,由于顺序模型仅接受层进行构建,因此需要使用函数式 API
:
import tensorflow as tf
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras import models
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input
import numpy as np
import cv2
# prebuild model with pre-trained weights on imagenet
base_model = VGG16(weights='imagenet', include_top=True)
print (base_model)
for i, layer in enumerate(base_model.layers):
print (i, layer.name, layer.output_shape)
# extract features from block4_pool block
model = models.Model(inputs=base_model.input,
outputs=base_model.get_layer('block4_pool').output)
img_path = 'cat.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
# get the features from this block
features = model.predict(x)
print(features)
使用预训练模型进行特征提取具有以下优点:
- 可以重用公开的大规模训练模型,并将学习的特征应用到新任务
- 可以节省大量的训练时间
- 即使在没有大量训练样本的情况下,也可以得到合理的解决方案
- 可以使用一个适合当前任务的初始网络结构,而不必从零开始构建模型
小结
通过使用小尺寸的卷积核和深层网络设计,VGG
能够有效地提取图像的特征,并在各种视觉任务中取得优异的表现。在实际应用中,可以通过迁移学习等方式,充分利用 VGG
的预训练模型,加速训练过程并提高分类效果。
系列链接
TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(6)——回归分析详解
TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(8)——卷积神经网络