keras学习笔记(1)CNN网络

cifar10_cnn.py解析

数据载入

数据的载入可以使用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'))
  • 卷积层1:32个3×3的卷积核,由于输入层为卷积层,所以要提供卷积层的输入[3,32,32](当卷积层作为中间层时,Convolution2D可以推断出输入的shape),不需要提供batch_size,border_mode='same'表示卷积操作不改变图像大小(周围像素用0填充)
  • 激活层2:激活函数为relu,可以通过model.add(Convolution2D(64,3,3, border_mode='same',Activation('relu'))合并到卷积层1中
  • 池化层3,池化大小是2x2,方式为最大值池化。也就是对输入特征的每个2x2大小的窗,选取其中最大的一个值作为输出。池化的目的是降低信息冗余
  • drop层4:用于随机断开一些连接,提高网络的泛化能力
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'))
  • 上诉代码是全链接层,输出为10个神经元Dense层。其中的Flatten()可以将多维的tensor转化为一维的tensor

网络模型的编译

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
              optimizer=sgd,
              metrics=['accuracy'])
  • lr参数为学习率,这是最值得调整的训练参数。
  • 损失函数为交叉熵损失函数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整除。

你可能感兴趣的:(keras学习笔记(1)CNN网络)