Keras介绍
Keras是用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行
手写数字识别Demo
手写数字识别可以说是神经网络搭建的“ hello wolrd ”,我们从MNIST Data获取data做实验,这个数据集可以帮助我们去做一些小实验。
第一步:定义模型
我们想建立两层hidden layers,每层500个神经元。
- 定义神经网络的样子
model = Sequential()
- 使用model.add,加一个Fully connect layer(这里用Dense表示)
model.add( Dense ( input_dim = "28*28", ouput_dim = 500) )
model.add ( Activation ('sigmoid') )
- 加上第二层layer,这个layer的input就是上一个layer的output,不用说input是500
model.add( Dense ( ouput_dim = 500) )
model.add ( Activation ('sigmoid') )
- 输出为10个维度,即10个数字,activation function是softmax
model.add( Dense ( ouput_dim = 10) )
model.add ( Activation ('softmax') )
这些激活函数都可以根据自己设计来改变,不一定是sigmoid和softmax
注
意
:
k
e
r
a
s
2.0
版
本
0
,
o
u
p
u
t
d
i
m
换
成
u
n
i
t
s
,
代
表
神
经
元
个
数
\color{red}{注意:keras2.0版本0,ouputdim换成units,代表神经元个数}
注意:keras2.0版本0,ouputdim换成units,代表神经元个数
第二步:模型评估
#编译模型
model.compile(loss = 'categorical crossentropy',
optimizer = 'adam' #优化器
metrics = ['accuracy']) #指标
定义Loss是什么,这里使用了cross entropy
第三步:挑选最优模型
optimizer后面可以跟不同的方式,这些方式都是gradient descent,只是用的learning rate不同,有一些machine会自己决定learning rate
寻找最优参数
把数据都存在numpy array中,
X_train的第一维度代表examples的数量,第二维度代表pixel
Y_train的第一维度代表examples的数量,第二维度代表label
参数batch-size详解
实际上我们并不会最小化 total loss,而是把训练集的数据分成几个一小块(mini-batch),步骤如下:
- 随机初始化神经网络的参数
- 先随机选择第一个batch出来,对选择出来的batch里面total loss, 计算偏微分,根据 L ′ {L}' L′去更新参数
- 然后随机选择第二个batch ,对第一个选择出来的batch里面total loss, 计算偏微分,根据 L ′ ′ {L}'' L′′更新参数
- 反复上述过程,直到把所有的batch都统统过一次,一个epoch才算结束。 注意:假设今天有100个batch的话,就把这个参数更新100次,把所有的batch都遍历过叫做一个epoch。
回到解释参数,batch_size代表一个mini-batch里面有多少个examples,nb_epoch表示对上面的操作进行多少次
为什么还要用mini-batch?
batch-szie不同时,一个epoch所需的时间是不一样的(上图用batch size=1是166s,当batch size=10是17s),batch =10相比于batch=1,较稳定。很大的batch size会导致很差的表现,GPU不一定能顶得住这么大(不能设置太大也不能设置太小)
为什么批量梯度下降比随机梯度下降要快?
因为利用计算机的平行运算,之前也提到过矩阵运算会使计算速度快很多。
GPU是如何平行运算的?
梯度下降的时候两个矩阵x是分开计算的,当用mini batch的时候,直接是用两个x合并在一起,一起计算得到
Z
1
Z^1
Z1 和
Z
2
Z^2
Z2,对GPU来说上面运算时间是下面运算时间的两倍,这就是为什么我们用上mini batch和GPU的时候速度会加快的原理。但是如果你用了GPU没用mini batch的话,那也达不到加速的效果。
创建完成模型之后,如何保存和运行,可以看上图的网址。
然后有两个关于test神经网络的case:
- 第一个case是你有testing set,也有testing set的答案,keras帮助你计算正确率
- 第二case是predict,你没有正确答案,只有test data,它会让你输入数据(例如图片),然后告诉你答案(手写数字)是多少
Keras 2.0
1.创建网络
我们要做手写数字识别,要建立一个Network,input是28x28的维度的一张图片,output是0-9哪个数字,ouput的一个维度对应一个数字,所以一共10个维度,假设要添加两层layer,一个500个neuron
- 宣告一个Network:
model=Sequential()
- 添加第一个hidden layer:
model.add(Dense(input_dim=28*28,units=500,activation='relu'))
Dense意思就是说你加一个全连接网络,可以换成其他,例如Con2d,即加一个convolution layer。input_dim代表输入的维度,units表示hidden layer的neuron数,activation就是激活函数,可以用很多激活函数,比如relu,softplus,softsign,sigmoid,tanh,hard_sigmoid
- 添加第二个hidden layer:
model.add(Dense(units=500,activation='relu'))
- output layer:
model.add(Dense(units=10,activation='softmax'))
最后一个layer,因为output是10维,所以units=10,activation一般选softmax,意味着输出每个dimension只会介于0-1之间,总和是1
2.网络的配置
定义loss function,选择optimizer,定义评估指标metrics
所有的optimizer都是Gradent descent based,只是有不同的方法来决定learning rate,比如Adam,SGD,RMSprop,Adagrad,Adalta,Adamax ,Nadam等。
model.compile(loss='categorical crossentropy',optimizer='adam',metrics=['accuracy'])
选择最优function
model.fit(x_train,y_train,batch_size=100,epochs=20)
model.fit 方法会用Gradent Descent帮你去train你的Network。x_train代表image,y_train代表image的label,关于x_train和y_train的格式,你都要存成numpy array。
X_train:第一个轴表示example,第二个轴代表每个example用多长vecter来表示它
Y_train:第一个维度一样代表training examples,第二维度代表着现在有多少不同的case。只有一维是1,其他的都是0,每一维都对应一个数字,比如第0维对应数字0,如果第N维是1,对应的数字就是N。
使用模型
你就要拿这个Network进行使用,使用有两个不同的情景,
一个是evaluation,意思就是说你的model在test data 上到底表现得怎样,call evaluate这个函数,然后把x_test,y_test喂给它,就会自动给你计算出Accuracy。它会output一个二维的向量,第一个维度代表了在test set上loss,第二个维度代表了在test set上的accuracy,这两个值是不一样的。loss可能用cross_entropy,Accuraccy是对与不对,即正确率。
score = model.evaluate(x_test,y_test)
print('Total loss on Testiong Set : ',score[0])
print('Accuracy of Testiong Set : ',score[1])
二个是做predict,就是系统上线后,没有正确答案的,call predict进行预测
result = model.predict(x_test)
代码实现:
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense,Dropout,Activation
from keras.optimizers import SGD,Adam
from keras.utils import np_utils
from keras.datasets import mnist
def load_data():
(x_train,y_train),(x_test,y_test) = mnist.load_data()
number = 10000
x_train = x_train[0:number]
y_train=y_train[0:number]
x_train=x_train.reshape(number,28*28)
x_test=x_test.reshape(x_test.shape[0],28*28)
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
y_train=np_utils.to_categorical(y_train,10)
y_test=np_utils.to_categorical(y_test,10)
x_train=x_train
x_test=x_test
x_train=x_train/255
x_test=x_test/255
return (x_train,y_train),(x_test,y_test)
(x_train,y_train),(x_test,y_test)=load_data()
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='mse',optimizer=SGD(lr=0.1),metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=100,epochs=20)
result= model.evaluate(x_test,y_test)
print('TEST ACC:',result[1])
最后的结果只有10%左右,调整一下参数变化也不会有太大,增加了层数也是,所以deep learning 并不是越deep越好,隐层的神经元个数调整,对整体效果也不一定有助益,关于deep learning 的实践,还是需要基于理论基础,而不是参数随便调来调去。