TensorFlow -将未知尺寸Tensor填充为特定尺寸?

pvcm50d1  于 2023-03-19  发布在  其他
关注(0)|答案(4)|浏览(259)

有没有办法用一个特定的填充值把一个可变大小的Tensor填充到一个给定的形状上?例如给定的Tensor:

[[1, 2],
 [3, 4]]

以及

[[1, 2, 3],
 [4, 5, 6]]

有没有一种方法可以有一个泛型操作,它可以取其中的一个,然后用一个值填充它们(比如,用值-1来整形[2, 4]),从而得到:

[[1, 2, -1, -1],
 [3, 4, -1, -1]]

以及

[[1, 2, 3, -1],
 [4, 5, 6, -1]]

我的推理(如果有更好的解决方案)是,我有来自TFRecords文件的示例,其中一部分具有可变长度。对于处理,静态长度使它们更容易处理。

pokxtpni

pokxtpni1#

是的,有,只要你不需要改变Tensor的秩,这是非常简单的。
tf.pad()接受带Tensor的常规python列表,填充的格式是一个在维度的每一侧填充多少的对列表。
例如:

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):
    diff = max_in_dims - tf.shape(t)
    paddings = tf.pad(diff[:, None], [[0, 0], [1, 0]])
    return tf.pad(t, paddings, 'CONSTANT', constant_values=constant_values)
# (note: see edits for the solution referred to by other answers on this question)

其中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具有相同数量的元素。

qco9c6ql

qco9c6ql2#

Multihunter's solution的一种扩展,以便仅在必要时执行填充,并且对于较长的输入不产生错误:
假设我们有一个序列输入inp_seq,它是一个秩为4的Tensor,应该被填充,以便在维度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)
jm2pwxwz

jm2pwxwz3#

我遇到了类似的情况。不完全通用,但你可以这样做:

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]]
vjrehmav

vjrehmav4#

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)

相关问题