深度学习图解,第三部分:卷积神经网络

原文:towardsdatascience.com/deep-learning-illustrated-part-3-convolutional-neural-networks-96b900b0b9e0

欢迎来到深度学习图解系列的第三部分。如果你错过了之前的文章,请务必回去阅读。它们为我们即将深入探讨的内容奠定了基础。

深度学习图解

为了快速回顾,我们之前通过构建一个简单的模型来预测冰淇淋店的日收入来讨论了神经网络的内部工作原理。我们发现,通过利用多个神经元的组合力量,神经网络可以处理复杂问题。这使得它们能够发现数据中的模式,这些模式可能难以识别。我们还了解到,神经网络主要解决两种类型的问题:回归或分类。

正如我们构建了收入预测模型一样,我们可以通过修改结构来创建解决各种问题的模型。卷积神经网络(CNN)是为图像识别任务而设计的专用模型。然而,它们与我们迄今为止遇到的模型(以及一些额外的步骤)遵循相同的根本原则。今天,我们将探索 CNN 的内部工作原理,并了解幕后究竟发生了什么。

对于我们首个 CNN,让我们构建一个“是 X 还是非 X”模型。这个模型应该确定一个图像是否代表 X。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/45a6bb08d18704a5847cdbd5248a6313.png

创新性的,我知道。对于硅谷的观察者来说,这个模型非常受我的朋友杨健的杰出热狗还是非热狗应用程序的启发。

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FACmydtFDTGs%3Ffeature%3Doembed&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DACmydtFDTGs&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FACmydtFDTGs%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube

在我们的收入模型中,我们使用了两个输入——温度和星期几——来预测收入。这些很容易输入,因为它们是数值。但我们是怎样将图像输入到神经网络而不是数值呢?

答案相当简单。当我们放大图像时,我们看到它基本上只是一堆像素:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/561914257b2c20b0a1dea673a9fd35b7.png

由于我们的“X”是一个简单的黑白图像,让我们将每个像素指定为 1(代表黑色像素)或 0(代表白色像素)。这些像素存储为 0 和 1 的矩阵

我们可以将这个 5×5 的矩阵转换成一列:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9597d4f64c530f9c4f872c0e82ea679d.png

这一列 25 个(5×5)的 1 和 0 现在可以成为我们输入到神经网络中的数据:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3d818d1efe6411c08aea00707d18f38f.png

从上一篇文章中,我们也知道一个训练好的神经网络带有权重和偏差项。假设这是一个训练好的神经网络,那么在这里,我们将有 25 个输入到这个神经元中,每个输入都有自己的权重,再加上一个偏差项。如果我们想要创建一个更复杂的神经网络(如图像通常需要),我们需要添加更多的神经元和/或层。然而,这种增加将指数级增加需要优化的权重和偏差项的数量,需要大量的计算能力。

尽管如此,对于非常非常小的图像,如我们的 5×5 像素图像,这仍然可能是可行的。然而,一个 256×256 像素的图像将产生 65536(256×256)个输入权重加上 1 个偏差项……对于一个只有 1 个神经元的神经网络!更复杂的图像需要更多的神经元和层(!!!)。因此,这种方法提供图像像素值可能无法有效扩展。

另一个担忧是图像可能不会总是看起来像预期的那样。例如,我们可能有这个理想居中的、漂亮的“X”:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/96d9dd44c717491eae4126869e61585c.png

或者像这样的不规则的:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/06f044236f447b1d018ae544a9711b71.png

或者像这样的偏离中心的:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/dd1232560621816e84d40d678093666f.png

所有图像都是“X”,但每个“X”看起来略有不同。如果我们使用完美居中的“X”来训练我们的神经网络,它可能不会很好地处理其他“X”图像。这是因为网络只识别完美居中的“X”。它不能识别偏离中心或扭曲的“X”。它只知道一个模式。这在实际应用中并不实用,因为图像很少那么简单直接。因此,我们需要调整我们的神经网络以处理“X”不是完美居中的情况。

在构建这个神经网络时,我们需要更加有创意,可能通过理解所有图像中的潜在模式,而不仅仅是某一种图像的模式。

如果你这么想——我们的思维以类似的方式识别图像,专注于图像的特征并将它们拼接在一起。鉴于我们遇到的大量信息,我们的大脑在识别特征和丢弃不必要的信息方面表现出色。

因此,我们需要解决两个问题:减少我们输入到神经网络的数据,以及找到一种在图像中检测模式的方法。

