Arguments and Operands#

An operation is expressed as a RuntimeArguments object that describes both the operation kind (e.g. GEMM) and the operands it runs on. Each operation has its own RuntimeArguments subclass. Operands are described by Operand subclasses such as DenseTensor and ScaledOperand. Tensor- and numeric-typed fields within Arguments and Operands accept any object matching the TensorLike / NumericLike protocols (e.g. torch.Tensor, cute.Tensor, cutlass.Numeric, torch.dtype).

RuntimeArguments#

class cutlass.operators.arguments.base.RuntimeArguments(
*,
performance: PerformanceControls | None = None,
)#

Bases: object

Describes the operands and all other arguments passed to an Operator at runtime.

It contains runtime operands (usually tensors) passed to the operation, as well as any custom epilogue fusions, and runtime performance controls.

This is an abstract base class, whose subclass describes the operation type itself (e.g. GemmArguments, GroupedGemmArguments, etc.). All operators that implement the same operation type accept the same RuntimeArguments subclass.

performance: PerformanceControls | None = None#

Optional runtime performance controls passed to the Operator

class cutlass.operators.arguments.base.PerformanceControls#

Bases: object

Optional runtime performance controls passed to the Operator.

Some operators may support performance options that can be controlled at runtime. This class is the general container for all such controls.

class cutlass.operators.arguments.gemm.GemmProblemSize(M: int, N: int, K: int, L: int)#

Bases: NamedTuple

Problem size for a GEMM operation.

A GEMM with problem size (M, N, K, L) has operands with the following shapes (batch, rows, columns):

  • A: (L, M, K)

  • B: (L, K, N)

  • out: (L, M, N)

M: int#

Number of rows in A and out

N: int#

Number of columns in B and out

K: int#

Number of columns in A and rows in B

L: int#

Number of batches of matrix multiplications

class cutlass.operators.arguments.gemm.GemmArguments(
A: TensorLike | Operand,
B: TensorLike | Operand,
out: TensorLike | Operand,
accumulator_type: NumericLike,
epilogue: EpilogueArguments | None = None,
)#

Bases: RuntimeArguments

Arguments for a Generalized Matrix Multiplication (GEMM) operation: out = A @ B.

The tensors must be all rank-3 or all rank-2. * L: Number of batches * M: Number of rows in A and out * K: Number of columns in A and rows in B * N: Number of columns in B and out

For convenience, construction for A, B, and out that are operands to a dense GEMM can be passed in without wrapping them in DenseTensor.

GemmArguments(A, B, out, accumulator_type)
# is equivalent to:
GemmArguments(DenseTensor(A), DenseTensor(B), DenseTensor(out), accumulator_type)

Other operand types must explicitly wrap tensors in a Operand subclass. For example, a scaled GEMM can be constructed as:

GemmArguments(
    ScaledOperand(A, ScaleATensor, scale_mode, scale_swizzle),
    ScaledOperand(B, ScaleBTensor, scale_mode, scale_swizzle),
    out, # No need to wrap in a `DenseTensor`
    accumulator_type,
)
A: Operand#

Input tensor A of shape (L, M, K) or (M, K)

B: Operand#

Input tensor B of shape (L, K, N) or (K, N)

out: Operand#

Output tensor C of shape (L, M, N) or (M, N)

accumulator_type: NumericLike#

Data type of the accumulator

epilogue: EpilogueArguments | None#

Optional custom epilogue fusion to be performed after the GEMM

property problem_size: GemmProblemSize#

Problem size for a GEMM operation.

class cutlass.operators.arguments.grouped_gemm.GroupedGemmArguments(
A: TensorLike | Operand,
B: TensorLike | Operand,
out: TensorLike | Operand,
accumulator_type: NumericLike,
offsets: TensorLike | Operand,
epilogue: EpilogueArguments | None = None,
)#

Bases: RuntimeArguments

Arguments for a grouped GEMM operation.

A grouped GEMM performs a series of independent GEMM operations, where each GEMM can have different matrix dimensions. The most basic formulation of a grouped GEMM is one that takes lists of tensors for each of A, B, and out, and computes the following:

for i in range(problems_in_group):
    out[i] = A[i] @ B[i]

While the abstract formulation uses lists of tensors, in practice, the tensors are often packed together contiguously in memory in a single tensor for each of A, B, and out. In this case, an offsets tensor delineates the ending positions of each problem in the group within those contiguous tensors.

Currently-supported variants of a grouped GEMM are:

