【问题标题】:时间分布(密集)与 Keras 中的密集 - 相同数量的参数
【发布时间】:2017-11-20 12:22:18
【问题描述】:

我正在构建一个模型,该模型使用循环层 (GRU) 将一个字符串转换为另一个字符串。我已经尝试将 Dense 和 TimeDistributed(Dense) 层作为最后一层,但我不明白使用 return_sequences=True 时两者之间的区别,特别是因为它们似乎具有相同数量的参数.

我的简化模型如下:

InputSize = 15
MaxLen = 64
HiddenSize = 16

inputs = keras.layers.Input(shape=(MaxLen, InputSize))
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs)
x = keras.layers.TimeDistributed(keras.layers.Dense(InputSize))(x)
predictions = keras.layers.Activation('softmax')(x)

网络总结是:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 64, 15)            0         
_________________________________________________________________
gru_1 (GRU)                  (None, 64, 16)            1536      
_________________________________________________________________
time_distributed_1 (TimeDist (None, 64, 15)            255       
_________________________________________________________________
activation_1 (Activation)    (None, 64, 15)            0         
=================================================================

这对我来说很有意义,因为我对 TimeDistributed 的理解是它在所有时间点应用相同的层,因此 Dense 层有 16*15+15=255 个参数(权重+偏差)。

但是,如果我切换到一个简单的 Dense 层:

inputs = keras.layers.Input(shape=(MaxLen, InputSize))
x = keras.layers.recurrent.GRU(HiddenSize, return_sequences=True)(inputs)
x = keras.layers.Dense(InputSize)(x)
predictions = keras.layers.Activation('softmax')(x)

我仍然只有 255 个参数:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 64, 15)            0         
_________________________________________________________________
gru_1 (GRU)                  (None, 64, 16)            1536      
_________________________________________________________________
dense_1 (Dense)              (None, 64, 15)            255       
_________________________________________________________________
activation_1 (Activation)    (None, 64, 15)            0         
=================================================================

我想知道这是否是因为 Dense() 只会使用形状中的最后一个维度,并且有效地将其他所有内容视为类似批处理的维度。但是后来我不再确定 Dense 和 TimeDistributed(Dense) 之间有什么区别。

更新看看https://github.com/fchollet/keras/blob/master/keras/layers/core.py,Dense 似乎只使用最后一个维度来调整自身大小:

def build(self, input_shape):
    assert len(input_shape) >= 2
    input_dim = input_shape[-1]

    self.kernel = self.add_weight(shape=(input_dim, self.units),

它还使用 keras.dot 来应用权重:

def call(self, inputs):
    output = K.dot(inputs, self.kernel)

keras.dot 的文档暗示它在 n 维张量上运行良好。我想知道它的确切行为是否意味着 Dense() 实际上会在每个时间步被调用。如果是这样,问题仍然是 TimeDistributed() 在这种情况下实现了什么。

【问题讨论】:

  • 让我补充一点,这两个模型在训练期间的表现几乎完全相同。
  • 我也一直在想。因此,您确认 Dense() 和 TimeDistributed(Dense()) 在您的情况下具有相同的性能?我认为更好的 API 设计是允许用户设置一个参数,无论是在时间步长上使用相同的 Dense 层还是在每个时间步长上使用单独的 Dense 层。
  • 在您的情况下,根据您的更新, Dense 和 Timedistributed(Dense) 具有相同的结果(更新查看 github.com/fchollet/keras/blob/master/keras/layers/core.py 似乎 Dense 仅使用最后一个维度来调整自身大小)。跨度>

标签: machine-learning neural-network keras recurrent-neural-network keras-layer


【解决方案1】:

TimeDistributedDense 在 GRU/LSTM 单元展开期间对每个时间步应用相同的密集。因此误差函数将介于预测的标签序列和实际的标签序列之间。 (这通常是序列到序列标记问题的要求)。

但是,对于return_sequences=FalseDense 层仅在最后一个单元格应用一次。当 RNN 用于分类问题时,通常会出现这种情况。如果return_sequences=TrueDense 层应用于每个时间步,就像TimeDistributedDense 一样。

因此,根据您的模型,两者都是相同的,但是如果您将第二个模型更改为 return_sequences=False,则 Dense 将仅应用于最后一个单元格。尝试更改它,模型将抛出错误,因为Y 的大小将是[Batch_size, InputSize],它不再是序列到序列,而是一个完整的序列到标签问题。

from keras.models import Sequential
from keras.layers import Dense, Activation, TimeDistributed
from keras.layers.recurrent import GRU
import numpy as np

InputSize = 15
MaxLen = 64
HiddenSize = 16

OutputSize = 8
n_samples = 1000

model1 = Sequential()
model1.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize)))
model1.add(TimeDistributed(Dense(OutputSize)))
model1.add(Activation('softmax'))
model1.compile(loss='categorical_crossentropy', optimizer='rmsprop')