过滤器

让我们先在所有的‘X’图像中找到一些一致的图案。例如,一个可能的图案可以是:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/49e3424fcaae81bdfe9a28236938446c.png

所有 3 个‘X’图像中的相同模式

然后我们可以通过确认这个模式存在于图像中来确定图像是‘X’。

这个模式在这里被称为过滤器。过滤器捕捉了‘X’的关键特征。因此,即使图像被旋转、缩小或扭曲,我们也能保持图像的本质。

这些过滤器通常是小的正方形矩阵,最常见的是 3×3 像素,尽管大小可以变化。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5d1c32f4c38ae0dd4aab48275d885531.png

应用一个过滤器到图像以进行模式检测,我们将 3×3 的过滤器滑过每个部分,并计算过滤器和它覆盖的部分的点积。所以对于第一个部分我们…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1e7bfa00898b167592dbd4356bea4faa.png

…然后乘以过滤器和矩阵中每个重叠像素值…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3626cba58b10da5c5533c9378069d849.png

…然后加起来这些乘积:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/acbeae7757b9dadb7ade6049c50ecf55.png

通过计算图像和过滤器的点积,我们可以说过滤器与图像进行了卷积,这就是卷积神经网络得名的原因。

我们现在通过滑动这个过滤器,根据称为步长的某个东西来对所有部分做同样的事情。步长决定了我们想要移动过滤器跨越多少个细胞。所以如果我们的步长=1,我们就这样移动到下一个部分…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9b8cb7d0cb30a51a238cc1059136c20c.png

…如果步长=2,我们就这样移动它:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/11252bb8db6eef429c0efa2c87530ecc.png

通常步长设置为 2,但在我们的情况下,让我们将其设置为 1。

当步长=1 时,如果我们把所有的点积存储在一个矩阵中,我们得到:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b0792364fbc170b9363a347006a0c204.png

然后我们向这个输出矩阵添加一个偏置项

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/186d7d254b19136ae96fc42519150516.png

…这导致了一个称为特征图的东西。

重要的是要注意,我们的步长越大,我们的特征图就会越小。在我们的例子中,我们使用了步长=1,结果得到一个相对较大的特征图。

当处理实际图像时,我们可能需要增加我们的步长。毕竟,在我们的例子中,我们处理的是一个 5×5 的输入图像,但现实世界的图像通常要大得多,也更复杂。

通常,这个特征图中每个值都会通过 ReLU 激活函数。作为一个快速提醒,从第一篇文章,以下是 ReLU 的公式:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/02e7573332d53ede903dd3b7cfa77792.png

如果输入大于 0,函数输出其值,如果输入小于或等于 0,则输出 0。因此,通过将特征图通过 ReLU 函数传递,我们获得以下更新的特征图:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3e4cc39174b61ecf3d721f9f9c10b476.png

在这种情况下,所有单元格都设置为 0,除了中间的一个单元格。

我知道这有很多步骤,但为了总结卷积过程,我们从一个 X 的输入图像开始…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6538509a00969b4ae40497811f03cbe6.png

…然后对它应用一个滤波器,也称为将滤波器与图像卷积…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/ff82aff5b303f46733cc1caeb484efdb.png

…随后,在卷积矩阵中添加了一个偏置项以创建特征图…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5a633f89c02fd3e127f1d675dbdf5190.png

…最后,我们通常将这个特征图通过 ReLU 函数传递以获得更新的特征图:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7143510e267a28f7b075381dd4069319.png

卷积步骤的主要目的是减少输入大小(从整个图像到特征图)以简化处理。一个可能出现的问题是,由于结果特征图矩阵中的值减少,我们是否丢失了大量的信息。确实,我们拥有的值更少,但滤波器被设计来检测图像的某些整体部分或特征,并消除所有不必要的信息。而且,就像我们之前讨论的那样,这类似于人眼识别物体,通常忽略无关的细节。我们不检查每个单独的像素,而是观察独特的特征。重点是保留这些基本特征。

与之前提到的滤波器类似,我们可以使用额外的滤波器来检测其他特征。例如,我们可以使用这个滤波器…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6278bbd8a7d521a98c4aaf04b32bc45c.png

…可以检测以下模式:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/71597055d4508b27fdd0064679eb6aec.png

因此,如果我们使用与上述相同的过程应用多个滤波器,我们将从相同的输入图像中获得一组特征图。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5cee2fd2467e91e3d24d2ed28b6c9753.png

