具有动态形状的tf.unstack

时间:2017-07-30 19:50:55

标签: tensorflow

我试图取消堆叠Tensor,因为我需要一个序列作为RNN的输入。我使用的是可变序列长度,这使我无法正确使用tf.unstack

def MapToSequences(x):
    # x.get_shape().as_list() = [64, 1, None, 512]
    x = tf.squeeze(x)
    # tf.shape(x) = [None, None, None], at runtime would be [64, seqlen, 512]
    x = tf.transpose(x, perm=[1, 0, 2])
    # [seqlen, 64, 512]
    # Here I'd like to unstack with seqlen as num
    x = tf.unstack(x) # Cannot infer num from shape (?, ?, ?)
    return x

我尝试使用tf.shape(x)推断seqlen并将其用作num,但我得到Expected int for argument 'num' not <tf.Tensor 'strided_slice:0' shape=() dtype=int32>

1 个答案:

答案 0 :(得分:6)

我相信这可以在别处回答,但这里有一个答案。您不能将tf.unstack与不可推断的维度一起使用。 这是因为张量流是如何设计定义张量变换的计算图形的。每个操作都添加一个节点,每个Tensor都是节点之间的边缘。当你tf.unstack张量时,你会产生多个新的张量(边缘)。如果从tf.unstack操作创建的新张量的数量未定义,则计算图具有未定义的边数,这些边不能是。 不向图表添加多个新边的操作允许输入具有推断尺寸的张量(大多数操作)。

为了解决这个问题,对于批量操作的情况有两个选择,例如,当您尝试tf.unstack时,尺寸为(batch_size, ...)batch_size的张量可以推断。

选择1

我会将batch_shape参数用于keras.topology.Input。 生成的权重Tensors总是可以与使用不同batch_size生成的另一个模型互换。

除非你需要访问具有不可推断维度的计算图,否则没有理由不这样做。

选择2

在您知道最大batch_size的情况下,第二个选项是使用tf.dynamic_partition

tensor = tf.placeholder(tf.float32,shape=(None,10))
partitions = tf.range(max_batch_size)
num_partitions = max_batch_size
partitioned = tf.dynamic_partition(tensor, partitions, num_partitions, name='dynamic_unstack')

当您实际提供batch_size时,它会为第一个batch_size索引生成未堆叠的Tesors,为其余的[]生成{{1}}个空张贴。