com.microsoft - Unique#

Unique - 1 (com.microsoft)#

Version

  • name: Unique (GitHub)

  • domain: com.microsoft

  • since_version: 1

  • function:

  • support_level:

  • shape inference:

This version of the operator has been available since version 1 of domain com.microsoft.

Summary

Finds all the unique values (deduped list) present in the given input tensor. This operator returns 3 outputs. The first output tensor ‘uniques’ contains all of the unique elements of the input, sorted in the same order that they occur in the input. The second output tensor ‘idx’ is the same size as the input and it contains the index of each value of the input in ‘uniques’. The third output tensor ‘counts’ contains the count of each element of ‘uniques’ in the input. Example:

input_x = [2, 1, 1, 3, 4, 3] output_uniques = [2, 1, 3, 4] output_idx = [0, 1, 1, 2, 3, 2] output_counts = [1, 2, 2, 1]

Inputs

  • x (heterogeneous) - T: A 1-D input tensor that is to be processed.

Outputs

  • y (heterogeneous) - T: A 1-D tensor of the same type as ‘x’ containing all the unique values in ‘x’ sorted in the same order that they occur in the input ‘x’

  • idx (heterogeneous) - tensor(int64): A 1-D INT64 tensor of the same size as ‘x’ containing the indices for each value in ‘x’ in the output ‘uniques’

  • counts (heterogeneous) - tensor(int64): A 1-D INT64 tensor containing the the count of each element of ‘uniques’ in the input ‘x’

Examples

_sorted_without_axis

node_sorted = onnx.helper.make_node(
    "Unique",
    inputs=["X"],
    outputs=["Y", "indices", "inverse_indices", "counts"],
)

x = np.array([2.0, 1.0, 1.0, 3.0, 4.0, 3.0], dtype=np.float32)
y, indices, inverse_indices, counts = np.unique(x, True, True, True)
indices, inverse_indices, counts = specify_int64(
    indices, inverse_indices, counts
)
expect(
    node_sorted,
    inputs=[x],
    outputs=[y, indices, inverse_indices, counts],
    name="test_unique_sorted_without_axis",
)

_not_sorted_without_axis

node_not_sorted = onnx.helper.make_node(
    "Unique",
    inputs=["X"],
    outputs=["Y", "indices", "inverse_indices", "counts"],
    sorted=0,
)
# numpy unique does not retain original order (it sorts the output unique values)
# https://github.com/numpy/numpy/issues/8621
# we need to recover unsorted output and indices
x = np.array([2.0, 1.0, 1.0, 3.0, 4.0, 3.0], dtype=np.float32)
y, indices, inverse_indices, counts = np.unique(x, True, True, True)

# prepare index mapping from sorted to unsorted
argsorted_indices = np.argsort(indices)
inverse_indices_map = {
    i: si for i, si in zip(argsorted_indices, np.arange(len(argsorted_indices)))
}

indices = indices[argsorted_indices]
y = np.take(x, indices, axis=0)
inverse_indices = np.asarray(
    [inverse_indices_map[i] for i in inverse_indices], dtype=np.int64
)
counts = counts[argsorted_indices]
indices, inverse_indices, counts = specify_int64(
    indices, inverse_indices, counts
)
# print(y)
# [2.0, 1.0, 3.0, 4.0]
# print(indices)
# [0 1 3 4]
# print(inverse_indices)
# [0, 1, 1, 2, 3, 2]
# print(counts)
# [1, 2, 2, 1]

expect(
    node_not_sorted,
    inputs=[x],
    outputs=[y, indices, inverse_indices, counts],
    name="test_unique_not_sorted_without_axis",
)

_sorted_with_axis

node_sorted = onnx.helper.make_node(
    "Unique",
    inputs=["X"],
    outputs=["Y", "indices", "inverse_indices", "counts"],
    sorted=1,
    axis=0,
)

x = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]], dtype=np.float32)
y, indices, inverse_indices, counts = np.unique(x, True, True, True, axis=0)
indices, inverse_indices, counts = specify_int64(
    indices, inverse_indices, counts
)
# print(y)
# [[1. 0. 0.]
#  [2. 3. 4.]]
# print(indices)
# [0 2]
# print(inverse_indices)
# [0 0 1]
# print(counts)
# [2 1]

expect(
    node_sorted,
    inputs=[x],
    outputs=[y, indices, inverse_indices, counts],
    name="test_unique_sorted_with_axis",
)

_sorted_with_axis_3d

node_sorted = onnx.helper.make_node(
    "Unique",
    inputs=["X"],
    outputs=["Y", "indices", "inverse_indices", "counts"],
    sorted=1,
    axis=1,
)

x = np.array(
    [
        [[1.0, 1.0], [0.0, 1.0], [2.0, 1.0], [0.0, 1.0]],
        [[1.0, 1.0], [0.0, 1.0], [2.0, 1.0], [0.0, 1.0]],
    ],
    dtype=np.float32,
)
y, indices, inverse_indices, counts = np.unique(x, True, True, True, axis=1)
indices, inverse_indices, counts = specify_int64(
    indices, inverse_indices, counts
)
# print(y)
# [[[0. 1.]
#  [1. 1.]
#  [2. 1.]]
# [[0. 1.]
#  [1. 1.]
#  [2. 1.]]]
# print(indices)
# [1 0 2]
# print(inverse_indices)
# [1 0 2 0]
# print(counts)
# [2 1 1]
expect(
    node_sorted,
    inputs=[x],
    outputs=[y, indices, inverse_indices, counts],
    name="test_unique_sorted_with_axis_3d",
)

_sorted_with_negative_axis

node_sorted = onnx.helper.make_node(
    "Unique",
    inputs=["X"],
    outputs=["Y", "indices", "inverse_indices", "counts"],
    sorted=1,
    axis=-1,
)

x = np.array([[1, 0, 0], [1, 0, 0], [2, 3, 3]], dtype=np.float32)
y, indices, inverse_indices, counts = np.unique(x, True, True, True, axis=-1)
indices, inverse_indices, counts = specify_int64(
    indices, inverse_indices, counts
)
# print(y)
# [[0. 1.]
#  [0. 1.]
#  [3. 2.]]
# print(indices)
# [1 0]
# print(inverse_indices)
# [1 0 0]
# print(counts)
# [2 1]

expect(
    node_sorted,
    inputs=[x],
    outputs=[y, indices, inverse_indices, counts],
    name="test_unique_sorted_with_negative_axis",
)