'Find Unique values in a 2D Tensor using Tensorflow
tf.unique currently only works on 1D tensors. How can I find unique values in a 2D tensor.
ip=tf.constant([[1,2,1],[3,4,1],[5,6,1],[1,2,1]])
#op should be = [[1,2,1],[3,4,1],[5,6,1]]
Solution 1:[1]
Following function takes 2D tensor as IP and will return Unique 2D Tensor
def tf_unique_2d(self, x):
x_shape = tf.shape(x) # (3,2)
x1 = tf.tile(x, [1, x_shape[0]]) # [[1,2],[1,2],[1,2],[3,4],[3,4],[3,4]..]
x2 = tf.tile(x, [x_shape[0], 1]) # [[1,2],[1,2],[1,2],[3,4],[3,4],[3,4]..]
x1_2 = tf.reshape(x1, [x_shape[0] * x_shape[0], x_shape[1]])
x2_2 = tf.reshape(x2, [x_shape[0] * x_shape[0], x_shape[1]])
cond = tf.reduce_all(tf.equal(x1_2, x2_2), axis=1)
cond = tf.reshape(cond, [x_shape[0], x_shape[0]]) # reshaping cond to match x1_2 & x2_2
cond_shape = tf.shape(cond)
cond_cast = tf.cast(cond, tf.int32) # convertin condition boolean to int
cond_zeros = tf.zeros(cond_shape, tf.int32) # replicating condition tensor into all 0's
# CREATING RANGE TENSOR
r = tf.range(x_shape[0])
r = tf.add(tf.tile(r, [x_shape[0]]), 1)
r = tf.reshape(r, [x_shape[0], x_shape[0]])
# converting TRUE=1 FALSE=MAX(index)+1 (which is invalid by default) so when we take min it wont get selected & in end we will only take values <max(indx).
f1 = tf.multiply(tf.ones(cond_shape, tf.int32), x_shape[0] + 1)
f2 = tf.ones(cond_shape, tf.int32)
cond_cast2 = tf.where(tf.equal(cond_cast, cond_zeros), f1, f2) # if false make it max_index+1 else keep it 1
# multiply range with new int boolean mask
r_cond_mul = tf.multiply(r, cond_cast2)
r_cond_mul2 = tf.reduce_min(r_cond_mul, axis=1)
r_cond_mul3, unique_idx = tf.unique(r_cond_mul2)
r_cond_mul4 = tf.subtract(r_cond_mul3, 1)
# get actual values from unique indexes
op = tf.gather(x, r_cond_mul4)
return (op)
Solution 2:[2]
The easiest way to do this is to first reshape your tensor to be a 1D tensor, then use tf.unique
(which currently only accepts 1D tensors, not sure why!) or tf.unique_with_counts
(depending on whether you also need the counts of the unique elements), and then, if you also need the indices of the unique values to have the same shape as the original tensor, you can reshape also the indices. The following TensorFlow 2.1 program illustrates this.
import tensorflow as tf # TF 2.1
def get_uniques(t):
t1d = tf.reshape(t, shape=(-1,))
# or tf.unique, if you don't need counts
uniques, idx, counts = tf.unique_with_counts(t1d)
return uniques, tf.reshape(idx, shape=tf.shape(t)), counts
if __name__ == '__main__':
my_tensor = tf.constant([[1, 2, 1], [3, 4, 1], [5, 6, 1], [1, 2, 1]])
uniques, idx, counts = get_uniques(my_tensor)
tf.print("tf.shape(uniques) =", tf.shape(uniques))
tf.print("tf.shape(idx) =", tf.shape(idx))
tf.print("tf.shape(counts) =", tf.shape(counts))
tf.print("uniques =", uniques)
Solution 3:[3]
Answer in April 2022
Since version 2.2, Tensorflow has supported find unique 1-D tensor in a 2D tensor using tf.raw_ops.UniqueV2
.
>>> import tensorflow as tf
>>> a = tf.constant([[1, 2, 1], [3, 4, 1], [5, 6, 1], [1, 2, 1]])
>>> y, idx = tf.raw_ops.UniqueV2(x=a, axis=[0])
>>> y
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=
array([[1, 2, 1],
[3, 4, 1],
[5, 6, 1]], dtype=int32)>
>>> idx
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([0, 1, 2, 0], dtype=int32)>
Check the docs for more details.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | borgr |
Solution 2 | nbro |
Solution 3 | BrokenBenchmark |