Unique#

Unique - 11#

Version

  • name: Unique (GitHub)

  • domain: main

  • since_version: 11

  • function:

  • support_level: SupportType.COMMON

  • shape inference: True

This version of the operator has been available since version 11.

Summary

Attributes

  • axis - INT : (Optional) The dimension to apply unique. If not specified, the unique elements of the flattened input are returned. Negative value means counting dimensions from the back. Accepted range is [-r, r-1] where r = rank(input).

  • sorted - INT : (Optional) Whether to sort the unique elements in ascending order before returning as output. Must be one of 0, or 1 (default).

Inputs

  • X (heterogeneous) - T:

Outputs

Between 1 and 4 outputs.

  • Y (heterogeneous) - T:

  • indices (optional, heterogeneous) - tensor(int64):

  • inverse_indices (optional, heterogeneous) - tensor(int64):

  • counts (optional, heterogeneous) - tensor(int64):

Type Constraints

  • T in ( tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) ): Input can be of any tensor type.

Examples

_sorted_without_axis

import numpy as np
import onnx

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

import numpy as np
import onnx

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

import numpy as np
import onnx

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

import numpy as np
import onnx

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

import numpy as np
import onnx

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",
)