Contiguous offset 2D-3D grouped GEMM:
  • A is a tensor of shape (TotalM, K) or (1, TotalM, K)

  • B is a tensor of shape (problems_in_group, K, N)

  • out is a tensor of shape (TotalM, N) or (1, TotalM, N)

  • offsets is a tensor delineating the ending positions of each problem in the group.

start = 0
for i in range(problems_in_group):
    end = offsets[i]
    out[start:end, :] = A[start:end, :] @ B[i, :, :]
    start = end
A: Operand#

Input tensor A

B: Operand#

Input tensor B

out: Operand#

Output tensor

accumulator_type: NumericLike#

Data type of the accumulator

offsets: Operand#

Offsets tensor delineating the ending positions of each problem in the group

epilogue: EpilogueArguments | None#

Optional custom epilogue fusion to be performed after the GEMM

class cutlass.operators.arguments.epilogue.EpilogueArguments(epilogue_fn: Callable | str, **kwargs)#

Bases: object

Describes a user-defined epilogue that is fused on top of the operation described by the primary RuntimeArguments.

An epilogue fusion is a custom function that performs tensor-level transformations on the result of a matrix multiplication. This transformation is fused into the kernel’s epilogue, which stores the final output.

EpilogueArguments encapsulates the epilogue function describing the transformation along with its arguments.

To support flexible definition of epilogues, EpilogueArguments is defined generically as taking in an epilogue_fn and additional kwargs.

Under the hood, the AST for epilogue_fn is parsed to determine the operands and outputs of the epilogue. kwargs must contain Tensors or scalars for all operands and outputs in the provided epilogue.

Structure of ``epilogue_fn``

The epilogue_fn is a function describing the custom transformation on the accumulator tensor (intermediate result before the epilogue).

The general structure of these functions is:

def custom_epi_name(accum, *args) -> TensorType | tuple[TensorType, ...]:
    '''Compute the epilogue.

    # Args:
        accum (TensorType): Result of the primary operation (e.g.
                        ``A @ B`` for a GEMM) before the epilogue.
        *args: Additional tensors or scalars used in the epilogue
                (e.g. aux tensors).

    # Returns:
        At least one tensor resulting from the epilogue computation.
    '''
    # Do some compute
    return D  # and potentially other values

epilogue_fn must be a Python callable (or its string representation) that must satisfy the following constraints:

  • Takes a first positional argument named accum – the result of the operation just before the epilogue. For a GEMM, accum = A @ B.

  • Returns at least one tensor resulting from the epilogue. Currently the return list must contain at least one output named D.

  • Each argument following accum is a tensor or scalar to be loaded.

  • Each variable in the return statement is a tensor or scalar to be stored.

  • Operations are represented in static single assignment (SSA) form. This means that each variable can be assigned exactly once.

The underlying implementation of the epilogue in the kernel will determine how operands are loaded and stored.

Structure of ``kwargs``

kwargs must contain sample Tensors or scalars for all operands and outputs in the provided epilogue. For example, with an epilogue of:

def my_epi(accum, alpha, C, beta):
    F = (accum * alpha) + (C * beta)
    D = relu(F)
    return D, F

A user would need to construct epilogue arguments as follows:

epi_args = EpilogueArguments(
    my_epi,
    alpha=..., C=..., beta=..., D=..., F=...
)
property parameters: list[cute.Tensor | Numeric]#

Returns the list of input and output parameters of the epilogue.

property parameter_names: list[str]#

Returns the list of names of the input and output parameters of the epilogue.

to_tensor_wrappers(permute: list[int] | None = None)#

Converts the input and output parameters of the epilogue to TensorWrappers.

trace(
accumulator_shape: tuple[int, ...],
accumulator_type: Numeric,
)#

Traces the epilogue function and generates an internal representation of the epilogue.

Parameters:
  • accumulator_shape (tuple[int, ...]) – The shape of the accumulator tensor. For example, for a GEMM, this would be the shape of the output tensor.

  • accumulator_type (Numeric) – The datatype of the accumulator tensor.

Operands#

class cutlass.operators.arguments.base.Operand#

Bases: ABC

Base class for all operands to Operators, which encapsulates one or more TensorLike objects.

In the most basic case, an Operand enacapsulates a single tensor.

In more complex cases, an Operand may encapsulate multiple tensors that encapsulate a single logical operand. For instance, a ScaledOperand encapsulates a quantized and scale tensor, that together reconstruct the logical value of the operand.

final copy() Operand#

Returns a copy of the operand. Does not copy the underlying tensor.

