如何使用Keras在Python中创建深度学习神经网络模型

155 阅读17分钟

Keras是一个功能强大且易于使用的免费开源Python库,用于开发和评估 深度学习模型.

它是TensorFlow库的一部分,允许你在短短几行代码中定义和训练神经网络模型。

在本教程中,你将发现如何使用Keras在Python中创建你的第一个深度学习神经网络模型。

Keras教程概述

所需的代码不多,但我们要慢慢来,这样你就会知道将来如何创建自己的模型。

在本教程中,你将会涉及的步骤如下:

  1. 载入数据
  2. 定义Keras模型
  3. 编译Keras模型
  4. 拟合Keras模型
  5. 评估Keras模型
  6. 将这一切联系起来
  7. 作出预测

这个 Keras 教程有几个要求:

  1. 你已经安装并配置了Python 2或3。
  2. 你有SciPy(包括NumPy)的安装和配置。
  3. 你已经安装并配置了Keras和一个后端(Theano或TensorFlow)。

如果你在环境方面需要帮助,请看教程:

创建一个名为keras_first_network.py的新文件,然后边输入或复制边粘贴代码到该文件中。

1.加载数据

第一步是定义我们打算在本教程中使用的函数和类。

我们将使用NumPy库来加载我们的数据集,我们将使用Keras库的两个类来定义我们的模型。

下面列出了所需的导入:

# first neural network with keras tutorial
from numpy import loadtxt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
...

现在我们可以加载我们的数据集。

在这个Keras教程中,我们将使用Pima Indians的糖尿病发病数据集。这是一个来自UCI机器学习资源库的标准机器学习数据集。它描述了皮马印第安人的医疗记录数据,以及他们在五年内是否有糖尿病发病的情况。

因此,它是一个二元分类问题(糖尿病发病为1或未发病为0)。所有描述每个病人的输入变量都是数字的。这使得它很容易直接用于期待数字输入和输出值的神经网络,也是我们在Keras中第一个神经网络的理想选择。

该数据集可从这里获得:

下载数据集并把它放在你的本地工作目录下,与你的python文件位置相同。

用这个文件名保存它:

pima-indians-diabetes.csv

看一下文件内部,你应该看到如下的数据行:

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()将该文件加载为一个数字矩阵。

这里有八个输入变量和一个输出变量(最后一列)。我们将学习一个模型,将输入变量(X)的行数映射到输出变量(Y),我们通常将其概括为y=f(X)。

这些变量可以总结为以下几点。

