有没有办法用特定的垫值将一个可变大小的张量填充到给定的形状?例如,鉴于张量:
[[1, 2],
[3, 4]]
和
[[1, 2, 3],
[4, 5, 6]]
有没有办法让一个通用的操作可以接受并用一个值填充它们(比如,用值[2, 4]
来塑造-1
)导致:
[[1, 2, -1, -1],
[3, 4, -1, -1]]
和
[[1, 2, 3, -1],
[4, 5, 6, -1]]
分别?我的推理(如果有更好的解决方案)是我有TFRecords文件的示例,其中一部分具有可变长度。对于处理,静态长度使它们更容易使用。
答案 0 :(得分:12)
是。有。如果你不需要改变张量的等级,那很简单。
tf.pad()
接受带有张量的常规python列表。填充的格式是在该维度的每一侧填充多少对的列表。
e.g。
t = tf.constant([[1, 2], [3, 4]])
paddings = [[0, 0], [0, 4-tf.shape(t)[0]]]
out = tf.pad(t, paddings, 'CONSTANT', constant_values=-1)
sess.run(out)
# gives:
# array([[ 1, 2, -1, -1],
# [ 3, 4, -1, -1]], dtype=int32)
如果您想将其概括为有用的功能,您可以执行以下操作:
def pad_up_to(t, max_in_dims, constant_values):
s = tf.shape(t)
paddings = [[0, m-s[i]] for (i,m) in enumerate(max_in_dims)]
return tf.pad(t, paddings, 'CONSTANT', constant_values=constant_values)
其中max_in_dims
基本上是所需的输出形状。 注意:如果您在任何维度上提供的图形严格小于t
,则此函数将失败。
您可以像以下一样使用它:
t = tf.constant([[1, 2], [3, 4]]) # shape = [2, 2]
t_padded = pad_up_to(t, [2, 4], -1) # shape = [2, 4], padded with -1s
或
t = tf.placeholder(tf.float32, [None, None]) # shape = [?, ?]
t_padded = pad_up_to(t, [5,5], -1) # shape = [5, 5], padded with -1s
t_np = np.random.uniform(0, 1, [3,4]) # shape = [3,4], no padding
t_padded_out = sess.run(t_padded, {t: t_np})
t_np2 = np.random.uniform(0, 1, [2,1]) # shape = [2,1], no padding
t_padded_out2 = sess.run(t_padded, {t: t_np2})
尽管尺寸大小是动态计算的,但尺寸数不是,因此请确保max_in_dims
与t.shape具有相同数量的元素。
答案 1 :(得分:2)
扩展Multihunter's solution,以便仅在必要时执行填充,而对于较长的输入不会产生错误:
假设我们有一个称为inp_seq
的顺序输入,它是第4级的张量,应进行填充以使维度1的最小长度为filter_size
。
def dynamic_padding(inp, min_size):
pad_size = min_size - tf.shape(inp)[1]
paddings = [[0, 0], [0, pad_size], [0, 0], [0, 0]] # assign here, during graph execution
return tf.pad(inp, paddings)
# Pad only if necessary
padded = tf.cond(tf.less(tf.shape(inp_seq)[1], filter_size), true_fn=lambda: dynamic_padding(inp_seq, filter_size), false_fn=lambda: inp_seq)
答案 2 :(得分:1)
test_a = tf.constant([[1, 2], [3, 4]])
test_b = tf.constant([[1, 2, 3], [4, 5, 6]])
def pad_second_dim(input, desired_size):
padding = tf.tile([[0]], tf.stack([tf.shape(input)[0], desired_size - tf.shape(input)[1]], 0))
return tf.concat([input, padding], 1)
with tf.Session() as sess:
print sess.run(pad_second_dim(test_a, 4))
# [[1 2 0 0] [3 4 0 0]]
print sess.run(pad_second_dim(test_b, 4))
# [[1 2 3 0] [4 5 6 0]]
答案 3 :(得分:0)
The accepted answer也不适合我,我也不愿意做assignments in the graph。在这里,我调整了Multihunter的答案,使其可以在可变大小下工作。对此的变化对我有用。具体来说,我正在使用tf.data.TFREcordDataset
使用数据,并希望在加载时应用填充,而不是写出预先填充的数据。
MIN_SIZE = 100
# v shape is undefined on the second dimension.
v = tf.get_variable(shape=(2, None), dtype=tf.int32)
# Note: this will blow up if `padding_len` < 0
padding_len = MIN_SIZE - tf.shape(v)[-1]
# paddings = [ [0, 0], [0, padding_len] ]
paddings = tf.concat( ([[0, 0]], [[0, padding_len ]]), axis=0)
# padded.shape = (2, 100)
padded = tf.pad(t, paddings, 'CONSTANT', constant_values=-1)
答案 4 :(得分:-1)
TensorFlow无法执行此操作。您必须预处理数据并添加一组-1以获得所需的长度。例如,您获得长度并循环list[0].append(-1)
和list[1].append(-1)
所需的次数 - 列表的长度。希望这有帮助!