如何在 Tensorflow 中对无维度的张量进行切片

Posted

技术标签:

【中文标题】如何在 Tensorflow 中对无维度的张量进行切片【英文标题】:How to slice a tensor with None dimension in Tensorflow 【发布时间】:2018-02-24 13:51:29 【问题描述】:

我想在“无”维度切张量。

例如,

tensor = tf.placeholder(tf.float32, shape=[None, None, 10], name="seq_holder")
sliced_tensor = tensor[:,1:,:] # it works well!

但是

# Assume that tensor's shape will be [3,10, 10]
tensor = tf.placeholder(tf.float32, shape=[None, None, 10], name="seq_holder")
sliced_seq = tf.slice(tensor, [0,1,0],[3, 9, 10]) # it doens't work!

当我使用另一个 place_holder 为 tf.slice() 提供大小参数时,我收到一条消息也是一样的。

第二种方法给了我“输入大小(输入深度)必须可以通过形状推断访问”错误消息。

我想知道这两种方法有什么不同,什么是更类似于 tensorflow 的方式。

[已编辑] 整个代码如下

import tensorflow as tf
import numpy as np

print("Tensorflow for tests!")

vec_dim = 5
num_hidden = 10
# method 1
input_seq1 = np.random.random([3,7,vec_dim])

# method 2
input_seq2 = np.random.random([5,10,vec_dim])
shape_seq2 = [5,9,vec_dim]
# seq: [batch, seq_len]
seq = tf.placeholder(tf.float32, shape=[None, None, vec_dim], name="seq_holder")

# Method 1
sliced_seq = seq[:,1:,:]

# Method 2
seq_shape = tf.placeholder(tf.int32, shape=[3])
sliced_seq = tf.slice(seq,[0,0,0], seq_shape)

cell = tf.contrib.rnn.GRUCell(num_units=num_hidden)
init_state = cell.zero_state(tf.shape(seq)[0], tf.float32)

outputs, last_state = tf.nn.dynamic_rnn(cell, sliced_seq, initial_state=init_state)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    # method 1
    # states = sess.run([sliced_seq], feed_dict=seq:input_seq1)
    # print(states[0].shape)

    # method 2
    states = sess.run([sliced_seq], feed_dict=seq:input_seq2, seq_shape:shape_seq2)
    print(states[0].shape)

【问题讨论】:

当您定义操作(运行这两行时)或尝试执行操作(例如,在会话中调用.run)时,您是否收到错误?我运行这两条指令没有问题。 将切片张量(第二种方法)放入动态 rnn 函数时出现错误。是不是dynamic_rnn的问题? 嗯,很难说...您可以编辑您的问题并添加更多详细信息,也许是您的问题出现的完整最小可重复示例? 我编辑了我的问题。现在有2种切片。谢谢:) 【参考方案1】:

issue #4590 准确描述了您的问题

问题在于tf.nn.dynamic_rnn 需要知道输入中最后一个维度的大小(“深度”)。不幸的是,正如问题所指出的,如果任何切片范围在图形构建时不完全已知,目前tf.slice 无法推断任何输出大小;因此,sliced_seq 最终的形状为 (?, ?, ?)

在您的情况下,第一个问题是您使用三个元素的占位符来确定切片的大小;这不是最好的方法,因为最后一个维度永远不会改变(即使您稍后通过vec_dim,它也可能导致错误)。最简单的解决方案是将seq_shape 变成大小为 2 的占位符(甚至是两个单独的占位符),然后像这样进行切片:

sliced_seq = seq[:seq_shape[0], :seq_shape[1], :]

由于某种原因,NumPy 风格的索引似乎具有更好的形状推断能力,这将保留 sliced_seq 中最后一个维度的大小。

【讨论】:

我明白了 :) 感谢您的详细解释!

以上是关于如何在 Tensorflow 中对无维度的张量进行切片的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Keras / Tensorflow 中将(无,)批量维度重新引入张量?

如何在图构建时获取张量的维度(在 TensorFlow 中)?

tensorflow之张量扩张Broadcasting合并分割

在 Tensorflow 中删除张量的维度

如何在 TensorFlow 中对批次进行切片并在每个切片上应用操作

如何在 TensorFlow 中交换张量轴?