GroupedMatMul¶
GroupedMatMul - 29¶
Version¶
name: GroupedMatMul (GitHub)
domain:
mainsince_version:
29function:
Truesupport_level:
SupportType.COMMONshape inference:
True
This version of the operator has been available since version 29.
Summary¶
GroupedMatMul multiplies each row of a token matrix by one or more selected
group (expert) weight matrices. Given input of shape [M, K], weights of
shape [G, K, N] when transB is zero (the default), and group_indices of shape
[M, S], where S is the number of selections per token, the output has shape
[M, S, N] and is defined by:
output[m, i] = input[m] @ weights[group_indices[m, i]]
When transB is non-zero, weights has shape [G, N, K] and each selected
weight matrix is transposed before multiplication:
output[m, i] = input[m] @ weights[group_indices[m, i]].T
M is the number of input rows, G is the number of groups, K is the
contraction dimension, and N is the output dimension. Only the last two axes
of weights are logically transposed; the group axis and the layouts of
input, output, and bias are unchanged.
If bias is present, it must have shape [G, N], and
bias[group_indices[m, i]] is added to each corresponding result.
If M or S is zero, the output is an empty tensor of shape [M, S, N].
Every value in group_indices must be in the range [0, G).
Values outside this range, including negative indices, are invalid input;
the behavior is undefined for such inputs. In particular, negative indices
do not select groups by counting backwards from G.
Quantized weights can be dequantized with DequantizeLinear before this operator.
The dequantized weights must have the shape specified by transB.
Attributes¶
transB - INT (default is
0):Whether to transpose the last two axes of weights before multiplication. If zero, weights has shape [G, K, N]; if non-zero, weights has shape [G, N, K].
Inputs¶
Between 3 and 4 inputs.
input (heterogeneous) - T:
Token matrix with shape [M, K].
weights (heterogeneous) - T:
Stack of G group weight matrices with shape [G, K, N] if transB is zero, or [G, N, K] if transB is non-zero.
group_indices (heterogeneous) - Tind:
Group index for each token and selection, with shape [M, S]. Values outside [0, G) are invalid input.
bias (optional, heterogeneous) - T:
Optional per-group bias with shape [G, N].
Outputs¶
output (heterogeneous) - T:
Per-group matrix multiplication results with shape [M, S, N].
Type Constraints¶
T in (
tensor(bfloat16),tensor(double),tensor(float),tensor(float16)):Constrain input, weights, bias, and output to floating-point tensors.
Tind in (
tensor(int32),tensor(int64)):Constrain group indices to int32 or int64 tensors.
Examples¶
_transposed_weights_nonzero¶
import numpy as np
import onnx
input = np.array([[1, 2, -1], [3, 0, 4]], dtype=np.float32)
weights = np.arange(18, dtype=np.float32).reshape(3, 2, 3)
group_indices = np.array([[2, 0], [1, 2]], dtype=np.int64)
output = grouped_matmul(input, weights, group_indices, transB=1)
for transB in (-1, 2):
node = onnx.helper.make_node(
"GroupedMatMul",
["input", "weights", "group_indices"],
["output"],
transB=transB,
)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name=f"test_groupedmatmul_transB_nonzero_{transB}",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_transposed_weights¶
import numpy as np
import onnx
input = np.array([[1, 2, -1], [3, 0, 4]], dtype=np.float32)
weights = np.arange(18, dtype=np.float32).reshape(3, 2, 3)
group_indices = np.array([[2, 0, 2], [1, 2, 0]], dtype=np.int64)
bias = np.array([[0.5, 1], [1.5, -2], [3, 0.25]], dtype=np.float32)
for bias_input in (None, "", "bias"):
input_names = ["input", "weights", "group_indices"]
values = [input, weights, group_indices]
if bias_input is not None:
input_names.append(bias_input)
if bias_input:
values.append(bias)
node = onnx.helper.make_node(
"GroupedMatMul", input_names, ["output"], transB=1
)
output = grouped_matmul(
input, weights, group_indices, bias if bias_input else None, transB=1
)
suffix = {None: "", "": "_explicit_empty_bias", "bias": "_with_bias"}[
bias_input
]
expect(
node,
inputs=values,
outputs=[output],
name=f"test_groupedmatmul_transB{suffix}",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_transposed_weights_empty¶
import numpy as np
import onnx
weights = np.arange(24, dtype=np.float32).reshape(2, 4, 3)
for m, s in ((0, 2), (2, 0)):
input = np.empty((m, 3), dtype=np.float32)
group_indices = np.empty((m, s), dtype=np.int32)
node = onnx.helper.make_node(
"GroupedMatMul",
["input", "weights", "group_indices"],
["output"],
transB=1,
)
output = grouped_matmul(input, weights, group_indices, transB=1)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name=f"test_groupedmatmul_transB_empty_{m}_{s}",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_additional_types¶
import numpy as np
import onnx
for dtype in (np.float16, np.float64):
for index_dtype in (np.int32, np.int64):
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices", "bias"],
outputs=["output"],
)
input = np.array([[1, 2], [3, 4]], dtype=dtype)
weights = np.array([[[1, 0], [0, 1]], [[0, 1], [1, 0]]], dtype=dtype)
group_indices = np.array([[0, 1], [1, 0]], dtype=index_dtype)
bias = np.array([[0.5, 1], [1.5, 2]], dtype=dtype)
output = grouped_matmul(input, weights, group_indices, bias)
expect(
node,
inputs=[input, weights, group_indices, bias],
outputs=[output],
name=f"test_groupedmatmul_{np.dtype(dtype).name}_{np.dtype(index_dtype).name}",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
default¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices"],
outputs=["output"],
)
input = np.array(
[[1, 0, -1], [0, 1, 2], [1, 1, 0], [0, 0, 1]], dtype=np.float32
)
weights = np.array(
[[[1, 0], [0, 1], [-1, 0]], [[0, 1], [1, 0], [0, 1]]],
dtype=np.float32,
)
group_indices = np.array([[0], [1], [0], [1]], dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_without_bias_explicit_empty_input¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices", ""],
outputs=["output"],
)
input = np.array(
[[1, 0, -1], [0, 1, 2], [1, 1, 0], [0, 0, 1]], dtype=np.float32
)
weights = np.array(
[[[1, 0], [0, 1], [-1, 0]], [[0, 1], [1, 0], [0, 1]]],
dtype=np.float32,
)
group_indices = np.array([[0], [1], [0], [1]], dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul_without_bias_explicit_empty_input",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_with_bias¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices", "bias"],
outputs=["output"],
)
input = np.array([[1, 0], [0, 1]], dtype=np.float32)
weights = np.array(
[[[1, 0], [0, 1]], [[0, 1], [1, 0]], [[1, 1], [0, 0]]],
dtype=np.float32,
)
group_indices = np.array([[0, 1], [2, 0]], dtype=np.int64)
bias = np.array([[0.1, 0.2], [0.3, 0.0], [0.5, 0.5]], dtype=np.float32)
output = grouped_matmul(input, weights, group_indices, bias)
expect(
node,
inputs=[input, weights, group_indices, bias],
outputs=[output],
name="test_groupedmatmul_with_bias",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_with_unused_group¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices"],
outputs=["output"],
)
input = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.float32)
weights = np.arange(12, dtype=np.float32).reshape(3, 2, 2)
group_indices = np.array([[0], [0], [2], [2]], dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul_with_unused_group",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_single_group¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices"],
outputs=["output"],
transB=0,
)
input = np.array([[1, 2], [3, 4], [5, 6]], dtype=np.float32)
weights = np.array([[[1, 2, 3], [4, 5, 6]]], dtype=np.float32)
group_indices = np.zeros((3, 1), dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul_single_group",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_zero_selections¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices"],
outputs=["output"],
)
input = np.arange(6, dtype=np.float32).reshape(2, 3)
weights = np.arange(24, dtype=np.float32).reshape(2, 3, 4)
group_indices = np.empty((2, 0), dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul_zero_selections",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)
_zero_tokens¶
import numpy as np
import onnx
node = onnx.helper.make_node(
"GroupedMatMul",
inputs=["input", "weights", "group_indices"],
outputs=["output"],
)
input = np.empty((0, 3), dtype=np.float32)
weights = np.arange(24, dtype=np.float32).reshape(2, 3, 4)
group_indices = np.empty((0, 2), dtype=np.int64)
output = grouped_matmul(input, weights, group_indices)
expect(
node,
inputs=[input, weights, group_indices],
outputs=[output],
name="test_groupedmatmul_zero_tokens",
opset_imports=[onnx.helper.make_opsetid("", 29)],
)