Keras_mnist学习

重新编辑于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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容