在CNN中,每个新滤波器对每个输入通道的权重是否不同,还是在输入通道中使用的每个滤波器的权重相同?


28

我的理解是,卷积神经网络的卷积层具有四个维度:input_channels,filter_height,filter_width,number_of_filters。此外,据我了解,每个新过滤器都只是在所有input_channels(或上一层的特征/激活图)上盘旋。

但是,CS231下图显示了每个滤波器(红色)应用于单个通道,而不是跨通道使用相同的滤波器。这似乎表明每个通道都有一个单独的滤镜(在这种情况下,我假设它们是输入图像的三个颜色通道,但是对所有输入通道都适用)。

这令人困惑-每个输入通道是否都有不同的唯一过滤器?

在此处输入图片说明

资料来源:http : //cs231n.github.io/convolutional-networks/

上图似乎与奥雷利(O'reilly)的“深度学习基础”节选中的矛盾:

“ ...过滤器不仅可以在单个要素地图上运行,而且还可以在特定图层上生成的全部要素地图上运行...因此,要素地图必须能够在多个实体上进行操作,不只是区域”

...此外,据我了解,以下这些图像表示THESAME过滤器仅在所有三个输入通道上卷积(与上面的CS231图形相反):

在此处输入图片说明

在此处输入图片说明


Answers:


13

在卷积神经网络中,每个输入通道是否都具有唯一的过滤器,还是在所有输入通道中都使用了相同的新过滤器?

前者。实际上,为每个输入通道/输出通道组合定义了一个单独的内核。

通常,对于CNN架构,在number_of_filters参数描述的单个过滤器中,每个输入通道有一个2D内核。有一input_channels * number_of_filters组权重,每个权重描述一个卷积核。因此,显示每个滤波器每个输入通道一组权重的图表是正确的。第一张图还清楚地表明,通过将这些内核求和并为每个输出通道增加偏差来组合应用这些内核的结果。

这可以被视为使用3D卷积为每个输出信道,即碰巧具有相同的深度作为输入。第二张图显示的是什么,还有许多库将在内部执行的操作。从数学上讲,这是相同的结果(假设深度精确匹配),但是通常将图层类型标记为“ Conv2D”或类似名称。同样,如果您的输入类型本质上是3D(例如体素或视频),则可以使用“ Conv3D”层,但在内部可以很好地将其实现为4D卷积。


感谢您的解释。听起来每个过滤器实际上都有权重不同的多个input_channels版本。您是否有证实这一理解的“官方”资源?
瑞安·蔡斯

@RyanChase:是的,这是正确的。我只想向您介绍吴安德
Neil Slater,

我想指出的是,在该源(cs231n.github.io/convolutional-networks)中,过滤器(权重或kernesl)是体积(即3维),并且它们具有相同的3维,其中一个是输入体积。此外,正如(至少)现在在该来源中所述,已在第3维上对体积进行了切片,以便更好地可视化过滤器对输入体积的应用。通常,我不认为“为每个输入通道/输出通道组合定义了单独的内核”。是正确的。
nbro

请注意,过滤器(或内核)是需要学习的权重(即它们不是固定的,但实际上是CNN的参数)。最后,它们可能(即过滤器的切片)在第3维上相同。
nbro

@nbro:是的,您可以将多个2D切片上的2D卷积实现为单个3D卷积,其内核深度与通道数相同。从数学上讲,这与我的描述相同。您也可以将其视为具有权重共享的截断的全连接前馈网络(其中许多为零)。该答案集中在2D滤镜的视图上,因为OP正在询问2D滤镜的排列方式。实际上,它们可能被安排在更大的3D内核中,但是仍然使用3D卷积等效的“技巧”将它们用作2D内核。
尼尔·斯莱特

12

您在问题中使用的以下图片非常准确地描述了正在发生的事情。请记住,3D滤镜(灰色立方体)的每个元素都由一个不同的值(个3x3x3=27值)组成。因此,可以将三个不同大小的2D滤镜3x3连接起来,以形成此一个3D大小的滤镜3x3x3

convnet2D

3x3x3从画面RGB块相乘的elementwise3D滤光器(示出为灰色)。在这种情况下,过滤器具有权3x3x3=27重。将这些权重按元素进行乘积然后求和时,得出一个值。


那么,每个输入通道是否有单独的滤波器?

是的图像中的2D滤镜数量与输入通道数一样多。但是,如果您认为对于具有多个通道的输入矩阵,只有一个3D过滤器(如上图所示),则将有所帮助。


那么为什么将其称为2D卷积(如果滤波器是3D而输入矩阵是3D)?

这是2D卷积,因为滤波器的步幅仅沿着高度和宽度尺寸(而不是深度),因此,该卷积产生的输出也是2D矩阵。过滤器的运动方向数量决定了卷积的大小。

注意: 如果您通过可视化单个3D滤镜而不是多个2D滤镜(每一层一个)来建立理解,那么您将很容易理解高级CNN架构,例如Resnet,InceptionV3等。


这是一个很好的解释,但更具体地说,我想理解的问题是,在每个输入通道上运行的过滤器是权重相同的副本,还是权重完全不同的副本。这实际上没有显示在图像中,实际上,对我而言,图像有点暗示它对每个通道应用了相同的权重(因为它们的颜色相同)...根据@neil slater的回答,听起来像每个过滤器实际上具有权重不同的多个input_channels版本。如果这也是您的理解,是否有“官方”消息证实这一点?
瑞安·蔡斯

是的,的确,这也是我的理解。对我来说,当我试图考虑由27个不同权重值组成的灰色立方体时,这很明显。这意味着有3个不同的2D滤镜,而相同的2D滤镜应用于每个输入层。
Mohsin Bukhari

我找不到任何官方消息来证实这一点。但是,当我试图围绕这个相同的概念时,我在Tensorflow中创建了一个虚拟输入和权重过滤器,并观察了输出。我对此感到满意。如果我找到任何官方解释。我将在上面编辑我的答案。
Mohsin Bukhari,

如果遵循Tensorflow路径。在向您的虚拟CNN图层显示输入样本后,您可以打印权重过滤器。
Mohsin Bukhari,

@Moshsin Bukhari我一定会尝试探索TensorFlow中的过滤器。您是否愿意分享有关探索过滤器中包含的内容的代码?例如,您是否可以在网络的每个步骤中打印过滤器的值?
瑞安·蔡斯

3

我将在上面的答案中举一个具体的例子,以期进一步阐明卷积如何分别针对输入和输出通道以及权重进行工作:

令示例如下(将其写入1个卷积层):

  • 输入张量是9x9x5,即5个输入通道,所以 input_channels=5
  • 过滤器/内核大小为4x4,跨度为1
  • 输出张量是6x6x56,即56个输出通道,所以 output_channels=56
  • 填充类型为“有效”(即无填充)

我们注意到:

  • 因为输入有5个通道,所以滤波器的尺寸变为4x4x5,即有5个单独的,唯一的2D滤波器,大小为4x4(即每个具有16个权重);为了对尺寸为9x9x5的输入进行卷积,滤波器变为3D,并且尺寸必须为4x4x5
  • 因此:对于每个输入通道,都有一个不同的2D滤波器,每个滤波器具有16个不同的权重。换句话说,2D滤波器的数量与输入通道的数量匹配
  • 由于有56个输出通道,因此必须有56个尺寸为4x4x5的3维滤波器W0,W1,...,W55(请参阅CS231图形中的2个3维滤波器W0,W1以说明2个输出通道),其中尺寸5的第3维表示到5个输入通道的链接(请参见CS231图形中的每个3D滤波器W0,W1的3维3,与3个输入通道匹配)
  • 因此:3D滤镜的数量等于输出通道的数量

因此,该卷积层包含:

56个3维滤波器,大小为4x4x5(每个= 80个不同的权重),以说明56个输出通道,其中每个通道的第3维尺寸值为5,以匹配5个输入通道。总共有

number_of_filters=input_channel*output_channels=5*56=280

尺寸为4x4的2D滤镜(即总权重为280x16)。


0

只有二​​维限制。为什么?

想象一个完全连接的层。

这将是巨大的,每个神经元可能会连接到1000x1000x3输入神经元。但是我们知道处理附近的像素很有意义,因此我们将自己限制在一个很小的2D邻域中,因此每个神经元仅以2D方式与3x3附近的神经元相连。我们对频道一无所知,因此我们连接到所有频道。

尽管如此,权重仍然太多。但是由于平移不变性,一个滤波器在一个区域内正常工作很可能在另一个区域内有用。因此,我们在2D上使用相同的权重集。同样,通道之间没有这样的翻译不变性,因此那里也没有这样的限制。


0

请参阅http://cs231n.github.io/convolutional-networks/中的 “本地连接”部分,并滑动7-18。

过滤器的“接收场”超参数仅由高度和宽度定义,因为深度由上一层的深度固定。

请注意,“沿深度轴的连通程度始终等于输入体积的深度”或激活图的DEPTH(在后面的层中)。

直观上,这必须是由于图像通道数据是交错而不是平面的事实造成的。这样,可以简单地通过列矢量相乘来实现应用滤波器。

注意,卷积网络会学习所有滤波器参数(包括深度尺寸),它们的总和为“ h w input_layer_depth + 1(bias)”。


0

我推荐硕士论文的第2.2.1章作为答案。要添加到其余答案中:

Keras是您的朋友以了解会发生什么:

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(32, input_shape=(28, 28, 3),
          kernel_size=(5, 5),
          padding='same',
          use_bias=False))
