我在找到了解决方法
脾气暴躁:Find consecutive ones in numpy array
但不在Tensorflow中。我发现的最接近的问题是: Reduce sum with condition in tensorflow
但是,这仅计算第一组,而不是查找最大的一组。基本上,如果存在与Matlab的RCUMSUMC相当的Tensorflow,则可以轻松解决该问题
https://uk.mathworks.com/matlabcentral/fileexchange/28685-rcumsumc
我的输入是一个NxHxW形状的二进制张量,并且输出应该是NxW,其中每一列代表连续的最大张数:
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]
答案 0 :(得分: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)
编辑:这是您可以对3维张量执行相同操作的方法,以在第二维上搜索一组张量:
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]]
假设输入是二进制张量(只有零和一),这是一种实现方法:
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]