欢迎来到雲闪世界。简单回顾一下,我们之前通过构建一个简单的模型来预测冰淇淋店的日收入,讨论了神经网络的内部工作原理。我们发现神经网络可以通过利用多个神经元的综合能力来处理复杂问题。这使它们能够发现数据中原本难以识别的模式。我们还了解到,神经网络主要解决两类问题:回归或分类。
就像我们构建收入预测模型一样,我们可以通过修改结构来创建解决各种问题的模型。卷积神经网络 (CNN) 是专为图像识别任务而设计的专用模型。但是,它们依赖于与我们迄今为止遇到的模型相同的基本原理(加上一些步骤)。今天,我们将探索 CNN 的内部工作原理,并准确了解幕后发生的事情。
对于我们的第一个 CNN,让我们建立一个 X-or-not-X 模型。该模型应该确定图像是否代表 X。
我知道,这是开创性的。对于硅谷观察家们来说,这种模式很大程度上受到了我儿子杨建的出色“热狗非热狗”应用程序的启发。
在我们的收入模型中,我们使用两个输入项(温度和星期几)来预测收入。这些输入项很容易输入,因为它们是数字。但是我们如何将图像而不是数字值输入到神经网络中呢?
答案很简单。当我们放大图像时,我们看到它基本上只是一堆像素:
由于我们的 X 是一张简单的黑白图像,我们将每个像素指定为 1(代表黑色像素)或 0(代表白色像素)。这些像素存储为0 和 1 的矩阵。
我们可以将这个 5x5 矩阵转换为一列:
现在这一列 25(5x5)个 1 和 0 就可以作为神经网络的输入了:
从上一篇文章中,我们还知道经过训练的神经网络带有权重和偏差项。假设这是一个经过训练的神经网络,那么这里,我们将有 25 个输入到这个神经元,每个输入都有自己的权重,外加一个偏差项。如果我们想要创建一个更复杂的神经网络(图像通常需要),我们需要添加更多的神经元和/或层。然而,这种增加将成倍增加需要优化的权重和偏差项的数量,需要大量的计算能力。
尽管如此,对于非常小的图像(例如我们的 5x5 像素图像),这种方法仍然可行。但是,对于只有 1 个神经元的神经网络,256x256 像素图像将产生 65536(256x256)个输入权重加上 1 个偏置项!更复杂的图像将需要更多的神经元和层(!!)。因此,这种输入图像像素值的方法可能无法有效扩展。
另一个问题是图像可能并不总是像预期的那样。例如,我们可以得到这个理想居中的、漂亮的小“X”:
或者像这样的奇怪的东西:
或者像这样的偏离中心的:
所有图像都是“X”,但每个“X”看起来都略有不同。如果我们使用完全居中的“X”来训练我们的神经网络,它可能无法很好地处理其他“X”图像。这是因为网络只能识别完全居中的“X”。它无法识别偏离中心或扭曲的“X”。它只知道一种模式。这对于现实世界的应用来说并不实用,因为图像很少如此简单。因此,我们需要调整我们的神经网络以处理“X”不完全居中的情况。
我们在构建这个神经网络的方法上需要更有创造力,也许可以理解所有图像中的底层模式,而不仅仅是某一类图像的模式。
如果你仔细想想,我们的大脑以类似的方式识别图像,专注于图像的特征并将它们拼凑在一起。鉴于我们遇到的大量信息,我们的大脑擅长识别特征并丢弃不必要的信息。
因此,我们需要解决两个问题:减少输入神经网络的信息并找到一种方法来检测图像中的模式。
筛选器
让我们首先在所有“X”图像中找到一些一致的模式。例如,一个可能的模式可能是:
所有 3 张“X”图像的模式相同
然后我们可以通过确认图像中存在这个图案来确定图像是一个“X”。
这种模式在这里被称为过滤器。过滤器捕捉“X”的关键特征。因此,即使图像被旋转、缩小或扭曲,我们仍能保持图像的本质。
这些过滤器通常是小的方阵,最常见的是 3x3 像素,但大小可以有所不同。
要将过滤器应用于图像以进行模式检测,我们将 3x3 过滤器滑过每个部分,并计算过滤器与其覆盖的部分的点积。因此,对于第一部分,我们……
...然后将过滤器和矩阵中每个重叠的像素值相乘...
...然后添加产品:
通过计算图像和过滤器之间的点积,我们可以说过滤器与图像卷积,这就是卷积神经网络名称的由来。
现在,我们通过根据可设置的步幅滑动此过滤器来对所有部分执行此操作。步幅决定了我们要将过滤器移动到多少个单元格。因此,如果我们的步幅 = 1,我们会像这样将其移动到下一个部分...
...如果 stride = 2,我们像这样移动它:
通常步幅设置为 2,但在我们的例子中,我们将其设置为 1。
当 stride = 1 时,如果我们将所有点积存储在矩阵中,我们将得到:
然后我们向这个输出矩阵添加一个偏差项……
…其结果就是产生了所谓的特征图。
需要注意的是,步幅越大,特征图就越小。在我们的示例中,我们使用了步幅 = 1,因此特征图相对较大。
在处理实际图像时,我们可能需要增加步幅。毕竟,我们在示例中处理的是 5x5 输入图像,但现实世界中的图像通常要大得多,也更复杂。
通常,此特征图中的每个值都会通过 ReLU 激活函数。作为第一篇文章的快速提醒,以下是 ReLU 的公式:
如果输入大于 0,则函数按原样输出该值;如果输入小于或等于 0,则输出 0。因此,通过将特征图传递给 ReLU 函数,我们得到以下更新的特征图:
在这种情况下,除中间的一个单元格外,所有单元格都设置为 0。
我知道步骤很多,但总结一下卷积过程,我们从 X 的输入图像开始……
...然后对其应用过滤器,也称为将过滤器与图像进行卷积...
...随后,将偏差项添加到卷积矩阵中以创建特征图...
...最后,我们通常将此特征图传递给 ReLU 函数以获得更新的特征图:
卷积步骤的主要目的是减少输入大小(从整个图像到特征图)以简化处理。一个合理的问题是,我们是否因为生成的特征图矩阵中的值减少而丢失了大量信息。确实,我们的值确实减少了,但过滤器旨在检测图像的某些组成部分或特征并消除所有不必要的信息。就像我们之前讨论的那样,这类似于人眼辨别物体的方式,通常会忽略不相关的细节。我们不会检查每个像素,而是查看不同的特征。重点是保留这些基本特征。
与前面提到的过滤器类似,我们可以使用其他过滤器来检测其他特征。例如,我们可以使用这个过滤器……
…可以检测以下模式:
因此,如果我们使用与上述相同的过程应用多个过滤器,我们将获得来自同一输入图像的特征图集合。
输入图像 -> 特征图
一个关键问题是,我们如何确定检测特征所需的过滤器?这是在训练过程中确定的,我们将很快讨论。
池化
现在我们的特征图已经准备好了,我们可以进入下一步——池化。这一步很简单。我们只需扫描之前创建的特征图,选择 2x2 的小部分,然后从每个部分中选择最大值。这是我们的第一步:
最大池化——步骤 1
我们采取的这些 2x2 部分不重叠,因此下一步将是这样的:
最大池化——步骤 2
在此步骤中,您会看到我们没有完整的 2x2 部分,但没关系,因为这些部分不需要是完美的 2x2。然后我们进入下一步:
最大池化——步骤 3
最后:
最大池化——步骤 4
我们将此方法称为最大池化,因为它从每个部分中获取最大值。或者,我们可以使用平均池化,它计算每个区域的平均值。结果如下所示:
来自均值池化的 2x2 矩阵
注意:Sum Pooling 是另一种选择,顾名思义,它将每个区域中的值相加。但是,Max Pooling 是最常用的方法。
最大池化主要用于进一步降低图像中的噪声。其有效性在图像较大时更加明显,因为它可以识别过滤器与输入图像最匹配的区域。与卷积步骤一样,池化特征图的创建会丢弃无关信息。在此过程中,特征图中大约 75% 的原始信息会丢失,因为我们只保留每组四个像素中的最大值,并丢弃其余信息。这些都是不必要的细节,如果删除它们,网络就可以更有效地运行。最大值的提取是池化步骤的关键点,是为了解决失真问题。
呼。这真是一段漫长的旅程,但我们还没有进入真正的神经网络部分!但别担心,如果你读过前面的文章,剩下的就很简单了。到目前为止,我们所做的所有工作都让我们做好了使用真实神经网络的准备。我们将使用池化步骤的结果作为神经网络的输入。
压平
将这些值输入神经网络的第一步是展平特征图矩阵。我们不能按原样输入特征图。因此,我们将其展平。例如,如果我们有四个过滤器,它们将产生四个特征图。反过来,这些特征图又会从最大池化步骤产生四个 2x2 矩阵。它们展平后的样子如下:
最大池化 -> 平坦化
神经网络(最终)
我们之前讨论过的所有特征都存储在这个扁平化的输出中,这使得我们可以使用扁平化的输出作为神经网络的输入。
这些特征已经为图像分类提供了良好的准确度。但我们希望提高模型的复杂性和精度。人工神经网络的工作就是获取这些数据并利用这些特征来提高图像分类效果,这也是我们创建卷积神经网络的主要原因。
因此,我们获取这些输入并将它们插入到完全连接的神经网络中。
注意:这被称为完全连接的神经网络,因为在这里我们确保每个输入和每个神经元都连接到另一个神经元。
我们将神经网络架构设置为:1 个隐藏层,包含 3 个神经元和 1 个输出神经元:
现在,我们需要选择激活函数。在上一篇文章中,我们对冰淇淋销售神经网络中的所有神经元都使用了 ReLU 激活函数。ReLU 激活函数对于内层来说仍然是一个不错的选择。然而,对于外部神经元,由于我们试图解决的问题的性质不同,它并不合适。
之前我们试图回答:给定星期几和温度,冰淇淋店的营业额是多少?现在我们的问题是:给定一张图片,它是字母 X 吗?问题的性质和我们寻求的答案有显著的不同,这意味着我们需要调整外部神经元的处理。
第一个场景是回归问题,而当前场景是分类问题。我们可以通过计算概率来解决当前问题。例如,给定一个输入图像,我们可以确定该图像代表“X”的可能性有多大。在这里,我们希望神经网络输出 0-1 范围内的值,其中 1 表示很可能是“X”,0 表示可能不是“X”。
为了实现这种类型的输出,从我们对激活函数的讨论来看,S形函数是一个不错的选择。
该函数接受输入并将其压缩成 S 形曲线,输出介于 0 和 1 之间的值。这非常适合预测概率。鉴于此,神经网络将如下所示:
假设这个神经网络已经过训练。然后我们知道,经过训练的神经网络中的每个输入都有相关的权重和偏差项。该网络随后输出 0 到 1 之间的值。
因此,如果我们将扁平化的示例输入到这个训练有素的神经网络中,输出为 0.98,这表明图像为“X”的概率为 98%。
再次回顾一下,让我们直观地看看到目前为止我们所做的工作。我们从输入图像开始:
然后通过应用过滤器对该图像进行卷积......
在输出中添加偏差项,并将它们传递给 ReLU 函数以获得特征图:
接下来,我们对特征图执行最大池化:
然后我们获取这些输出,将其扁平化,并将它们传递到我们的神经网络……
...得到 0.98 的预测值!
好的,这很棒。但现在我们需要一种方法来检查这个 0.98 预测有多好。在这种情况下,我们知道原始图像是“X”,所以我们可以说 — “CNN 在这里做得很好!”,但我们需要一个从数学角度告诉我们同样的事情的东西。
在上一篇文章中,我们使用均方误差 (MSE) 成本函数来评估预测的准确性,并将其用于训练过程。同样,我们需要在这里使用成本函数。但正如我们之前讨论的那样,由于预测类型不同,我们不能使用 MSE。
在这种情况下,我们将使用一种称为Log Loss函数的函数,如果您阅读了有关Logistic 回归的文章,这个函数听起来会很熟悉。在 Logistic 回归中,我们试图检查类似输出的准确性。尽管 CNN 比 Logistic 回归模型复杂得多,但我们试图回答同一类型的问题。
对数损失成本函数如下所示:
这里,如果图像是“X”,则 y = 1,如果不是,则 y = 0,p_hat 是预测概率。sigma 只是将我们要评估的所有图像预测的所有值相加。因此,对于此示例,y = 1(因为我们知道图像是“X”),预测概率 p_hat = 0.98,n = 1,因为我们只是试图评估一个图像的输出:
在这里,我们看到成本函数非常接近 0,这很好。成本函数越低越好。所以从数学角度来说,这说明了我们之前所说的—— “CNN 在这里做得很好!”
训练
注意:我们不会在本文中详细介绍训练过程,因为我们在上一篇文章中已经详细介绍了它。因此,请确保在阅读本节之前先阅读上一篇文章!
记得上一篇文章中说过,神经网络通过梯度下降的训练过程学习最佳权重和偏差。这涉及通过网络运行训练集、进行预测和计算成本。我们一直这样做,直到得到最佳值。当我们训练卷积神经网络时,也会发生同样的过程,但有两个变化。
首先,我们使用对数损失函数,而不是 MSE 成本函数。其次,除了寻找最佳权重和偏差之外,我们还在卷积步骤中寻找最佳滤波器和偏差项。滤波器只是 3x3 数字矩阵。因此,目标是找到所有这些元素的最优值——滤波器、卷积步骤中的偏差项以及神经网络中的权重和偏差项。
如果您想更深入地了解训练过程背后的数学原理,这段视频将对您有很大帮助。