快速而简单地深入了解Keras的深度学习

131 阅读14分钟

快速而简单地深入了解Keras的深度学习

一份简单的指南,向你介绍Keras的深度学习世界

深度学习是近几年来人气大增的编程领域之一。越来越难找到一个领域,这个新的流行语没有被应用于这样或那样的目的。

语音和图像识别。自然语言处理。大数据。所有这些领域都在深度学习的帮助下取得了重大突破。由于深度学习的力量,像自动驾驶汽车这样在几年前还是一种幻想的东西,现在几乎成为现实。

因此,我们认为现在是开发者闯入这一领域的理想时机,即使你只是在做实验。Keras是Python中最强大的深度学习库之一,使任何人都能更容易地利用这项技术,而不必担心复杂的基础理论。

在本教程中,我们将给你一个关于深度学习的简单介绍,然后,不在理论方面关注太长时间,直接进入使用Keras构建DL模型。

正如你在本篇文章结束时发现的那样,Keras让初学者也变得超级简单。但如果你对简单的机器学习概念有一些了解,我们在本教程中做出的某些决定对你来说会更有意义。


什么是深度学习?

深度学习是机器学习的一个子集。它模仿人脑及其神经网络的结构,使机器有能力从原始数据中得出输出。

传统机器学习的主要缺点之一是特征提取。由于传统的ML模型不能处理原始数据本身,我们必须在将数据传递给模型之前提取数据中的重要特征。

程序员需要对问题领域有深刻的理解,才能得出哪些特征应该被提取,以及如何提取这些特征。更不用说,这个过程中的人为干预为没有捕捉到原始数据中重要的高层特征提供了可能。

但深度学习消除了对特征提取的需求。深度学习模型中的神经网络可以学习识别原始数据中的抽象和隐含模式,并自行映射它们对某种输出的影响。换句话说,DL结合了特征提取和分类,并在一个模型中进行。

这使得深度学习在理解原始数据中的隐藏模式和特征方面比机器学习有优势。因此,它们提供了比ML模型更好的结果,特别是随着数据集规模的增加。


典型神经网络的架构

DL模型中的典型神经网络是由几层组成的。每个节点包含一组携带数值的节点(如0.3,2.45)。

相邻两层的节点之间的连接是由权重定义的。它定义了前一个节点的值对决定后一个节点的值的权重(如1.2,5)。换句话说,权重决定了一个节点在决定另一个节点的价值方面所具有的影响。权重值是在神经网络的训练过程中计算的。

神经网络的第一层被称为输入层。输入层的层数取决于输入向量的大小。如果输入向量的大小为12,那么输入层的大小也应该是12。

神经网络的最后一层是输出层。当模型执行分类任务时,输出层应该为每一个可能的分类结果包含一个节点。

例如,如果一个DL模型被用来识别输入图像中显示的数字(从0-9),它在输出层应该有10个节点。当模型对一个给定的输入图像进行预测时,每个输出节点都给出了图像中的数字是该节点所代表的数字的概率。具有最高概率的数字被认为是模型的最终预测结果。

在输入和输出层之间的所有其他层被称为神经网络的隐藏层。这些层和连接其节点的权重进行数学运算以输出模型的最终预测结果。一个神经网络可以有一个以上的隐藏层,这取决于它所要完成的任务。


什么是卷积神经网络(CNN)?

由于我们将在本教程中使用Keras构建一个简单的CNN,因此在继续之前,让我们试着了解CNN与普通神经网络的区别。

CNN是一个以图像作为输入的神经网络。换句话说,当我们调整神经网络的属性,特别是调整其与图像输入及其固有特质的良好合作关系时,我们称其为CNN。

因此,与普通的神经网络相比,一个CNN架构包括一些特定类型的层。卷积层、池化层和全连接层就是这样的几个例子。

卷积层

卷积层应用一个过滤器,使用名为卷积的数学运算来总结图像中一小块区域的特征。例如,我们可以用一个大小为3x3的内核(可以认为是一个窗口)来定义卷积层。它通过图像向量,在给定的时间对内核内的9个元素进行卷积。然后这个层根据卷积结果修改图像向量中的输入值。

看看这个giphy,看看卷积层是如何作用于图像的:https://giphy.com/gifs/blog-daniel-keypoints-i4NjAwytgIRDW

池化层

池化层是用来通过去除输入的冗余数据来减少输入的大小。它通过使输入图像中的特定特征难以映射到一个准确的位置来增加模型的灵活性。

池化将图像分为一组不重叠的区域,并通过一个简单的操作将它们的值汇集成一个值,如找到值的最大、最小或平均。最大池化是最常用的池化技术类型。

扁平化

扁平化层简单地将一个多维向量扁平化为一个长的单维向量。如果你把一个13x13的向量传给扁平化层,它就会输出一个大小为169的长向量。

全连接层

全连接层结合了前一层中不同节点所识别的各个特征,以描绘出关于输入的更大画面。因此,全连接中的每个节点都应该与前一层的每个节点相连。


什么是Keras?

