使用 Python 和 Keras 实现卷积神经网络

你有没有想过 Snapchat 如何检测人脸?自动驾驶汽车如何知道道路在哪里?你是对的,他们正在使用一种用于计算机视觉的特殊神经网络——卷积神经网络。在上一篇文章中,我们有机会研究它们是如何工作的。我们涵盖了这些网络的各个层及其功能。基本上,卷积神经网络的附加层以标准神经网络可以使用的格式预处理图像。这样做的第一步是检测输入图像上的某些特征或属性。这是由卷积层完成的。

该层使用过滤器来检测低级特征,如边缘和曲线,以及更高级别的特征,如脸或手。卷积神经网络使用额外的层来从图像中去除线性,这可能会导致过度拟合。去除线性后,将使用用于压缩图像和展平数据的附加层。最后,这些信息被传递到一个神经网络中,在卷积神经网络的世界中称为全连接层。本文的目标是向您展示如何实现所有这些概念,以及有关这些层的更多详细信息。

在我们进入我们正在解决的问题和代码本身之前,请确保设置您的环境。与本系列之前的所有文章一样,我将使用 Python 3.6。另外,我使用的是 Anaconda 和 Spyder,但您可以使用您喜欢的任何 IDE。但是,重要的是要安装 Tensorflow 和 Keras。

MNIST 数据集

因此,在本文中,我们将教我们的网络如何识别图像中的数字。为此,我们将使用另一个著名的数据集——MNIST 数据集。该数据集扩展了其前身NIST,具有 60,000 个样本的训练集和 10,000 个手写数字图像的测试集。所有数字都经过尺寸标准化和居中。图像的大小也是固定的,因此预处理图像数据被最小化。这就是为什么这个数据集如此受欢迎的原因。它被认为是Hello World卷积神经网络世界中的“”示例。

MNIST 数据集样本

此外,使用卷积神经网络,我们可以获得几乎人类的结果。目前,该记录由并行计算中心(乌克兰赫梅利尼茨基)保持。他们使用了一个只有 5 个卷积神经网络的集合,得到了 0.21% 的错误率。很酷,不是吗?

导入库和数据

与本系列之前的文章一样,我们将首先导入所有必要的库。其中一些是熟悉的,但其中一些我们将进一步解释。

import numpy as np 
from matplotlib import pyplot as plt
from keras.utils.np_utils import to_categorical 
from keras.models import Sequential 
from keras.layers.core import Dense, Dropout, Flatten 
from keras.layers import Conv2D, MaxPooling2D

如您所见,我们将使用numpy我们在前面的示例中已经用于多维数组和矩阵操作的库。此外,您可以看到我们正在使用Keras本文中已经使用的库中的一些功能,但也有一些新功能。用于创建模型层和标准层,即全连接层SequentialDense

此外,我们可以看到我们使用的一些新类KerasConv2D是我们将用来创建卷积层的类。MaxPooling2D是用于池化层的类,Flatten类用于扁平化级别。我们也使用to_categoricalfrom Keras utils。此类用于将向量(整数)转换为二进制类矩阵,即用于one-hot 编码。最后,请注意我们将matplotlib用于显示结果。

在我们导入所有必要的库和类之后,我们需要处理数据。幸运的是,Keras 提供了 MNIST 数据集,所以我们不需要下载它。如前所述,所有这些图像已经部分预处理。这意味着它们具有相同的大小,并且显示在它们上的数字位置正确。所以,让我们导入这个dataset并为我们的模型准备数据:

from keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()

rows, cols = X_train[0].shape[0], X_train[0].shape[1] 
X_train = X_train.reshape(X_train.shape[0], rows, cols, 1) 
X_test = X_test.reshape(X_test.shape[0], rows, cols, 1) 

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

num_of_classes = len(set(y_train)) 
y_train = to_categorical(y_train, num_of_classes) 
y_test = to_categorical(y_test, num_of_classes) 

如您所见,我们datasetKeras datasets. 然后我们将数据加载到训练和测试矩阵中。之后,我们使用shape属性获取图像的尺寸,并对输入数据进行重新整形,使其代表一个通道的输入图像。基本上,我们只使用该图像的一个通道,而不是常规的三个 (RGB)。这样做是为了简化此实现。然后我们对输入矩阵中的数据进行归一化。最后,我们使用 对输出矩阵进行编码to_categorical

模型创建

现在,当数据准备好后,我们可以进行有趣的事情——模型的创建:

model = Sequential() 