model2 = Sequential()
model2.add(GRU(HiddenSize, return_sequences=True, input_shape=(MaxLen, InputSize)))
model2.add(Dense(OutputSize))
model2.add(Activation('softmax'))
model2.compile(loss='categorical_crossentropy', optimizer='rmsprop')

model3 = Sequential()
model3.add(GRU(HiddenSize, return_sequences=False, input_shape=(MaxLen, InputSize)))
model3.add(Dense(OutputSize))
model3.add(Activation('softmax'))
model3.compile(loss='categorical_crossentropy', optimizer='rmsprop')

X = np.random.random([n_samples,MaxLen,InputSize])
Y1 = np.random.random([n_samples,MaxLen,OutputSize])
Y2 = np.random.random([n_samples, OutputSize])

model1.fit(X, Y1, batch_size=128, nb_epoch=1)
model2.fit(X, Y1, batch_size=128, nb_epoch=1)
model3.fit(X, Y2, batch_size=128, nb_epoch=1)

print(model1.summary())
print(model2.summary())
print(model3.summary())

在上述架构示例中,model1model2 是样本(序列到序列模型),model3 是完整序列到标签模型。

【讨论】:

  • 感谢您的回答。我不确定我是否可以遵循,因为我知道这两种情况下的输出都是一个序列。在这两种情况下,循环层的 return_sequences=True,两种情况下的输出形状都是 3D 并且完全相同(batch_size, 64, 15)。所以在我看来,密集层也适用于每个时间步。
  • 我已经用更好的解释更新了我的答案,希望对你有所帮助。
  • 谢谢。为免生疑问,当您说“因此,根据您的模型,两者都是相同的,但是如果您将第二个模型更改为“return_sequences = True”,则密集将仅应用于最后一个单元格。” - 你的意思是如果我将return_sequences 更改为False?您的回答似乎暗示如果 return_sequences 为 True,则 Dense() 和 TimeDistributed(Dense()) 做同样的事情。你能证实这一点吗?这是有道理的,但是为什么 Keras 需要 TimeDistributed() 呢?
  • 再次感谢。是的,我同意其他图层类型需要 TimeDistributed() 。在我看来,在返回序列的循环层之后的简单 Dense() 确实有效,但更多的是偶然而不是设计。从旧的 Keras 示例中,我认为曾经有一个 TimeDistributedDense() - 如果 Dense() 无论如何都可以工作,为什么需要它对我来说仍然是个谜。
  • 嗨@thon,我得出了同样的结论。这也很奇怪,因为如果> 2,Dense() 应该将输入尺寸展平,如文档中所引用:“注意:如果图层的输入等级大于 2,那么它会在初始点积之前展平与内核”。你找到答案了吗?
【解决方案2】:

这是一段验证TimeDistirbuted(Dense(X))Dense(X) 相同的代码:

import numpy as np 
from keras.layers import Dense, TimeDistributed
import tensorflow as tf

X = np.array([ [[1, 2, 3],
                [4, 5, 6],
                [7, 8, 9],
                [10, 11, 12]
               ],
               [[3, 1, 7],
                [8, 2, 5],
                [11, 10, 4],
                [9, 6, 12]
               ]
              ]).astype(np.float32)
print(X.shape)

(2, 4, 3)

dense_weights = np.array([[0.1, 0.2, 0.3, 0.4, 0.5],
                          [0.2, 0.7, 0.9, 0.1, 0.2],
                          [0.1, 0.8, 0.6, 0.2, 0.4]])
bias = np.array([0.1, 0.3, 0.7, 0.8, 0.4])
print(dense_weights.shape)

(3, 5)

dense = Dense(input_dim=3, units=5, weights=[dense_weights, bias])
input_tensor = tf.Variable(X, name='inputX')
output_tensor1 = dense(input_tensor)
output_tensor2 = TimeDistributed(dense)(input_tensor)
print(output_tensor1.shape)
print(output_tensor2.shape)

(2, 4, 5)

(2, ?, 5)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    output1 = sess.run(output_tensor1)
    output2 = sess.run(output_tensor2)

print(output1 - output2)

而不同的是:

[[[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]

 [[0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]
  [0. 0. 0. 0. 0.]]]

【讨论】:

  • 这是错误的;会话图结果不等同于完整模型图结果 - 后者涉及梯度和权重更新。来自documentation“如果层的输入具有大于 2 的等级,则它在与内核的初始点积之前被展平” - 对比 TimeDistributedDense,它不会展平. Counterexample code
猜你喜欢
  • 1970-01-01
  • 2017-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 2019-11-14
  • 2021-07-20
相关资源
最近更新 更多