本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本篇博客主要讲解一下VGG16,之所以称之为16,指的是13个卷积层+3个全连接层,网络的结构如下所示。
在图片中首先看到的是输入,为224x224x3的图像,相比于之前的CIFAR10的32x32大了可不止一半点,这也是为啥imagenet数据集达到了130多个G的原因。图中黑色框表示的是卷积层,有13个,红色表示的是池化层有5个,全连接层有三个,softmax一个,这个就是整个的网络结构,整体没有太难。代码让如下所示
# VGG16的网络结构
def VGG_16_struct():
model = models.Sequential()
# 将输入的图片在上下左右各填充一行0,为的是保证卷积后的尺寸保持原来输入大小
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'))
# 最大池化,步长为2,完成后输入图像大小变为(224-2+2*0)/2+1=112
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'))
# 最大池化,步长为2,完成后输入图像大小变为(112-2+2*0)/2+1=56
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'))
# 最大池化,步长为2,完成后输入图像大小变为(56-2+2*0)/2+1=28
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'))
# 最大池化,步长为2,完成后输入图像大小变为(28-2+2*0)/2+1=14
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'))
# 最大池化,步长为2,完成后输入图像大小变为(14-2+2*0)/2+1=7
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(layers.Flatten())
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))
# imagenet数据集有1000类
# 类别见网址https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a
model.add(layers.Dense(1000, activation='softmax'))
return model
按照之前的写作风格,此时应该给出完整的代码,不过呢,由于电脑的原因,imagenet数据集太大,训练一次太久了。。。。所以我只把网络结构放上去,然后用tensorflow现成的训练结果进行演示,代码如下
# 使用VGG-16实现CIFAR10数据集的训练和预测
# 导入依赖包
import tensorflow as tf
from tensorflow.keras import datasets, optimizers, layers, models
from tensorflow.keras.applications.vgg16 import VGG16
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 导入数据集
model = VGG16(weights='imagenet', include_top=True)
model.compile(optimizer='sgd', loss='categorical_crossentropy')
img = cv2.resize(cv2.imread("./cat2.jpg"), (224, 224))
img = np.expand_dims(img, axis=0)
rest = model.predict(img)
index = np.argmax(rest)
print("列别为:", index)
plt.plot(rest.ravel())
plt.show()
这样即使用了VGG16,又使用了Imagenet数据集上的训练模型,识别结果如下所示 我测试的图片放一张
识别结果如下所示
对应类别为283,对照网址中(gist.github.com/yrevar/942d…)
给出的类别显示为tiger cat,可能差不多吧,因为我也分不清楚这是什么种类的猫。