Keras 初探

追求真理 2019-06-27

Keras 初探

最近在接触些深度学习的东西,也对一些深度学习的框架进行了大致的了解。Python的科学计算包主要是TheanoTensorFlow,特点就是很强大,但对于初学者不太友好、有点难用。但Keras可以基于这两种包之一方便地建立神经网络。

什么是Keras

Keras是一个高层神经网络API,Keras由纯Python编写而成并基TensorflowTheano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果。

Keras可在Python 2.7或3.5运行,无缝调用后端的CPU或GPU网络。Keras由Google的Francois Chollet开发,并遵循以下原则:

  • 模块化:每个模块都是单独的流程或图,深度学习的所有问题都可以通过组装模块解决
  • 简单化:提供解决问题的最简单办法,不加装饰,最大化可读性
  • 扩展性:新模块的添加特别容易,方便试验新想法
  • Python:不使用任何自创格式,只使用原生Python

    如下图所示,在终端调用keras,后面会输出下面的提示,说明keras默认的后端为tensorflow

    Using TensorFlow backend.

Keras 初探

如果说默认的后端不是tensorflow,而是theano,我们可以配置后端文件进行修改:

~/.keras/keras.json

里面是:

{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}

我们把backend参数改为tensorflow即可。

序贯模型

Keras的目标就是搭建模型。最主要的模型是Sequential:不同层的叠加。模型创建后可以编译,调用后端进行优化,可以指定损失函数和优化算法。

编译后的模型需要导入数据:可以一批批加入数据,也可以一次性全加入。训练后的模型就可以做预测或分类了。大体上的步骤是:

  1. 定义模型:创建Sequential模型,加入每一层
  2. 编译模型:指定损失函数和优化算法,使用模型的compile()方法
  3. 拟合数据:使用模型的fit()方法拟合数据
  4. 进行预测:使用模型的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大小不应包含在其中。
  • 有些2D层,如Dense,支持通过指定其输入维度input_dim来隐含的指定输入数据shape,是一个Int类型的数据。一些3D的时域层支持通过参数input_diminput_length来指定输入shape。
  • 如果你需要为输入指定一个固定大小的batch_size,可以传递batch_size参数到一个层中,例如你想指定输入张量的batch大小是32,数据shape是(6,8),则你需要传递batch_size=32input_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接收三个参数:

  • 优化器optimizer:该参数可指定为已预定义的优化器名,如rmspropadagrad,或一个Optimizer类的对象。
  • 损失函数loss:该参数为模型试图最小化的目标函数,它可为预定义的损失函数名,如categorical_crossentropymse,也可以为一个损失函数。
  • 指标列表metrics:对分类问题,我们一般将该列表设置为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实战

本文主要是介绍Keras的基本用法,所以数据集采用经典数据集,中间的数据清洗过程便可以省略一些。数据集用的是UCI数据集中的 皮马人糖尿病数据集(pima-indians-diabetes),在UCI的机器学习网站(http://mlearn.ics.uci.edu/dat...)可以免费下载。

数据集的内容是皮马人的医疗记录,以及过去5年内是否有糖尿病。所有的数据都是数字,问题是(是否有糖尿病是1或0),是二分类问题。数据的数量级不同,有8个属性:

  1. 怀孕次数
  2. 2小时口服葡萄糖耐量试验中的血浆葡萄糖浓度
  3. 舒张压(毫米汞柱)
  4. 2小时血清胰岛素(mu U/ml)
  5. 体重指数(BMI)
  6. 糖尿病血系功能
  7. 年龄(年)
  8. 类别:过去5年内是否有糖尿病

所有的数据都是数字,可以直接导入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等。看客莫急,后面会慢慢写到的。


Keras 初探

相关推荐