重新编辑于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)
# 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
网友评论