Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7c3abf6
[Common] More CuTeDSL MXFP8 special kernels
kainzhong Oct 7, 2026
6e854d5
Merge branch 'main' into more_cutedsl_mxfp8_specialized
kainzhong Oct 7, 2026
1be6447
wip
kainzhong Oct 8, 2026
1995fea
wip
kainzhong Oct 8, 2026
3e7a653
refactor
kainzhong Oct 9, 2026
79c5d53
refactor
kainzhong Oct 9, 2026
c51a3b8
refactor
kainzhong Oct 9, 2026
f14e433
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 9, 2026
5f9ece2
fix
kainzhong Oct 9, 2026
870b23c
disable invariant temporarily
kainzhong Oct 9, 2026
4ef3404
fix
kainzhong Oct 10, 2026
ef9877d
refactor
kainzhong Oct 12, 2026
d6bb258
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 12, 2026
fffc874
fix
kainzhong Oct 12, 2026
2fd0aca
fix
kainzhong Oct 12, 2026
8afd230
also support swizzled scale for g2r bidim
kainzhong Oct 12, 2026
87ab24e
lint
kainzhong Oct 12, 2026
cae94f5
add tests
kainzhong Oct 12, 2026
f67b1e5
fix
kainzhong Oct 12, 2026
177647e
nit
kainzhong Oct 12, 2026
8f4c54d
refactor
kainzhong Oct 13, 2026
fddd076
refactor
kainzhong Oct 14, 2026
3a8a882
more refactor
kainzhong Oct 14, 2026
30c92ab
g2r bidim can also support colwise only
kainzhong Oct 14, 2026
5c3465a
make g2r support activations
kainzhong Oct 15, 2026
b1db277
fix
kainzhong Oct 15, 2026
dcd8b08
fix
kainzhong Oct 15, 2026
86233c8
+0 and -0 should both legal
kainzhong Oct 15, 2026
dba8dbf
nit
kainzhong Oct 15, 2026
287505f
fix
kainzhong Oct 17, 2026
2c6f6ec
fix
kainzhong Oct 20, 2026
53bc647
close fp32 perf gap
kainzhong Oct 21, 2026
bfdb240
can always use static tile num
kainzhong Oct 21, 2026
2e19e63
[Common] Add MXFP8 2D quantization in CuTeDSL
kainzhong Oct 28, 2026
2eb13b1
Merge branch 'main' into mxfp8_2d_quant
kainzhong Nov 9, 2026
8a81e6e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2026
1f27ee2
fix nan
kainzhong Nov 10, 2026
363f74f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,14 @@ def fill():
return fill(), fill()


def run_quantize(method, act, x, ain, rowwise, columnwise, fp8_dtype, swizzled):
def run_quantize(method, act, x, ain, rowwise, columnwise, fp8_dtype, swizzled, use_2d_quant):
"""Quantize via the public dispatch; returns (mxfp8_tensor, dbias_or_None)."""
q = MXFP8Quantizer(fp8_dtype=fp8_dtype, rowwise=rowwise, columnwise=columnwise)
q = MXFP8Quantizer(
fp8_dtype=fp8_dtype,
rowwise=rowwise,
columnwise=columnwise,
with_2d_quantization=use_2d_quant,
)
# Emit scales in the GEMM-swizzled layout (MXFP8QuantConfig::swizzled).
q.optimize_for_gemm = swizzled
if method == "CAST_ONLY":
Expand All @@ -216,7 +221,7 @@ def run_quantize(method, act, x, ain, rowwise, columnwise, fp8_dtype, swizzled):
raise ValueError(f"unknown method {method!r}")