model.add(Conv2D(32, kernel_size=(3, 3), activation='rectifier', input_shape=(rows, cols, 1)))
model.add(Conv2D(64, kernel_size=(3, 3), activation='rectifier')) 
model.add(Conv2D(128, kernel_size=(3, 3), activation='rectifier')) 

model.add(Dropout(0.5)) 

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

model.add(Flatten())

model.add(Dense(128, activation='relu')) 
model.add(Dropout(0.5)) 
model.add(Dense(num_of_classes, activation='softmax'))

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

当然,我们使用Sequential了这个,并从使用Conv2D类添加卷积层开始。如您所见,这个类使用的参数很少,所以让我们来探索一下。第一个参数是定义将使用的过滤器数量,即,将检测到的特征数量。从 32 开始,然后从那一刻开始进入更大数量的特征是一个常见的过程。这正是我们正在做的,在第一个卷积层中,我们检测到 32 个特征,在第二个中检测到 64 个特征,在第三个也是最后一个 128 个特征中检测。将使用的过滤器的大小使用下一个参数 – 定义kernel_size我们选择了 3 x 3 个过滤器。

对于激活函数,我们使用rectifier函数。这样,我们会自动为每个卷积层添加非线性级别。实现这一点的另一种方法,更高级一点,是使用LeakyReLUform keras.layers.advanced_activations。这不像标准的整流器函数,而是将所有低于某个值的值压缩到0,它有一个轻微的负斜率。如果您决定使用它,请注意您必须在Conv2D这是一个示例:

from keras.layers.advanced_activations import LeakyReLU

model.add(Conv2D(32, kernel_size=(3, 3), activation='linear',input_shape=(rows, cols, 1)))
model.add(LeakyReLU(alpha=0.1))

我们跑题了。让我们回到Conv2D它的参数。另一个非常重要的参数是input_shape。使用此参数,我们定义输入图像的尺寸。如前所述,我们只使用一个通道,这就是为什么我们的最终维度input_shape1。我们从输入图像中获取的其他维度。

此外,我们还在模型中添加了其他层。Dropout 层帮助我们进行过拟合,之后我们通过使用MaxPooling2D类添加了池化层。该层显然使用了该max-pool算法,池化过滤器的大小为 2 x 2。池化层之后是 Flattening 层,然后是全连接层。对于最终的全连接层,我们添加了具有两层的神经网络,为此我们使用了Dense类。最后,我们编译了我们的模型,并使用了 Adam 优化器。

训练

很好,我们的数据经过预处理并创建了模型。让我们将它们合并在一起,并训练我们的模型。为此,我们正在使用已经很熟悉的函数拟合。我们传递输入矩阵并定义batch_size和数量的时期。我们正在做的另一件事是定义validation_split. 此参数用于定义测试数据的哪一部分将用作验证数据。

基本上,模型会留出一部分训练数据,但它会在每个 epoch 结束时使用它来评估损失和其他模型指标。这与测试数据不同,因为我们在每个 epoch 之后都使用它。

model.fit(X_train, y_train, batch_size=128, epochs=20, verbose=1, validation_split=0.2) 

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

print('Accuracy:', score[1])

之后,我们的模型就被训练并准备好了。我们正在使用evaluate方法并通过测试集。在这里,我们将获得卷积神经网络的准确性。

预测

我们可以做的另一件事是在测试中收集对我们网络的预测dataset。这样,我们可以将预测结果与实际结果进行比较。为此,我们将使用predict方法。使用这种方法,我们还可以对单个输入进行预测。

predictions = model.predict(X_test)

结果

让我们使用我们刚刚收集的这些预测来对我们的实现进行最后的润色。我们将显示预测数字和实际数字。我们将显示我们做出预测的图像。基本上,我们将为我们的实现做出很好的视觉表示,毕竟我们在这里处理图像。

plt.figure(figsize=(15, 15)) 
for i in range(10):    
    ax = plt.subplot(2, 10, i + 1)    
    plt.imshow(X_test[i, :, :, 0], cmap='gray')    
    plt.title("Digit: {}\nPredicted:    {}".format(np.argmax(y_test[i]), np.argmax(predictions[i])))    
    plt.axis('off') 
plt.show()

在这里,我们曾经pyplot展示了十张带有实际结果和我们预测的图像。这就是我们运行实现时的样子:

我们已经运行了 20 个 epoch 并获得了准确率 – 99.39%。一点也不差。当然,总是有改进的余地。

结论

卷积神经网络是一个非常有趣的子领域,也是计算机视觉领域最具影响力的创新之一。在这里,您可以看到如何实现这些网络的一个简单版本,以及如何使用它来检测 MNIST 数据集上的数字。

发表评论

邮箱地址不会被公开。 必填项已用*标注