Separable 卷积层的 layer.get_weights() 是什么意思?

What does layer.get_weights() of a Separable convolutional layer means?

我了解到我们可以使用函数layer.get_weights()来获取层的权重和偏差。这将 return 一个长度为 2 的列表。层的权重存储在 layer.get_weights()[0] 中,偏差存储在 layer.get_weights()[1] 中(如果在层定义期间未禁用偏差) .对于普通的卷积层也是如此。

我最近在 EfficientDet model 中使用 Separable 卷积层作为我的层之一。

layers.SeparableConv2D(num_channels, kernel_size=kernel_size, strides=strides, padding='same',
                            use_bias=True, name=str(name)+"/conv")

当我尝试使用相同的 layer.get_weights() 函数时,它 return 给我一个 length 3 的列表,我期望它是 2 是相同的如上所述。 在这里,我对列表中的三个值是什么感到有点困惑。 任何帮助和建议将不胜感激。

SeparableConv2D 层正在计算深度可分离卷积,与普通卷积不同,它需要 2 个内核(2 个权重张量)。无需过多赘述,它使用第一个内核计算深度卷积,应用此操作后,它使用第二个内核计算点向卷积。这背后的主要思想是减少参数的数量,从而减少计算的数量。

这是一个简单的例子。假设我们有 28x28x3(宽度、高度、#channels)的输入图像并且我们应用普通的 2D 卷积(假设 16 个过滤器和 5x5 内核,没有 stride/padding)。

如果我们进行计算,那么我们最终得到 5x5x3x16(5x5 滤波器大小,3 个输入通道和 16 个滤波器)= 1200 个内核参数 + 16 个偏置参数(每个滤波器一个)= 1216。我们可以验证这一点

model = tf.keras.models.Sequential([
    tf.keras.layers.Input(shape=(28, 28, 3)),
    tf.keras.layers.Conv2D(16, (5, 5)),
])
model.summary()

给我们

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 24, 24, 16)        1216

如果我们提取内核参数。

print(model.layers[0].get_weights()[0].shape)

这给了我们

(5, 5, 3, 16)

现在,让我们考虑具有 2 个内核的可分离 2D 卷积,深度内核由每个输入通道的单独 5x5x1 权重矩阵组成,在我们的例子中是 5x5x3(5x5x3x1 - 与 4D keras 张量一致)。这给了我们 75 个参数。

逐点内核是一个简单的 1x1 卷积(它对每个输入点进行操作),用于将结果的深度增加到指定过滤器的数量。在我们的例子中 - 1x1x3x16,它给了我们 48 个参数。

总的来说,第一个内核有 75 个参数,第二个内核有 48 个参数,这给了我们 123 个参数加上 16 个偏置参数。即139个参数。

在喀拉斯,

model = tf.keras.models.Sequential([
    tf.keras.layers.Input(shape=(28, 28, 3)),
    tf.keras.layers.SeparableConv2D(16, (5, 5)),
])
model.summary()

给我们

Layer (type)                 Output Shape              Param #   
=================================================================
separable_conv2d_7 (Separabl (None, 24, 24, 16)        139   

正如我们所见,该层的输出形状与普通卷积层的输出形状完全相同,但现在我们有 2 个参数更少的内核。同样,我们可以提取这两个内核的参数,

print(model.layers[0].get_weights()[0].shape)
print(model.layers[0].get_weights()[1].shape)

这给了我们

(5, 5, 3, 1)
(1, 1, 3, 16)

如果您想了解有关可分离卷积如何工作的更多详细信息,可以阅读 this article