卷积层是卷积神经网络中使用的主要构建块。
卷积是过滤器在输入上的简单应用,从而产生激活。对同一输入重复应用相同的过滤器会产生一个激活图,称为特征图,指示输入(例如图像)中检测到的特征的位置和强度。
卷积神经网络的创新之处在于能够根据特定预测建模问题的约束,例如图像分类,在训练数据集中并行自动学习大量特定过滤器。结果是高度特定的特征,可以在输入图像中的任何位置检测到。
在本教程中,您将了解卷积在卷积神经网络中的工作原理。
完成本教程后,您将了解:
- 卷积神经网络将过滤器应用于输入以创建特征图,该特征图总结了输入中检测到的特征的存在。
- 过滤器可以是手工制作的,例如线条检测器,但卷积神经网络的创新在于在特定预测问题的上下文中训练期间学习过滤器。
- 如何在卷积神经网络中计算一维和二维卷积层的特征图。
通过我的新书 《计算机视觉深度学习》 开启您的项目,其中包括分步教程和所有示例的Python源代码文件。
让我们开始吧。

深度学习神经网络卷积层的入门介绍
照片来源:mendhak,保留部分权利。
教程概述
本教程分为四个部分;它们是
- 卷积神经网络中的卷积
- 计算机视觉中的卷积
- 学习过滤器的力量
- 卷积层的工作示例
想通过深度学习实现计算机视觉成果吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
卷积神经网络中的卷积
卷积神经网络(简称 CNN)是一种专门的神经网络模型,用于处理二维图像数据,尽管它们也可以用于处理一维和三维数据。
卷积神经网络的核心是为其名称提供来源的卷积层。该层执行称为“卷积”的操作。
在卷积神经网络的上下文中,卷积是一种线性运算,涉及一组权重与输入的乘法,这与传统神经网络非常相似。鉴于该技术是为二维输入设计的,乘法是在输入数据数组和二维权重数组(称为过滤器或卷积核)之间执行的。
过滤器比输入数据小,在过滤器大小的输入块和过滤器之间应用的乘法类型是点积。一个 点积 是过滤器大小的输入块和过滤器的逐元素乘法,然后求和,结果始终是单个值。由于它产生一个单一的值,该操作通常被称为“标量积”。
有意使用比输入小得多的过滤器,因为它允许相同的过滤器(一组权重)在输入的不同位置多次与输入数组相乘。具体来说,过滤器系统地应用于输入数据的每个重叠部分或过滤器大小的块,从左到右,从上到下。
在整个图像中系统地应用相同过滤器的这种方式是一个强大的想法。如果过滤器旨在检测输入中的特定类型特征,那么系统地将该过滤器应用于整个输入图像将允许过滤器有机会在图像的任何位置发现该特征。此功能通常称为平移不变性,例如,普遍关注特征是否存在,而不是它在哪里。
如果更关心某个特征是否存在而不是它确切的位置,那么局部平移不变性可能是一个非常有用的属性。例如,在确定图像是否包含人脸时,我们不必确切知道像素级的人脸眼睛位置,我们只需要知道人脸的左侧有一只眼睛,人脸的右侧有一只眼睛。
— 第 342 页,《深度学习》,2016 年。
一次将过滤器与输入数组相乘的结果是一个单一的值。当过滤器多次应用于输入数组时,结果是表示输入过滤的二维输出值数组。因此,此操作产生的二维输出数组称为“特征图”。
一旦创建了特征图,我们就可以将特征图中的每个值通过非线性函数(例如 ReLU)传递,就像我们对全连接层的输出所做的那样。

