数据预处理
现在模型也定义好了,原始数据也准备好了,但是在将数据填入模型之前,需要进行预处理才能使用,填入模型的是浮点数张量。而当前数据是以JPEG文件的形式保存在硬盘中,预处理步骤如下:
- 读取图像文件
- 将JPEG文件解码为RGB像素网格
- 将像素网格转化为浮点数张量
- 将像素值缩放到0~1区间
Keras提供了自动完成这些步骤的工具:keras.preprocessing.image
,其中有一个ImageDataGenerator
类,可以帮助我们快速创建Python生成器,将硬盘上的图像文件自动转换为预处理好的张量。
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
这里直接通过ImageDataGenerator
来生成一个数据生成器,其中rescale
参数指定将图像张量的数字缩放。
具体使用起来如下,主要是flow_from_directory函数的使用:
train_generator = train_datagen.flow_from_directory(
train_dir, # 目标目录
target_size=(150, 150), # 所有图像调整为150x150
batch_size=20,
class_mode='binary') # 二进制标签,我们用了binary_crossentropy损失函数
validation_generator = test_datagen.flow_from_directory(
validation_dir, # 目标目录
target_size=(150, 150), # 所有图像调整为150x150
batch_size=20,
class_mode='binary')
为了更好的理解,我们先回顾一下Python生成器的概念。
Python生成器
英文名叫Python Generator
,是一个类似于迭代器的对象,能够与for...in
一起使用,其中生成器是用yield
运算符构造的。
举个例子:
def generator():
i = 0
while 1:
i += 1
yield i
for item in generator():
print(item)
if item > 4:
break
这个生成器一直生成,所以我们需要手动在使用时指定结束条件。
而再看上面的图像生成代码,输出的是150x150的RGB图像,形状为(20, 150, 150, 3)的4D张量,二进制标签的形状是1D张量,即一个向量,形状是(20,)。即一批输出20个样本。生成器h不停生成这些batch,我们自己指定在何时终止循环。
for data_batch, labels_batch in train_generator:
print('data batch shape: ', data_batch.shape)
print('labels batch shape: ', labels_batch.shape)
break # 一把就结束
# 输出结果
# data batch shape: (20, 150, 150, 3)
# labels batch shape: (20,)
应用在模型中也很简单直接:
# 使用批量生成器拟合模型
history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50)
使用生成器,我们就可以让模型对数据进行拟合,这里用fit_generator
方法,第一个参数就是我们定义好的生成器,数据不断生成,每一轮epoch要生成多少样本呢,由steps_per_epoch
指定批量数,生成器中定义的是batch_size
,然后拟合时再指定到底要训练多少轮次epochs,这是一种分层次的定义。
本例中,共有2000个样本,所以batch_size=20
时,100个批量可以抽完这些样本完成一个轮次的训练。
同时,在fit_generator
时,传入validation_data
参数,和在fit
函数中效果相同。使用数据生成器时,而生成器是源源不断生成数据的,所以需要指定到底要给出多少个批量,因为一个batch_size
是20,验证集共1000个样本,所以需要50个批次。
另外,我们在train
文件夹中按照类别分成了两个文件夹,训练时是将train
文件夹下数据全部采用。
数据增强
# 数据增强增加学习样本
datagen = 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' # 填充新创建像素的方法
)
from keras.preprocessing import image # 图像预处理模块
fnames = [os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)]
img_path = fnames[3] # 选择一张图片进行增强
img = image.load_img(img_path, target_size=(150, 150)) # 读取图像并调整大小
x = image.img_to_array(img) # 形状转换为(150,150,3)的Numpy数组
x = x.reshape((1,) + x.shape)
i = 0
# 生成随机变换后图像批量,循环是无限生成,也需要我们手动指定终止条件
for batch in datagen.flow(x, batch_size=1):
plt.figure(i)
imgplot = plt.imshow(image.array_to_img(batch[0]))
i += 1
if i % 4 == 0:
break
plt.show()
对比上面两种使用例子,可以看出,我们首先要定义一个ImageDataGenerator
实例,定义实例时,需要指定一些参数,数据增强需要的一些变换参数在这里添加即可。
然后分别调用flow_from_directory
函数和flow
函数即可,二者都需要指定结束条件,细节有所不同。
数据增强的使用,具体如下:
# 训练
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
test_datagen = ImageDataGenerator(rescale=1./255) # 验证集不用增强
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(150, 150),
batch_size=32,
class_mode='binary'
)
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=32,
class_mode='binary'
)
history = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=100,
validation_data=validation_generator,
validation_steps=50
)
我们指定steps_per_epoch=100
,且batch_size=32
,所以训练数据用了3200张图片,本身只有2000张,数据增强造出了1200张。而验证集并没有增强。
END.
参考:
《Deep Learning with Python》