追求真理 2019-06-27
最近在接触些深度学习的东西,也对一些深度学习的框架进行了大致的了解。Python的科学计算包主要是Theano和TensorFlow,特点就是很强大,但对于初学者不太友好、有点难用。但Keras可以基于这两种包之一方便地建立神经网络。
Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果。
Keras可在Python 2.7或3.5运行,无缝调用后端的CPU或GPU网络。Keras由Google的Francois Chollet开发,并遵循以下原则:
Python:不使用任何自创格式,只使用原生Python
如下图所示,在终端调用keras,后面会输出下面的提示,说明keras默认的后端为tensorflow
Using TensorFlow backend.
如果说默认的后端不是tensorflow
,而是theano
,我们可以配置后端文件进行修改:
~/.keras/keras.json
里面是:
{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}
我们把backend参数改为tensorflow即可。
Keras的目标就是搭建模型。最主要的模型是Sequential
:不同层的叠加。模型创建后可以编译,调用后端进行优化,可以指定损失函数和优化算法。
编译后的模型需要导入数据:可以一批批加入数据,也可以一次性全加入。训练后的模型就可以做预测或分类了。大体上的步骤是:
Sequential
模型,加入每一层compile()
方法fit()
方法拟合数据evaluate()
或 predict()
方法进行预测Sequential(序贯模型)是多个网络层的线性堆叠,说人话就是“一条路走到黑”。
我们一般通过.add()
方法一个个的将layer加入模型:
from keras.models import Sequential from keras.layers import Dense, Activation model = Sequential() model.add(Dense(32, input_shape=(784,))) model.add(Activation('relu'))
Sequential
的第一层需要接受一个关于输入数据shape的参数,后面的各个层则可以自动的推导出中间数据的shape,因此不需要为每个层都指定这个参数。
有几种方法来为第一层指定输入数据的shape
input_shape
的关键字参数给第一层,input_shape
是一个tuple类型的数据,其中也可以填入None
,如果填入None
则表示此位置可能是任何正整数。数据的batch大小不应包含在其中。Dense
,支持通过指定其输入维度input_dim
来隐含的指定输入数据shape,是一个Int类型的数据。一些3D的时域层支持通过参数input_dim
和input_length
来指定输入shape。batch_size
参数到一个层中,例如你想指定输入张量的batch大小是32,数据shape是(6,8),则你需要传递batch_size=32
和input_shape=(6,8)
。model = Sequential() model.add(Dense(32, input_shape=(784,)))
一些重要概念:
batch:我们经常用到的优化算法——梯度下降,在该算法中参数更新的方式主要有2种。
第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度。这种方法每更新一次参数都要把数据集里的所有样本都看一遍,计算量开销大,计算速度慢,不支持在线学习,这称为Batch gradient descent,批梯度下降。
第二种,每看一个数据就算一下损失函数,然后求梯度更新参数,这个称为随机梯度下降,stochastic gradient descent。这个方法速度比较快,但是收敛性能不太好,可能在最优点附近晃来晃去,hit不到最优点。两次参数的更新也有可能互相抵消掉,造成目标函数震荡的比较剧烈。
为了克服两种方法的缺点,现在一般采用的是一种折中手段,mini-batch gradient decent,小批的梯度下降,这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,计算量也不是很大。
基本上现在的梯度下降都是基于mini-batch的,所以Keras的模块中经常会出现batch_size,指的就是这个。
epochs:
指的就是训练过程中数据将被“轮”多少次。
在训练模型之前,我们需要通过compile
来对学习过程进行配置。compile
接收三个参数:
rmsprop
、adagrad
,或一个Optimizer
类的对象。categorical_crossentropy
、mse
,也可以为一个损失函数。metrics=['accuracy']
。指标可以是一个预定义指标的名字,也可以是一个用户定制的函数.指标函数应该返回单个张量,或一个完成metric_name - > metric_value
映射的字典。比如对于多分类问题:
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
训练模型一般使用fit
函数。
model.fit(data, labels, epochs=10, batch_size=32)
本文主要是介绍Keras的基本用法,所以数据集采用经典数据集,中间的数据清洗过程便可以省略一些。数据集用的是UCI数据集中的 皮马人糖尿病数据集(pima-indians-diabetes),在UCI的机器学习网站(http://mlearn.ics.uci.edu/dat...)可以免费下载。
数据集的内容是皮马人的医疗记录,以及过去5年内是否有糖尿病。所有的数据都是数字,问题是(是否有糖尿病是1或0),是二分类问题。数据的数量级不同,有8个属性:
所有的数据都是数字,可以直接导入Keras,数据前5行长下面这样。。
6,148,72,35,0,33.6,0.627,50,1 1,85,66,29,0,26.6,0.351,31,0 8,183,64,0,0,23.3,0.672,32,1 1,89,66,23,94,28.1,0.167,21,0 0,137,40,35,168,43.1,2.288,33,1
因为数据全部为数字,这里我们用NumPy的loadtxt()
函数可以直接导入数据,其实用pandas的read_csv
也可以,随意啦。并将数据集分成特征和标签。
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",") X = dataset[:,0:8] Y = dataset[:,8]
delimiter参数为指定数据的界定符
Keras的模型由层构成:我们建立一个Sequential
模型,一层层加入神经元。第一步是确定输入层的数目正确:在创建模型时用input_dim
参数确定。
全连接层用Dense
类定义:第一个参数是本层神经元个数,然后是初始化方式和激活函数。这里的初始化方法是0到0.05的连续型均匀分布(uniform
),Keras的默认方法也是这个。也可以用高斯分布进行初始化(normal
)。
前两层的激活函数是线性整流函数(relu
),最后一层的激活函数是S型函数(sigmoid
)。之前大家喜欢用S型和正切函数,但现在线性整流函数效果更好。
为了保证输出是0到1的概率数字,最后一层的激活函数是S型函数,这样映射到0.5的阈值函数也容易。前两个隐层分别有12和8个神经元,最后一层是1个神经元(是否有糖尿病)。
隐层设置:不太好设置吧,我的理解是,一般来说,如果网络够大,即使存在问题也不会有影响。这个例子里我们用3层全连接网络。
model = Sequential() model.add(Dense(12, input_dim=8, init='uniform', activation='relu')) model.add(Dense(8, init='uniform', activation='relu')) model.add(Dense(1, init='uniform', activation='sigmoid'))
Keras会调用Theano或者TensorFlow编译模型。
我们需要定义损失函数和优化算法,以及需要收集的数据。我们使用binary_crossentropy
,错误的对数作为损失函数;adam
作为优化算法。基于本问题是分类问题,so我们收集每轮的准确率。
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
网络按轮训练,通过nb_epoch
参数控制。每次送入的数据可以用batch_size
参数控制。这里我们只跑150轮,每次10个数据。
model.fit(X, Y, nb_epoch=150, batch_size=10)
我们把测试数据拿出来检验一下模型的效果(注意这样不能测试在新数据的预测能力)我们应该将数据分成训练和测试集。调用模型的evaluation()
方法,传入训练时的数据。输出是平均值,包括平均误差和其他的数据,例如准确度。
scores = model.evaluate(X, Y) print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
... Epoch 143/150 768/768 [==============================] - 0s - loss: 0.4614 - acc: 0.7878 Epoch 144/150 768/768 [==============================] - 0s - loss: 0.4508 - acc: 0.7969 Epoch 145/150 768/768 [==============================] - 0s - loss: 0.4580 - acc: 0.7747 Epoch 146/150 768/768 [==============================] - 0s - loss: 0.4627 - acc: 0.7812 Epoch 147/150 768/768 [==============================] - 0s - loss: 0.4531 - acc: 0.7943 Epoch 148/150 768/768 [==============================] - 0s - loss: 0.4656 - acc: 0.7734 Epoch 149/150 768/768 [==============================] - 0s - loss: 0.4566 - acc: 0.7839 Epoch 150/150 768/768 [==============================] - 0s - loss: 0.4593 - acc: 0.7839 768/768 [==============================] - 0s acc: 79.56%
最后模型的准确率为79.56%,还不是特别高。本文的目的只是为了将keras的特点展示出来。对于该数据集,我们还可以进行很多优化,比如神经网络中的隐层的设计、引入交叉验证调参、dropout等。看客莫急,后面会慢慢写到的。