- Keras深度学习教程
- Keras深度学习 - 首页
- Keras深度学习 - 简介
- 深度学习
- 项目设置
- 导入库
- 创建深度学习模型
- 编译模型
- 准备数据
- 训练模型
- 评估模型性能
- 测试数据预测
- 保存模型
- 加载模型进行预测
- 结论
- Keras深度学习资源
- Keras深度学习快速指南
- Keras深度学习 - 有用资源
- Keras深度学习 - 讨论
Keras深度学习快速指南
Keras深度学习 - 简介
近年来,深度学习已成为人工智能(AI)领域的一个热门词汇。多年来,我们一直使用机器学习(ML)来赋予机器智能。近年来,由于深度学习在预测方面优于传统的机器学习技术,因此变得越来越流行。
深度学习本质上意味着使用海量数据训练人工神经网络(ANN)。在深度学习中,网络可以自我学习,因此需要海量数据进行学习。而传统的机器学习本质上是一组解析数据并从中学习的算法。然后,它们利用这些学习成果做出明智的决策。
现在,谈到Keras,它是一个高级神经网络API,运行在TensorFlow之上——一个端到端的开源机器学习平台。使用Keras,您可以轻松定义复杂的人工神经网络架构,以在您的海量数据上进行实验。Keras还支持GPU,这对于处理海量数据和开发机器学习模型至关重要。
在本教程中,您将学习如何在构建深度神经网络中使用Keras。我们将通过实践示例进行教学。手头的问题是使用经过深度学习训练的神经网络识别手写数字。
为了让您对深度学习更加兴奋,以下是Google趋势中关于深度学习的截图:
从图中可以看出,过去几年人们对深度学习的兴趣稳步增长。深度学习已成功应用于许多领域,例如计算机视觉、自然语言处理、语音识别、生物信息学、药物设计等等。本教程将帮助您快速入门深度学习。
所以请继续阅读!
Keras深度学习 - 深度学习
如引言中所述,深度学习是使用海量数据训练人工神经网络的过程。训练完成后,网络将能够对未见数据进行预测。在进一步解释深度学习是什么之前,让我们快速了解一下训练神经网络中使用的一些术语。
神经网络
人工神经网络的想法源于我们大脑中的神经网络。典型的神经网络包含三层——输入层、输出层和隐藏层,如下面的图片所示。
这也被称为浅层神经网络,因为它只包含一层隐藏层。您可以在上述架构中添加更多隐藏层以创建更复杂的架构。
深度网络
下图显示了一个包含四个隐藏层、一个输入层和一个输出层的深度网络。
随着向网络添加更多隐藏层,其训练在所需资源和完全训练网络所需的时间方面变得更加复杂。
网络训练
定义网络架构后,您需要对其进行训练以执行某些类型的预测。训练网络是一个为网络中每个链接找到合适权重的过程。在训练期间,数据通过各个隐藏层从输入层流向输出层。由于数据始终沿一个方向从输入到输出移动,因此我们将此网络称为前馈网络,并将数据传播称为前向传播。
激活函数
在每一层,我们计算输入的加权和并将其馈送到激活函数。激活函数为网络引入了非线性。它只是一个将输出离散化的数学函数。一些最常用的激活函数包括sigmoid、双曲正切(tanh)、ReLU和Softmax。
反向传播
反向传播是一种用于监督学习的算法。在反向传播中,误差从输出层反向传播到输入层。给定一个误差函数,我们计算误差函数相对于分配给每个连接的权重的梯度。梯度的计算从网络向后进行。首先计算最后一层权重的梯度,最后计算第一层权重的梯度。
在每一层,梯度的部分计算都会在计算前一层的梯度时重复使用。这称为梯度下降。
在本项目教程中,您将定义一个前馈深度神经网络,并使用反向传播和梯度下降技术对其进行训练。幸运的是,Keras为我们提供了所有高级API,用于定义网络架构并使用梯度下降对其进行训练。接下来,您将学习如何在Keras中做到这一点。
手写数字识别系统
在这个小型项目中,您将应用前面描述的技术。您将创建一个深度学习神经网络,用于训练识别手写数字。在任何机器学习项目中,第一个挑战都是收集数据。特别是对于深度学习网络,您需要海量数据。幸运的是,对于我们试图解决的问题,有人已经创建了一个用于训练的数据集。这称为mnist,它作为Keras库的一部分提供。数据集包含多个28x28像素的手写数字图像。您将在该数据集的大部分数据上训练您的模型,其余数据将用于验证您训练的模型。
项目描述
mnist数据集包含70000张手写数字图像。这里复制了一些示例图像供您参考
每张图像的大小为28 x 28像素,总共有768个不同灰度级别的像素。大多数像素倾向于黑色阴影,而只有少数像素倾向于白色。我们将这些像素的分布放入数组或向量中。例如,典型数字4和5图像的像素分布如下图所示。
每张图像的大小为28 x 28像素,总共有768个不同灰度级别的像素。大多数像素倾向于黑色阴影,而只有少数像素倾向于白色。我们将这些像素的分布放入数组或向量中。例如,典型数字4和5图像的像素分布如下图所示。
显然,您可以看到像素的分布(特别是那些倾向于白色色调的像素)有所不同,这区分了它们所代表的数字。我们将这784个像素的分布作为输入馈送到我们的网络。网络的输出将包含10个类别,表示0到9之间的数字。
我们的网络将包含4层——一个输入层、一个输出层和两个隐藏层。每个隐藏层将包含512个节点。每一层都完全连接到下一层。当我们训练网络时,我们将计算每个连接的权重。我们通过应用前面讨论的反向传播和梯度下降来训练网络。
Keras深度学习 - 项目设置
有了这些背景知识,让我们现在开始创建项目。
项目设置
我们将通过Anaconda导航器使用Jupyter来进行我们的项目。由于我们的项目使用TensorFlow和Keras,您需要在Anaconda设置中安装它们。要在控制台窗口中安装Tensorflow,请运行以下命令
>conda install -c anaconda tensorflow
要安装Keras,请使用以下命令:
>conda install -c anaconda keras
您现在可以开始使用Jupyter了。
启动Jupyter
当您启动Anaconda导航器时,您将看到以下启动屏幕。
单击“Jupyter”以启动它。屏幕将显示驱动器上现有的项目(如果有)。
启动新项目
通过选择以下菜单选项,在Anaconda中启动一个新的Python 3项目:
File | New Notebook | Python 3
菜单选择的屏幕截图显示在下面,供您快速参考:
一个新的空白项目将显示在您的屏幕上,如下所示:
通过单击并编辑默认名称“UntitledXX”将项目名称更改为DeepLearningDigitRecognition。
Keras深度学习 - 导入库
我们首先导入项目代码中所需的各种库。
数组处理和绘图
像往常一样,我们使用numpy进行数组处理,使用matplotlib进行绘图。这些库使用以下import语句导入到我们的项目中
import numpy as np import matplotlib import matplotlib.pyplot as plot
抑制警告
由于Tensorflow和Keras不断更新,如果您没有在项目中同步其相应的版本,则在运行时您会看到大量警告错误。由于它们会分散您学习的注意力,因此我们将在本项目中抑制所有警告。这可以通过以下代码行完成:
# silent all warnings import os os.environ['TF_CPP_MIN_LOG_LEVEL']='3' import warnings warnings.filterwarnings('ignore') from tensorflow.python.util import deprecation deprecation._PRINT_DEPRECATION_WARNINGS = False
Keras
我们使用Keras库导入数据集。我们将使用mnist数据集进行手写数字识别。我们使用以下语句导入所需的包
from keras.datasets import mnist
我们将使用Keras包定义深度学习神经网络。我们导入Sequential、Dense、Dropout和Activation包以定义网络架构。我们使用load_model包保存和检索我们的模型。我们还使用np_utils进行项目中需要的一些实用程序。这些导入通过以下程序语句完成:
from keras.models import Sequential, load_model from keras.layers.core import Dense, Dropout, Activation from keras.utils import np_utils
运行此代码时,您将在控制台上看到一条消息,指出Keras使用TensorFlow作为后端。此阶段的屏幕截图显示如下:
现在,由于我们已经拥有项目所需的所有导入,我们将继续为深度学习网络定义架构。
创建深度学习模型
我们的神经网络模型将包含一个线性层堆栈。要定义这样的模型,我们调用Sequential函数:
model = Sequential()
输入层
我们使用以下程序语句定义输入层,它是网络中的第一层:
model.add(Dense(512, input_shape=(784,)))
这会创建一个包含 512 个节点(神经元)的层,以及 784 个输入节点。如下图所示:
请注意,所有输入节点都完全连接到第一层,即每个输入节点都连接到第一层的全部 512 个节点。
接下来,我们需要为第一层的输出添加激活函数。我们将使用 ReLU 作为我们的激活函数。激活函数使用以下程序语句添加:
model.add(Activation('relu'))
接下来,我们使用下面的语句添加 20% 的 Dropout。Dropout 是一种用于防止模型过拟合的技术。
model.add(Dropout(0.2))
至此,我们的输入层已完全定义。接下来,我们将添加一个隐藏层。
隐藏层
我们的隐藏层将包含 512 个节点。隐藏层的输入来自我们之前定义的输入层。所有节点都像之前的情况一样完全连接。隐藏层的输出将传递到网络中的下一层,这将是我们的最终输出层。我们将使用与上一层相同的 ReLU 激活函数和 20% 的 Dropout。添加此层的代码如下所示:
model.add(Dense(512)) model.add(Activation('relu')) model.add(Dropout(0.2))
此时,网络可以可视化为:
接下来,我们将向我们的网络添加最终层,即输出层。请注意,您可以使用类似于此处使用的代码添加任意数量的隐藏层。添加更多层会使网络训练变得复杂;但是,在许多情况下(尽管并非所有情况)都能带来更好的结果的显著优势。
输出层
输出层仅包含 10 个节点,因为我们希望将给定的图像分类为 10 个不同的数字。我们使用以下语句添加此层:
model.add(Dense(10))
由于我们希望将输出分类为 10 个不同的单元,因此我们使用 softmax 激活函数。在 ReLU 的情况下,输出是二进制的。我们使用以下语句添加激活函数:
model.add(Activation('softmax'))
此时,我们的网络可以可视化为下图所示:
此时,我们的网络模型已在软件中完全定义。运行代码单元,如果没有任何错误,您将在屏幕上看到确认消息,如下面的屏幕截图所示:
接下来,我们需要编译模型。
使用 Keras 进行深度学习 - 编译模型
编译是使用一个名为 **compile** 的方法调用执行的。
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='adam')
**compile** 方法需要几个参数。loss 参数指定为类型 **'categorical_crossentropy'**。metrics 参数设置为 **'accuracy'**,最后我们使用 **adam** 优化器来训练网络。此阶段的输出如下所示:
现在,我们准备将数据馈送到我们的网络中。
加载数据
如前所述,我们将使用 Keras 提供的 **mnist** 数据集。当我们将数据加载到我们的系统中时,我们将将其拆分为训练数据和测试数据。数据通过调用 **load_data** 方法加载,如下所示:
(X_train, y_train), (X_test, y_test) = mnist.load_data()
此阶段的输出如下所示:
现在,我们将了解加载数据集的结构。
提供给我们的数据是大小为 28 x 28 像素的图形图像,每个图像包含 0 到 9 之间的单个数字。我们将在控制台上显示前十张图像。执行此操作的代码如下所示:
# printing first 10 images for i in range(10): plot.subplot(3,5,i+1) plot.tight_layout() plot.imshow(X_train[i], cmap='gray', interpolation='none') plot.title("Digit: {}".format(y_train[i])) plot.xticks([]) plot.yticks([])
在 10 次计数的迭代循环中,我们在每次迭代中创建一个子图,并在其中显示来自 **X_train** 向量的图像。我们从相应的 **y_train** 向量为每个图像添加标题。请注意,**y_train** 向量包含 **X_train** 向量中相应图像的实际值。我们通过调用两个方法 **xticks** 和 **yticks** 并使用空参数来删除 x 和 y 轴标记。运行代码时,您将看到以下输出:
接下来,我们将准备数据以将其馈送到我们的网络中。
使用 Keras 进行深度学习 - 准备数据
在将数据馈送到网络之前,必须将其转换为网络所需的形式。这称为为网络准备数据。它通常包括将多维输入转换为一维向量并标准化数据点。
重塑输入向量
我们数据集中图像包含 28 x 28 个像素。这必须转换为大小为 28 * 28 = 784 的一维向量,以便将其馈送到我们的网络中。我们通过对向量调用 **reshape** 方法来做到这一点。
X_train = X_train.reshape(60000, 784) X_test = X_test.reshape(10000, 784)
现在,我们的训练向量将包含 60000 个数据点,每个数据点包含一个大小为 784 的一维向量。类似地,我们的测试向量将包含 10000 个数据点,每个数据点包含一个大小为 784 的一维向量。
标准化数据
输入向量当前包含的数据具有 0 到 255 之间的离散值 - 灰度级。将这些像素值标准化为 0 到 1 之间有助于加快训练速度。由于我们将使用随机梯度下降,因此标准化数据还有助于减少陷入局部最优解的可能性。
为了标准化数据,我们将其表示为浮点类型并将其除以 255,如下面的代码片段所示:
X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train /= 255 X_test /= 255
现在让我们看看标准化后的数据是什么样子。
检查标准化数据
要查看标准化后的数据,我们将调用直方图函数,如下所示:
plot.hist(X_train[0]) plot.title("Digit: {}".format(y_train[0]))
在这里,我们绘制了 **X_train** 向量第一个元素的直方图。我们还打印了此数据点表示的数字。运行上述代码的输出如下所示:
您会注意到值接近零的点的密度很大。这些是图像中的黑点,显然是图像的主要部分。其余的灰度点,即接近白色,表示数字。您可以查看另一个数字的像素分布。以下代码打印训练数据集中索引为 2 的数字的直方图。
plot.hist(X_train[2]) plot.title("Digit: {}".format(y_train[2])
运行上述代码的输出如下所示:
比较以上两张图,您会注意到两张图像中白色像素的分布不同,表明表示不同的数字 - 上述两张图片中的“5”和“4”。
接下来,我们将检查完整训练数据集中数据的分布。
检查数据分布
在使用我们的数据集中训练机器学习模型之前,我们应该了解数据集中唯一数字的分布。我们的图像表示 10 个不同的数字,范围从 0 到 9。我们想知道数据集中数字 0、1 等的数量。我们可以使用 NumPy 的 **unique** 方法获取此信息。
使用以下命令打印唯一值的个数以及每个值的出现次数
print(np.unique(y_train, return_counts=True))
运行上述命令时,您将看到以下输出:
(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([5923, 6742, 5958, 6131, 5842, 5421, 5918, 6265, 5851, 5949]))
它显示有 10 个不同的值 - 0 到 9。数字 0 出现了 5923 次,数字 1 出现了 6742 次,依此类推。此处显示输出的屏幕截图:
作为数据准备的最后一步,我们需要对数据进行编码。
编码数据
我们的数据集中有十个类别。因此,我们将使用独热编码将我们的输出编码为这十个类别。我们使用 NumPy 实用程序的 to_categorial 方法执行编码。输出数据编码后,每个数据点将转换为大小为 10 的一维向量。例如,数字 5 现在将表示为 [0,0,0,0,0,1,0,0,0,0]。
使用以下代码段对数据进行编码:
n_classes = 10 Y_train = np_utils.to_categorical(y_train, n_classes)
您可以通过打印分类后的 Y_train 向量的前 5 个元素来查看编码结果。
使用以下代码打印前 5 个向量:
for i in range(5): print (Y_train[i])
您将看到以下输出:
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.] [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.] [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
第一个元素表示数字 5,第二个元素表示数字 0,依此类推。
最后,您还必须对测试数据进行分类,这可以通过以下语句完成:
Y_test = np_utils.to_categorical(y_test, n_classes)
此时,您的数据已完全准备好馈送到网络中。
接下来,是最重要的部分,即训练我们的网络模型。
使用 Keras 进行深度学习 - 训练模型
模型训练在一个名为 fit 的方法调用中完成,该方法采用以下代码中所示的一些参数:
history = model.fit(X_train, Y_train, batch_size=128, epochs=20, verbose=2, validation_data=(X_test, Y_test)))
fit 方法的前两个参数指定训练数据集的特征和输出。
**epochs** 设置为 20;我们假设训练将在最多 20 个 epochs(迭代)内收敛。训练后的模型在测试数据上进行验证,如最后一个参数中指定的那样。
运行上述命令的部分输出如下所示:
Train on 60000 samples, validate on 10000 samples Epoch 1/20 - 9s - loss: 0.2488 - acc: 0.9252 - val_loss: 0.1059 - val_acc: 0.9665 Epoch 2/20 - 9s - loss: 0.1004 - acc: 0.9688 - val_loss: 0.0850 - val_acc: 0.9715 Epoch 3/20 - 9s - loss: 0.0723 - acc: 0.9773 - val_loss: 0.0717 - val_acc: 0.9765 Epoch 4/20 - 9s - loss: 0.0532 - acc: 0.9826 - val_loss: 0.0665 - val_acc: 0.9795 Epoch 5/20 - 9s - loss: 0.0457 - acc: 0.9856 - val_loss: 0.0695 - val_acc: 0.9792
为了方便参考,下面给出了输出的屏幕截图:
现在,由于模型已在我们的训练数据上进行了训练,我们将评估其性能。
评估模型性能
为了评估模型性能,我们调用 **evaluate** 方法,如下所示:
loss_and_metrics = model.evaluate(X_test, Y_test, verbose=2)
为了评估模型性能,我们调用 **evaluate** 方法,如下所示:
loss_and_metrics = model.evaluate(X_test, Y_test, verbose=2)
我们将使用以下两个语句打印损失和准确率:
print("Test Loss", loss_and_metrics[0]) print("Test Accuracy", loss_and_metrics[1])
运行上述语句时,您将看到以下输出:
Test Loss 0.08041584826191042 Test Accuracy 0.9837
这表明测试准确率为 98%,这对我们来说应该是可以接受的。这意味着在 2% 的情况下,手写数字将无法正确分类。我们还将绘制准确率和损失指标,以查看模型在测试数据上的表现。
绘制准确率指标
我们使用训练期间记录的 **history** 来获取准确率指标的图表。以下代码将绘制每个 epoch 的准确率。我们选择训练数据准确率 (“acc”) 和验证数据准确率 (“val_acc”) 进行绘图。
plot.subplot(2,1,1) plot.plot(history.history['acc']) plot.plot(history.history['val_acc']) plot.title('model accuracy') plot.ylabel('accuracy') plot.xlabel('epoch') plot.legend(['train', 'test'], loc='lower right')
输出图如下所示:
如您在图中看到的,准确率在前两个 epoch 中迅速提高,表明网络学习速度很快。之后,曲线趋于平缓,表明不需要太多 epoch 来进一步训练模型。通常,如果训练数据准确率 (“acc”) 持续提高,而验证数据准确率 (“val_acc”) 却变差,则说明您遇到了过拟合。这表明模型开始记忆数据。
我们还将绘制损失指标来检查模型的性能。
绘制损失指标
同样,我们绘制训练 (“loss”) 和测试 (“val_loss”) 数据上的损失。这是使用以下代码完成的:
plot.subplot(2,1,2) plot.plot(history.history['loss']) plot.plot(history.history['val_loss']) plot.title('model loss') plot.ylabel('loss') plot.xlabel('epoch') plot.legend(['train', 'test'], loc='upper right')
此代码的输出如下所示:
如您在图中看到的,训练集上的损失在前两个 epoch 中迅速下降。对于测试集,损失下降的速度不如训练集,但在多个 epoch 中保持几乎平坦。这意味着我们的模型能够很好地推广到未见过的数据。
现在,我们将使用训练好的模型来预测测试数据中的数字。
测试数据预测
预测未见过数据中的数字非常简单。您只需调用 **model** 的 **predict_classes** 方法,并将包含未知数据点的向量传递给它即可。
predictions = model.predict_classes(X_test)
方法调用会将预测结果返回到一个向量中,可以针对实际值测试 0 和 1。这是使用以下两个语句完成的:
correct_predictions = np.nonzero(predictions == y_test)[0] incorrect_predictions = np.nonzero(predictions != y_test)[0]
最后,我们将使用以下两个程序语句打印正确预测和错误预测的次数:
print(len(correct_predictions)," classified correctly") print(len(incorrect_predictions)," classified incorrectly")
运行代码后,您将获得以下输出:
9837 classified correctly 163 classified incorrectly
现在,由于您已经成功训练了模型,我们将保存它以备将来使用。
使用 Keras 进行深度学习 - 保存模型
我们将训练后的模型保存在本地驱动器中的 models 文件夹中,该文件夹位于当前工作目录中。要保存模型,请运行以下代码:
directory = "./models/" name = 'handwrittendigitrecognition.h5' path = os.path.join(save_dir, name) model.save(path) print('Saved trained model at %s ' % path)
运行代码后的输出如下所示:
现在,由于您已保存了一个训练好的模型,您可以稍后使用它来处理未知数据。
加载模型进行预测
要预测未见数据,您首先需要将训练好的模型加载到内存中。这可以通过以下命令完成:
model = load_model ('./models/handwrittendigitrecognition.h5')
请注意,我们只是将 .h5 文件加载到内存中。这会在内存中设置整个神经网络,以及分配给每一层的权重。
现在,要对未见数据进行预测,请将数据(可以是一个或多个项目)加载到内存中。对数据进行预处理以满足模型的输入要求,就像您之前对训练和测试数据所做的那样。预处理后,将其馈送到您的网络。模型将输出其预测结果。
使用 Keras 进行深度学习 - 结论
Keras 提供了一个高级 API 用于创建深度神经网络。在本教程中,您学习了如何创建一个用于查找手写文本中数字的深度神经网络。为此创建了一个多层网络。Keras 允许您在每一层定义您选择的激活函数。使用梯度下降,网络在训练数据上进行了训练。在测试数据上测试了训练后的网络预测未见数据的准确性。您学习了如何绘制准确性和误差指标。网络完全训练后,您将网络模型保存以备将来使用。