在本教程中,我们将使用Keras建立一个深度学习模型。Keras是一个用Python编写的深度学习库。Keras抽象了深度学习算法背后的复杂逻辑,即使是初学者也能简化构建新模型。Keras允许在实施过程中使用几个后端,包括Tensorflow和Theano。

安装和设置Keras

在安装Keras之前,你应该在系统中安装Python(版本3.6-3.8)和pip。然后,只需运行以下命令就可以开始安装。

pip install keras

Keras与Tensorflow 2发行版捆绑在一起,你可以将其导入为tensorflow.keras。在这个实现中,默认使用的后端是Tensorflow。

pip install tensorflow

为了设置该项目,我们只需从Keras中导入Numpy和相关模块。

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Convolution2D, MaxPooling2D
from tensorflow.keras.utils import to_categorical

加载数据集

在本教程中,我们使用的是MNIST手写数字数据集。它包含28x28的0-9的手写数字的灰度图像。它的测试数据集包含60000张图像,而测试集包含10000张图像。

我们建立的CNN旨在将图像作为输入,并从10个可能的输出中预测其显示的数字。

由于MNIST数据集与Keras分布捆绑在一起,我们可以直接加载它而不需要任何额外的努力。

from tensorflow.keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()

load_data函数加载训练和测试数据集。每个数据集都包含一组图像(X_train,X_test)和一组它们显示的数字的标签(y_train,y_test)。

如果我们检查图像数据的形状。

print(X_train.shape)  #(60000, 28, 28)
print(X_test.shape) #(10000, 28, 28)

这个输出证实了我们有60000张训练图像和10000张大小为28x28的测试图像。

我们还可以绘制一个图像,以更好地了解数据集的情况:

from matplotlib import pyplot as plt
plt.imshow(X_train[1])

预处理图像数据

在将图像用于训练和测试我们的深度学习模型之前,我们需要对图像进行标准化和重塑。

将图像像素值归一化为0和1之间,使模型的训练更加容易和快速。为了在不损失数据的情况下进行归一化,首先,我们应该将其类型转换为32位浮点。

X_train = X_train.astype("float32") / 255
X_test = X_test.astype("float32") / 255

我们用Keras构建的神经网络将需要3D图像作为输入。由于这些MNIST图像是灰度的,我们必须使用expand_dims方法专门添加一个深度为1的第三维。

X_train = np.expand_dims(X_train, axis=3)
X_test = np.expand_dims(X_test, axis=3)

如果我们检查一下这个重塑步骤之后的图像数据集的新形状。

print(X_train.shape) #(60000, 28, 28, 1)
print(X_test.shape) #(10000, 28, 28, 1)

我们可以看到图像现在有了一个新的第三维。


预处理图像标签

如果我们检查图像标签变量的形状。

print(y_train.shape) #(60000,)
print(y_test.shape) #(10000,)

你可以看到测试和训练标签数据都被存储为一维数组。

如果我们检查存储在其中一个数组中的数值,以获得一个更好的想法。

print(y_train[1]) #0

你可以看到,这些标签数组已经直接存储了图像中的数字。但是我们的神经网络必须在输出层使用10个节点来识别每个数字。因此,我们必须对这些标签数据进行编码,用十个类来表示每个数字。例如,5应该被编码为[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]

Keras提供了一个实用的方法来轻松地执行这项任务。

y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

现在,图像标签数据集的形状是。

print(y_train.shape) #(60000, 10)
print(y_test.shape) #(10000, 10)

是时候创建深度学习模型了

我们要建立的模型将由7层组成,包括输入和输出层。在现实中,决定添加到网络中的层的数量和类型取决于大量的实验、经验和良好的数学剂量。

在本教程中,我们不打算深入研究这些理论或花时间进行实验。相反,我们将采用一个在构建CNN时常用的架构。

然而,你可以完全自由地调整这个架构,并尝试不同的层,以了解它们对最后的结果有何影响。

在用Keras构建模型时,我们必须使用序列类或模型类作为其基本基础。我们要使用的序列类允许建立一个线性的层叠。让我们开始创建这个类的一个实例。

model = Sequential()

我们添加到模型中的第一个层将作为输入层。而我们添加的输入层也是一个二维卷积层。

model.add(Convolution2D(32, kernel_size=(3,3), activation="relu", input_shape=(28, 28, 1)))

在这里,我们正在创建一个卷积层,它使用32个3x3核来从输入中提取特征。它使用ReLU作为激活函数。

我们的神经网络的下一层是一个池子大小为2x2的池子层。

model.add(MaxPooling2D(pool_size=(2, 2)))

然后,我们在模型中加入另一个卷积层和一个池化层。额外的卷积层可以训练我们的模型来识别图像中的高级特征,而额外的池化层则提高了模型的灵活性。

