如何在 Tensorflow 中用 None 维度对张量进行切片
How to slice a tensor with None dimension in Tensorflow
我想在 "None" 维度对张量进行切片。
例如,
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() 提供大小参数时,我收到一条消息是一样的。
第二种方法给了我 "Input size (depth of inputs) must be accessible via shape inference" 错误信息。
我想知道这两种方法有什么不同,什么是更像 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)
描述的正是您的问题
问题是 tf.nn.dynamic_rnn
需要知道输入中最后一个维度的大小("depth")。不幸的是,正如问题所指出的,如果在图形构建时任何切片范围不完全已知,目前 tf.slice
无法推断出任何输出大小;因此,sliced_seq
最终具有 (?, ?, ?)
.
的形状
在您的情况下,第一个问题是您使用三个元素的占位符来确定切片的大小;这不是最好的方法,因为最后一个维度永远不会改变(即使您稍后通过 vec_dim
,也可能会导致错误)。最简单的解决方案是将 seq_shape
变成大小为 2 的占位符(或者甚至是两个单独的占位符),然后像这样进行切片:
sliced_seq = seq[:seq_shape[0], :seq_shape[1], :]
出于某种原因,NumPy 风格的索引似乎具有更好的形状推断能力,这将保留 sliced_seq
中最后一个维度的大小。
我想在 "None" 维度对张量进行切片。
例如,
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() 提供大小参数时,我收到一条消息是一样的。
第二种方法给了我 "Input size (depth of inputs) must be accessible via shape inference" 错误信息。
我想知道这两种方法有什么不同,什么是更像 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)
问题是 tf.nn.dynamic_rnn
需要知道输入中最后一个维度的大小("depth")。不幸的是,正如问题所指出的,如果在图形构建时任何切片范围不完全已知,目前 tf.slice
无法推断出任何输出大小;因此,sliced_seq
最终具有 (?, ?, ?)
.
在您的情况下,第一个问题是您使用三个元素的占位符来确定切片的大小;这不是最好的方法,因为最后一个维度永远不会改变(即使您稍后通过 vec_dim
,也可能会导致错误)。最简单的解决方案是将 seq_shape
变成大小为 2 的占位符(或者甚至是两个单独的占位符),然后像这样进行切片:
sliced_seq = seq[:seq_shape[0], :seq_shape[1], :]
出于某种原因,NumPy 风格的索引似乎具有更好的形状推断能力,这将保留 sliced_seq
中最后一个维度的大小。