输入变量(X):

  1. 怀孕次数
  2. 口服葡萄糖耐量试验中的血浆葡萄糖浓度a 2小时
  3. 舒张压(mm Hg)
  4. 肱三头肌皮褶厚度(mm)
  5. 2小时血清胰岛素(mu U/ml)
  6. 身体质量指数(体重(公斤)/(身高(米)^2
  7. 糖尿病血统功能
  8. 年龄(岁)

输出变量(y):

  1. 类别变量(0或1)

一旦CSV文件被加载到内存中,我们就可以将数据列分成输入变量和输出变量。

数据将被存储在一个二维数组中,其中第一维是行,第二维是列,例如:[行,列]。

我们可以通过使用标准的NumPy分片操作符或": "选择列的子集,将数组分成两个数组。 我们可以通过分片0:8选择从索引0到索引7的前8列。然后我们可以通过索引8选择输出列(第9个变量)。

...
# load the dataset
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=',')
# split into input (X) and output (y) variables
X = dataset[:,0:8]
y = dataset[:,8]
...

现在我们已经准备好定义我们的神经网络模型了。

注意,数据集有9列,范围0:8将选择从0到7的列,在索引8之前停止。如果这对你来说是新的,那么你可以在这篇文章中了解更多关于数组切片和范围的信息。

2.定义Keras模型

Keras中的模型被定义为一个层的序列。

我们创建一个*序列模型*,然后一个一个地添加层,直到我们对我们的网络架构感到满意。

首先要做的是确保输入层有正确数量的输入特征。这可以在创建第一个层的时候用input_shape参数来指定,并将其设置为(8,) ,以便将8个输入变量以矢量形式呈现。

我们如何知道层的数量和它们的类型?

这是一个非常难的问题。我们可以使用一些启发式的方法,通常最佳的网络结构是通过试错实验的过程找到的(我在这里解释了更多关于这个问题)。一般来说,你需要一个足够大的网络来捕捉问题的结构。

在这个例子中,我们将使用一个有三层的全连接网络结构。

全连接层是用Dense类定义的。我们可以指定层中的神经元或节点的数量作为第一个参数,并使用激活参数指定激活函数。

我们将在前两层使用被称为ReLU的整顿线性单元激活函数,在输出层使用Sigmoid函数。

过去的情况是,所有层都首选Sigmoid和Tanh激活函数。这些年,使用ReLU激活函数可以获得更好的性能。我们在输出层使用sigmoid,以确保我们的网络输出在0和1之间,并且容易映射到第1类的概率,或者用0.5的默认阈值扣到任一类别的硬分类。

我们可以通过添加每一层将其拼凑起来。

  • 该模型希望有8个变量的数据行(*input_shape=(8,)*参数)。
  • 第一个隐藏层有12个节点,使用relu激活函数。
  • 第二个隐藏层有8个节点,使用relu激活函数。
  • 输出层有一个节点,使用sigmoid激活函数。
...
# define the keras model
model = Sequential()
model.add(Dense(12, input_shape=(8,), activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
...

注意,这里最令人困惑的是,模型的输入形状被定义为第一个隐藏层上的一个参数。这意味着添加第一个Dense层的那行代码在做两件事,定义输入或可见层和第一个隐藏层。

3.编译Keras模型

现在,模型已经定义好了,我们可以编译它

编译模型时,会使用盖子下面的高效数值库(即所谓的后端),如Theano或TensorFlow。后台会自动选择最好的方式来表示网络的训练和进行预测,以便在你的硬件上运行,如CPU或GPU甚至分布式。

在编译时,我们必须指定训练网络时需要的一些额外属性。请记住,训练网络意味着找到最佳的权重集来映射我们数据集中的输入和输出。

我们必须指定用于评估一组权重的损失函数,优化器用于搜索网络的不同权重,以及任何我们想在训练期间收集和报告的可选指标。

在这种情况下,我们将使用交叉熵作为损失参数。这个损失是针对二元分类问题的,在Keras中被定义为 "binary_crossentropy"。你可以在这里了解更多关于根据你的问题选择损失函数的信息。

我们将把优化器定义为高效的随机梯度下降算法 "adam"。这是一个流行的梯度下降版本,因为它可以自动调整自己,并在广泛的问题中给出良好的结果。要了解更多关于亚当版本的随机梯度下降算法的信息,请看这篇文章。

最后,因为这是一个分类问题,我们将收集并报告分类准确率,通过度量参数定义。

...
# compile the keras model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
...

4.拟合Keras模型

我们已经定义了我们的模型,并编译了它,准备好进行有效的计算。

现在是时候在一些数据上执行该模型了。

我们可以通过调用模型上的**fit()**函数,在我们加载的数据上训练或拟合我们的模型。

训练是在历时中进行的,每个历时被分成几批:

  • 纪元:训练数据集中的所有行的一次通过。
  • 批次:在权重更新之前,模型在一个历时内考虑的一个或多个样本。

一个历时是由一个或多个批次组成的,基于所选择的批次大小,模型是适合许多历时的。更多关于历时和批次之间的区别,请看这篇文章。

训练过程将通过数据集运行固定数量的迭代,称为epochs,我们必须使用epochs参数指定。我们还必须设置在每个epoch内更新模型权重之前所考虑的数据集行数,称为批处理大小,用batch_size参数设置。

对于这个问题,我们将运行少量的epochs(150),并使用相对较小的batch size(10)。

这些配置可以通过试验和错误来选择。我们希望对模型进行足够的训练,以便它能学到一个好的(或足够好的)输入数据行与输出分类的映射。该模型总是有一些错误,但对于一个给定的模型配置来说,错误量在某一时刻后会趋于平稳。这就是所谓的模型收敛。

...
# fit the keras model on the dataset
model.fit(X, y, epochs=150, batch_size=10)
...

这是在你的CPU或GPU上发生的工作。

这个例子不需要GPU,但如果你对如何在云端的GPU硬件上廉价运行大型模型感兴趣,请看这篇文章。

5.评估Keras模型

我们已经在整个数据集上训练了我们的神经网络,我们可以在同一个数据集上评估网络的性能。

这只能让我们了解到我们对数据集的建模情况(如训练精度),但不知道算法在新数据上可能的表现如何。我们这样做是为了简单起见,但理想情况下,你可以将你的数据分成训练和测试数据集,用于训练和评估你的模型。

你可以在你的训练数据集上使用**evaluate()**函数来评估你的模型,并将用于训练模型的相同输入和输出传递给它。

这将为每个输入和输出对生成一个预测,并收集分数,包括平均损失和你配置的任何指标,如准确性。

**evaluate()**函数将返回一个有两个值的列表。第一个是模型在数据集上的损失,第二个是模型在数据集上的准确性。我们只对报告准确性感兴趣,所以我们将忽略损失值。

...
# evaluate the keras model
_, accuracy = model.evaluate(X, y)
print('Accuracy: %.2f' % (accuracy*100))

6.6.把所有的东西联系起来

你刚刚看到了如何在Keras中轻松创建你的第一个神经网络模型。

让我们把这一切联系起来,形成一个完整的代码示例。

# first neural network with keras tutorial
from numpy import loadtxt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
# load the dataset
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=',')
# split into input (X) and output (y) variables
X = dataset[:,0:8]
y = dataset[:,8]
# define the keras model
model = Sequential()
model.add(Dense(12, input_shape=(8,), activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# compile the keras model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit the keras model on the dataset
model.fit(X, y, epochs=150, batch_size=10)
# evaluate the keras model
_, accuracy = model.evaluate(X, y)
print('Accuracy: %.2f' % (accuracy*100))

你可以将所有的代码复制到你的Python文件中,并将其保存为 "keras_first_network.py",与你的数据文件 "pima-indians-diabetes.csv"放在同一目录中。然后你可以从你的命令行(命令提示符)将Python文件作为一个脚本运行,如下所示。

python keras_first_network.py

运行这个例子,你应该看到150个epochs中的每一个都打印出损失和准确率的信息,然后是训练数据集上的训练模型的最终评估。

在我的工作站上,在CPU上运行,需要大约10秒钟的时间来执行。

理想情况下,我们希望损失为零,准确率为1.0(例如100%)。除了最微不足道的机器学习问题,这是不可能的。相反,我们的模型中总是会有一些误差。我们的目标是选择一个模型配置和训练配置,使其在给定的数据集上实现最低的损失和最高的准确性。

...
768/768 [==============================] - 0s 63us/step - loss: 0.4817 - acc: 0.7708
Epoch 147/150
768/768 [==============================] - 0s 63us/step - loss: 0.4764 - acc: 0.7747
Epoch 148/150
768/768 [==============================] - 0s 63us/step - loss: 0.4737 - acc: 0.7682
Epoch 149/150
768/768 [==============================] - 0s 64us/step - loss: 0.4730 - acc: 0.7747
Epoch 150/150
768/768 [==============================] - 0s 63us/step - loss: 0.4754 - acc: 0.7799
768/768 [==============================] - 0s 38us/step
Accuracy: 76.56

注意:如果你尝试在IPython或Jupyter笔记本中运行这个例子,你可能会得到一个错误。

原因是训练期间的输出进度条。你可以通过在调用fit()evaluate()函数时设置verbose=0来轻松关闭这些。

...
# fit the keras model on the dataset without progress bars
model.fit(X, y, epochs=150, batch_size=10, verbose=0)
# evaluate the keras model
_, accuracy = model.evaluate(X, y, verbose=0)
...

注意:鉴于算法或评估程序的随机性,或数字精度的差异,你的结果可能会有所不同。考虑将这个例子运行几次,并比较平均结果。

你得到什么分数?
在下面的评论中发表你的结果。

神经网络是一种随机算法,这意味着相同的算法在相同的数据上可以训练出不同的模型,每次运行代码时的技能都不同。这是一个特点,而不是一个错误。你可以在这篇文章中了解到更多信息。

模型性能的差异意味着,为了合理地接近你的模型性能如何,你可能需要多次拟合它,并计算出准确率分数的平均值。关于这种评估神经网络的方法的更多信息,请看这篇文章。

例如,下面是重新运行该例子5次后的准确率分数:

Accuracy: 75.00
Accuracy: 77.73
Accuracy: 77.60
Accuracy: 78.12
Accuracy: 76.17

我们可以看到,所有的准确率分数都在77%左右,平均为76.924%。

7.进行预测

我被问到的第一个问题是:

在我训练了我的模型之后,我怎样才能用它来对新的数据进行预测?

好问题。

我们可以改编上面的例子,用它来生成对训练数据集的预测,假装它是一个我们以前没有见过的新数据集。

进行预测就像在模型上调用**predict()**函数一样简单。我们在输出层使用了一个sigmoid激活函数,所以预测结果将是一个在0和1之间的概率。我们可以通过四舍五入将它们转换为这个分类任务的清晰的二进制预测。

比如说:

...
# make probability predictions with the model
predictions = model.predict(X)
# round predictions 
rounded = [round(x[0]) for x in predictions]

另外,我们也可以将概率转换为0或1,直接预测清晰的类别,例如。

...
# make class predictions with the model
predictions = (model.predict(X) > 0.5).astype(int)

下面的完整例子对数据集中的每个例子进行预测,然后打印出数据集中前5个例子的输入数据、预测类别和预期类别。

# first neural network with keras make predictions
from numpy import loadtxt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
# load the dataset
dataset = loadtxt('pima-indians-diabetes.csv', delimiter=',')
# split into input (X) and output (y) variables
X = dataset[:,0:8]
y = dataset[:,8]
# define the keras model
model = Sequential()
model.add(Dense(12, input_shape=(8,), activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# compile the keras model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit the keras model on the dataset
model.fit(X, y, epochs=150, batch_size=10, verbose=0)
# make class predictions with the model
predictions = (model.predict(X) > 0.5).astype(int)
# summarize the first 5 cases
for i in range(5):
	print('%s => %d (expected %d)' % (X[i].tolist(), predictions[i], y[i]))

由于我们将verbose参数设置为0,所以运行该例子时不会像以前那样显示进度条。

模型拟合后,对数据集中的所有例子进行了预测,并打印了前5个例子的输入行和预测类值,并与预期类值进行比较。

我们可以看到,大多数行都被正确预测了。事实上,根据我们在上一节中对模型性能的估计,我们预计大约有76.9%的行是正确预测的。

[6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0] => 0 (expected 1)
[1.0, 85.0, 66.0, 29.0, 0.0, 26.6, 0.351, 31.0] => 0 (expected 0)
[8.0, 183.0, 64.0, 0.0, 0.0, 23.3, 0.672, 32.0] => 1 (expected 1)
[1.0, 89.0, 66.0, 23.0, 94.0, 28.1, 0.167, 21.0] => 0 (expected 0)
[0.0, 137.0, 40.0, 35.0, 168.0, 43.1, 2.288, 33.0] => 1 (expected 1)

如果你想知道更多关于如何用Keras模型进行预测的信息,请看这篇文章。

Keras教程总结

在这篇文章中,你发现了何使用强大的深度学习的Keras Python库创建你的第一个神经网络模型。

具体来说,你学到了使用Keras创建神经网络或深度学习模型的六个关键步骤,逐步包括:

  1. 如何加载数据
  2. 如何在Keras中定义一个神经网络
  3. 如何使用高效的数字后台编译一个Keras模型
  4. 如何在数据上训练一个模型
  5. 如何在数据上评估一个模型
  6. 如何用模型进行预测

你对Keras或本教程有什么问题吗?
在评论中提出你的问题,我将尽力回答。

Keras教程扩展

干得好,你已经成功地使用Python中的Keras深度学习库开发了你的第一个神经网络。

本节提供了本教程的一些扩展,你可能想要探索一下。

  • 调整模型:改 变模型或训练过程的配置,看看你是否能提高模型的性能,例如,达到优于76%的准确性。
  • 保存模型:更新教程,将模型保存到文件中,然后在以后加载它,用它来进行预测(见本教程)。
  • 总结模型:更新教程,对模型进行总结,并创建一个模型层的图(见本教程)。
  • 分离训练和测试数据集:将加载的数据集拆分为训练和测试集(根据行数拆分),用一个集来训练模型,另一个集来估计模型在新数据上的表现。
  • 绘制学习曲线:fit()函数返回一个历史对象,该对象总结了每个历时结束时的损失和准确性。创建该数据的线状图,称为学习曲线(见本教程)。
  • 学习一个新的数据集:更新教程以使用不同的表格数据集,也许是来自UCI机器学习资源库
  • 使用功能性API:更新教程,使用Keras Functional API来定义模型(见本教程)。

进一步阅读

你在寻找更多的Python和Keras的深度学习教程吗?

请看看其中的一些内容。

相关教程