DML_GATHER_OPERATOR_DESC structure (directml.h)

Gathers elements from the input tensor along Axis, using IndicesTensor to remap indices. This operator performs the following pseudocode, where "..." represents a series of coordinates, with the exact behavior determined by the axis and indices dimension count:

output[...] = input[..., indices[...], ...]

Syntax

struct DML_GATHER_OPERATOR_DESC {
  const DML_TENSOR_DESC *InputTensor;
  const DML_TENSOR_DESC *IndicesTensor;
  const DML_TENSOR_DESC *OutputTensor;
  UINT                  Axis;
  UINT                  IndexDimensions;
};

Members

InputTensor

Type: const DML_TENSOR_DESC*

The tensor to read from.

IndicesTensor

Type: const DML_TENSOR_DESC*

A tensor containing the indices. The DimensionCount of this tensor must match InputTensor.DimensionCount.

Starting with DML_FEATURE_LEVEL_3_0, this operator supports negative index values when using a signed integral type with this tensor. Negative indices are interpreted as being relative to the end of the axis dimension. For example, an index of -1 refers to the last element along that dimension.

Invalid indices will yield incorrect outputs, but no failure will occur, and all reads will be clamped safely within the input tensor's memory.

OutputTensor

Type: const DML_TENSOR_DESC*

The tensor to write the results to. The DimensionCount and DataType of this tensor must match InputTensor.DimensionCount. The expected OutputTensor.Sizes are the concatenation of the InputTensor.Sizes leading and trailing segments split at the current Axis with the IndicesTensor.Sizes inserted between.

OutputTensor.Sizes = {
    InputTensor.Sizes[0..Axis],
    IndicesTensor.Sizes[(IndicesTensor.DimensionCount - IndexDimensions) .. IndicesTensor.DimensionCount],
    InputTensor.Sizes[(Axis+1) .. InputTensor.DimensionCount]
}

The dimensions are right-aligned such that any leading 1 values from the input sizes are cropped which would otherwise overflow the output DimensionCount.

The number of relevant dimensions in this tensor depends on IndexDimensions and the original rank of InputTensor. The original rank is the number of dimensions prior to any padding with leading ones. The number of relevant dimensions in the output can be computed by the original rank of InputTensor + IndexDimensions - 1. This value must be less than or equal to the DimensionCount of OutputTensor.

Axis

Type: UINT

The axis dimension of InputTensor to gather on, ranging [0, *InputTensor.DimensionCount*).

IndexDimensions

Type: UINT

The number of actual index dimensions within the IndicesTensor after ignoring any irrelevant leading ones, ranging [0, IndicesTensor.DimensionCount). For example, given IndicesTensor.Sizes = { 1, 1, 4, 6 } and IndexDimensions = 3, the actual meaningful indices are { 1, 4, 6 }.

Examples

Example 1. 1D remapping

Axis: 0
IndexDimensions: 1

InputTensor: (Sizes:{4}, DataType:FLOAT32)
    [11,12,13,14]

IndicesTensor: (Sizes:{5}, DataType:UINT32)
    [3,1,3,0,2]

// output[x] = input[indices[x]]
OutputTensor: (Sizes:{5}, DataType:FLOAT32)
    [14,12,14,11,13]

Example 2. 2D output, 1D indices, Axis 0, concatenate rows

Axis: 0
IndexDimensions: 1

InputTensor: (Sizes:{3,2}, DataType:FLOAT32)
    [[1,2], // row 0
     [3,4], // row 1
     [5,6]] // row 2

IndicesTensor: (Sizes:{1, 4}, DataType:UINT32)
    [[0,
      1,
      1,
      2]]

// output[y, x] = input[indices[y], x]
OutputTensor: (Sizes:{4,2}, DataType:FLOAT32)
    [[1,2], // input row 0
     [3,4], // input row 1
     [3,4], // input row 1
     [5,6]] // input row 2

Example 3. 2D, Axis 1, swap columns

Axis: 1
IndexDimensions: 2

InputTensor: (Sizes:{3,2}, DataType:FLOAT32)
    [[1,2],
     [3,4],
     [5,6]]

IndicesTensor: (Sizes:{1, 2}, DataType:UINT32)
    [[1,0]]

// output[y, x] = input[y, indices[x]]
OutputTensor: (Sizes:{3,2}, DataType:FLOAT32)
    [[2,1],
     [4,3],
     [6,5]]

Example 4. 2D, Axis 1, nested indices

Axis: 2
IndexDimensions: 2

InputTensor: (Sizes:{1, 3,3}, DataType:FLOAT32)
    [ [[1,2,3],
       [4,5,6],
       [7,8,9]] ]

IndicesTensor: (Sizes:{1, 1,2}, DataType:UINT32)
    [ [[0,2]] ]

// output[z, y, x] = input[z, indices[y, x]]
OutputTensor: (Sizes:{3,1,2}, DataType:FLOAT32)
    [[[1,3]],
     [[4,6]],
     [[7,9]]]

Example 5. 2D, Axis 0, nested indices

Axis: 1
IndexDimensions: 2

InputTensor: (Sizes:{1, 3,2}, DataType:FLOAT32)
    [ [[1,2],
       [3,4],
       [5,6]] ]

IndicesTensor: (Sizes:{1, 2,2}, DataType:UINT32)
    [ [[0,1],
       [1,2]] ]

// output[z, y, x] = input[indices[z, y], x]
OutputTensor: (Sizes:{2,2,2}, DataType:FLOAT32)
    [[[1,2], [3,4]],
     [[3,4], [5,6]]]

Availability

This operator was introduced in DML_FEATURE_LEVEL_1_0.

Tensor constraints

  • IndicesTensor, InputTensor, and OutputTensor must have the same DimensionCount.
  • InputTensor and OutputTensor must have the same DataType.

Tensor support

DML_FEATURE_LEVEL_4_1 and above

Tensor Kind Supported dimension counts Supported data types
InputTensor Input 1 to 8 FLOAT64, FLOAT32, FLOAT16, INT64, INT32, INT16, INT8, UINT64, UINT32, UINT16, UINT8
IndicesTensor Input 1 to 8 INT64, INT32, UINT64, UINT32
OutputTensor Output 1 to 8 FLOAT64, FLOAT32, FLOAT16, INT64, INT32, INT16, INT8, UINT64, UINT32, UINT16, UINT8

DML_FEATURE_LEVEL_3_0 and above

Tensor Kind Supported dimension counts Supported data types
InputTensor Input 1 to 8 FLOAT32, FLOAT16, INT32, INT16, INT8, UINT32, UINT16, UINT8
IndicesTensor Input 1 to 8 INT64, INT32, UINT64, UINT32
OutputTensor Output 1 to 8 FLOAT32, FLOAT16, INT32, INT16, INT8, UINT32, UINT16, UINT8

DML_FEATURE_LEVEL_2_1 and above

Tensor Kind Supported dimension counts Supported data types
InputTensor Input 4 FLOAT32, FLOAT16, INT32, INT16, INT8, UINT32, UINT16, UINT8
IndicesTensor Input 4 UINT32
OutputTensor Output 4 FLOAT32, FLOAT16, INT32, INT16, INT8, UINT32, UINT16, UINT8

DML_FEATURE_LEVEL_1_0 and above

Tensor Kind Supported dimension counts Supported data types
InputTensor Input 4 FLOAT32, FLOAT16
IndicesTensor Input 4 UINT32
OutputTensor Output 4 FLOAT32, FLOAT16

Requirements

Requirement Value
Header directml.h