我正在阅读使用Scikit-Learn和TensorFlow进行动手机器学习的第14章。它说:
尽管使用
OutputProjectionWrapper
是将RNN输出序列的维数降低到每个时间步长(每个实例)仅一个值的最简单解决方案,但这并不是最有效的方法。有一个更棘手但更有效的解决方案:您可以调整RNN输出的形状,然后应用具有适当输出大小的单个完全连接的层。 [...]这可以大大提高速度,因为只有一层完全连接的层,而不是每个时间步长一层。
这对我来说毫无意义。对于OutputProjectionWrapper
,我们需要在每个时间步执行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
,另一个带有BasicRNNCell
和tf.layers.dense
)-都创建了14个变量具有相同的形状。因此,这些方法之间绝对没有内存差异。
答案 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所示。