TensorFlow - 将未知大小张量填充到特定大小?

时间:2017-02-20 00:26:38

标签: tensorflow

有没有办法用特定的垫值将一个可变大小的张量填充到给定的形状?例如,鉴于张量:

[[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文件的示例,其中一部分具有可变长度。对于处理,静态长度使它们更容易使用。

5 个答案:

答案 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)所需的次数 - 列表的长度。希望这有帮助!