输入图像 -> 特征图

一个关键问题是,我们如何确定检测特征所需的滤波器?这将在训练过程中确定,我们将在稍后讨论。

池化

现在我们已经准备好了特征图,我们可以进行下一步——池化。这一步相当简单。我们只需扫描之前创建的特征图,选择小的 2×2 部分,并从每个部分中选择最大值。这是我们的第一步:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fbe5ad19322369864ada22e8fe034e57.png

最大池化 – 步骤 1

我们取的这些 2×2 部分不重叠,所以我们的下一步将看起来像这样:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/75da370775202c3e7192ef2cfaafb411.png

最大池化 – 步骤 2

在这一步,你会看到我们并没有一个完整的 2×2 部分,但这没关系,因为这些部分不需要是完美的 2×2。然后我们进入下一步:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/03e52e82fc83626081cdff693ef3c9e4.png

最大池化 – 第 3 步

最后:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d43755df3d93aaebca1adda86d0a5e79.png

最大池化 – 第 4 步

我们称这种方法为最大池化,因为它从每个部分取最大值。或者,我们也可以使用平均池化,它计算每个区域的平均值。结果看起来会是这样:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/410b081ec3054e5758ed7d7031e34c28.png

平均池化的 2×2 矩阵

注意:求和池化是另一种选择,正如其名所示,它会对每个区域的值进行求和。然而,最大池化是最常用的方法。

最大池化主要用于进一步减少图像中的噪声。其有效性在较大图像中更为明显,因为它确定了滤波器与输入图像最佳匹配的区域。就像在卷积步骤中一样,创建池化特征图会丢弃多余的信息。在这个过程中,特征图中的大约 75%的原始信息被丢失,因为我们只保留了每四像素一组中的最大值,其余的都被丢弃。这些是不必要的细节,当它们被移除时,使得网络能够更有效地工作。池化步骤的关键点——提取最大值,是为了补偿扭曲。

呼,这真是一段漫长的旅程,但我们还没有到达真正的神经网络部分!但别担心,如果你已经阅读了前面的文章,接下来的内容将会非常直接。我们迄今为止所做的一切都是为了使用真正的神经网络。我们将使用池化步骤的结果作为神经网络的输入。

展平

将这些值输入神经网络的第一步涉及将特征图矩阵展平。我们不能直接输入特征图,因此需要将其展平。例如,如果我们有四个过滤器,它们将产生四个特征图。这些特征图反过来会产生从最大池化步骤得到的四个 2×2 矩阵。展平后的样子如下:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a944e4dff520f03d279eb1174b1244da.png

最大池化 -> 展平

神经网络(终于)

我们之前讨论的所有特征都存储在这个展平的输出中,这使得我们可以将展平的输出用作神经网络的输入。

这些特征已经为图像分类提供了良好的准确度。但我们希望提高模型复杂度和精度。人工神经网络的职责就是利用这些数据以及这些特征来改善图像分类,这也是我们创建卷积神经网络的主要原因。

因此,我们将这些输入插入到一个全连接的神经网络中。

注意:这被称为全连接神经网络,因为在这里我们确保每个输入和每个神经元都连接到另一个神经元。

让我们将我们的神经网络架构设置为:1 个隐藏层,3 个神经元和 1 个输出神经元:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/ff7f4c36b4a6d50c288abdc35a3b5c5e.png

现在,我们需要选择我们的激活函数。在之前的文章中,我们为我们的神经网络中的所有神经元使用了 ReLU 激活函数来预测冰淇淋销售。ReLU 激活函数对于内部层来说仍然是一个不错的选择。然而,对于外部神经元来说,由于我们试图解决的问题的性质不同,它并不合适。

之前,我们试图回答:给定星期几和温度,冰淇淋店的收入会是多少? 现在,我们的问题是:给定一个图像,它是字母 X 吗? 我们所寻求的问题的性质和答案有显著的不同,这意味着我们需要调整外部神经元的处理。

第一个场景是一个回归问题,而当前的一个是分类问题。我们可以通过计算概率来处理我们当前的问题。例如,给定一个输入图像,我们可以确定图像代表‘X’的可能性有多大。在这里,我们希望神经网络输出 0 到 1 范围内的值,其中 1 表示高度可能是‘X’,而 0 表示可能不是‘X’。

为了实现这种类型的输出,从我们的激活函数讨论中,sigmoid 函数是一个不错的选择。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/10160f77ffb56e7917b29e549953f1a3.png