将过滤器应用于二维输入以创建特征图的示例
如果您来自数字信号处理领域或相关的数学领域,您可能会理解矩阵上的卷积操作有所不同。具体来说,过滤器(卷积核)在应用于输入之前会被翻转。严格来说,卷积在卷积神经网络中的使用实际上是“互相关”。尽管如此,在深度学习中,它被称为“卷积”运算。
许多机器学习库都实现了互相关,但称之为卷积。
— 第 333 页,《深度学习》,2016 年。
总之,我们有一个输入,例如像素值的图像,我们有一个过滤器,它是一组权重,过滤器系统地应用于输入数据以创建特征图。
计算机视觉中的卷积
将卷积运算应用于图像数据的思想并不新鲜,也不是卷积神经网络独有的;它是计算机视觉中常用的技术。
历史上,过滤器是由计算机视觉专家手工设计的,然后将其应用于图像以产生特征图或通过应用过滤器获得的输出,从而以某种方式使图像分析更容易。
例如,下面是一个手工制作的 3x3 元素过滤器,用于检测垂直线
1 2 3 |
0.0, 1.0, 0.0 0.0, 1.0, 0.0 0.0, 1.0, 0.0 |
将此过滤器应用于图像将生成一个仅包含垂直线的特征图。它是一个垂直线检测器。
您可以从过滤器中的权重值中看出这一点;中心垂直线中的任何像素值都将正激活,而两侧的像素将负激活。系统地将此过滤器应用于图像中的像素值只能突出显示垂直线像素。
也可以创建水平线检测器并将其应用于图像,例如
1 2 3 |
0.0, 0.0, 0.0 1.0, 1.0, 1.0 0.0, 0.0, 0.0 |
组合两个过滤器的结果,例如组合两个特征图,将突出显示图像中的所有线条。
可以设计数十个甚至数百个其他小型过滤器来检测图像中的其他特征。
在神经网络中使用卷积运算的创新之处在于,过滤器的值是在网络训练期间学习的权重。
网络将学习从输入中提取哪种类型的特征。具体来说,在随机梯度下降下训练时,网络被迫学习从图像中提取最小化特定任务损失的特征,网络正在为此目的进行训练,例如提取对将图像分类为狗或猫最有用的特征。
在这种情况下,您可以看到这是一个强大的想法。
学习过滤器的力量
学习针对机器学习任务的单个过滤器是一种强大的技术。
然而,卷积神经网络在实践中取得了更多成就。
多个过滤器
卷积神经网络不学习单个过滤器;事实上,它们会从给定的输入中并行学习多个特征。
例如,卷积层通常从 32 到 512 个过滤器中为给定输入并行学习。
这使模型有 32 种,甚至 512 种不同的从输入中提取特征的方式,或者“学习看”和训练后“看”输入数据的许多不同方式。
这种多样性允许专业化,例如,不仅仅是线条,而是您特定训练数据中看到的特定线条。
多个通道
彩色图像有多个通道,通常每个颜色通道一个,例如红色、绿色和蓝色。
从数据的角度来看,这意味着输入到模型中的单个图像实际上是三个图像。
过滤器必须具有与输入相同的通道数,通常称为“深度”。如果输入图像有 3 个通道(例如深度为 3),那么应用于该图像的过滤器也必须有 3 个通道(例如深度为 3)。在这种情况下,一个 3x3 的过滤器实际上将是 3x3x3 或 [3, 3, 3],分别代表行、列和深度。无论输入深度和过滤器深度如何,过滤器都通过点积运算应用于输入,该运算产生单个值。
这意味着,如果一个卷积层有 32 个过滤器,那么这 32 个过滤器不仅仅是二维的用于二维图像输入,它们也是三维的,为三个通道中的每一个都具有特定的过滤器权重。然而,每个过滤器都会产生一个特征图。这意味着使用 32 个过滤器应用卷积层的输出深度是 32,用于创建的 32 个特征图。
多个层
卷积层不仅应用于输入数据,例如原始像素值,还可以应用于其他层的输出。
卷积层的堆叠允许输入的层次分解。
考虑直接在原始像素值上操作的过滤器将学习提取低级特征,例如线条。
操作第一层线条的过滤器可能会提取低级特征组合的特征,例如构成多个线条以表达形状的特征。
这个过程一直持续到非常深的层提取人脸、动物、房屋等。
这正是我们在实践中看到的。随着网络深度的增加,特征的抽象化程度越来越高。
卷积层的工作示例
Keras 深度学习库提供了一套卷积层。
通过查看一些包含人为数据和手工过滤器的工作示例,我们可以更好地理解卷积运算。
在本节中,我们将研究一维卷积层和二维卷积层的示例,以便使卷积运算具体化并提供使用 Keras 层的实际示例。
一维卷积层示例
我们可以定义一个一维输入,它有八个元素,值都为 0.0,中间有两个元素的隆起,值为 1.0。
1 |
[0, 0, 0, 1, 1, 0, 0, 0] |
Keras 的输入对于一维卷积层必须是三维的。
第一个维度表示每个输入样本;在这种情况下,我们只有一个样本。第二个维度表示每个样本的长度;在这种情况下,长度为八。第三个维度表示每个样本中的通道数;在这种情况下,我们只有一个通道。
因此,输入数组的形状将是 [1, 8, 1]。
1 2 3 |
# 定义输入数据 data = asarray([0, 0, 0, 1, 1, 0, 0, 0]) data = data.reshape(1, 8, 1) |
我们将定义一个模型,该模型期望输入样本的形状为 [8, 1]。
模型将有一个过滤器,形状为 3,即三个元素宽。Keras 将过滤器的形状称为核大小(kernel_size)。
1 2 3 |
# 创建模型 model = Sequential() model.add(Conv1D(1, 3, input_shape=(8, 1))) |
默认情况下,卷积层的过滤器会用随机权重进行初始化。在这个人为的例子中,我们将手动指定单个过滤器的权重。我们将定义一个能够检测隆起的过滤器,即被低输入值包围的高输入值,正如我们在输入示例中所定义的。
我们将定义的三个元素的过滤器如下所示
1 |
[0, 1, 0] |
卷积层还有一个偏置输入值,它也需要一个权重,我们将将其设置为零。
因此,我们可以强制我们的一个维度卷积层的权重使用我们手工制作的过滤器,如下所示
1 2 3 4 |
# 定义垂直线检测器 weights = [asarray([[[0]],[[1]],[[0]]]), asarray([0.0])] # 将权重存储在模型中 model.set_weights(weights) |
权重必须以三维结构指定,即行、列和通道。过滤器有一行、三列和一个通道。
我们可以检索权重并确认它们已正确设置。
1 2 |
# 确认它们已存储 print(model.get_weights()) |
最后,我们可以将单个过滤器应用于我们的输入数据。
我们可以通过调用模型的predict() 函数来实现这一点。这将直接返回特征图:即系统地将过滤器应用于输入序列的结果。
1 2 3 |
# 将滤波器应用于输入数据 yhat = model.predict(data) print(yhat) |
将所有这些联系在一起,完整的示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 1d 卷积计算示例 from numpy import asarray from keras.models import Sequential from keras.layers import Conv1D # 定义输入数据 data = asarray([0, 0, 0, 1, 1, 0, 0, 0]) data = data.reshape(1, 8, 1) # 创建模型 model = Sequential() model.add(Conv1D(1, 3, input_shape=(8, 1))) # 定义垂直线检测器 weights = [asarray([[[0]],[[1]],[[0]]]), asarray([0.0])] # 将权重存储在模型中 model.set_weights(weights) # 确认它们已存储 print(model.get_weights()) # 将滤波器应用于输入数据 yhat = model.predict(data) print(yhat) |
运行示例首先打印网络的权重;这是我们手工过滤器已按预期设置为模型的确认。
接下来,将过滤器应用于输入模式,计算并显示特征图。从特征图的值可以看出,隆起被正确检测到。
1 2 3 4 5 6 7 8 9 10 |
[array([[[0.]], [[1.]], [[0.]]], dtype=float32), array([0.], dtype=float32)] [[[0.] [0.] [1.] [1.] [0.] [0.]]] |
让我们仔细看看这里发生了什么。
请记住,输入是一个八元素向量,其值为:[0, 0, 0, 1, 1, 0, 0, 0]。
首先,通过计算点积(“.”运算符),将三个元素的过滤器 [0, 1, 0] 应用于输入 [0, 0, 0] 的前三个输入,这在特征图中产生了一个单一的输出值零。
请记住,点积是逐元素乘法的总和,或者在这里它是 (0 x 0) + (1 x 0) + (0 x 0) = 0。在 NumPy 中,这可以手动实现为
1 2 |
from numpy import asarray print(asarray([0, 1, 0]).dot(asarray([0, 0, 0]))) |
在我们的手动示例中,如下所示
1 |
[0, 1, 0] . [0, 0, 0] = 0 |
然后过滤器沿着输入序列的一个元素移动,并重复该过程;具体来说,相同的过滤器应用于索引 1、2 和 3 处的输入序列,这也导致特征图中输出为零。
1 |
[0, 1, 0] . [0, 0, 1] = 0 |
我们是系统化的,所以再次,过滤器沿着输入再移动一个元素,并应用于索引 2、3 和 4 处的输入。这次输出是特征图中的一个值。我们检测到了该特征并进行了适当的激活。
1 |
[0, 1, 0] . [0, 1, 1] = 1 |
这个过程一直重复,直到我们计算完整个特征图。
1 |
[0, 0, 1, 1, 0, 0] |
请注意,特征图有六个元素,而我们的输入有八个元素。这是过滤器如何应用于输入序列的一个伪影。还有其他方法可以应用过滤器来输入序列,从而改变结果特征图的形状,例如填充,但我们不会在本文中讨论这些方法。
您可以想象,使用不同的输入,我们可能会以更大的强度或更小的强度检测到该特征,并且使用过滤器中的不同权重,我们会检测到输入序列中的不同特征。
二维卷积层示例
我们可以将上一节中的隆起检测示例扩展到二维图像中的垂直线检测器。
同样,我们可以约束输入,在这种情况下,约束为具有单个通道(例如灰度)的 8x8 像素方形输入图像,中间有一条垂直线。
1 2 3 4 5 6 7 8 |
[0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] [0, 0, 0, 1, 1, 0, 0, 0] |
Conv2D 层的输入必须是四维的。
第一个维度定义样本;在这种情况下,只有一个样本。第二个维度定义行数;在这种情况下,为八。第三个维度定义列数,同样为八,最后是通道数,在这种情况下为一。
因此,输入必须具有四维形状 [样本、行、列、通道] 或在这种情况下为 [1, 8, 8, 1]。
1 2 3 4 5 6 7 8 9 10 11 |
# 定义输入数据 data = [[0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0]] data = asarray(data) data = data.reshape(1, 8, 8, 1) |
我们将像上一节的 Conv1D 示例一样,定义一个 Conv2D,其中包含一个过滤器。
过滤器将是二维的且为正方形,形状为 3x3。该层将期望输入样本的形状为 [列、行、通道] 或 [8, 8, 1]。
1 2 3 |
# 创建模型 model = Sequential() model.add(Conv2D(1, (3,3), input_shape=(8, 8, 1))) |
我们将定义一个垂直线检测器过滤器来检测输入数据中的单条垂直线。
过滤器如下所示
1 2 3 |
0, 1, 0 0, 1, 0 0, 1, 0 |
我们可以按如下方式实现此目标
1 2 3 4 5 6 7 8 9 |
# 定义垂直线检测器 detector = [[[[0]],[[1]],[[0]]], [[[0]],[[1]],[[0]]], [[[0]],[[1]],[[0]]]] weights = [asarray(detector), asarray([0.0])] # 将权重存储在模型中 model.set_weights(weights) # 确认它们已存储 print(model.get_weights()) |
最后,我们将过滤器应用于输入图像,这将产生一个特征图,我们可以期望该特征图显示输入图像中的垂直线被检测到。
1 2 |
# 将滤波器应用于输入数据 yhat = model.predict(data) |
特征图输出的形状将是四维的,形状为 [批次, 行, 列, 过滤器]。我们将执行单个批次,并且只有一个过滤器(一个过滤器和一个输入通道),因此输出形状为 [1, ?, ?, 1]。我们可以如下格式化打印单个特征图的内容
1 2 3 |
for r in range(yhat.shape[1]): # 打印行中的每一列 print([yhat[0,r,c,0] for c in range(yhat.shape[2])]) |
将所有这些联系在一起,完整的示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# 2d 卷积计算示例 from numpy import asarray from keras.models import Sequential from keras.layers import Conv2D # 定义输入数据 data = [[0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0]] data = asarray(data) data = data.reshape(1, 8, 8, 1) # 创建模型 model = Sequential() model.add(Conv2D(1, (3,3), input_shape=(8, 8, 1))) # 定义垂直线检测器 detector = [[[[0]],[[1]],[[0]]], [[[0]],[[1]],[[0]]], [[[0]],[[1]],[[0]]]] weights = [asarray(detector), asarray([0.0])] # 将权重存储在模型中 model.set_weights(weights) # 确认它们已存储 print(model.get_weights()) # 将滤波器应用于输入数据 yhat = model.predict(data) for r in range(yhat.shape[1]): # 打印行中的每一列 print([yhat[0,r,c,0] for c in range(yhat.shape[2])]) |
运行示例首先确认手工过滤器已正确定义在层权重中
接下来,打印计算出的特征图。从数字的规模可以看出,过滤器确实在特征图的中间检测到了单条垂直线,并具有强激活。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[array([[[[0.]], [[1.]], [[0.]]], [[[0.]], [[1.]], [[0.]]], [[[0.]], [[1.]], [[0.]]]], dtype=float32), array([0.], dtype=float32)] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] [0.0, 0.0, 3.0, 3.0, 0.0, 0.0] |
让我们仔细看看计算了什么。
首先,过滤器应用于图像的左上角,或一个 3x3 元素的图像块。严格来说,图像块是三维的,只有一个通道,过滤器具有相同的尺寸。我们不能在 NumPy 中使用 dot() 函数来实现这一点,而是必须使用 tensordot() 函数,以便我们可以跨所有维度进行适当的求和,例如
1 2 3 4 5 6 7 8 9 |
from numpy import asarray from numpy import tensordot m1 = asarray([[0, 1, 0], [0, 1, 0], [0, 1, 0]]) m2 = asarray([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) print(tensordot(m1, m2)) |
此计算产生一个单一的输出值 0.0,即未检测到该特征。这给出了特征图左上角第一个元素。
手动计算如下
1 2 3 |
0, 1, 0 0, 0, 0 0, 1, 0 . 0, 0, 0 = 0 0, 1, 0 0, 0, 0 |
过滤器向左移动一列,并重复该过程。同样,未检测到该特征。
1 2 3 |
0, 1, 0 0, 0, 1 0, 1, 0 . 0, 0, 1 = 0 0, 1, 0 0, 0, 1 |
再向左移动一列到下一列,特征首次被检测到,从而产生强激活。
1 2 3 |
0, 1, 0 0, 1, 1 0, 1, 0 . 0, 1, 1 = 3 0, 1, 0 0, 1, 1 |
这个过程一直重复,直到过滤器的边缘与输入图像的边缘或最后一列对齐。这给出了特征图第一完整行的最后一个元素。
1 |
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0] |
然后过滤器向下移动一行,回到第一列,并从左到右重复该过程,得到特征图的第二行。一直到过滤器底部与输入图像的底部或最后一行对齐。
同样,与上一节一样,我们可以看到特征图是一个 6x6 的矩阵,比 8x8 的输入图像小,因为过滤器在应用到输入图像时受到限制。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
文章
书籍
- 第9章:卷积网络,深度学习,2016年。
- 第5章:深度学习计算机视觉,Python 深度学习,2017年。
API
总结
在本教程中,您了解了卷积在卷积神经网络中的工作原理。
具体来说,你学到了:
- 卷积神经网络将过滤器应用于输入以创建特征图,该特征图总结了输入中检测到的特征的存在。
- 过滤器可以是手工制作的,例如线条检测器,但卷积神经网络的创新在于在特定预测问题的上下文中训练期间学习过滤器。
- 如何在卷积神经网络中计算一维和二维卷积层的特征图。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
非常感谢您的精彩解释,我有两个问题
第一个是关于如何微调卷积中的过滤器以从输入图像中提取特定特征,我的意思是我们可以更改过滤器的值吗?以及如何更改?。
第二个问题是为什么是 32 到 512 个过滤器?以及这些过滤器的值是否由模型以随机方式假定?
谢谢。好问题!
不,过滤器值(权重)是学习到的。它们通常不是手动修改/指定的。
过滤器的数量是一个超参数,最好通过试错法来确定
https://machinelearning.org.cn/how-to-configure-the-number-of-layers-and-nodes-in-a-neural-network/
同样的问题,我想问。
如果我们不能选择过滤器的权重,那么我们如何选择?然后,我们取随机值吗?
这些过滤器权重可以在训练过程中学习吗?如何学习?
嗨 Isha…以下资源可能会有所帮助
https://machinelearning.org.cn/why-initialize-a-neural-network-with-random-weights/
我仍然不清楚卷积层中的权重是如何调整的
嗨 Harsh…以下资源可能值得关注
https://datascience.stackexchange.com/questions/25754/updating-the-weights-of-the-filters-in-a-cnn
很好的解释!
我的疑问是
为什么池化和展平中的参数为零?仅仅是因为在池化 - 最大池化或平均池化时,节点数减少了吗?
而对于展平,因为它被转换为一维数组。
很好的问题!
这些层没有权重,它们只是在展平的情况下转换输入的形状,或者在池化的情况下选择输入值的子集。
谢谢 Jason
感谢 Jason 的精彩文章!
您能为我澄清几件事吗?
首先,过滤器的数量是否等于特征图的数量?
在我看来,靠近输入层的层检测线条和形状等特征,而靠近输出层的层检测更具体的对象,如桌子和椅子。
然而,我们不在网络的开始处靠近输入时需要更多的过滤器来检测许多小形状和线条,然后在靠近输出时缩小它们?
我也认为从输入附近的较小窗口(卷积核)开始,然后向输出方向扩大它会更好。
这在我看来是合理的,但显然是不正确的。
在我目前看到的模型中,过滤器的数量在增加,而窗口大小似乎保持不变。
您是否愿意解释一下它是如何工作的?
是的,过滤器的数量 == 特征图的数量,总的来说。
过滤器数量和过滤器大小以及它们检测的内容之间的直觉会失效。模型架构是经验性的,而不是基于理论的,例如
https://machinelearning.org.cn/review-of-architectural-innovations-for-convolutional-neural-networks-for-image-classification/
首先,非常感谢您提供的精彩文章,讲解得非常好!
我想知道,如果您堆叠卷积层,每层有多个过滤器,那么维度似乎会增加。例如,对于二维图像,第一个卷积层会产生一个二维 x 过滤器数量,即三维。这成为第二层的输入,然后又产生三维 x 第二个卷积层的过滤器数量,即四维。
通过搜索*,我了解到可以通过使第二层中的第三个维度等于第一层的过滤器数量来避免这种情况。因此,第二层仍然只产生三维。
您能否对此方法发表评论?如果方法不正确或被忽略了细微之处,也许值得在文章中添加一个关于顺序卷积层的部分。
* https://datascience.stackexchange.com/questions/9175/how-do-subsequent-convolution-layers-work?newreg=82cdb799f5f04512a8c00e2a7b445c95
再次感谢!
好问题。
过滤器的大小会缩小输入区域。“相同”填充可以用来避免这种情况。
过滤器的数量定义了输出的通道或第三个维度。这不会随着一个过滤器应用于输入中的所有通道而线性增加。因此,在每一层,您可以选择输出深度/通道作为过滤器的数量。
这有帮助吗?
首先,非常感谢您提供的所有教程。清晰的教程和基本信息拯救了我很多次。我使用 CNN 已经有一段时间了,在我搜索和学习的过程中,仍然有一个问题没有得到解答。根据我的理解,每个卷积层提取特定类型的特征。假设第一层提取各种边缘特征(例如水平、垂直、对角线等),结果是该层的输出是许多图像,每个图像都显示某种边缘。第二层应该提取纹理特征。由于第一层的输出不再是原始图像,第二层如何从中提取纹理?也许我的问题很荒谬,或者我没有正确理解卷积运算的目的。尽管如此,如果您能纠正我,我将不胜感激。再次感谢您的教程和演示代码。
是的,靠近输入的层提取简单特征,靠近输出的层提取更高级别的特征。
每个过滤器都不同,所以我们在给定层提取 128 或 256 种不同的特征。
这也许可以帮助您举例说明正在提取什么
https://machinelearning.org.cn/how-to-visualize-filters-and-feature-maps-in-convolutional-neural-networks/
嗨,感谢您的精彩文章。文章中的以下段落让我感到困惑。您能否阐明一下?
摘自文章
“第一个维度定义样本;在这种情况下,只有一个样本。第二个维度定义行数;在这种情况下,为八。第三个维度定义列数,同样为八,最后是通道数,在这种情况下为一。
因此,输入必须具有四维形状 [样本、列、行、通道] 或在这种情况下为 [1, 8, 8, 1]。”
这是 [样本、行、列、通道],而不是 [样本、列、行、通道] 吗?
看起来是个笔误,已修正。谢谢!
哦,谢谢。我从未遇到过那个教程页面。它真的很有帮助。
不客气。
我打算了解各种轻量级 cnn(深度学习网络)和相关文献
轻量级 cnn 与串行和 DAG cnn 网络有何不同
shufflenet、mobilenetv2 和 squeezenet 模型是轻量级的吗?
您所说的“轻量级 cnn”是什么意思?
你好,
我目前正在使用 CNN 在 MATLAB 中识别属于特定语言的手写字符。
训练 CNN 后,我获得了大约 90% 的验证集准确率,但在测试阶段,我没有得到令人满意的结果(字符被错误分类)。
如何在训练和测试阶段都获得令人满意的结果?
您能否就此问题提供帮助?
提前感谢!
这是一个很大的话题,您可以从这里开始
https://machinelearning.org.cn/start-here/#better
嗨,能帮帮我吗?
我是一名计算机科学硕士生,我想要您的电子邮件。
你随时可以在这里联系我
https://machinelearning.org.cn/contact/
先生,如何在我的 10 类分类中使用 conv2D 层作为分类输出层,而不是密集层?
提前感谢!
添加一个全局池化层。
很棒的教程
谢谢!
你好 Jason,您的网站对我非常有帮助,非常感谢!
我在这里发现了一个错误,一开始您在谈论
当引用 Goodfellow 等人(第 342 页)时,您谈论的是池化操作,而不是过滤器在整个图像上滑动。
当我们谈论过滤器在图像上滑动时,它应该是对平移的*等变性*(第 338 页),
找到新位置的任何特征,之后图片可能会发生平移变换。
当平移不变性谈论的是池化结果*完全相同*时,当图片平移 1-2 像素时(因为池化会返回相同的值)。
不变性:无论应用什么操作,结果都相同:f(g(x)) = f(x)
等变性:结果会随着操作而改变,即特征图输出会改变
当平移后的特征出现在图片的其他位置时。
第 338 页:f(g(x)) = g(f(x))
谢谢,很高兴听到这个。
谢谢!
嗨 Jason。感谢您的文章。它确实很有启发性。
我有一个疑问,这与使用两个堆叠的卷积层与单个卷积层有关。
(a) 例如,两个堆叠的卷积层,每层有 8 个过滤器,与单个具有 8 个过滤器的卷积层有何不同?堆叠两个卷积层是否有助于识别详细特征?
(b) 对于堆叠两个卷积层的情况,为每个层使用不同的过滤器,例如第一层 8 个,第二层 16 个,是否比为两层使用相同的过滤器学习效果更好或更差?
提前感谢!
下一层作用于第一层输出的特征图。
它可能有助于解决某些问题。
嗨,在 conv2D 部分,文章提到“过滤器向左移动一列,并重复该过程。再次,特征未被检测到。”但看起来过滤器是向右移动的,因为数据中的 1 从右侧移入。
嘿 Jason,我一直在寻找一篇关于 2D 卷积但应用于 RGB 图像的文章。灰度还可以,因为它只有 1 个通道。但是当有三个通道时,过滤器也有 3 个深度。我假设红色层匹配过滤器的单层,并像灰度一样进行卷积。但是,我们是否留下了一个深度为 3 的特征图?每个过滤器一层?我不明白为什么特征图只有一个过滤器,但深度为 1。
我明白使用多个过滤器时它们是堆叠的,但是一个过滤器如何等于一个深度层?
是的。每个过滤器和通道有一个特征图。
这可能有帮助
https://machinelearning.org.cn/how-to-develop-a-cnn-from-scratch-for-cifar-10-photo-classification/
也许这会有帮助
https://machinelearning.org.cn/a-gentle-introduction-to-channels-first-and-channels-last-image-formats-for-deep-learning/
如果我们减少 Cnn 中的过滤器大小,例如 64,32,16 个过滤器,而不是增加过滤器大小,会发生什么?
这将改变模型的能力,进而改变模型的性能。尝试一下,看看结果。
我是一位来自图像处理行业的资深工程师,当时我们不得不使用离散乘法器和累加器(我们也构建了自己的图形卡,而且我的 PC 以 6 MHz 运行时非常“时髦”)来构建自己的卷积引擎。图像处理的内核过滤器是固定的,符合应用要求。
我对使用 CNN 的 DNN 的理解是,内核过滤器在训练过程中进行了调整。我可能错了,但不确定内核过滤器的术语现在是否是“权重”。这些“权重”被调整,直到达到 DNN 的期望输出。
我知道 CNN 阶段使用的权重有许多集,代表了不同的卷积滤波器。我也知道为了节省内存空间,大量的权重被格式化。
我的期望是每个内核过滤器都必须有其在系统内存中的唯一空间。我的问题是,是否有办法访问用作卷积过滤器的完全训练过的权重?是的,这取决于格式化和使用的 CNN 框架。我做过使用 Darknet 框架和 YOLO 的项目,并且我目前正在学习 Pytorch,但我的问题似乎过于基础。
请纠正我可能做出的任何不正确的假设。
汤姆
是的,大多数 API 都提供了一种提取模型训练权重的方法。在 Keras 中是 model.get_weights(),我不确定 Pytorch 的具体情况。
您不会只有一个过滤器,根据模型的深度和复杂性,您会有数百或数千个过滤器。
非常感谢您的回复。是的,当然,您说得对,过滤器的数量可能有数百或数千个。
只有一个额外的问题,我希望它不会太天真。是否可以说,在基于 CNN 的 DNN 中,过滤器的数量与网络需要完成的工作之间存在直接相关性?例如,如果网络被训练来区分 100 种不同的物体类型,而不是一种物体类型,是否需要更多的过滤器?准确性对于该物体类型是相等的。
感谢您的内容。
汤姆
是的,我们称之为模型的容量。它与建模/预测任务的难度有关(尽管关系很复杂)。
这可能很有意义
https://machinelearning.org.cn/how-to-control-neural-network-model-capacity-with-nodes-and-layers/
嗨,Jason,
使用 3 x 3 过滤器在 conv 层中使用 224 x 224 x 3 输入图像的适当过滤器数量是多少?
没有最佳数量,尝试不同的值并找出最适合您的特定模型和数据集的值。
嗨,Jason,
您能向我解释一下过滤器值是如何确定的吗?CNN 是随机选择它,然后更新权重后其值会更新吗?我们可以根据需要设计其值吗?请回复
层数和过滤器数量可以通过多种方式选择,请参阅此
https://machinelearning.org.cn/faq/single-faq/how-many-layers-and-nodes-do-i-need-in-my-neural-network
这使我的实施工作变得更加轻松;
提前感谢 Jason;
请继续做好工作,您的文章非常有趣且知识渊博 😉
不客气。很高兴听到你这么说。
工作出色,非常感谢
谢谢!
先生
为什么卷积层中的过滤器称为可学习过滤器。
卷积核的初始值是随机的,它提取特征。学习在哪里进行?过滤器值在哪里更新?
我真的很困惑
因为称为权重的模型参数会根据训练数据进行调整。
嗨,感谢您的精彩教程。
我有两个问题,请。
一个卷积层的输出是多个特征图。这些特征图是数字矩阵或“图像”,可以直接输入到下一组卷积层——就像我们将图像输入到第一个卷积层一样。
通常,我们在卷积层之间放置池化层,以减小矩阵(图像)的尺寸。
Dropout 是一种正则化技术,有助于减缓学习过程,并使模型更通用(在未见过的数据上预测更好)。
不客气。
一个卷积层的输出是多个特征图。这些特征图是数字矩阵或“图像”,可以直接输入到下一组卷积层——就像我们将图像输入到第一个卷积层一样。
通常,我们在卷积层之间放置池化层,以减小矩阵(图像)的尺寸。
Dropout 是一种正则化技术,有助于减缓学习过程,并使模型更通用(在未见过的数据上预测更好)。
https://machinelearning.org.cn/dropout-for-regularizing-deep-neural-networks/
太好了,谢谢你的回答。
我仍然不明白 Dropout 在卷积层之间是如何工作的。我知道它会丢弃全连接层中的神经元,但由于我们有在卷积层之间传递的特征图,所以我不太明白它是如何作用于这些特征图的。你能为我解释一下吗?或者推荐一些有用的资源?
再次感谢你的帮助!
感谢教程!
不客气!
非常感谢——这太棒了!我喜欢你的内容。继续努力!
谢谢!
你对读者想要什么以及应该在哪里强调有一些出色的理解,这样读者就能更好地理解。我的意思是,理解所提到的概念并获得直觉在各个方面都是恰当的。非常感谢这项伟大的工作。
谢谢!
谢谢 Jason,你总是支持我。
我有一个问题,经过 max pooling 后,矩阵被展平以输入神经网络,那么在 CNN 中反向传播是如何发生的,例如核是如何更新的?
好问题,也是一个很棒的未来博文教程建议!谢谢。
嗨 Jason。你对 CNN 的解释非常棒。非常感谢!我有一个小问题。我们应该如何决定滤波器的形状以及所需的滤波器数量?
不客气。
您可以使用试错法来确定滤波器的形状和数量。或者复制其他模型中使用的值作为起点。
一如既往,文章写得非常棒。感谢您花时间分享您的知识!
谢谢!
这是一篇很棒的文章。谢谢。
谢谢。
嗨,Jason,
首先,非常感谢您提供的所有精彩内容!我真的很喜欢您的解释,并且通过阅读您的帖子学到了很多!
我有一个关于滤波器的问题。您提到一个卷积层会使用许多滤波器(例如 32、64、128),但我不太明白这些滤波器会有何不同。您能否解释一下,尽管它们应用于同一张图像,但滤波器是如何学习到不同特征的?
谢谢!
假设您有一张相当大的图像。您可能想找到的一个特征是图像中的亮点。您可以使用 32×32 的滤波器和平均池化来查找任何 32×32 区域的平均亮度,或者使用 128×128 的滤波器查找 128×128 区域的平均亮度。因此,滤波器大小将为您提供不同的视野。
嗨,Jason,
感谢您的回复!您的回答听起来像是我们对图像应用了一个特征,无论是 3×3 还是 32×32 等。然而,我以为像这样的层
model.add(Conv2D(32, (3, 3), activation=’relu’, kernel_initializer=’he_uniform’, padding=’same’, input_shape=(200, 200, 3)))
会创建许多滤波器(在本例中是 32 个)。这是真的吗?如果是,我的问题更多是关于这些滤波器即使应用于同一张图像,它们之间是如何不同的。
再次感谢!非常感谢所有内容!
*这些滤波器之间是如何不同的
您的理解是正确的。至于不同滤波器之间为何不同,我不知道。但在训练网络时,它可能会神奇地收敛到不同的东西(例如,一个拾取水平边缘,另一个拾取垂直边缘)。也许您想阅读这篇博文:https://machinelearning.org.cn/how-to-visualize-filters-and-feature-maps-in-convolutional-neural-networks/
那很有趣。谢谢!
我还没有在任何地方明确看到这一点,希望您能澄清一下。假设我有一堆 64,64,3 的图像,但它们不是像 :,64,64,3 这样堆叠的,而是为了建模目的将它们组织成更高的维度,例如 (:,5,5,5,64,64,3)。然后我运行一个 2D 卷积(TensorFlow)并设置 stride=1,得到 (:,5,5,5,64,64,1)。我能假设卷积遍历了每个批次样本的 5x5x5=125 个 64x64x3 图像实例吗?因此,直观上保持了我的结构的完整性。我希望它能默认处理三个最高维度,并且足够智能地遍历所有其他维度。
Python 对我来说有点不透明,所以我对做出假设有点紧张。
嗨 diospyros……您可能会发现以下资源对您建立 Python 技能很有兴趣。
https://machinelearning.org.cn/start-here/#pythonskills
谢谢这个链接。但我对 Python 已经相当熟悉了。我只是习惯于在需要理解库如何工作时,能够看到 C++/C 中底层数据结构中的地址和位级别。😉
我更感兴趣的是 TensorFlow 在底层做出的假设(或者至少没有清楚说明的)。我想我可以直接 reshape 低维度,但我想知道这是否是不必要的。
完美的解释。
感谢您的反馈!我们很感激!
嗨,Jason,
在一个标准的 U-net 中,有一个输入层,后面跟着两个使用 64 个滤波器的层,显然第一层有 64 个滤波器,因此产生 64 个特征图,这对我来说是直观的。然而在第二层,您有 64 个特征图和 64 个滤波器,因此我预计后续层的特征图数量将是 64^2 个特征图——但根据架构图,显然只有 64 个。这是因为特征图在传递到第二层之前被聚合了吗?如果不是这种情况,您能给我一个解释吗?
嗨 Adam……您的理解是正确的!
您确定吗?我在其他地方读到,后续的每个特征图只被后续层中的一个滤波器考虑。也就是说,特征图 1-64 通过另一个 CNN 层,定义的滤波器数量是 64,每个滤波器只作用于一个特征图。所以您会有 kern1 作用于 fmap1,kern2 作用于 fmap2……kern 64 作用于 fmap64。但您永远不会有 kern64 作用于 fmap22。您能否澄清一下?
您确定吗?我在其他地方读到,后续的每个特征图只被后续层中的一个滤波器考虑。也就是说,特征图 1-64 通过另一个 CNN 层,定义的滤波器数量是 64,每个滤波器只作用于一个特征图。所以您会有 kern1 作用于 fmap1,kern2 作用于 fmap2……kern 64 作用于 fmap64。但您永远不会有 kern64 作用于 fmap22。您能否澄清一下?您确定吗?我在其他地方读到,后续的每个特征图只被后续层中的一个滤波器考虑。也就是说,特征图 1-64 通过另一个 CNN 层,定义的滤波器数量是 64,每个滤波器只作用于一个特征图。所以您会有 kern1 作用于 fmap1,kern2 作用于 fmap2……kern 64 作用于 fmap64。但您永远不会有 kern64 作用于 fmap22。您能否澄清一下?