Keras 密集层输出形状

Posted

技术标签:

【中文标题】Keras 密集层输出形状【英文标题】:Keras Dense layer Output Shape 【发布时间】:2020-08-17 00:42:17 【问题描述】:

我无法理解获取第一个隐藏层的输出形状背后的逻辑。我举了一些随意的例子如下;

示例 1:

model.add(Dense(units=4,activation='linear',input_shape=(784,)))  
model.add(Dense(units=10,activation='softmax'))
model.summary()

Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_7 (Dense)              (None, 4)                 3140      
_________________________________________________________________
dense_8 (Dense)              (None, 10)                50        
=================================================================
Total params: 3,190
Trainable params: 3,190
Non-trainable params: 0

示例 2:

model.add(Dense(units=4,activation='linear',input_shape=(784,1)))   
model.add(Dense(units=10,activation='softmax'))
model.summary()
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_11 (Dense)             (None, 784, 4)            8         
_________________________________________________________________
dense_12 (Dense)             (None, 784, 10)           50        
=================================================================
Total params: 58
Trainable params: 58
Non-trainable params: 0

示例 3:

model.add(Dense(units=4,activation='linear',input_shape=(32,28)))    
model.add(Dense(units=10,activation='softmax'))
model.summary()
Model: "sequential_8"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_15 (Dense)             (None, 32, 4)             116       
_________________________________________________________________
dense_16 (Dense)             (None, 32, 10)            50        
=================================================================
Total params: 166
Trainable params: 166
Non-trainable params: 0

示例 4:

model.add(Dense(units=4,activation='linear',input_shape=(32,28,1)))    
model.add(Dense(units=10,activation='softmax'))
model.summary()
Model: "sequential_9"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_17 (Dense)             (None, 32, 28, 4)         8         
_________________________________________________________________
dense_18 (Dense)             (None, 32, 28, 10)        50        
=================================================================
Total params: 58
Trainable params: 58
Non-trainable params: 0

请帮助我理解逻辑。

另外,我认为input_shape=(784,)input_shape=(784,1) 的等级相同,那么为什么它们的Output Shape 不同?

【问题讨论】:

这个问题已经被here 提出过(不过,措辞不同)。 【参考方案1】:

keras 是一个高级 API,它处理了很多抽象。以下示例可能会帮助您更好地理解。它是您问题中最接近 keras 抽象的原始 tensorflow 等价物:

import tensorflow as tf
from pprint import pprint


for shape in [(None,784,), (None, 784,1), (None, 32,28), (None, 32,28,1)]:
    shapes_list = []

    input_layer_1 = tf.compat.v1.placeholder(dtype=tf.float32, shape=shape, name=None)
    shapes_list.append(input_layer_1.shape)
    d1 = tf.compat.v1.layers.dense(
        inputs=input_layer_1, units=4, activation=None, use_bias=True, kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(), kernel_regularizer=None,
        bias_regularizer=None, activity_regularizer=None, kernel_constraint=None,
        bias_constraint=None, trainable=True, name=None, reuse=None
    )
    shapes_list.append(d1.shape)
    d2 = tf.compat.v1.layers.dense(
        inputs=d1, units=10, activation=tf.compat.v1.nn.softmax, use_bias=True, kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(), kernel_regularizer=None,
        bias_regularizer=None, activity_regularizer=None, kernel_constraint=None,
        bias_constraint=None, trainable=True, name=None, reuse=None
    )
    shapes_list.append(d2.shape)
    print('++++++++++++++++++++++++++')
    pprint(shapes_list)
    print('++++++++++++++++++++++++++')

Dense 函数用于制作密集连接层或Perceptron。

根据您的代码 sn-p,您似乎创建了一个多层感知器(具有线性激活函数 f(x)=x),其中隐藏层 1 有 4 个神经元,输出层为 10 个类/标签定制被预测。

每一层的神经元数量由 units 参数决定。 layer_L中每个神经元的Shape由前一个layer_L-1的输出决定。

如果一个密集层的输入是(BATCH_SIZE, N, l),那么输出的形状就是(BATCH_SIZE, N, value_passed_to_argument_units_in_Dense)

如果输入为(BATCH_SIZE, N, M, l),则输出形状为(BATCH_SIZE, N, M, value_passed_to_argument_units_in_Dense),依此类推。

注意:

这只发生在Dense神经元的情况下,因为它不会改变batch_size和last_channel之间的中间尺寸。

但是,对于像 Conv2D->(Max/Avg)pooling 这样的其他神经元,中间维度可能(取决于传递的参数)也会发生变化,因为这些神经元也作用于这些维度。

【讨论】:

【参考方案2】:

逻辑很简单:致密层独立应用于前一层的最后一个维度。因此,形状为(d1, ..., dn, d) 的输入通过具有m 单元的密集层会导致形状为(d1, ..., dn, m) 的输出,并且该层具有d*m+m 参数(m 偏差)。

