TensorFlow - return 多维张量的不同子张量

TensorFlow - return distinct sub-tensors of multidimensional tensor

在 TensorFlow 中,tf.unique 函数可用于 return 一维 Tensor 的不同元素。我怎样才能得到不同的子 Tensor 沿着更高维 Tensor 的轴 0?例如,给定以下 Tensor,所需的 distinct 函数将 return 指定的结果:

input = tf.constant([
    [0,3],
    [0,1],
    [0,4],
    [0,1],
    [1,5],
    [3,9],
    [3,2],
    [3,6],
    [3,5],
    [3,3]])

distinct(input) == tf.constant([
    [0,3],
    [0,1],
    [0,4],
    [1,5],
    [3,9],
    [3,2],
    [3,6],
    [3,5],
    [3,3]])

如何为任意维数的 Tensor 生成不同的多维元素?

一种方法是寻找前一个子 Tensor 沿轴 0 相等的元素,然后将其过滤掉:

  1. 使用 tf.equal 获取输入的各个轴 -1 元素沿轴 0 与自身交叉的成对相等性。
  2. 使用 tf.math.reduce_all 聚合成对等式,直到您拥有输入的轴 0 元素的二维等式矩阵。
  3. 生成一个 upper-triangular 假值矩阵
  4. 使用该三角矩阵将我们的相等性比较限制在沿轴 0 的一个方向上。
  5. tf.reduce_any找哪个轴0元素等于后面的任何元素;它们是将被删除的重复项。
  6. 使用tf.math.logical_nottf.boolean_mask仅获取轴0的non-duplicate个元素。

此过程在以下 Python 代码中实现,已在 TensorFlow 2.0 beta 中测试:

def distinct(input:tf.Tensor) -> tf.Tensor:
    """Returns only the distinct sub-Tensors along the 0th dimension of the provided Tensor"""
    is_equal = tf.equal(input[:,tf.newaxis], input[tf.newaxis,:])
    while len(is_equal.shape) > 2:
        is_equal = tf.math.reduce_all(is_equal, axis=2)
    all_true = tf.constant(True, shape=is_equal.shape)
    true_upper_tri = tf.linalg.band_part(all_true, 0, -1)
    false_upper_tri = tf.math.logical_not(true_upper_tri)
    is_equal_one_way = tf.math.logical_and(is_equal, false_upper_tri)
    is_duplicate = tf.reduce_any(is_equal_one_way, axis=1)
    is_distinct = tf.math.logical_not(is_duplicate)
    distinct_elements = tf.boolean_mask(input, is_distinct, 0)
    return distinct_elements

不保留顺序

您可以使用 tf.py_function 并调用 np.unique 到 return 个沿 axis=0 的唯一多维张量。请注意,这会找到唯一行但不会保留顺序。

def distinct(a):
    _a =  np.unique(a, axis=0)
    return _a

>> input = tf.constant([
[0,3],
[0,1],
[0,4],
[0,1],
[1,5],
[3,9],
[3,2],
[3,6],
[3,5],
[3,3]])

>> tf.py_function(distinct, [input], tf.int32)
<tf.Tensor: id=940, shape=(9, 2), dtype=int32, numpy=
array([[0, 1],
   [0, 3],
   [0, 4],
   [1, 5],
   [3, 2],
   [3, 3],
   [3, 5],
   [3, 6],
   [3, 9]], dtype=int32)>

保留订单

def distinct_with_order_preserved(a):
    _a = a.numpy()
    return pd.DataFrame(_a).drop_duplicates().values

>> tf.py_function(distinct_with_order_preserved, [input], tf.int32)
<tf.Tensor: id=950, shape=(9, 2), dtype=int32, numpy=
array([[0, 3],
   [0, 1],
   [0, 4],
   [1, 5],
   [3, 9],
   [3, 2],
   [3, 6],
   [3, 5],
   [3, 3]], dtype=int32)>