OutputProjectionWrapper与RNN之上的完全连接层

时间:2019-03-22 13:52:33

标签: tensorflow machine-learning deep-learning recurrent-neural-network

我正在阅读使用Scikit-Learn和TensorFlow进行动手机器学习的第14章。它说:

  

尽管使用OutputProjectionWrapper是将RNN输出序列的维数降低到每个时间步长(每个实例)仅一个值的最简单解决方案,但这并不是最有效的方法。有一个更棘手但更有效的解决方案:您可以调整RNN输出的形状,然后应用具有适当输出大小的单个完全连接的层。 [...]这可以大大提高速度,因为只有一层完全连接的层,而不是每个时间步长一层。

这对我来说毫无意义。对于OutputProjectionWrapper,我们需要在每个时间步执行2个操作:

  1. 根据先前的隐藏状态和输入来计算新的隐藏状态。
  2. 通过将密集层应用于计算出的隐藏状态来计算输出。

当然,当我们在顶部使用普通BasicRNNCell +稠密层时,每个时间步(第一个)仅需执行一个操作,但是随后我们需要通过稠密将每个输出张量通过管道传输层。因此,在两种情况下我们都需要执行相同数量的操作。

此外,我无法理解以下部分:

  

这可以大大提高速度,因为只有一层完全连接的层,而不是每个时间步长一层。

在这两种情况下,我们不是只有一个完全连接的层吗?据我了解,OutputProjectionWrapper在每个时间步都使用相同的共享层。我什至不知道它如何为每个时间步创建不同的图层,因为OutputProjectionWrapper没有关于我们将使用的时间步长的信息。

如果有人能解释这些方法之间的区别,我将不胜感激。

UPD 这是该问题的伪代码。我想念什么吗?

# 2 time steps, x1 and x2 - inputs, h1 and h2 - hidden states, y1 and y2 - outputs.

# OutputProjectionWrapper
h1 = calc_hidden(x1, 0)
y1 = dense(h1)
h2 = calc_hidden(x2, h1)
y2 = dense(h2)

# BasicRNNCell + dense layer on top of all time steps
h1 = calc_hidden(x1, 0)
y1 = h1
h2 = calc_hidden(x2, h1)
y2 = h2

y1 = dense(y1)
y2 = dense(y2)

UPD 2 我创建了两个小代码段(一个带有OutputProjectionWrapper,另一个带有BasicRNNCelltf.layers.dense)-都创建了14个变量具有相同的形状。因此,这些方法之间绝对没有内存差异。

2 个答案:

答案 0 :(得分:0)

我的猜测是,由于矩阵乘法优化,将一层应用于形状(x,n)的张量比将同一层应用于形状(x)的张量要快n倍。

答案 1 :(得分:-1)

此网页针对您的问题进行了详细说明。

https://www.oreilly.com/library/view/neural-networks-and/9781492037354/ch04.html

这是上一页的节选。希望这会有所帮助。

尽管使用OutputProjectionWrapper是将RNN输出序列的维数减少到每个时间步长(每个实例)仅一个值的最简单解决方案,但这并不是最有效的。有一个更棘手但更有效的解决方案:您可以将RNN输出的形状从[batch_size,n_steps,n_neurons]重塑为[batch_size * n_steps,n_neurons],然后应用具有适当输出大小的单个完全连接层(在本例中仅为1 ),将导致输出张量的形状为[batch_size * n_steps,n_outputs],然后将该张量整形为[batch_size,n_steps,n_outputs]。这些操作如图4-10所示。