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





5.00/5 (7投票s)
使用 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` 库中的一些功能,这些功能我们已经在本文章中使用过,但也有几个新的。`Sequential` 和 `Dense` 用于创建模型和标准层,即全连接层。
此外,我们可以看到我们从 `Keras` 中使用的一些新类。`Conv2D` 是我们将用于创建卷积层的类。`MaxPooling2D` 是用于池化层的类,`Flatten` 类用于展平层。我们还使用 `Keras utils` 中的 `to_categorical`。此类的作用是将向量(整数)转换为二进制类矩阵,即它用于 独热编码。最后,请注意我们将使用 `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)
如您所见,我们从 `Keras datasets` 导入了 MNIST `dataset`。然后我们将数据加载到训练和测试矩阵中。之后,我们使用 `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` 定义,我们选择了 3x3 的过滤器。
对于激活函数,我们使用 `整流器` 函数。这样,我们自动为每个卷积层添加了非线性级别。另一种实现此目的的方法(更高级一些)是使用 `keras.layers.advanced_activations` 中的 `LeakyReLU`。这不像标准整流器函数,但它不是将所有低于某个值的值压缩到 `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_shape` 的最终维度是 `1`。其他维度我们是从输入图像中获取的。
此外,我们还在模型中添加了其他层。Dropout 层帮助我们避免过拟合,之后我们使用 `MaxPooling2D` 类添加了池化层。该层显然使用 `max-pool` 算法,池化过滤器的大小为 2x2。池化层之后是展平层,再之后是全连接层。对于最终的全连接层,我们添加了一个包含两层的神经网络,为此我们使用了 `Dense` 类。最后,我们编译了模型,并使用了 Adam 优化器。
培训
非常好,我们的数据已经预处理,模型也已创建。让我们将它们合并在一起,并训练我们的模型。为此,我们使用已熟悉的 `fit` 函数。我们传递输入矩阵并定义 `batch_size` 和 epoch 数量。我们做的另一件事是定义 `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` 显示了十张带有实际结果和我们预测的图像。这就是我们运行实现时的样子
我们运行了二十个 epoch,获得了 99.39% 的准确率。一点也不差。当然,总有改进的空间。
结论
卷积神经网络是一个非常有趣的子领域,也是计算机视觉领域最具影响力的创新之一。在这里,您可以看到如何实现这些网络的一个简单版本,以及如何使用它来检测 MNIST 数据集上的数字。
感谢阅读!