可分离卷积层的layer.get_weights是什么意思?

问题描述

我了解到我们可以使用函数layer.get_weights()获取图层的权重和偏差。这将返回一个长度为2的列表。图层的权重存储在layer.get_weights()[0],偏差存储在layer.get_weights()[1](如果在定义图层时未禁用偏差)。对于正常的卷积层来说就是这样。

我最近在EfficientDet model中将可分离卷积层用作我的层之一。

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

当我尝试使用相同的layer.get_weights()函数时,它向我返回了length 3的列表,我希望它是2,与上面的相同。 对此,我对列表中的三个值分别感到有些困惑。 任何帮助和建议,将不胜感激。

解决方法

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

这是一个简单的例子。假设我们输入的图像为28x28x3(宽度,高度,#channels),并且应用了正常的2D卷积(假设有16个滤镜和5x5内核,没有跨步/填充)。

如果我们进行计算,则结果为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,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,tf.keras.layers.SeparableConv2D(16,])
model.summary()

给我们

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

我们可以看到,该层的输出形状与普通卷积层完全相同,但是现在我们有了2个内核,它们的参数要少得多。同样,我们可以提取这两个内核的参数,

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

这给了我们

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

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