请注意,相同的权重是独立应用的,因此您的示例 4 的工作原理如下:

for i in range(32):
    for j in range(28):
        output[i, j, :] = input[i, j, :] @ layer.weights + layer.bias

@ 是矩阵乘法。 input[i, j] 是形状为 (1,) 的向量,layer.weights 的大小为 (1,4)layer.bias(1,) 的向量。

这也解释了为什么(784,)(784,1) 给出不同的结果:它们的最后一个维度是不同的,784 和 1。

【讨论】:

【参考方案3】:

根据 keras

Dense layer is applied on the last axis independently. [1]

https://github.com/keras-team/keras/issues/10736#issuecomment-406589140

第一个例子:

input_shape=(784,)
model.add(Dense(units=4,activation='linear',input_shape=(784,)))

它说输入只有 784 行。模型的第一层有 4 个单元。密集层中的每个单元都连接到所有 784 行。

这就是为什么

Output shape=  (None, 4) 

None 代表 batch_size,这里不知道。

第二个例子

这里输入 2 阶张量

input_shape=(784,1)
Units = 4

所以现在输入是 784 行和 1 列。 现在,密集层的每个单元都连接到总共 784 行中的每个元素中的 1 个元素。 输出形状 =(None, 784, 4) 批量大小无。

第三个例子

 input_shape=(32,28)

现在每个密集层单元都连接到 32 行中的每一个的 28 个元素。所以

output_shape=(None,32,4)

最后一个例子

model.add(Dense(units=4,activation='linear',input_shape=(32,28,1)))   

再次将密集层应用于最后一个轴,输出形状变为

Output Shape =(None,32,28,4)

注意

rank 在 (784,) 处为 1,逗号不代表另一个维度。 排名在 (784,1) 时为 2

stackcoverflow 帖子中的图表可能会对您有所帮助。

【讨论】:

【参考方案4】:

图层的输出形状取决于所使用的图层类型。例如,Dense 层的输出形状基于层中定义的units,而Conv 层的输出形状取决于filters

要记住的另一件事是,默认情况下,任何输入的最后一个维度都被视为通道数。在输出形状估计的过程中,通道数被替换为层中定义的units。对于input_shape=(784,)等一维输入,最后使用,很重要。

示例 1(一维)、示例 2(二维,通道 =1)、示例 3(二维,通道 =28)和示例 4(3 维,通道 =1)。如上所述,最后一个维度由Dense 层中定义的units 替换。

*** 答案中非常清楚地提到了有关尺寸、轴、通道、input_dim 等的更多详细信息。

【讨论】:

【参考方案5】:

根据 Keras 的官方文档,对于密集层,当您将输入作为 input_shape=(input_units,) 时,模态将作为形状 (*, input_units) 的输入数组并输出形状为 (*, output_units) 的数组[在您的情况下为 @987654325 @ 被视为input shape=(*, 784),输出为output_shape=(*,4)]

一般而言,对于(batch_size, ..., input_dim) 的输入维度,模态会给出大小为(batch_size, ..., units) 的输出。

因此,当您将输入作为 input_shape=(784,) 时,模态将作为形状 (*, 784) 的输入数组,其中 * 是批量大小,784 作为 input_dim,输出形状为 (*, 4)

当输入为(784,1)时,模态将其视为(*, 784, 1),其中*是批量大小,784...1是input_dim =>(batch_size, ..., input_dim)并输出为@ 987654342@ => (batch_size, ..., units).

input_shape=(32,28)=>(*,32,28) 也是如此,输出(*,32,4)input_shape=(32,28,1)=>(*,32,28,1) 输入,其中* 是batch_size,32,28...1 是 input_dim =>@987654351 @

None 是什么意思,请查看What is the meaning of the "None" in model.summary of KERAS?

【讨论】:

【参考方案6】:

密集层需要输入为 (batch_size, input_size),大多数时候我们跳过 batch_size 并在训练期间定义它。

如果您的输入形状是一维的,在您的第一种情况下 (784,) 模型将采用形状 (~, 784) 的输入数组和形状 (~,4) 的输出数组。默认情况下,它将添加 4 的偏差(因为 4 个单位)。所以总参数将是

parameters -> 784*4 + 4 = 3140

如果您的输入形状是二维的,则在第二种情况下 (784,1) 模型将采用形状 (784,1) 的输入数组和形状 (None,784,4) 的输出数组。None 是批次维度。默认情况下,它将添加 4 的偏差(因为 4 个单位)。所以总参数将是

parameters -> 4(output units) + 4(bias) = 8

【讨论】:

以上是关于Keras 密集层输出形状的主要内容,如果未能解决你的问题,请参考以下文章

Keras:密集层和激活层之间的形状不匹配

使用 keras ResNet50 模型进行二进制分类的输出层

密集层没有给出预期的输出形状

keras中不兼容的密集层错误

在 Keras 自定义层中连接多个形状为 (None, m) 的 LSTM 输出

合并具有不同输入形状的不同模型的输出