数据的载入可以使用cifar10.load_data()这个函数完成,第一次运行时会自动下载cifar10数据,并返回训练集(5W)和测试集(1W)。注意:如果使用theano后端,图片的shape为[样本数,通道数,行数,列数],如果使用的是tensorflow后端,图片的shape为[样本数,行数,列数,通道数]
from __future__ import print_function
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.optimizers import SGD
from keras.utils import np_utils
batch_size = 32
nb_classes = 10
nb_epoch = 200
data_augmentation = True
img_rows, img_cols = 32, 32
img_channels = 3
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
上诉代码中的np_utils.to_categorical(y_train, nb_classes)可以将类别转化为one-hot编码,这里的nb_classes为10。用astype()函数可以将数据转化为float32类型。X_train /= 255
将训练数据归一化到0~1(也可以做一下去均值)。
这里选用最简单的Sequential模型,也可以选用Model范型模型来构造更为复杂的网络。
model = Sequential()
model.add(Convolution2D(32, 3, 3, border_mode='same',
input_shape=X_train.shape[1:]))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
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'))
Convolution2D
可以推断出输入的shape),不需要提供batch_size,border_mode='same'
表示卷积操作不改变图像大小(周围像素用0填充)model.add(Convolution2D(64,3,3, border_mode='same',Activation('relu'))
合并到卷积层1中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'))
Flatten()
可以将多维的tensor转化为一维的tensorsgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])
categorical_crossentropy
SGD
accuracy
if not data_augmentation:
print('Not using data augmentation.')
model.fit(X_train, Y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test),
shuffle=True)
else:
print('Using real-time data augmentation.')
datagen = ImageDataGenerator(
featurewise_center=False, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=False, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
zca_whitening=False, # apply ZCA whitening
rotation_range=0, # randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.1, # randomly shift images vertically (fraction of total height)
horizontal_flip=True, # randomly flip images
vertical_flip=False) # randomly flip images
datagen.fit(X_train)
model.fit_generator(datagen.flow(X_train, Y_train,
batch_size=batch_size),
samples_per_epoch=X_train.shape[0],
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test))
定义了一个数据生成器(严格的说是一个能够生成生成器的类),如果你对生成器的概念不了解,请查阅Python相关内容。大致的说,生成器只在每次调用的时候才返回数据。譬如我们在python中经常写 for i in range(n)这种句子,range(n)生成一个长为n的列表,如果n很大的话需要占用很大的内存空间,而同样功能的for i in xrange(n)就不必如此,这里xrange(n)返回的就是一个生成器,在每次for循环使用的时候才计算下一个数,而不是一次计算完毕。
从ImageDataGenerator的参数名字上我们大致可以推测出这个生成器都做了哪些数据提升,包括去中心化等预处理,旋转,水平位移,垂直位移,水平翻转等。有些处理,如按特征进行的归一化,白化等需要了解整个样本集的统计信息。
在定义完datagen后,调用model的fit_generator进行训练,model有两组训练/测试/评估的函数,不带generator的就是普通版本,如上面用的model.fit,普通版本的数据是直接用numpy array放进去的。带generator的是生成器版本,生成器版本的数据是通过生成器返回的。
git_generator的第一个参数是生成数据的生成器,这里用的是dategen内置的,当然我们也可以自己写,只要返回的数据是形如(X_train, Y_train)或(X_train,Y_train,class_weights)的形式即可。Keras规定这里的生成器是一个无限返回数据的死循环,所以还需要添加samples_per_epoch和nb_epoch两个参数来确定什么时候训练终止,这两个参数指定了每个epoch包含多少个样本以及要训练多少个epoch。samples_per_epoch最好能被batch_size整除。