该函数将输入挤压成一个 S 形曲线,输出 0 到 1 之间的值。这对于预测概率非常完美。鉴于这一点,以下是神经网络的外观:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9d5345b70e972c07bdbedc8892cdaa06.png

假设这个神经网络已经训练好。那么我们知道,在训练好的神经网络中,每个输入都有关联的权重和偏置项。这个网络随后输出 0 到 1 之间的值。

因此,如果我们把我们的展平示例输入到这个训练好的神经网络中,输出是 0.98,这表明有 98%的概率图像是‘X’。

再次总结一下,让我们直观地看看我们到目前为止所做的工作。我们从一个输入图像开始:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/ecdb706ccc4937af688dd4919792f824.png

然后通过应用过滤器对这个图像进行卷积…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e47a3e8ae659d5fdb39f3e35c75d410d.png

将偏置项添加到输出中,并通过 ReLU 函数传递以获取特征图:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/93d23d4f0cb80b22a6105ce253409c05.png

接下来,我们对特征图执行最大池化操作:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7e0854ba73360449a1b811a6fa103a3b.png

然后,我们取这些输出,将它们展平,并通过我们的神经网络传递…

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9e6033944bf4d43e482e906f29a6d20f.png

…以得到 0.98 的预测!

好的,这很好。但现在我们需要一种方法来检查这个 0.98 预测有多好。在这种情况下,我们知道原始图像是一个‘X’,所以我们可以说——“卷积神经网络在这里做得很好!”,但我们需要一些在数学上表达相同意思的东西。

上一篇文章中,我们使用了均方误差(MSE)代价函数来评估我们预测的准确性,并将其用于我们的训练过程。同样,我们在这里也需要使用一个代价函数。但正如我们之前讨论的,由于预测的类型不同,我们不能使用 MSE。

在这个例子中,我们将使用一种称为对数损失的函数,如果你阅读了关于逻辑回归的文章,这会听起来很熟悉。在逻辑回归中,我们试图检查类似输出的准确性。尽管卷积神经网络比逻辑回归模型复杂得多,但我们试图回答相同类型的问题。

对数损失代价函数看起来是这样的:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/847bd9aa49d00c7cf30d6947a7677f50.png

在这里,如果图像是‘X’,则 y = 1,如果不是,则 y = 0,p_hat 是预测概率。而 sigma 只是对所有想要评估的图像预测值求和。所以对于这个例子,y = 1(因为我们知道图像是‘X’),预测概率 p_hat = 0.98,n = 1,因为我们只是试图评估一个图像的输出:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3f6f2e95ad1a5e4afebd0aeefe603618.png

在这里,我们看到代价函数非常接近 0,这是好的。***代价函数越低,越好。**所以从数学的角度来说,这就是我们之前所说的——“卷积神经网络在这里做得很好!”

训练

注意:本文不会详细介绍训练过程,因为我们已经在上一篇文章中进行了广泛的介绍。所以请确保在阅读这一部分之前先阅读那篇文章!

记住,从上一篇文章中我们知道,神经网络通过**使用梯度下降的训练过程**来学习最优权重和偏差。这涉及到将训练集通过网络,进行预测,并计算代价。我们一直这样做,直到得到最优值。当我们训练卷积神经网络时,发生同样的过程,但有两次变化。

首先,我们不是使用均方误差(MSE)成本函数,而是使用对数损失(Log Loss)。其次,除了找到最佳权重和偏差外,我们还在卷积步骤中寻找最佳的滤波器和偏差项。滤波器只是 3×3 的数字矩阵。因此,目标是找到所有这些元素的最佳值——滤波器、卷积步骤中的偏差项,以及神经网络中的权重和偏差项。

如果您想深入了解训练过程背后的数学原理,这个视频做得非常出色。


就这些了!这是一篇相当丰富的文章,所以可能需要阅读它和前两篇文章几次,并自己处理一些逻辑,以便让概念同步。

查看这篇文章,它通过在 TensorFlow 中从头开始构建 CNN,使这个 X 或非 X 分类器变得生动起来!

在 TensorFlow 中实现卷积神经网络


第四部分关于循环神经网络的内容现已上线!

深度学习图解,第四部分:循环神经网络

注意:除非另有说明,所有图像均由作者绘制。

如往常一样,如果您有任何问题或评论,请随时通过LinkedIn与我联系!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值