model.add(Conv2D(17, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(13, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(7, (3, 3), padding='same', use_bias=False))
model.compile(loss='categorical_crossentropy', optimizer='adam')

print(model.summary())

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)        2400      
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 17)        4896      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 28, 28, 13)        1989      
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 28, 28, 7)         819       
=================================================================
Total params: 10,104

尝试制定您的选择。如果还有其他情况,这对参数意味着什么?

2400=32355

这种方法还可以帮助您处理其他图层类型,而不仅仅是卷积图层。

另请注意,您可以自由实施其他解决方案,这些解决方案可能具有其他数量的参数。


0

为了使两个细节绝对清晰:

ññ3×3ñ2ñ

ñ2ñ3×3×

使自己相信这一点的最简单方法是,想象一下在其他情况下会发生什么,并看到计算退化了-也就是说,如果您不交织并重新组合结果,那么不同的输出实际上将无能为力-它们与合并权重的单个输出具有相同的效果。


0

对于想了解如何计算卷积的任何人,这是Pytorch中有用的代码段:

batch_size = 1
height = 3 
width = 3
conv1_in_channels = 2
conv1_out_channels = 2
conv2_out_channels = 2
kernel_size = 2
# (N, C_in, H, W) is shape of all tensors. (batch_size, channels, height, width)
input = torch.Tensor(np.arange(0, batch_size*height*width*in_channels).reshape(batch_size, in_channels, height, width))
conv1 = nn.Conv2d(in_channels, conv1_out_channels, kernel_size, bias=False) # no bias to make calculations easier
# set the weights of the convolutions to make the convolutions easier to follow
nn.init.constant_(conv1.weight[0][0], 0.25)
nn.init.constant_(conv1.weight[0][1], 0.5)
nn.init.constant_(conv1.weight[1][0], 1) 
nn.init.constant_(conv1.weight[1][1], 2) 
out1 = conv1(input) # compute the convolution

