使用Tensorflow找到连续1的最大数量

3
我已经在Matlab中找到了解决方案: https://uk.mathworks.com/matlabcentral/answers/85143-find-maximum-number-of-consecutive-negative-values 在Numpy中也有类似的解决方案: Find consecutive ones in numpy array 但是在Tensorflow中没有找到相应的解决方案。最接近的问题是这个: Reduce sum with condition in tensorflow 然而,它只计算第一组连续的数字,而不是找到最大的一组。基本上,如果有一个Tensorflow等效于Matlab的RCUMSUMC,那么问题就很容易解决了。

https://uk.mathworks.com/matlabcentral/fileexchange/28685-rcumsumc

我的输入是一个形状为NxHxW的二进制张量,期望的输出是NxW,其中每一列代表连续1的最大数量:

Input = [[1,1,0,0,1,0,1,1,1,1,0,0,1],
         [1,0,0,1,1,1,1,1,1,0,0,1,0],
         [0,0,0,1,1,1,0,0,1,0,1,1,0]]

Output = [4,6,3]


你能提供一个简单的输入和期望的输出示例吗? - thushv89
输入:Hello World!输出:你好,世界! - metalruka
2个回答

1

好的,这有点复杂。但是构思它很有趣。(在TF 2.0和TF 1.15上进行了测试)

# Let's assume a simpler example for demonstration [0, 1, 1, 1, 0, 1]
tf_a = tf.constant([[1,1,0,0,1,0,1,1,1,1,0,0,1],
         [1,0,0,1,1,1,1,1,1,0,0,1,0],
         [0,0,0,1,1,1,0,0,1,0,1,1,0]])

# You get the cumsum [0, 1, 2, 3, 3, 4]
tf_a_sum = tf.cumsum(tf_a, axis=1)
# You get the range  [0, 1, 2, 3, 4, 5]
tf_range = tf.range(tf_a.shape[1])

# You get the difference [0, 0, 0, 0, 1, 1]
tf_diff = tf_range - tf_a_sum
# To make sure it's starting with 0
tf_diff = tf_diff - tf.reduce_min(tf_diff, axis=1, keepdims=True)

# Now comes the tricky bit. We are using segment_sum
# I would have liked to achieve this with tf.map_fn but segment_sum didn't play nicely with map_fn
# So we are first unstacking the arrays on rows
# Applying segment_sum to individual rows
# And restacking them

tf_list_diff = tf.unstack(tf_diff)
tf_list_a = tf.unstack(tf_a)

# [0, 1, 1, 1, 0, 1] => summing segment-wise with [0, 0, 0, 0, 1, 1]
# Gives [3,1]
# And you get max of that which is 3
tf_res = tf.stack([tf.reduce_max(tf.math.segment_sum(a, diff)) for a, diff in zip(tf_list_a, tf_list_diff)])
警告: 只有在您想要获取一个只包含0和1的数组中1的数量时,此方法才有效。如果数组中有其他数字,则此方法将无效。因此,此解决方法非常特定于您想要解决的问题。

1

编辑:以下是如何在三维张量上搜索第二个维度中的一组1的方法:

import tensorflow as tf

inp = tf.random.stateless_uniform((3, 4, 5), [0, 0], 0, 2, tf.int32)
tf.print(inp)
# [[[0 1 0 0 0]
#   [0 0 0 1 1]
#   [0 1 1 0 0]
#   [0 0 0 0 0]]
# 
#  [[1 1 0 0 0]
#   [0 1 1 0 0]
#   [0 1 0 1 0]
#   [0 0 0 0 0]]
# 
#  [[1 1 1 0 0]
#   [0 0 1 1 1]
#   [0 1 1 0 1]
#   [0 1 0 0 0]]]
# Pad with ones to avoid all-zeros
inp = tf.pad(inp, [(0, 1), (0, 0), (0, 0)], constant_values=1)
s = tf.shape(inp)
# Transpose and reshape
inp_t = tf.reshape(tf.transpose(inp, [0, 2, 1]), [-1, s[1]])
# Surround with zeros
inp_t = tf.pad(inp_t, [(0, 0), (1, 1)])
# Find bounds of groups of ones
groups = tf.reshape(tf.where(tf.not_equal(inp_t[:, 1:], inp_t[:, :-1])), [-1, 2, 2])
# Compute group sizes
group_sizes = groups[:, 1, 1] - groups[:, 0, 1]
# Find maximum group sizes
max_ones_group = tf.math.segment_max(group_sizes, groups[:, 0, 0], name=None)
# Reshape back
out = tf.reshape(max_ones_group, [s[0], s[2]])[:-1]
tf.print(out)
# [[0 1 1 1 1]
#  [1 3 1 1 0]
#  [1 2 3 1 2]]

假设输入是一个二进制张量(只有0和1),以下是一种实现方法:

import tensorflow as tf

inp = tf.constant([[1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1],
                   [1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0],
                   [0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0]])
# Surround with zeros
inp = tf.pad(inp, [(0, 0), (1, 1)])
# Find bounds of groups of ones
groups = tf.reshape(tf.where(tf.not_equal(inp[:, 1:], inp[:, :-1])), [-1, 2, 2])
# Compute group sizes
group_sizes = groups[:, 1, 1] - groups[:, 0, 1]
# Find maximum group sizes
max_ones_group = tf.math.segment_max(group_sizes, groups[:, 0, 0], name=None)
tf.print(max_ones_group)
# [4 6 3]

它适用于N=1,但如果我们有许多样本呢?对于形状为NxHxW的输入,输出需要是NxW。 - metalruka
@metalruka 我添加了一个带有3D张量的示例。 - jdehesa
1
只是一点小提示,如果输入数组中没有1,则此方法会失败。在输入数组的顶部填充一个单独的行1是一个简单的解决方法。 - metalruka
@metalruka 你说得对,感谢反馈。是的,我认为填充是最简单的解决方案,我已经更新了答案。 - jdehesa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接