class cutlass.operators.arguments.operand.DenseTensor(tensor: cutlass.operators.typing.TensorLike)#

Bases: Operand

An operand encapsulating a simple, single dense tensor.

class cutlass.operators.arguments.operand.ScaledOperand(
quantized: TensorLike | DenseTensor,
scale: TensorLike | DenseTensor,
mode: ScaleMode | tuple[int, ...],
swizzle: ScaleSwizzleMode,
)#

Bases: Operand

An operand whose logical value is a quantized tensor multiplied by a tensor of scale factors.

A ScaledOperand encapsulates physical quantized and scale tensors that together represent the logical value scale * quantized: each entry of scale broadcasts and multiplies a contiguous block of quantized, where the block shape is given by mode.

This Operand is typically used to express narrow-precision formats (such as OCP MXFP8 / MXFP4 and NVIDIA NVFP4), which store the data as a quantized narrow-precision tensor multiplied by a separate tensor of scale factors that recover dynamic range.

The scale mode and swizzle describe the physical layout of the scale tensor.

The mode describes how scale factors are broadcast over the quantized tensor, and therefore determines its size. It’s usually dictated by the data format you seek to represent – MXFP8 / MXFP4 / NVFP4 require specific scale modes. See ScaleMode for more details.

The swizzle describes the in-memory layout of the scale tensor. It’s usually dictated by the hardware architecture – for example, Blackwell block-scaled MMAs require a specific swizzle layout, and most kernels using them require the input to be pre-arranged in this layout. See ScaleSwizzleMode for more details.

Example