conv2 = nn.Conv2d(conv1_out_channels, conv2_out_channels, kernel_size, bias=False)
nn.init.constant_(conv2.weight[0][0], 0.25)
nn.init.constant_(conv2.weight[0][1], 0.5)
nn.init.constant_(conv2.weight[1][0], 1) 
nn.init.constant_(conv2.weight[1][1], 2) 
out2 = conv2(out1) # compute the convolution

for tensor, name in zip([input, conv1.weight, out1, conv2.weight, out2], ['input', 'conv1', 'out1', 'conv2', 'out2']):
    print('{}: {}'.format(name, tensor))
    print('{} shape: {}'.format(name, tensor.shape))

运行此命令可获得以下输出:

input: tensor([[[[ 0.,  1.,  2.],
          [ 3.,  4.,  5.],
          [ 6.,  7.,  8.]],

         [[ 9., 10., 11.],
          [12., 13., 14.],
          [15., 16., 17.]]]])
input shape: torch.Size([1, 2, 3, 3])
conv1: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv1 shape: torch.Size([2, 2, 2, 2])
out1: tensor([[[[ 24.,  27.],
          [ 33.,  36.]],

         [[ 96., 108.],
          [132., 144.]]]], grad_fn=<MkldnnConvolutionBackward>)
out1 shape: torch.Size([1, 2, 2, 2])
conv2: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv2 shape: torch.Size([2, 2, 2, 2])
out2: tensor([[[[ 270.]],

         [[1080.]]]], grad_fn=<MkldnnConvolutionBackward>)
out2 shape: torch.Size([1, 2, 1, 1])

请注意,卷积的每个通道如何在所有先前通道的输出上求和。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.