【问题标题】:Dynamic tensor shape for tensorflow RNN张量流 RNN 的动态张量形状
【发布时间】:2016-12-21 17:20:41
【问题描述】:

我正在尝试一个非常简单的 tensorflow RNN 示例。 在那个例子中,我使用了动态 rnn。代码如下:

data = tf.placeholder(tf.float32, [None, 10,1]) #Number of examples, number of input, dimension of each input
target = tf.placeholder(tf.float32, [None, 11])
num_hidden = 24
cell = tf.nn.rnn_cell.LSTMCell(num_hidden,state_is_tuple=True)
val, _ = tf.nn.dynamic_rnn(cell, data, dtype=tf.float32)
val = tf.transpose(val, [1, 0, 2])
last = tf.gather(val, int(val.get_shape()[0]) - 1)
weight = tf.Variable(tf.truncated_normal([num_hidden, int(target.get_shape()[1])]))
bias = tf.Variable(tf.constant(0.1, shape=[target.get_shape()[1]]))
prediction = tf.nn.softmax(tf.matmul(last, weight) + bias)
cross_entropy = -tf.reduce_sum(target * tf.log(tf.clip_by_value(prediction,1e-10,1.0)))
optimizer = tf.train.AdamOptimizer()
minimize = optimizer.minimize(cross_entropy)
mistakes = tf.not_equal(tf.argmax(target, 1), tf.argmax(prediction, 1))
error = tf.reduce_mean(tf.cast(mistakes, tf.float32))

其实代码就是取自这个tutorial。 这个 RNN 网络的输入是一个二进制数序列。每个数字都放入一个数组中。例如,序列的格式为:
[[1],[0],[0],[1],[1],[0],[1],[1],[1],[0]] 输入的形状是 [None,10,1],分别是批量大小、序列大小和嵌入大小。现在因为动态 rnn 可以接受可变输入形状,所以我将代码更改如下:

data = tf.placeholder(tf.float32, [None, None,1])

基本上,我想使用可变长度序列(当然,同一批次中所有序列的长度相同,但批次之间不同)。但是,它会引发错误:

Traceback (most recent call last):
  File "rnn-lstm-variable-length.py", line 48, in <module>
    last = tf.gather(val, int(val.get_shape()[0]) - 1)
TypeError: __int__ returned non-int (type NoneType)

我了解第二个维度是None,不能在get_shape()[0]中使用。但是,我相信必须有办法克服这个问题,因为 RNN 通常接受可变长度输入。 我该怎么做?

【问题讨论】:

  • 查看此blog 帖子。
  • 你确定它们是正确的吗?他们使用sequence = tf.placeholder(tf.float32, [None, max_length, frame_size]),这意味着序列长度是固定的。
  • 出于某种原因,我的印象实际上并不是动态长度,而是填充。

标签: tensorflow recurrent-neural-network


【解决方案1】:

tl;dr:尝试使用tf.batch(..., dynamic_pad=True) 批处理您的数据。


@chris_anderson 的评论是正确的。最终,您的网络需要使用密集的数字矩阵,并且有几种策略可以将可变长度数据转换为超矩形:

  1. 将所有批次填充为固定大小(例如,假设每个输入的最大长度为 500 个项目,并且每个批次中的每个项目都填充为 500)。这种策略没有任何动态性。
  2. 将每个批次的填充应用于批次中最长项目的长度(动态填充)。
  3. 根据长度存储您的输入,并按批次应用填充。这与 #2 相同,但整体填充较少。

您也可以使用other strategies。

要执行此批处理,请使用:

  1. tf.train.batch - 默认没有填充,你需要自己实现。
  2. tf.train.batch(..., dynamic_pad=True)
  3. tf.contrib.training.bucket_by_sequence_length

我怀疑您也对tf.nn.dynamic_rnn 的使用感到困惑。需要注意的是,dynamic_rnn 中的 dynamic 指的是 TensorFlow 展开网络循环部分的方式。在tf.nn.rnn 中,递归是在图中静态完成的(没有内部循环,它在图构建时展开)。然而,在 dynamic_rnn 中,TensorFlow 使用 tf.while_loop 在运行时在图形内部进行迭代。要使用动态填充,您需要使用动态展开,但它不会自动执行。

【讨论】:

  • 我的问题不同。实际上,批次中的每个项目都具有相同的序列长度。但是,该长度是未知的,并且在批次之间有所不同。因此,我无法分配输入数据占位符的形状。如果我使用 [batch_size,None,None],稍后在 tf.gather(val, int(val.get_shape()[0]) - 1) 中,它会抛出错误 TypeError: __int__ returned non-int (type NoneType)
  • 哦,对了,tf.gather 无论如何都需要一个张量,所以你可以使用tf.shape(val) 来获得一个在运行时计算的张量,用于val 的形状 - 例如tf.gather(val, tf.shape(val)[0] - 1).
  • 正确,我试过了,效果很好。如果您用此评论替换答案,我会接受。非常感谢。
  • @lenhhoxung - 完成,我会把它留在这里,以防它帮助其他人。
【解决方案2】:

tf.gather 需要一个张量,因此您可以使用tf.shape(val) 来获得一个张量,在运行时计算,用于val 的形状 - 例如tf.gather(val, tf.shape(val)[0] - 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多