quantized_A = torch.randn(M, K, dtype=torch.float8_e4m3fn, device="cuda")
scale_A = torch.randn(M, K // 32, dtype=torch.float8_e8m0fnu, device="cuda")
A = ScaledOperand(
    quantized_A, scale_A, ScaleMode.Blockwise1x32, ScaleSwizzleMode.Swizzle32x4x4,
)

See also

  • ScaleMode: granularity of the scaling, and the format-to-mode mapping.

  • ScaleSwizzleMode: in-memory layout of the scale tensor.

References

quantized: DenseTensor#

Narrow-precision tensor holding the quantized values.

The dequantized logical value is scale * quantized: each scale factor broadcasts over a block of this tensor (block shape given by mode) and multiplies its values.

scale: DenseTensor#

Tensor of scale factors.

Each entry of this tensor broadcasts over a block of quantized and scales it. Its shape and layout are determined together by mode and swizzle.

This tensor must be contiguous and have exactly ScaledOperand.numel_scale() (quantized_shape, mode, swizzle) elements. It must already be arranged in the layout named by swizzle. Its shape is otherwise unconstrained and not validated.

mode: ScaleMode | tuple[int, ...]#

Block shape over which each scale factor is broadcast.

Typically, a block of quantized-tensor elements share the same scale factor value. The logical value of the scaled operand is the result of broadcasting the scale factor along the block shape described by mode, and then multiplying it element-wise with the quantized tensor.

This may be a ScaleMode enum for commonly used block shapes, or a bare (L, M, K) tuple for custom block shapes. For instance, (1, 1, 32) means that each scale factor covers 32 elements along the K axis, and 1 element along the L and M axes.

swizzle: ScaleSwizzleMode#

In-memory layout of the scale factor tensor.

The scale factor tensor is sometimes required to be stored in a specific swizzled layout, often dictated by the hardware MMA’s contract.

static numel_scale(
quantized_shape: tuple[int, ...],
mode: ScaleMode | tuple[int, ...],
swizzle: ScaleSwizzleMode,
) int#

Return the number of elements expected in scale for an operand of quantized_shape.

quantized_shape is (L, outer, K) for a 3D operand, where outer is M for an A-side scale and N for a B-side scale. One scale factor covers V elements along K, so the scale tensor has logical shape (L, outer, ceil_div(K, V)).

scale.numel() must equal the value returned by this method. The shape of the scale tensor is otherwise unconstrained.

Returned value depends on swizzle:

where V = ScaleMode.numel(mode) is the number of quantized-tensor elements covered by one scale factor.

Parameters:
  • quantized_shape (tuple[int, ...]) – Logical shape of the operand the scale will be paired with, as (L, outer, K) or (outer, K).

  • mode (ScaleMode | tuple[int, ...]) – Block shape of the scaling.

  • swizzle (ScaleSwizzleMode) – In-memory layout of the scale tensor.

Returns:

Required number of scale-factor elements.

Return type:

int

Raises:

ValueError – If quantized_shape is not rank 2 or 3, or swizzle is not a recognised ScaleSwizzleMode.

class cutlass.operators.arguments.operand.ScaleMode(value)#

Bases: Enum

An enum over commonly used block scaling modes for a ScaledOperand.

Each member’s value is a (batch, row, col) tuple giving the shape of the block of quantized-tensor elements that share a scale factor. Each scale factor is broadcast & multiplied over this block of quantized-tensor elements.

For block shapes that are not enumerated here, bare (batch, row, col) tuples are also accepted as ScaledOperand.mode

See also

Blockwise1x16 = (1, 1, 16)#

Scale over (1, 1, 16) block. Used by NVIDIA NVFP4 (FP8 E4M3 scale dtype).

Blockwise1x32 = (1, 1, 32)#

Scale over (1, 1, 32) block. Used by OCP MXFP8 / MXFP4 (E8M0 scale dtype).

static compare(
mode1: ScaleMode | tuple[int, ...],
mode2: ScaleMode | tuple[int, ...],
) bool#

Return whether two scale modes describe the same scaling.

Allows mixed comparisons between ScaleMode enums and bare tuples, and tolerates differing tuple lengths as long as the longer tuple has leading 1 s for the extra positions (so that, e.g., (1, 1, 16) == (1, 16)).

Parameters:
  • mode1 (ScaleMode | tuple[int, ...]) – First mode.

  • mode2 (ScaleMode | tuple[int, ...]) – Second mode.

Returns:

True if mode1 and mode2 describe the same scaling.

Return type:

bool

static numel(
scale: ScaleMode | tuple[int, ...],
) int#

Return the number of quantized-tensor elements scaled by one scale factor.

For a scale mode of block shape (L, M, K), this is the block volume L * M * K – the number of contiguous elements in a quantized tensor that share (and are multiplied by) the same scale factor.

Parameters:

scale (ScaleMode | tuple[int, ...]) – Scale mode whose tuple entries give the block shape.

Returns:

Product of the entries of scale (e.g. numel(Blockwise1x32) == 32).

Return type:

int

class cutlass.operators.arguments.operand.ScaleSwizzleMode(value)#

Bases: Enum

In-memory layout of the scale tensor in a ScaledOperand.

Hardware MMAs that consume block-scaled inputs typically require their scale tensors to be stored in a specific non-trivial layout.

ScaleSwizzleMode indicates that scale factors inside a ScaledOperand are already stored in one of those specific layouts.

Operator API validates that the scale tensor is contiguous and has the element count required by (mode, swizzle), but it does not inspect or rearrange the values. The producer of the scale tensor (typically a quantizer) is responsible for writing values in the named layout.

See also

  • ScaledOperand: the operand that consumes this enum.

  • ScaleMode: granularity of the scaling.

  • PyTorch torch.nn.functional.SwizzleType, which this enum closely resembles.

SwizzleNone = 1#

Scale tensor stored in the natural ordering implied by ScaleMode.

For an (L, M, K) operand at mode (1, 1, V), this is a tensor of L * M * (K // V) scale factors with one value per mode block.

Swizzle32x4x4 = 2#

1D block-scaling layout dictated by Blackwell tcgen05.mma block-scaled MMAs.

This is used for MXFP8 / MXFP4 / NVFP4 GEMMs on Blackwell. Under this layout, each tile contains 128x4 scale factors, and the 128 rows are interleaved in groups of 32, matching the warp-group structure of the Blackwell tensor core.

For a quantized tensor of shape (L, M, K) and a scale vector size of V, the scale tensor is required to have L * round_up(M, 128) * round_up(ceil_div(K, V), 4) elements.

References

Type markers#

Type markers for CUTLASS Operator API field annotations.

cutlass.operators.typing.TensorLike#

Tensor-like inputs accepted by the Operator API.

Includes:
  • Any DLPack-compatible tensor (torch.Tensor, jax.Array, numpy.ndarray, …).

  • cutlass.cute.Tensor (CuTe DSL host tensor; does not implement DLPack but is handled natively by TensorWrapper).

  • cutlass.operators.utils.tensor.TensorWrapper (implements DLPack).

alias of _SupportsDLPack | Tensor | TensorWrapper

class cutlass.operators.typing.NumericLike(*args, **kwargs)#

Bases: Protocol

Type marker for fields that accept numeric-like types.

Fields annotated with NumericLike accept the following:
  • cutlass.Numeric

  • torch.dtype