VGG19是VGG网络中一个更复杂的网络,相比较于VGG16,它的层数更深。
VGG19网络都使用了同样大小的卷积核尺寸(3x3)和最大池化尺寸(2x2)。但是它的训练时间过长,调参难度大,并且需要的存储容量大,不利于部署。
本次基于CNN和VGG19,对灵笼人物进行识别。其中VGG19网络分别调用了官方模型和自己搭建的模型。
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import os,PIL,pathlib
from tensorflow import keras
from tensorflow.keras import layers,models,Sequential,Input
from tensorflow.keras.layers import Conv2D,MaxPooling2D,Dense,Flatten,Dropout
from tensorflow.keras.models import Model
①添加文件路径
data_dir = "E:/tmp/.keras/datasets/linglong_photos"
data_dir = pathlib.Path(data_dir)
②构建一个ImageDataGenerator
#因为训练集和测试集是在一个文件夹中,所以构建一个ImageDataGenerator就可以
train_data_gen = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1./255,
rotation_range=45,
shear_range=0.2,
validation_split=0.2,#以8:2的比例划分训练集和测试集
horizontal_flip=True
)
③划分训练集和测试集
train_ds = train_data_gen.flow_from_directory(
directory=data_dir,
target_size=(height,width),
batch_size=batch_size,
shuffle=True,
class_mode='categorical',
subset='training'
)
test_ds = train_data_gen.flow_from_directory(
directory=data_dir,
target_size=(height,width),
batch_size=batch_size,
class_mode='categorical',
subset='validation'
)
结果如下:
Found 225 images belonging to 6 classes.
Found 55 images belonging to 6 classes.
height = 224
width = 224
batch_size = 16
epochs = 10
网络结构:3层卷积池化层+Flatten+全连接层
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,3,padding="same",activation="relu",input_shape=(height,width,3)),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(32,3,padding="same",activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64,3,padding="same",activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(128,3,padding="same",activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1024,activation="relu"),
tf.keras.layers.Dense(512,activation="relu"),
tf.keras.layers.Dense(6,activation="softmax")
])
网络编译&&运行
model.compile(optimizer="adam",
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["acc"])
history = model.fit(
train_ds,
validation_data=test_ds,
epochs=epochs
)
实验结果如下:
不尽如人意,这个上下波动就很无语。将epochs调大后的结果如下:
opt = tf.keras.optimizers.Adam(learning_rate=1e-5)
model.compile(optimizer=opt,
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["acc"])
在改变优化器之后,效果得到了很大的改善,准确率也得到了提高。
conv_base = tf.keras.applications.VGG19(weights='imagenet',include_top=False)
#设置为不可训练
conv_base.trainable =False
#模型搭建
model = tf.keras.Sequential()
model.add(conv_base)
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(1024,activation='relu'))
model.add(tf.keras.layers.Dense(6,activation='sigmoid'))
opt = tf.keras.optimizers.Adam(learning_rate=1e-5)
model.compile(optimizer=opt,
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["acc"])
history = model.fit(
train_ds,
validation_data=test_ds,
epochs=epochs
)
实验结果如下所示(epochs=10):
相比于上面的网络,效果还算可以。没有出现大规模的波动,最后的准确率也比较高。
②自己搭建VGG19网络
参考自K同学啊
def VGG19(nb_classes,input_shape):
input_ten = Input(shape=input_shape)
#1block
x = Conv2D(64,(3,3),activation='relu',padding='same',name='block1_conv1')(input_ten)
x = Conv2D(64,(3,3),activation='relu',padding='same',name='block1_conv2')(x)
x = MaxPooling2D((2,2),strides=(2,2),name='block1_pool')(x)
#2block
x = Conv2D(128,(3,3),activation='relu',padding='same',name='block2_conv1')(x)
x = Conv2D(128,(3,3),activation='relu',padding='same',name='block2_conv2')(x)
x = MaxPooling2D((2,2),strides=(2,2),name='block2_pool')(x)
#3block
x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv4')(x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
#4block
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv4')(x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
#5block
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv4')(x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
#Full
x = Flatten()(x)
x = Dense(4096, activation='relu', name='fc1')(x)
x = Dense(4096, activation='relu', name='fc2')(x)
output_ten = Dense(nb_classes, activation='softmax', name='predictions')(x)
model = Model(input_ten, output_ten)
return model
model = VGG19(6,(width,height,3))
实验结果如下所示:
就特么离谱,都不知道为啥会有这么大的差别,希望路过的大佬批评指正。
总结
经过改变优化器以及增加epochs之后,自己搭建的CNN准确率是比较好的,但是出现了较大规模的波动。VGG19网络的训练速度确实比较慢,但是官方模型的准确率是比较好的,没有出现CNN模型的波动情况。由于硬件原因,博主在实验时的epochs设置的都比较小,可以尝试一下epochs增大时的效果如何。自己搭建的VGG19网络,最后的模型准确率也比较高,但是波动较大,而且很不稳定,具体原因不清楚。