model.add(Convolution2D(64, kernel_size=(3,3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))

下一步是使用扁平化层对输入向量进行扁平化。

model.add(Flatten())

我们需要给我们的模型添加一个剔除层,以防止它对训练集过度拟合。剔除层故意忽略或 "剔除 "以前节点的输出,以逃避过度拟合。我们的剔除层接受的剔除率为0.5。

model.add(Dropout(0.5))

最后,我们在神经网络中加入一个全连接层作为输出层。它使用softmax激活函数来确定输出值。

model.add(Dense(10, activation='softmax'))

就这样了。我们的模型架构现在已经完成。下面,你可以在一个地方看到该模型的完整架构。

model = Sequential()

model.add(Convolution2D(32, kernel_size=(3,3), activation="relu", input_shape=(28, 28, 1)))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Convolution2D(64, kernel_size=(3,3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dropout(0.5))

model.add(Dense(10, activation='softmax'))

我们可以使用以下函数查看模型的摘要。

model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_7 (Conv2D)            (None, 26, 26, 32)        320
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 13, 13, 32)        0
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 11, 11, 64)        18496
_________________________________________________________________
max_pooling2d_7 (MaxPooling2 (None, 5, 5, 64)          0
_________________________________________________________________
flatten_4 (Flatten)          (None, 1600)              0
_________________________________________________________________
dropout_4 (Dropout)          (None, 1600)              0
_________________________________________________________________
dense_5 (Dense)              (None, 10)                16010
=================================================================
Total params: 34,826
Trainable params: 34,826
Non-trainable params: 0

编译和训练模型

在训练模型之前,我们应该通过传递一个优化函数(adam、SGD等)、损失函数和评价指标来编译模型。

model.compile('adam', loss='categorical_crossentropy', metrics=['accuracy'])

现在,我们可以使用Keras的拟合方法来训练这个模型。它将在10个epochs中进行训练,批次大小为128。我们还使用10%的训练数据来验证该模型。

model.fit(X_train, y_train, batch_size=128, epochs=10, validation_split=0.1)
Epoch 1/10
422/422 [==============================] - 21s 49ms/step - loss: 0.3711 - accuracy: 0.8857 - val_loss: 0.0863 - val_accuracy: 0.9770
Epoch 2/10
422/422 [==============================] - 22s 53ms/step - loss: 0.1151 - accuracy: 0.9651 - val_loss: 0.0564 - val_accuracy: 0.9840
Epoch 3/10
422/422 [==============================] - 24s 57ms/step - loss: 0.0852 - accuracy: 0.9740 - val_loss: 0.0487 - val_accuracy: 0.9873
Epoch 4/10
422/422 [==============================] - 23s 53ms/step - loss: 0.0735 - accuracy: 0.9779 - val_loss: 0.0428 - val_accuracy: 0.9893
Epoch 5/10
422/422 [==============================] - 23s 54ms/step - loss: 0.0642 - accuracy: 0.9799 - val_loss: 0.0418 - val_accuracy: 0.9885
Epoch 6/10
422/422 [==============================] - 23s 54ms/step - loss: 0.0577 - accuracy: 0.9823 - val_loss: 0.0374 - val_accuracy: 0.9898
Epoch 7/10
422/422 [==============================] - 26s 61ms/step - loss: 0.0538 - accuracy: 0.9831 - val_loss: 0.0354 - val_accuracy: 0.9907
Epoch 8/10
422/422 [==============================] - 23s 54ms/step - loss: 0.0485 - accuracy: 0.9852 - val_loss: 0.0375 - val_accuracy: 0.9897
Epoch 9/10
422/422 [==============================] - 22s 53ms/step - loss: 0.0468 - accuracy: 0.9852 - val_loss: 0.0344 - val_accuracy: 0.9908
Epoch 10/10
422/422 [==============================] - 25s 60ms/step - loss: 0.0434 - accuracy: 0.9865 - val_loss: 0.0304 - val_accuracy: 0.9912

这真是令人难以置信的简单。现在我们有一个训练好的深度学习模型,它在验证数据上显示出超过99%的准确率,可以识别手写数字的图像。


评估该模型

为了确认我们模型的准确性,我们可以使用我们的测试数据集来评估它。

score = model.evaluate(X_test, y_test, verbose=0)

现在,如果我们打印评估结果:

print("accuracy", score[1]) #accuracy 0.9894999861717224
print("loss", score[0]) #loss 0.028314810246229172

我们的模型在测试数据集上取得了接近99%的准确性。这难道不令人惊讶吗?


使用训练后的模型进行预测

最后,我们可以使用这个新训练的深度学习模型来进行预测。让我们获得该模型对测试数据集中前20张图片的预测,并对照原始图片标签查看结果。

predictions = model.predict(X_test[:20])
print("predictions:", np.argmax(predictions, axis=1))
print("labels     :", np.argmax(y_test[:20], axis=1))
predictions: [7 2 1 0 4 1 4 9 5 9 0 6 9 0 1 5 9 7 3 4]
labels     : [7 2 1 0 4 1 4 9 5 9 0 6 9 0 1 5 9 7 3 4]

我们的模型已经得到了所有的正确结果!


总结

今天,我们向你介绍了一个近年来在开发者社区相当流行的编程领域。尽管这是一个具有大量数学理论的艰难领域,但Keras使神经网络的工作变得非常容易,即使是完全的初学者。所以我希望这篇文章能让你兴奋起来,继续尝试深度学习,建立有趣而有用的人工智能模型。

谢谢您的阅读!