张量流:将零移到末尾

时间:2018-08-17 17:49:10

标签: tensorflow

在张量流中给出张量(数字> = 0)。我需要将所有零移动到每行的末尾,并删除仅包含0的列。 例如

0 2 3 4
0 1 0 5 
2 3 1 0

应转换为

2 3 4
1 5 0
2 3 1

在tensorflow中有什么不错的方法吗?顺便说一句,非零元素的顺序应该相同(不排序)。

3 个答案:

答案 0 :(得分:1)

下面的代码可以解决问题,尽管我敢肯定会有更优雅的解决方案,但我很想看到这些解决方案。令人讨厌的部分是每行有不同数量的零。

a = tf.constant([[0, 2, 3, 4],[0, 1, 0, 5],[2, 3, 1, 0]])

boolean_mask = tf.logical_not(tf.equal(a, tf.zeros_like(a)))

# all the non-zero values in a flat tensor
non_zero_values = tf.gather_nd(a, tf.where(boolean_mask))
# number of non-zero values in each row
n_non_zero = tf.reduce_sum(tf.cast(boolean_mask, tf.int64), axis=-1)
# max number of non-zeros -> this will be the padding length
max_non_zero = tf.reduce_max(n_non_zero).numpy() 

(这很难看)

# Split the tensor into flat tensors with the non-zero values of each row
rows = tf.split(non_zero_values, n_non_zero)

# Pad with zeros wherever necessary and recombine into a single tensor
tf.stack([tf.pad(r, paddings=[[0, max_non_zero - r.get_shape().as_list()[0]]]) for r in rows])

产生所需的结果:

<tf.Tensor: id=49, shape=(3, 3), dtype=int32, numpy=
array([[2, 3, 4],
       [1, 5, 0],
       [2, 3, 1]], dtype=int32)>

答案 1 :(得分:0)

参差不齐的张量方法

最好的方法

def rm_zeros(pred):
    pred = tf.cast(pred, tf.float32)
    # num_non_zero element in every row
    num_non_zero = tf.count_nonzero(pred, -1)  #[3 2 3]
    # flat input and remove all zeros
    flat_pred = tf.reshape(pred, [-1])
    mask = tf.math.logical_not(tf.equal(flat_pred, tf.zeros_like(flat_pred)))
    flat_pred_without_zero = tf.boolean_mask(flat_pred, mask) #[2. 3. 4. 1. 5. 2. 3. 1.]       
    # create a ragged tensor and change it to tensor, rows will be padded to max length 
    ragged_pred = tf.RaggedTensor.from_row_lengths(values=flat_pred_without_zero, row_lengths=num_non_zero)
    paded_pred = ragged_pred.to_tensor(default_value=0.)
    return paded_pred

a = tf.constant([[0, 2, 3, 4],[0, 1, 0, 5],[2, 3, 1, 0]])
print(rm_zeros(a))

输出

tf.Tensor(
[[2. 3. 4.]
 [1. 5. 0.]
 [1. 2. 3.]], shape=(3, 3), dtype=float32)

排序方法

如果您不介意对原始数据进行排序,则以下代码可能会有所帮助。虽然这不是最佳解决方案。

这里的想法是
1.将所有零更改为无穷大
2.对张量进行排序
3.将所有无穷变回零
4.切片张量以获得最小的填充

def rm_zeros_sorted(input):
    input = tf.cast(input, tf.float32)

    # 1. change all zeros to infinity  
    zero_to_inf = tf.where(tf.equal(input, tf.zeros_like(input)), np.inf*tf.ones_like(input), input)

    # 2. sort the tensor  
    input_sorted = tf.sort(zero_to_inf, axis=-1, direction='ASCENDING')

    # 3. change all infinity back to zeros  
    inf_to_zero = tf.where(tf.math.is_inf(input_sorted), tf.zeros_like(input_sorted), input_sorted)

    # 4. slice the tensor to get minimal padding
    num_non_zero = tf.count_nonzero(inf_to_zero, -1)  
    max_non_zero = tf.reduce_max(num_non_zero)
    remove_useless_zero = inf_to_zero[..., 0:max_non_zero]
    return remove_useless_zero

a = tf.constant([[0, 2, 3, 4],[0, 1, 0, 5],[2, 3, 1, 0]])
print(rm_zeros_sorted(a))

输出

tf.Tensor(
[[2. 3. 4.]
 [1. 5. 0.]
 [1. 2. 3.]], shape=(3, 3), dtype=float32)

答案 2 :(得分:0)

def shift_zeros(data, mask):
    data_flat = tf.boolean_mask(data, mask)
    nonzero_lens = tf.reduce_sum(tf.cast(mask, dtype=tf.int32), axis=-1)
    nonzero_mask = tf.sequence_mask(nonzero_lens, maxlen=tf.shape(mask)[-1])
    nonzero_data = tf.scatter_nd(tf.cast(tf.where(nonzero_mask), dtype=tf.int32), data_flat, shape=tf.shape(data))
    return nonzero_data