通过上一次提前收集好的训练集和验证集来做此次实验。
构建训练集和验证集
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, BatchNormalization, Conv2D, MaxPool2D
num_classes = 4 # 类别 (zhou,wu,zheng,wang)
face_h, face_w = 64, 64 #头像尺寸
batch_size = 8
train_data_dir = './dataset/train'
validation_data_dir = './dataset/valid'
ImageDataGenerator是对待训练的数据集执行一系列随机变换后进行训练模型,提高模型的通用性,使得模型具有更好的泛化能力。
flow_from_directory(directory): 以文件夹路径为参数,生成经过数据提升/归一化后的数据,在一个无限循环中无限产生batch数据
# 数据增强
train_datagen = ImageDataGenerator(rescale=1./255)
validation_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(face_h, face_w),
batch_size=batch_size,
class_mode='categorical',
shuffle=True)
validation_generator = validation_datagen.flow_from_directory(
validation_data_dir,
target_size=(face_h, face_w),
batch_size=batch_size,
class_mode='categorical',
shuffle=True)
模仿 VGG-16 模型的结构
自定义CNN模型(老师教的使用这个,但是好像添点层数反而会下降很多,缺点层数准确率反而
会上升,这块有点不明白,有大佬看见可以解释一下么)
conv=33filter,s=1 max-tool=22,s=2
# 定义模型
model = Sequential(name = 'Face_Model')
#BLOCK1
# 卷积层1
model.add(Conv2D(32, (3, 3), padding = 'same', activation = 'relu',input_shape = (face_h, face_w, 3)))
model.add(BatchNormalization())
# 卷积层2
model.add(Conv2D(32, (3, 3), padding = "same", activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(pool_size=(2, 2)))
# Block2
# 卷积层3
model.add(Conv2D(64, (3, 3), padding = "same", activation = 'relu'))
model.add(BatchNormalization())
# 卷积层4
model.add(Conv2D(64, (3, 3), padding = "same", activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(pool_size=(2, 2)))
# Block3:
# 卷积层5
model.add(Conv2D(128, (3, 3), padding = "same", activation = 'relu'))
model.add(BatchNormalization())
# 卷积层6
model.add(Conv2D(128, (3, 3), padding = "same", activation = 'relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(pool_size=(2, 2)))
# Block4
# 卷积层7
# model.add(Conv2D(256, (3, 3), padding = "same", activation = 'relu'))
# model.add(BatchNormalization())
# # 卷积层8
# model.add(Conv2D(256, (3, 3), padding = "same", activation = 'relu'))
# model.add(BatchNormalization())
# model.add(MaxPool2D(pool_size=(2, 2)))
# Block5
# 全连接层FC:第9层
model.add(Flatten())
model.add(Dense(64, activation = 'relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))
# Block6
# 全连接层FC:第10层
model.add(Dense(64, activation = 'relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))
# Block7
# 全连接层FC:第11层,Softmax分类
model.add(Dense(num_classes, activation = 'softmax'))
# 模型结构
model.summary()
模型训练
fit函数返回一个History的对象,其History.history属性记录了损失函数和其他指标的数值随epoch变化的情况,如果有验证集的话,也包含了验证集的这些指标变化情况。
(计时性能测试%%time:用%%time 计算时间的单元(cell)的变量被释放,不能继续被下一单元使用,我用的jupyter )
from tensorflow.keras.optimizers import Adam #优化算法
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau#回调函数
%%time
# 定义回调函数:保存最优模型
checkpoint = ModelCheckpoint("./Trained_Models/face_recognition_model.h5",
monitor="val_loss",
mode="min",
save_best_only = True,
save_weights_only=False,
verbose=1)
# 定义回调函数:提前终止训练
earlystop = EarlyStopping(monitor = 'val_loss',
min_delta = 0,
patience = 5,
verbose = 1,
restore_best_weights = True)
# 定义回调函数:学习率衰减
reduce_lr = ReduceLROnPlateau(monitor = 'val_loss',
factor = 0.8,
patience = 3,
verbose = 1,
min_delta = 0.0001)
# 将回调函数组织为回调列表
callbacks = [earlystop, checkpoint, reduce_lr]
# 模型编译,指定损失函数、优化算法、学习率和模型评价标准
model.compile(loss = 'categorical_crossentropy',
optimizer = Adam(lr=0.01),
metrics = ['accuracy'])
#训练集样本数量
n_train_samples = train_generator.n
#验证集样本数量
n_validation_samples =validation_generator.n
# 训练代数
epochs = 20
# 开始训练
history = model.fit(
train_generator,
steps_per_epoch = n_train_samples // batch_size,
epochs = epochs,
callbacks = callbacks,
validation_data = validation_generator,
validation_steps = n_validation_samples // batch_size)
迭代完成
绘制模型准确率曲线
最后绘制一下曲线(记得要加%matplotlib inline这个,要不然图像不显示
)
import matplotlib.pyplot as plt
%matplotlib inline
x = range(1, len(history.history['accuracy'])+1)
plt.plot(x, history.history['accuracy'])
plt.plot(x, history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.xticks(x)
plt.legend(['Train', 'Val'], loc='upper left')
plt.show()
#绘制模型损失函数曲线
plt.plot(x, history.history['loss'])
plt.plot(x, history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.xticks(x)
plt.legend(['Train', 'Val'], loc='upper right')
得到结果