Tensorflow:张量重塑并在某些行的末尾填充零 [英] Tensorflow: Tensor reshape and pad with zeros at the end of some rows

查看:121
本文介绍了Tensorflow:张量重塑并在某些行的末尾填充零的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在 Tensorflow 中重塑张量的方法.我有一个包含行序列的张量.我想对该张量进行整形,以将给定序列的所有行都放在整形张量的单行上.

I am looking for a way to reshape a tensor in Tensorflow. I have a tensor containing sequences of rows. I want to reshape that tensor to have all the rows of a given sequence on a single row in the reshaped tensor.

难点在于序列的长度不同.在下面的例子中,我知道一个序列最多有 3 行.第一个序列为 2 行,第二个序列为 3 行,第三个序列为 1 行.

The difficulty is that sequences are of varying length. In the example hereunder, I know that a sequence is of maximum 3 rows. First sequence is 2 rows, second sequence is 3 rows and third sequence is 1 row.

#Data Tensor
[
[1,1,1],
[2,2,2],
[4,4,4],
[5,5,5],
[6,6,6],
[7,7,7]]

#To be reshaped into
[
[1,1,1,2,2,2,0,0,0],
[4,4,4,5,5,5,6,6,6],
[7,7,7,0,0,0,0,0,0]]

#Argument could be of the form: rows to pad
[1 0 2]

#Or its complementary: sequence length
[2 3 1]

有人知道怎么做吗?

一种方法是在初始张量的正确位置插入一些零行,然后使用简单的 tf.reshape.但我不知道如何插入零行.

One way would be to insert some zeros rows in the initial tensor at the right place and then use a simple tf.reshape. But I don't know how to do this insertion of zeros rows.

另一种方法是在直接重塑时进行.而且我也不知道该怎么做.

Another way would be to do it when reshaping directly. And I also don't know how to do it.

推荐答案

这应该可以,并且易于扩展(例如,使用不同种类的填充等).请让我知道它是否按您的预期工作!

This should do, and be easy to expand (f.e. with different sorts of padding etc). Please let me know if it works as you expected!

import tensorflow as tf

def split_and_pad_tensor(tensor, lengths):
    """
    Input: a rank 2 tensor of shape (A,B) and a collection of indexes that
    sum up to A (otherwise tf.split crashes).
    The tensor is then split in len(lengths) tensors of the given lengths,
    and then each splitted tensor is zero-padded at the right until all have
    B*max(idxs) elements. Output is then a rank 2 tensor of shape
    (len(idxs), B*max(idxs))
    """
    length_result, max_length = len(lengths), max(lengths)
    splitted = tf.split(tensor, lengths, 0)
    # pad's second argument can be seen as [[left, right], [up, down]]
    padded = tf.stack([tf.pad(s, [[0,max_length-l],[0,0]]) for l,s in zip(lengths, splitted)])
    # flatten last two axes:
    return tf.reshape(padded, [length_result, tf.shape(tensor)[1]*max_length])

# make some data and test for different valid inputs:
DATA = tf.constant([[x,x,x] for x in [1,2,4,5,6,7]])
with tf.Session() as sess:
    for lengths in ([4,2], [2,3,1], [2,2,1,1]):
        print sess.run(split_and_pad_tensor(DATA, lengths))

输出:

[[1 1 1 2 2 2 4 4 4 5 5 5]
 [6 6 6 7 7 7 0 0 0 0 0 0]]
[[1 1 1 2 2 2 0 0 0]
 [4 4 4 5 5 5 6 6 6]
 [7 7 7 0 0 0 0 0 0]]
[[1 1 1 2 2 2]
 [4 4 4 5 5 5]
 [6 6 6 0 0 0]
 [7 7 7 0 0 0]]

<小时>

带有占位符的纯 TF 版本:

以下代码与上面的功能相同,但输入是占位符,tf.map_fn + tf.gather 组合用于允许全形动感:


Pure-TF version with placeholders:

The following code has the same functionality as above, but inputs are placeholders, and the tf.map_fn + tf.gather combo is used to allow full shape dynamism:

import tensorflow as tf

class SplitAndPadGraph(object):
    def __init__(self):
        # minimal assumptions on the placeholderes' shapes
        data_ph = tf.placeholder(tf.float32, shape=[None, None])
        lengths_ph = tf.placeholder(tf.int32, shape=[None])
        # extract information about input shapes
        data_len = tf.shape(data_ph)[0]
        out_dim0 = tf.shape(lengths_ph)[0]
        out_dim1 = tf.reduce_max(lengths_ph)
        out_dim2 = tf.shape(data_ph)[-1]
        # create a [[x,y,z], ...] tensor, where x=start_idx, y=length, z=pad_size
        start_idxs = tf.concat([[0], tf.cumsum(lengths_ph)], 0)[:-1]
        pads = tf.fill([out_dim0], out_dim1)-lengths_ph
        reconstruction_metadata = tf.stack([start_idxs, lengths_ph, pads], axis=1)
        # pass the xyz tensor to map_fn to create a tensor with the proper indexes.
        # then gather the indexes from data_ph and reshape
        reconstruction_data = tf.map_fn(lambda x: tf.concat([tf.range(x[0],x[0]+x[1]),
                                                             tf.fill([x[2]], data_len)],
                                                            0), reconstruction_metadata)
        output = tf.gather(tf.concat([data_ph, tf.zeros((1,out_dim2))], 0),
                           tf.reshape(reconstruction_data, [out_dim0*out_dim1]))
        output = tf.reshape(output, [out_dim0, out_dim1*out_dim2])
        # graph interface to access input and output nodes from outside
        self.data_ph = data_ph
        self.lengths_ph = lengths_ph
        self.output = output

DATA = [[x,x,x] for x in [1,2,4,5,6,7]]
g = SplitAndPadGraph()
with tf.Session() as sess:
    for lengths in [[4,2], [2,3,1], [2,2,1,1]]:
        print "lengths =", lengths
        print sess.run(g.output, feed_dict={g.data_ph:DATA, g.lengths_ph:lengths})

干杯!安德烈斯

这篇关于Tensorflow:张量重塑并在某些行的末尾填充零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