一、什么是生成器?Generator
《深度学习技术图像处理入门》P113:
当我们的训练数据是已一张张图片的形式保存在硬盘中,如何实现一个函数,每调用一次,就会读取指定张数的图片,将其转化为四维张量(图像编号,图像高度,图像宽度,RGB层),然后返回输出,进而在接下来的环节中交给深度学习神经网络。
一个函数只有被调用才能被执行。
廖雪峰博客中的话:
创建一个包含100万个元素的list,不仅要占用很大的内存,如果只是仅仅访问前面几个元素,那后面绝大多数元素占用的空间白白浪费掉了。所以,如果list元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断的推算出后续的元素呢?这样就不用创建完整的list。从而节省大量的空间。在Python中,这种一边循环一边计算的机制称为生成器。
概括而言:生成器可以节省内存占用,将成千上万的图片保存在硬盘中就好,模型需要时再调入内存。
《Python深度学习》图灵图书:5.2.4 数据预处理
你已经知道,将数据输入圣神经网络之前,应该将数据格式化为经过处理的浮点数张量。现在,数据以JPEG文件的形式保存在硬盘上,所以数据预处理的步骤大致如下:
(1)读取图像文件;
(2)将JPEG文件解码为RGB像素网格;
(3)将这些像网格转化为浮点数张量
(4)将像素值(0~255范围内)缩放到[0,1]区间(正如你所知,神经网络喜欢处理较小的输入值)
理解Python生成器:
Python生成器(Python generator)是一个类似于迭代器的对象,一个可以和for…in运算符一起使用的对象,生成器是用yield运算符来构造的。
生成器的例子:
def generator():
i = 0
while True:
i += 1
yield i #使用yield运算符构造i
for item in generartor():
print(item)
if item > 4:
break
生成器会不断的生成这些批量数据,它会不断地循环目标文件夹中的图像,因此需要显式声明在某个时刻终止迭代循环。
keras官网的解释:图像预处理ImageDataGenerator类
keras.preprocessing.image.ImageDataGenerator(
featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
zca_epsilon=1e-06,
rotation_range=0,
width_shift_range=0.0,
height_shift_range=0.0,
brightness_range=None,
shear_range=0.0,
zoom_range=0.0,
channel_shift_range=0.0,
fill_mode='nearest',
cval=0.0,
horizontal_flip=False,
vertical_flip=False,
rescale=None,
preprocessing_function=None,
data_format='channels_last',
validation_split=0.0,
interpolation_order=1,
dtype='float32')
使用实时数据增强生成一批张量图像数据。数据将会被循环。
使用示例:
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 31 09:41:04 2019
@author: Administrator
"""
from keras.preprocessing.image import ImageDataGenerator
from keras.datasets import cifar10
from keras.utils import np_utils#utilities 实例
from keras.models import Sequential
num_classes = 10
epochs = 50
'''数据分片'''
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
'''数据标签转换为one-hot编码'''
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
'''图像预处理ImageDataGenerator类'''
'''既然是类,那么这个就相当于一个构造函数,指定参数的构造函数'''
datagen = ImageDataGenerator(
featurewise_center = True,
featurewise_std_normalization = True,
rotation_range = 20,
width_shift_range = 0.2,
horizontal_flip = True
)
'''
cpmpute quantities required for featurewise normalization
(std, mean, and principal components if ZCA whitening is applied)
'''
'''
把样本数据装载到生成器中。
'''
datagen.fit(x_train)
'''
调用fit之后得到的结果是什么?
一个迭代器产生一个元组(x, y),其中x是图像数据的numpy数组,或者是numpy的list数组,同时,x与y的标签对应。如果没有y,则返回值只有x,且x是numpy数组。
也就是说,将二维的彩色图像,转换为计算机中的数组。将人理解的图像转换为计算机理解的图像。
'''
'''fits the model on batches with real-time data augmentation:'''
model = Sequential()
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32),
steps_per_epoch=len(x_train)/32,
epochs = epochs)
#here's a more "manual" example
for e in range(epochs):
print('Epoch', e)
batches = 0
for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size = 32):
model.fit(x_batch, y_batch)
batches += 1
if batches >= len(x_train) / 32:
#we need to break the loop by hand because
#the generator loops infefinitely
break
二、数据增强的目的?
数据增强的目的就是为了扩充数据集。
那又是怎么扩充数据集的呢?
就是对已有的数据集上进行一些旋转,镜像等变换,以生成更多的数据集。
所以生成器的命名由此而来。
总结:
(1)什么是生成器?–用来根据已有图像,并对已有图像进行旋转等操作,进一步生成稍微不同图像的一个类。需要构造类对象
(2)为什么需要生成器?–为了数据增强,扩充数据集
三、cifar10中ImageDataGenerator的运用:
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
"""
from __future__ import print_function
import numpy as np
from keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPool2D
from keras.utils import np_utils
from keras.callbacks import ModelCheckpoint
from keras.preprocessing.image import ImageDataGenerator
from keras.datasets import cifar10
from keras.backend.tensorflow_backend import set_session
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
set_session(tf.Session(config = config))
np.random.seed(0)
#定义变量
batch_size = 32
nb_classes = 10
nb_epoch = 50
img_rows, img_cols = 32, 32
nb_filters = [32, 32, 64, 64]
pool_size = (2, 2)
kernel_size = (3,3)
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
X_train = X_train.astype("float32") / 255
X_test = X_test.astype("float32") / 255
y_train = y_train
y_test = y_test
input_shape = (img_rows, img_cols, 3)
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
#基于生成器的批量生成模块
datagen = ImageDataGenerator(
featurewise_center = False,
samplewise_center = False,
featurewise_std_normalization = False,
zca_whitening = False,
rotation_range = 0,
width_shift_range = 0.1,
horizontal_flip = True,
vertical_flip = False
)
datagen.fit(X_train)
#搭建神经网络
model = Sequential()
model.add(Conv2D(nb_filters[0], kernel_size, padding = 'same', input_shape = X_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(nb_filters[1], kernel_size))
model.add(MaxPool2D(pool_size = pool_size))
model.add(Dropout(0.25))
model.add(Conv2D(nb_filters[2], kernel_size = kernel_size, padding = 'same'))
model.add(Activation('relu'))
model.add(Conv2D(nb_filters[3], kernel_size = kernel_size))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size = pool_size))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
adam = Adam(lr = 0.0001)
model.compile(loss='categorical_crossentropy', optimizer = adam, metrics=['accuracy'])
best_model = ModelCheckpoint("cifar10_best.h5", monitor = 'val_loss', verbose=0, save_best_only=True)
tb = TensorBoard(log_dir = "./logs")
model.fit_generator(
datagen.flow(X_train,Y_train, batch_size = batch_size),
steps_per_epoch = X_train.shape[0] // batch_size,
epochs = nb_epoch, verbose = 1,
validation_data = (X_test, Y_test),
callbacks = [best_model, tb]
)
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print("Accuracy: %.2f%%" % (score[1]*100))
print("Compiled!")