1.资料获取
辨别猫狗的图片资源来自与Kaggle的数据集,自行搜索下载即可。由于知名原因,如果没有条件进入到Kaggle竞赛网站,可以使用以下链接下载:https://pan.baidu.com/s/1pBSenGv248oxqcpws500Yg 提取码:wtm2
下载之后的数据大概猫狗各25000张左右,由于我们希望使用更少的数据达到效果,所以我们再额外建好文件夹(文件夹根目录下为训练集,验证集和测试集,其中每个文件夹内又有两个文件夹分别存放猫和狗的图片,这样利于keras处理),然后使用shutil中的copyfile从原始数据集中复制2000张用于训练,各1000张用于测试和验证。
2.数据预处理
由于获取到的图片大小不一,且并非神经网络希望的张量形式,于是需要对图片进行适当的转换,以达到神经网络能够处理的张量形式,keras的preprocessing.image.ImageDataGenerator可以帮助我们快速达到目的。
ImageDataGenerator一方面可以将图片每个pixel进行rescale,另一方面也可以将原始图片进行各种变换以达到数据增强的目的,该类下的方法flow_from_directory可以将预设好下的文件夹所有图片进行调整大小并按照之前 ImageDataGenerator的设定进行数据增强。返回值是一个生成器,大小在原函数中已预设好,生成器由变换后的数据矩阵和对应labelbatch构成,这个生成器在一个无限循环中不断的返回batch数据。由于生成数据的过程是无限不循环的,所以在后续fit_generator时要设定好每个epoch需要执行的次数,这个次数是总训练数据除以生成器的批量。
from keras.preprocessing.image import ImageDataGenerator
train_gen = ImageDataGenerator(rescale=1./255) # 将值转为float型并进行归一化
val_gen = ImageDataGenerator(rescale=1./255) # 将值转为float型并进行归一化
train_generator = train_gen.flow_from_directory(train_dir,target_size=(150,150),batch_size=20,class_mode='binary')
val_generator = val_gen.flow_from_directory(val_dir,target_size=(150,150),batch_size=20,class_mode='binary')
network.fit_generator(train_generator,steps_per_epoch=100,epochs=50,validation_data=val_generator,validation_steps=50)
这里需要注意一点的是,函数flow_from_directory中输入的路径下,必须将类别分别存放在不同的文件夹中,由于生成器是无限循环产生的,所以在后续的fit_generator要设置好steps_per_epoch以确定每个epoch取多少次生成器。
3.数据增强
为防止过拟合,除之前文章中提及的四种方法,图片处理中还可以使用一招:数据增强。过拟合的一部分原因是数据过少,神经网络甚至可以记忆所有的数据,导致没有很好的泛化能力。数据增强是通过某种变换生成可信图像,以达到模型在训练中两次不会看到同一图像的目的,这样模型可以观察到图片的更多模式,也就具有更好的泛化能力。
keras中,实现数据增强的工具仍然是ImageDataGenerator,除rescale外,其余参数中包含上下,左右平移,旋转,剪切变换,大小变换,水平翻转等。
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest') # fill_mode用于填充变换后的空白处
后面如果我们想以生成器的形式训练,则其过程与上文类似,此外,若想查看某图经变换后的结果,可先使用load_img导入图片,然后将图片转为向量img_to_array,最后使用flow函数查看某一图片的变换结果。
4.dropout
数据增强来训练一个新网络,那么网络将不会两次看到同样的输入。但网络看到的输入仍然是高度相关的,因为这些输入都来自于少量的原始图像。无法生成新信息,而只能混合现有信息。因此,这种方法可能不足以完全消除过拟合。为了进一步降低过拟合,还需要向模型中添加一个Dropout层,添加到密集连接分类器之前。
5.查看增强后的图片
2中提到的flow_from_directory实际上做了三件事,一是读入文件并转换为设定大小,这原本可以使用preprocessing中的image.load_img实现,代码如下
img = image.load_img(file_path,target_size=(150,150))
第二件事是把图片转为张量形式,这在imge中的img_to_array,
x = image.img_to_array(img)
最后使用ImageDataGenerator实例化后的对象方法flow进行数据增强,其输入要求为四维张量,同时也要设置batch_size,这个batch_size是一次从数据集中抽取数据的个数,然后对整个batch中的每个数据做一次数据增强,flow返回的生成器也是无限的返回这样的batch。
i = 0
for batch in img_gen.flow(x,batch_size=1):
plt.figure(i)
plt.imshow(x.array_to_img(batch[0]))
i += 1
if i>4:
break
plt.show()