.. _op_ai_onnx_Gather: Gather ====== - **Domain**: ``ai.onnx`` - **Since version**: 13 Given ``data`` tensor of rank r >= 1, and ``indices`` tensor of rank q, gather entries of the axis dimension of ``data`` (by default outer-most one as axis=0) indexed by ``indices``, and concatenates them in an output tensor of rank q + (r - 1). It is an indexing operation that indexes into the input ``data`` along a single (specified) axis. Each entry in ``indices`` produces a ``r-1`` dimensional slice of the input tensor. The entire operation produces, conceptually, a ``q``-dimensional tensor of ``r-1`` dimensional slices, which is arranged into a ``q + (r-1)``-dimensional tensor, with the ``q`` dimensions taking the place of the original ``axis`` that is being indexed into. The following few examples illustrate how ``Gather`` works for specific shapes of ``data``, ``indices``, and given value of ``axis``: | data shape | indices shape | axis | output shape | output equation | | --- | --- | --- | --- | --- | | (P, Q) | ( ) (a scalar) | 0 | (Q) | output[q] = data[indices, q] | | (P, Q, R) | ( ) (a scalar) | 1 | (P, R) | output[p, r] = data[p, indices, r] | | (P, Q) | (R, S) | 0 | (R, S, Q) | output[r, s, q] = data[ [indices[r, s], q] | | (P, Q) | (R, S) | 1 | (P, R, S) | output[p, r, s] = data[ p, indices[r, s]] | More generally, if ``axis = 0``, let ``k = indices[i_{0}, ..., i_{q-1}]`` then ``output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2}] = input[k , j_{0}, ..., j_{r-2}]``: .. code-block:: data = [ [1.0, 1.2], [2.3, 3.4], [4.5, 5.7], ] indices = [ [0, 1], [1, 2], ] output = [ [ [1.0, 1.2], [2.3, 3.4], ], [ [2.3, 3.4], [4.5, 5.7], ], ] If ``axis = 1``, let ``k = indices[i_{0}, ..., i_{q-1}]`` then ``output[j_{0}, i_{0}, ..., i_{q-1}, j_{1}, ..., j_{r-2}] = input[j_{0}, k, j_{1}, ..., j_{r-2}]``: .. code-block:: data = [ [1.0, 1.2, 1.9], [2.3, 3.4, 3.9], [4.5, 5.7, 5.9], ] indices = [ [0, 2], ] axis = 1, output = [ [[1.0, 1.9]], [[2.3, 3.9]], [[4.5, 5.9]], ] **Inputs** - **data** (*T*): Tensor of rank r >= 1. - **indices** (*Tind*): Tensor of int32/int64 indices, of any rank q. All index values are expected to be within bounds [-s, s-1] along axis of size s. It is an error if any of the index values are out of bounds. **Outputs** - **output** (*T*): Tensor of rank q + (r - 1). **Attributes** - **axis** (*int*): Which axis to gather on. Negative value means counting dimensions from the back. Accepted range is [-r, r-1] where r = rank(data). **Type Constraints** - **T**: Constrain input and output types to any tensor type. Allowed types: tensor(bfloat16), 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). - **Tind**: Constrain indices to integer types Allowed types: tensor(int32), tensor(int64). Examples -------- **test_cc_gather_0** .. code-block:: text Node: Gather(data, indices) -> (output) Attributes: axis = 0 .. code-block:: text Inputs: data: shape=(5, 4), dtype=float32 [[0. , 0.1, 0.2, 0.3], [1. , 1.1, 1.2, 1.3], [2. , 2.1, 2.2, 2.3], [3. , 3.1, 3.2, 3.3], [4. , 4.1, 4.2, 4.3]] indices: shape=(2, 2), dtype=int64 [[0, 1], [1, 2]] Outputs: output: shape=(2, 2, 4), dtype=float32 [[[0. , 0.1, 0.2, 0.3], [1. , 1.1, 1.2, 1.3]], [[1. , 1.1, 1.2, 1.3], [2. , 2.1, 2.2, 2.3]]] **test_cc_gather_1** .. code-block:: text Node: Gather(data, indices) -> (output) Attributes: axis = 1 .. code-block:: text Inputs: data: shape=(3, 3), dtype=float32 [[1. , 1.2, 1.9], [2.3, 3.4, 3.9], [4.5, 5.7, 5.9]] indices: shape=(1, 2), dtype=int64 [[0, 2]] Outputs: output: shape=(3, 1, 2), dtype=float32 [[[1. , 1.9]], [[2.3, 3.9]], [[4.5, 5.9]]] **test_cc_gather_2d_indices** .. code-block:: text Node: Gather(data, indices) -> (output) Attributes: axis = 1 .. code-block:: text Inputs: data: shape=(3, 3), dtype=float32 [[1. , 1.2, 1.9], [2.3, 3.4, 3.9], [4.5, 5.7, 5.9]] indices: shape=(1, 2), dtype=int64 [[0, 2]] Outputs: output: shape=(3, 1, 2), dtype=float32 [[[1. , 1.9]], [[2.3, 3.9]], [[4.5, 5.9]]] **test_cc_gather_negative_indices** .. code-block:: text Node: Gather(data, indices) -> (output) Attributes: axis = 0 .. code-block:: text Inputs: data: shape=(5,), dtype=float32 [0., 1., 2., 3., 4.] indices: shape=(3,), dtype=int64 [ 0, -1, -2] Outputs: output: shape=(3,), dtype=float32 [0., 4., 3.] Differences with previous version (11) -------------------------------------- **SchemaDiff**: ``Gather`` (domain ``'ai.onnx'``) * old version: 11 * new version: 13 * breaking: no **Type constraints:** * changed 'T': added types: ['tensor(bfloat16)'] **Documentation:** * line similarity: 0.22 (+51/-43 lines) .. code-block:: diff --- Gather v11 +++ Gather v13 @@ -3,54 +3,62 @@ entries of the axis dimension of `data` (by default outer-most one as axis=0) indexed by `indices`, and concatenates them in an output tensor of rank q + (r - 1). -axis = 0 : +It is an indexing operation that indexes into the input `data` along a single (specified) axis. +Each entry in `indices` produces a `r-1` dimensional slice of the input tensor. +The entire operation produces, conceptually, a `q`-dimensional tensor of `r-1` dimensional slices, +which is arranged into a `q + (r-1)`-dimensional tensor, with the `q` dimensions taking the +place of the original `axis` that is being indexed into. -Let -k = indices[i_{0}, ..., i_{q-1}] -Then -output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2}] = input[k , j_{0}, ..., j_{r-2}] +The following few examples illustrate how `Gather` works for specific shapes of `data`, +`indices`, and given value of `axis`: +| data shape | indices shape | axis | output shape | output equation | +| --- | --- | --- | --- | --- | +| (P, Q) | ( ) (a scalar) | 0 | (Q) | output[q] = data[indices, q] | +| (P, Q, R) | ( ) (a scalar) | 1 | (P, R) | output[p, r] = data[p, indices, r] | +| (P, Q) | (R, S) | 0 | (R, S, Q) | output[r, s, q] = data[ [indices[r, s], q] | +| (P, Q) | (R, S) | 1 | (P, R, S) | output[p, r, s] = data[ p, indices[r, s]] | + +More generally, if `axis = 0`, let `k = indices[i_{0}, ..., i_{q-1}]` +then `output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2}] = input[k , j_{0}, ..., j_{r-2}]`: ``` - data = [ - [1.0, 1.2], - [2.3, 3.4], - [4.5, 5.7], - ] - indices = [ - [0, 1], - [1, 2], - ] - output = [ - [ - [1.0, 1.2], - [2.3, 3.4], - ], - [ - [2.3, 3.4], - [4.5, 5.7], - ], - ] +data = [ + [1.0, 1.2], + [2.3, 3.4], + [4.5, 5.7], +] +indices = [ + [0, 1], + [1, 2], +] +output = [ + [ + [1.0, 1.2], + [2.3, 3.4], + ], + [ + [2.3, 3.4], + [4.5, 5.7], + ], +] ``` -axis = 1 : -Let -k = indices[i_{0}, ..., i_{q-1}] -Then -output[j_{0}, i_{0}, ..., i_{q-1}, j_{1}, ..., j_{r-2}] = input[j_{0}, k, j_{1}, ..., j_{r-2}] +If `axis = 1`, let `k = indices[i_{0}, ..., i_{q-1}]` +then `output[j_{0}, i_{0}, ..., i_{q-1}, j_{1}, ..., j_{r-2}] = input[j_{0}, k, j_{1}, ..., j_{r-2}]`: ``` - data = [ - [1.0, 1.2, 1.9], - [2.3, 3.4, 3.9], - [4.5, 5.7, 5.9], - ] - indices = [ - [0, 2], - ] - axis = 1, - output = [ - [[1.0, 1.9]], - [[2.3, 3.9]], - [[4.5, 5.9]], - ] +data = [ + [1.0, 1.2, 1.9], + [2.3, 3.4, 3.9], + [4.5, 5.7, 5.9], +] +indices = [ + [0, 2], +] +axis = 1, +output = [ + [[1.0, 1.9]], + [[2.3, 3.9]], + [[4.5, 5.9]], +] ``` Version History --------------- - :doc:`Version 11 ` - :doc:`Version 1 `