def get_cfg_key(method, act, in_dtype, fp8_dtype, rowwise, colwise, swizzled):
def get_cfg_key(method, act, in_dtype, fp8_dtype, rowwise, colwise, swizzled, use_2d_quant):
"""Mirror of MXFP8QuantConfig::to_key (quantize_mxfp8_cutedsl.cuh): the name the CuTeDSL backend registers its compiled kernel under for this config.
Used to check if the CuTeDSL implementation is registered
"""
Expand All @@ -229,8 +234,7 @@ def get_cfg_key(method, act, in_dtype, fp8_dtype, rowwise, colwise, swizzled):
elif with_dact:
desc = f"d{act['desc']}"
# with_amax is hardcoded to False for now because currently MXFP8 quantizers never allocate an amax
# The last False is for use_2d_quantization; these cases never request 2D block scaling
flags = (rowwise, colwise, swizzled, False, with_dbias, with_dact, with_act, False)
flags = (rowwise, colwise, swizzled, False, with_dbias, with_dact, with_act, use_2d_quant)
major, minor = device_compute_capability()
return (
f"cutedsl_mxfp8_sm{major * 10 + minor}_"
Expand Down Expand Up @@ -271,7 +275,15 @@ def extract_quantized_output(out, rowwise, columnwise, swizzled):


def run_test_case(
method, act, shape, block_size, in_dtype, fp8_dtype, swizzled=False, input_offset=0
method,
act,
shape,
block_size,
in_dtype,
fp8_dtype,
swizzled=False,
input_offset=0,
use_2d_quant=False,
):
"""Assert the CuTeDSL and CUDA backends produce bit-identical outputs for the
same input and config. input_offset (in elements) shifts x's data pointer past the
Expand All @@ -287,14 +299,14 @@ def run_test_case(

set_cutedsl_backend(False)
out_cuda, dbias_cuda = run_quantize(
method, act, x, act_input, rowwise, columnwise, fp8_dtype, swizzled
method, act, x, act_input, rowwise, columnwise, fp8_dtype, swizzled, use_2d_quant
)
cuda_output = extract_quantized_output(out_cuda, rowwise, columnwise, swizzled)

set_cutedsl_backend(True)
try:
out_cutedsl, dbias_cutedsl = run_quantize(
method, act, x, act_input, rowwise, columnwise, fp8_dtype, swizzled
method, act, x, act_input, rowwise, columnwise, fp8_dtype, swizzled, use_2d_quant
)
cutedsl_output = extract_quantized_output(out_cutedsl, rowwise, columnwise, swizzled)
finally:
Expand All @@ -304,7 +316,7 @@ def run_test_case(
# CuTeDSL backend supports, so its kernel must have been registered under the
# config key. If not, the backend rejected or missed the config and the
# comparison above was CUDA vs CUDA.
key = get_cfg_key(method, act, in_dtype, fp8_dtype, rowwise, columnwise, swizzled)
key = get_cfg_key(method, act, in_dtype, fp8_dtype, rowwise, columnwise, swizzled, use_2d_quant)
assert tvm_ffi.get_global_func(key, allow_missing=True) is not None, (
f"CuTeDSL kernel not registered for {key}; the CuTeDSL backend fell back "
"to CUDA and this case compared CUDA against itself"
Expand All @@ -314,6 +326,8 @@ def run_test_case(
tag = (
f"{method}/{act['name']}/{M}x{N}/{DTYPE_TO_STR[in_dtype]}/{FP8_TO_STR[fp8_dtype]}/{layout}"
)
if use_2d_quant:
tag += "/2d"
for name, cuda_bytes in cuda_output.items():
assert torch.equal(
cutedsl_output[name], cuda_bytes
Expand All @@ -334,6 +348,18 @@ def test_cast_only(swizzled, fp8_dtype, in_dtype, block_size, shape):
run_test_case("CAST_ONLY", IDENTITY, shape, block_size, in_dtype, fp8_dtype, swizzled)


# 2D block scaling (one scale per 32x32 block) is only reachable as a plain cast.
@pytest.mark.parametrize("shape", MATRIX_SIZES, ids=get_shape_id)
@pytest.mark.parametrize("block_size", BLOCK_SIZES, ids=get_block_id)
@pytest.mark.parametrize("in_dtype", IN_DTYPES, ids=get_dtype_id)
@pytest.mark.parametrize("fp8_dtype", FP8_DTYPES, ids=get_fp8_id)
@pytest.mark.parametrize("swizzled", SWIZZLE_MODES, ids=get_swizzle_id)
def test_cast_only_2d(swizzled, fp8_dtype, in_dtype, block_size, shape):
run_test_case(
"CAST_ONLY", IDENTITY, shape, block_size, in_dtype, fp8_dtype, swizzled, use_2d_quant=True
)


def test_cast_only_rowwise_specialized_grid_y_overflow():
"""Fall back when the specialized rowwise launch would exceed CUDA's grid.y limit."""
# The specialized kernel covers four rows per CTA, so this shape would require
Expand Down
Loading
Loading