使用VGG-16实现ImageNet数据集分类

877 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本篇博客主要讲解一下VGG16,之所以称之为16,指的是13个卷积层+3个全连接层,网络的结构如下所示。

vgg.jpg

在图片中首先看到的是输入,为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数据集上的训练模型,识别结果如下所示 我测试的图片放一张

cat2.jpg 识别结果如下所示

2.PNG 对应类别为283,对照网址中(gist.github.com/yrevar/942d…)

给出的类别显示为tiger cat,可能差不多吧,因为我也分不清楚这是什么种类的猫。