美文网首页
Keras_mnist学习

Keras_mnist学习

作者: 苟且偷生小屁屁 | 来源:发表于2017-09-19 15:57 被阅读0次

    重新编辑于20180301, 曾经写过的内容有不严谨的地方,毕竟当时自己也是初学者, 括号内为新加的内容

    今天我们来逐条学一下基于keras的mnist网络的搭建,因为只是单纯的复制和粘贴别人的代码是永远学不会DL的,当然还有Markdown。

        # 这部分是声明
        from __future__ import print_function(这句可以不要)
        import keras (这句也没啥用)
        from keras.datasets import mnist
        from keras.models import Sequential(序贯模型,还有另一种更高级,更灵活的Model模型)
        from keras.layers import Dense, Dropout, Flatten(一些基本的层,Dropout在这种简单网络中作用不明确,不明显)
        from keras.layers import Conv2D, MaxPooling2D
        from keras import backend as K
    
    # batch_size 太小会导致训练慢,过拟合等问题,太大会导致欠拟合。所以要适当选择
    (batchsize太小可能会导致波动幅度过大,极端情况,=1的时候,等于随机梯度下降,根据你的显存大小而定,选择合适的大小,实在显存受限=1也是可以的)
    batch_size = 128
    
    # 0-9手写数字一个有10个类别
    num_classes = 10
    
    # 12次完整迭代,差不多够了
    (一般还是搞50以上吧,取决于loss是否收敛了)
    epochs = 12
    
    # 输入的图片是28*28像素的灰度图
    img_rows, img_cols = 28, 28
    
    # 训练集,测试集收集非常方便
    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    
    # keras输入数据有两种格式,一种是通道数放在前面,一种是通道数放在后面,
    # 其实就是格式差别而已,图像数量,颜色通道,行,列
    (实际上就是使数据和网络的输入在维度上保持一致,这在其他的模型训练中也是需要经常注意的)
    if K.image_data_format() == 'channels_first':
        x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
        x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
        input_shape = (1, img_rows, img_cols)   #这里再次提示了一次数据格式
    else:
        x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
        x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
        input_shape = (img_rows, img_cols, 1)
    #此时,x_train(所有图像,1灰度通道,行,列)
    
    
    (数据的归一化处理,减去均值除以范围,最终是0-1的范围,
    所以最后的激活函数应该是sigmoid,如果是-1~1,那么激活函数应该是tanh)
    # 把数据变成float32更精确
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train /= 255
    x_test /= 255
    
    (想看看维度的话就显示一下,或者监控显示x_train.shape也可以)
    print('x_train shape:', x_train.shape)
    print(x_train.shape[0], 'train samples')
    print(x_test.shape[0], 'test samples')
    
    # 把类别0-9变成2进制,方便训练(one-hot, 为最后的softmax输出判断类别做准备)
    y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
    
    # Sequential类可以让我们灵活地插入不同的神经网络层
    model = Sequential()
    
    # 加上一个2D卷积层, 32个输出(也就是卷积通道),激活函数选用relu,
    # 卷积核的窗口选用3*3像素窗口
    model.add(Conv2D(32,
                     activation='relu',
                     input_shape=input_shape, (注意首个网络层需要指定shape)
                     nb_row=3,
                     nb_col=3))
    # 自己改写成了:
    model.add(Conv2D(32,3,
                     activation='relu',input_shape=input_shape))
    # 效果完全一致
    
    • keras.layers.convolutional.Conv2D
      (filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)
    • 二维卷积层,即对图像的空域卷积。该层对二维输入进行滑动窗卷积,当使用该层作为第一层时,应提供input_shape参数。例如input_shape = (128,128,3)代表128*128的彩色RGB图像(data_format='channels_last')

    - Conv2D最重要的参数,
    其一,filters即输出的维度,也就是卷积核的数目,也就是将平面的图像,拉伸成filters维的空间矩阵,
    其二,strides,也就是步长,它和padding一起决定了卷积操作后的图像大小,
    其三,注意,第一层需要指定input_shape,例如,input_shape = (128,128,3),也就是原图的大小以及颜色通道数量。

    Conv2D

    这里详细说明Conv2D的用法(有点跑题了,mark下图像卷积,以及维度变化的内涵):

    • filters:是输出的维度,它不用考虑输入维度,nice

    • kernel_size:是卷积核的大小,有什么作用?
      程序里直接没提kernel_size的大小。

    • strides:决定每次卷积核前进的数量,如果是1,则卷积后的大小与原先图像大小一致,如果是2,则图像的大小减半。

    • padding:
      valid: new_height = new_width = (W – F + 1) / S #结果向上取整
      same: new_height = new_width = W / S #结果向上取整

    图片.png
    • activation:激活函数,为预定义的激活函数名(参考激活函数),或逐元素(element-wise)的Theano函数。如果不指定该参数,将不会使用任何激活函数(即使用线性激活函数:a(x)=x)
    图片.png
    # 64个通道的卷积层
    model.add(Conv2D(64, activation='relu',
                     nb_row=3,
                     nb_col=3))
    
    # 池化层是2*2像素的
    model.add(MaxPooling2D(pool_size=(2, 2)))
    

    MaxPooling2D层

    keras.layers.pooling.MaxPooling2D(pool_size=(2, 2), strides=None, padding='valid', data_format=None)
    
    • 参数

      • pool_size:整数或长为2的整数tuple,代表在两个方向(竖直,水平)上的下采样因子,如取(2,2)将使图片在两个维度上均变为原长的一半。为整数意为各个维度值相同且为该数字。
      • strides:整数或长为2的整数tuple,或者None,步长值。
      • border_mode:‘valid’或者‘same’
    • 参考源程序分析:

    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    • 可以看到只有一个pool_size,strides默认应该是1,padding默认是valid,所以这里并不需要考虑输出的大小,这点非常好用。

    下面继续叠加一层卷积层和一层maxpooling层

    这里研究一下激活函数的类型

    • softmax:对输入数据的最后一维进行softmax,输入数据应形如(nb_samples, nb_timesteps, nb_dims)或(nb_samples,nb_dims)
    • elu
    • selu: 可伸缩的指数线性单元(Scaled Exponential Linear Unit),参考Self-Normalizing Neural Networks
    • softplus
    • softsign
    • relu
    • tanh
    • sigmoid
    • hard_sigmoid
    • linear

    Dropout层

    • Dropout, Dense,Flatten层都是keras的
    # 对于池化层的输出,采用0.35概率的Dropout
    model.add(Dropout(0.35))
    
    • keras.layers.core.Dropout(rate, noise_shape=None, seed=None)
      为输入数据施加Dropout。Dropout将在训练过程中每次更新参数时按一定概率(rate)随机断开输入神经元,Dropout层用于防止过拟合。
    • rate:0~1的浮点数,控制需要断开的神经元的比例

    Flatten层

    (把卷积核展开成向量,这里损失了像素的空间关系,参数数量急剧增加,为了克服这些,可以采用1*1卷积,请自行百度)

    keras.layers.core.Flatten()
    
    • Flatten层用来将输入“压平”,即把多维的输入一维化,常用在从卷积层到全连接层的过渡。Flatten不影响batch的大小。
    # 展平所有像素,比如[28*28] -> [784]
    model.add(Flatten())
    

    Dense层

    # 对所有像素使用全连接层,输出为128,激活函数选用relu
    model.add(Dense(128, activation='relu'))
    
    • 用法:
      keras.layers.core.Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)
    # 对输入采用0.5概率的Dropout
    model.add(Dropout(0.5))
    
    # 对刚才Dropout的输出采用softmax激活函数,得到最后结果0-9
    model.add(Dense(num_classes, activation='softmax'))
    

    Model.Compile

    # 模型我们使用交叉熵损失函数,最优化方法选用Adadelta
    model.compile(loss=keras.metrics.categorical_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy'])
    
    • compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)

    编译用来配置模型的学习过程,其参数有:

    • optimizer:字符串(预定义优化器名)或优化器对象,参考优化器
    • loss:字符串(预定义损失函数名)或目标函数,参考损失函数
    • metrics:列表,包含评估模型在训练和测试时的网络性能的指标,典型用法是metrics=['accuracy']

    Model.fit

    # 令人兴奋的训练过程
    model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
              verbose=1, validation_data=(x_test, y_test))
    
    

    fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0)

    用法:

    • x:输入数据。如果模型只有一个输入,那么x的类型是numpy array,如果模型有多个输入,那么x的类型应当为list,list的元素是对应于各个输入的numpy array
    • y:标签,numpy array
    • batch_size:整数,指定进行梯度下降时每个batch包含的样本数。训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步。
    • epochs:整数,训练的轮数,每个epoch会把训练集轮一遍。
    • validation_data:形式为(X,y)的tuple,是指定的验证集。此参数将覆盖validation_spilt。

    这里的validation_data是可以不写的

    Model.evaluate

    score = model.evaluate(x_test, y_test, verbose=1)
    print('Test loss:', score[0])
    print('Test accuracy:', score[1])
    

    用法:

    evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)

    感谢大家观看,最后更新放出完整代码了,喜欢的话请点个赞,欢迎转载,转载请复制出处.

    # coding:utf-8
    
    from keras.datasets import mnist
    from keras.models import Sequential
    from keras.layers import Conv2D,MaxPool2D,Dense,Flatten, Activation
    from keras.callbacks import TensorBoard
    from keras.models import save_model,load_model
    import keras,numpy
    from keras.utils import plot_model
    
    batch_size = 32
    num_classes = 10
    epoch = 20
    img_rows, img_cols = 28, 28
    input_shape = (img_rows,img_cols,1)
    
    (x_train,y_train),(x_test,y_test) = mnist.load_data()
    if keras.backend.image_data_format()=='channels_first':
        x_train = numpy.reshape(x_train,[x_train.shape[0],1,img_rows,img_cols])
        x_test = numpy.reshape(x_test, [x_test.shape[0], 1,img_rows, img_cols])
        input_shape = (1,img_rows,img_cols)
    else:
        x_train = numpy.reshape(x_train,[x_train.shape[0],img_rows,img_cols,1])
        x_test = numpy.reshape(x_test, [x_test.shape[0],img_rows, img_cols,1])
        input_shape = (img_rows,img_cols,1)
    
    # 数据预处理,归一化,one-hot化
    x_train = x_train.astype('float32')
    x_test = x_test.astype('float32')
    x_train = x_train/255
    x_test = x_test/255
    
    y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
    
    
    # 构造lenet模型,简化版
    mnist_model = Sequential()
    mnist_model.add(Conv2D(6, (5, 5), activation='relu', input_shape=input_shape))
    # mnist_model.add(Conv2D(6,1,5,5))
    mnist_model.add(Activation('relu'))
    mnist_model.add(MaxPool2D(pool_size=(2, 2)))
    
    mnist_model.add(Conv2D(16, (5, 5), activation='relu'))
    mnist_model.add(MaxPool2D(pool_size=(2, 2)))
    
    mnist_model.add(Flatten())
    mnist_model.add(Dense(120, activation='relu'))
    mnist_model.add(Dense(84, activation='relu'))
    
    mnist_model.add(Dense(num_classes, activation='softmax'))
    
    
    # 保存模型(拓扑图)
    plot_model(mnist_model, to_file='lenet.png')
    
    # 编译
    mnist_model.compile(optimizer='Adadelta',loss='categorical_crossentropy',
                       metrics=['accuracy'])
    
    # 训练
    mnist_model.fit(x_train,y_train,batch_size = batch_size,epochs=epoch,verbose=1,
                   callbacks=[TensorBoard(log_dir='./log')])
    
    # 保存模型
    save_model(mnist_model,'lenet.h5')
    
    # 测试
    score = mnist_model.evaluate(x_test,y_test,verbose=1)
    print('\n')
    
    print('test loss:',score[0])
    print('test accuracy:',score[1])
    
    
    选区_001.png

    相关文章

      网友评论

          本文标题:Keras_mnist学习

          本文链接:https://www.haomeiwen.com/subject/lehisxtx.html