"""如何在小型数据集上进行卷积神经网络的训练
小型数据集:在实际应用场景中,可能会遇到数据量不够的情况
这里的小可能是几百张图像,也可能是几万张图像
面临的问题:
小型数据集由于数据量不够,网络训练过程中记忆容易出现过拟合
常见的解决方案:
①从头开始自己训练一个小型模型
②使用预训练的网络做特征提取
③对预训练的网络进行微调"""
"""本次实验,我们使用kaggle竞赛中的猫狗分类数据集,我们从中抽取:
猫狗各1000张作为训练集,猫狗各500张作为验证集,猫狗各500张作为测试集
我们从头开始训练一个小型网络:4层卷积+2层全连接"""
from tensorflow.keras import layers
from tensorflow.keras import models
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(150,150,3))) #注意图片尺寸不统一,在输入网络之前,我们将尺寸统一至150*150
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(1,activation="sigmoid"))
# print(model.summary())
"""数据预处理:
keras内部具有从文夹中读取图片,并将对其进行预处理(缩放,数据类型转换等),并对其进行批量化的生成器"""
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import os
#查看对应文件夹的文件数
new_data_dir="cat_and_dog_small" #存放小数据集路径
#构建小数据集中的训练,验证,测试数据文件夹
train_data_dir=os.path.join(new_data_dir,"train")
val_data_dir=os.path.join(new_data_dir,'val')
test_data_dir=os.path.join(new_data_dir,"test")
#猫的训练数据存储
train_cats_dir=os.path.join(train_data_dir,"cats")
val_cats_dir=os.path.join(val_data_dir,"cats")
test_cats_dir=os.path.join(test_data_dir,"cats")
#狗的训练数据存储
train_dogs_dir=os.path.join(train_data_dir,"dogs")
val_dogs_dir=os.path.join(val_data_dir,'dogs')
test_dogs_dir=os.path.join(test_data_dir,"dogs")
#构建生成器
train_data_gen=ImageDataGenerator(rescale=1.0/255)
test_data_gen=ImageDataGenerator(rescale=1.0/255)
#生成器配置,加载数据
train_generator=train_data_gen.flow_from_directory(train_data_dir,target_size=(150,150),batch_size=20,class_mode="binary")
val_generator=test_data_gen.flow_from_directory(val_data_dir,target_size=(150,150),batch_size=20,class_mode="binary")
# for data,target in train_generator:
# print(data.shape)
# print(target.shape)
# break
"""训练过程配置"""
from tensorflow.keras import optimizers
from tensorflow.keras import losses
model.compile(optimizer=optimizers.RMSprop(lr=1e-4),loss=losses.binary_crossentropy,metrics=["acc"])
"""训练,对于批量数据生成器,我们可以使用fit_generator
steps_per_epoch:根据数据量/batch_size 算出
validation_steps:验证数据量/batch_Size算出"""
history=model.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=val_generator,validation_steps=50)
"""模型的保存"""
model.save("cats_and_dogs_smallNet_1.h5") #keras权重保存文件以h5为后缀
"""绘制训练过程,训练集和验证集上损失值和准确率曲线"""
import matplotlib.pyplot as plt
import numpy as np
"""损失函数绘制"""
history_dict=history.history
train_loss_values=history_dict["loss"]
val_loss_values=history_dict["val_loss"]
epochs=np.arange(1,len(train_loss_values)+1)
plt.figure(1)
plt.plot(epochs,train_loss_values,label="training loss")
plt.plot(epochs,val_loss_values,label="val loss")
plt.title("Training and Val Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
"""精度(准确率)绘制"""
train_acc=history_dict["acc"]
val_acc=history_dict["val_acc"]
plt.figure(2)
plt.plot(epochs,train_acc,label="Training Acc")
plt.plot(epochs,val_acc,label="Val Acc")
plt.title("Training and Val Acc")
plt.xlabel("Epoch")
plt.ylabel("Acc")
plt.legend()
plt.show()
图片数据存放方式
:
训练结果
:
观察上图结果,很明显模型训练过程中出现了过拟合,这是因为训练数据太少的原因,本次实验中训练样本仅仅为2000个,可以尝试采用数据增强(data agumentation
)的方式解决过拟合问题
"""model.py中,由于训练样本数目过少,导致在训练过程中出现了过拟合现象,下面尝试使用数据增强方式解决过拟合问题
数据增强:
从现有的训练样本中生成更多的训练数据
其方法是利用多种能够生成可信图像的随机变换来增加样本
其目标是模型在训练时不会两次查看完全相同的图像,让模型能够观察到数据更多的内容,从而具有更好的泛化能力"""
"""keras中的数据增强:
使用ImageDataGenerator自动进行数据增强"""
from tensorflow.keras.preprocessing import image
import os
import matplotlib.pyplot as plt
datagen=image.ImageDataGenerator(
rotation_range=40 #图像随机旋转的角度范围,取值可以为0~180
,width_shift_range=0.2 #图像在水平方向上平移的范围,其值代表平移的距离与图像尺寸的比例
,height_shift_range=0.2 ##图像在垂直方向上平移的范围,其值代表平移的距离与图像尺寸的比例
,shear_range=0.2 #随机错切变换的角度
,zoom_range=0.2 #图像随机缩放的范围
,horizontal_flip=True #随机将一半图像进行水平翻转
,fill_mode='nearest' #用于填充新像素的方法,新像素由平移或旋转产生
)
"""观察进行图像增强后的数据
随机选择一张图片,这种图像增强的机制是无限的,可以生成多种图像"""
#对应文件夹
new_data_dir="cat_and_dog_small" #存放小数据集路径
#构建小数据集中的训练,验证,测试数据文件夹
train_data_dir=os.path.join(new_data_dir,"train")
val_data_dir=os.path.join(new_data_dir,'val')
test_data_dir=os.path.join(new_data_dir,"test")
#猫的训练数据存储
train_cats_dir=os.path.join(train_data_dir,"cats")
val_cats_dir=os.path.join(val_data_dir,"cats")
test_cats_dir=os.path.join(test_data_dir,"cats")
#狗的训练数据存储
train_dogs_dir=os.path.join(train_data_dir,"dogs")
val_dogs_dir=os.path.join(val_data_dir,'dogs')
test_dogs_dir=os.path.join(test_data_dir,"dogs")
fnames=[os.path.join(train_cats_dir,file) for file in os.listdir(train_cats_dir)]
img_path=fnames[3] #随机挑选一张图片
img=image.load_img(img_path,target_size=(150,150))
img=image.img_to_array(img) #转换为numpy数组
img=img.reshape((1,)+img.shape)
i=0
for x in datagen.flow(img,batch_size=1): #每次数据增强生成1张图片,且无休止的迭代,所以后面要加中止条件
plt.figure(i)
plt.imshow(image.array_to_img(x[0]))
i+=1
if i%4==0:
break
plt.show()
结果
: