chore: import upstream snapshot with attribution
PR Test AMD / cancel-on-close (push) Has been skipped
PR Test NVIDIA ARM / scan (push) Has been skipped
PR Test NVIDIA / cancel-on-close (push) Has been skipped
PR Test AMD / scan (push) Has been skipped
PR Test NVIDIA ARM / cancel-on-close (push) Has been skipped
PR Test NVIDIA / scan (push) Has been skipped
Release Docker Images / build (cu129-torch-2.11.0) (push) Has been skipped
Release Docker Images / build (cu130-torch-2.11.0) (push) Has been skipped
Release PyPI / publish (push) Has been skipped
Scheduler Python Test / test (push) Successful in 27m19s
Docs / build (push) Successful in 28m8s
Scheduler C++ Test / test (push) Successful in 28m19s
Scheduler C++ Test / test-flat (push) Successful in 28m18s
Docs / deploy (push) Has been cancelled
PR Test AMD / finish (push) Has been cancelled
PR Test NVIDIA / finish (push) Has been cancelled
PR Test NVIDIA ARM / finish (push) Has been cancelled
PR Test NVIDIA ARM / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test AMD / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test NVIDIA / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:32:31 +08:00
commit 59a0a3844c
1103 changed files with 340460 additions and 0 deletions
@@ -0,0 +1,376 @@
# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import annotations
from typing import Literal
import torch
from tokenspeed_kernel.profiling import ShapeCapture, kernel_scope
from tokenspeed_kernel.selection import select_kernel
from tokenspeed_kernel.signature import dense_tensor_format, format_signature
__all__ = [
"quantize_fp8",
"quantize_fp8_with_scale",
"quantize_mxfp8",
"quantize_nvfp4",
"quantize_mxfp4",
]
def quantize_fp8(
x: torch.Tensor,
scale: float | torch.Tensor | None = None,
# kernel options
enable_pdl: bool = False,
# dispatch options
override: str | None = None,
solution: str | None = None,
) -> torch.Tensor:
"""Quantize x to same-shape FP8 with an optional scalar scale.
This API covers static activation-scale cases such as GPT-OSS MXFP4 MoE
W4A8 input quantization and plain FP8 casts. If scale is provided, it is
the actual quantization scale, so the backend computes x / scale before
casting. If scale is omitted, the backend performs a pure FP8 cast.
Args:
x: Input tensor.
scale: Optional scalar scale, as a Python value or scalar tensor. If
provided, the backend computes x / scale before casting. If omitted,
the backend performs a pure FP8 cast.
enable_pdl: Whether to request Programmatic Dependent Launch support.
override: Optional exact kernel name or solution override.
solution: Optional registered solution to select.
Returns:
Quantized FP8 tensor with the same shape as x.
Non-scalar scales belong in dynamic quantization APIs and should be
on-device tensors.
"""
traits = {
"has_scale": scale is not None,
}
signature = format_signature(x=dense_tensor_format(x.dtype))
kernel = select_kernel(
"quantization",
"fp8",
signature,
traits=traits,
solution=solution,
override=override,
)
shape_params = {
"shape": tuple(x.shape),
"has_scale": scale is not None,
}
ShapeCapture.get().record("quantization", "fp8", kernel.name, x.dtype, shape_params)
with kernel_scope(
"quantization", "fp8", x.dtype, kernel_name=kernel.name, **shape_params
):
return kernel(
x,
scale=scale,
enable_pdl=enable_pdl,
)
def quantize_fp8_with_scale(
x: torch.Tensor,
# quantization options
granularity: Literal["tensor", "token", "token_group"] = "tensor",
group_size: int | None = None,
scale_encoding: Literal["float32", "ue8m0", "packed_ue8m0"] = "float32",
# kernel options
enable_pdl: bool = False,
# dispatch options
override: str | None = None,
solution: str | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Quantize x to FP8 while dynamically computing scales.
Use granularity="tensor" for one scale over the whole tensor,
granularity="token" for one scale per row/token, and
granularity="token_group" for one scale per row/token and contiguous group
along the last dimension.
Args:
x: Input tensor.
granularity: Scale granularity. Supported values are tensor, token, and
token_group.
group_size: Number of contiguous values per scale group along the last
dimension. Required for token_group granularity.
scale_encoding: Scale encoding for token_group granularity, such as
float32, ue8m0, or packed_ue8m0.
enable_pdl: Whether to request Programmatic Dependent Launch support.
override: Optional exact kernel name or solution override.
solution: Optional registered solution to select.
Returns:
Tuple of quantized FP8 tensor and scale tensor.
The expected scale shapes are [1] for tensor granularity, [M, 1] for token
granularity, and [M, ceil(K / group_size)] or a backend-specific layout for
token_group granularity, where M = x.reshape(-1, x.shape[-1]).shape[0].
Returned scales use float32 dtype for scale_encoding="float32" and a
backend-specific encoded integer dtype for non-float encodings such as
"ue8m0".
"""
if granularity not in {"tensor", "token", "token_group"}:
raise ValueError(f"unsupported FP8 dynamic granularity: {granularity!r}")
if granularity == "token_group":
if group_size is None or group_size <= 0:
raise ValueError(
f"token_group granularity requires positive group_size, got {group_size}"
)
granularity_trait = f"token_group_{group_size}"
else:
granularity_trait = granularity
traits = {
"granularity": granularity_trait,
"scale_encoding": scale_encoding,
}
signature = format_signature(x=dense_tensor_format(x.dtype))
kernel = select_kernel(
"quantization",
"fp8_with_scale",
signature,
traits=traits,
solution=solution,
override=override,
)
shape_params = {
"shape": tuple(x.shape),
"granularity": granularity_trait,
"group_size": group_size,
"scale_encoding": scale_encoding,
}
ShapeCapture.get().record(
"quantization", "fp8_with_scale", kernel.name, x.dtype, shape_params
)
with kernel_scope(
"quantization",
"fp8_with_scale",
x.dtype,
kernel_name=kernel.name,
**shape_params,
):
return kernel(
x,
granularity=granularity,
group_size=group_size,
scale_encoding=scale_encoding,
enable_pdl=enable_pdl,
)
def quantize_mxfp8(
x: torch.Tensor,
# kernel options
enable_pdl: bool = False,
# dispatch options
override: str | None = None,
solution: str | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Quantize x to MXFP8 format.
MXFP8 uses FP8 data plus encoded vector scales, commonly one scale per 32
values along the last dimension.
Args:
x: Input tensor.
enable_pdl: Whether to request Programmatic Dependent Launch support.
override: Optional exact kernel name or solution override.
solution: Optional registered solution to select.
Returns:
Tuple of quantized MXFP8 tensor and encoded scale tensor.
"""
traits = {}
signature = format_signature(x=dense_tensor_format(x.dtype))
kernel = select_kernel(
"quantization",
"mxfp8",
signature,
traits=traits,
solution=solution,
override=override,
)
shape_params = {
"shape": tuple(x.shape),
}
ShapeCapture.get().record(
"quantization", "mxfp8", kernel.name, x.dtype, shape_params
)
with kernel_scope(
"quantization", "mxfp8", x.dtype, kernel_name=kernel.name, **shape_params
):
return kernel(
x,
enable_pdl=enable_pdl,
)
def quantize_nvfp4(
x: torch.Tensor,
scale: float | torch.Tensor | None = None,
# quantization options
scale_layout: Literal["linear", "swizzled"] = "swizzled",
# kernel options
enable_pdl: bool = False,
# dispatch options
override: str | None = None,
solution: str | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Quantize x to packed NVFP4.
NVFP4 uses packed E2M1x2 data with one E4M3 scale factor per 16 values.
The quantized output is usually shaped [M, K/2].
scale is the actual input scale. Backend adapters should handle any
backend-specific inverse-scale convention internally.
Args:
x: Input tensor.
scale: Optional scalar input scale.
scale_layout: Scale-factor layout. "linear" returns unswizzled scales;
"swizzled" requests the backend-specific layout used by FP4 GEMM.
enable_pdl: Whether to request Programmatic Dependent Launch support.
override: Optional exact kernel name or solution override.
solution: Optional registered solution to select.
Returns:
Tuple of packed NVFP4 tensor and scale-factor tensor.
"""
traits = {
"scale_layout": scale_layout,
"has_scale": scale is not None,
}
signature = format_signature(x=dense_tensor_format(x.dtype))
kernel = select_kernel(
"quantization",
"nvfp4",
signature,
traits=traits,
solution=solution,
override=override,
)
shape_params = {
"shape": tuple(x.shape),
"scale_layout": scale_layout,
"has_scale": scale is not None,
}
ShapeCapture.get().record(
"quantization", "nvfp4", kernel.name, x.dtype, shape_params
)
with kernel_scope(
"quantization", "nvfp4", x.dtype, kernel_name=kernel.name, **shape_params
):
return kernel(
x,
scale=scale,
scale_layout=scale_layout,
enable_pdl=enable_pdl,
)
def quantize_mxfp4(
x: torch.Tensor,
# quantization options
global_scale: float | None = None,
scale_size: int = 32,
scale_layout: Literal["linear", "128x4", "8x4"] = "128x4",
# kernel options
enable_pdl: bool = False,
# dispatch options
override: str | None = None,
solution: str | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Quantize x to packed MXFP4.
MXFP4 uses packed E2M1x2 data with one UE8M0 scale factor per scale_size
values, usually scale_size=32. The quantized output is usually shaped
[M, K/2].
global_scale is optional because some backends compute the global scale
internally from the input. If provided, it is the actual global scale.
Args:
x: Input tensor.
global_scale: Optional scalar global scale.
scale_size: Number of values per scale-factor vector.
scale_layout: Scale-factor layout, such as linear, 128x4, or 8x4.
enable_pdl: Whether to request Programmatic Dependent Launch support.
override: Optional exact kernel name or solution override.
solution: Optional registered solution to select.
Returns:
Tuple of packed MXFP4 tensor and scale-factor tensor.
"""
if scale_size <= 0:
raise ValueError(f"scale_size must be positive, got {scale_size}")
traits = {
"scale_size": scale_size,
"scale_layout": scale_layout,
"has_global_scale": global_scale is not None,
"scale_encoding": "ue8m0",
}
signature = format_signature(x=dense_tensor_format(x.dtype))
kernel = select_kernel(
"quantization",
"mxfp4",
signature,
traits=traits,
solution=solution,
override=override,
)
shape_params = {
"shape": tuple(x.shape),
"scale_size": scale_size,
"scale_layout": scale_layout,
"has_global_scale": global_scale is not None,
}
ShapeCapture.get().record(
"quantization", "mxfp4", kernel.name, x.dtype, shape_params
)
with kernel_scope(
"quantization", "mxfp4", x.dtype, kernel_name=kernel.name, **shape_params
):
return kernel(
x,
global_scale=global_scale,
scale_size=scale_size,
scale_layout=scale_layout,
enable_pdl=enable_pdl,
)
# Backend registration (side-effect imports).
import tokenspeed_kernel.ops.quantization.flashinfer # noqa: E402,F401
import tokenspeed_kernel.ops.quantization.triton # noqa: E402,F401
import tokenspeed_kernel.ops.quantization.trtllm # noqa: E402,F401
@@ -0,0 +1,27 @@
# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""CUDA quantization kernels."""
from tokenspeed_kernel.registry import error_fn
try:
from tokenspeed_kernel.thirdparty.cuda.marlin import gptq_marlin_repack
except ImportError:
gptq_marlin_repack = error_fn
__all__ = ["gptq_marlin_repack"]
@@ -0,0 +1,105 @@
# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import annotations
import torch
from tokenspeed_kernel.platform import (
ArchVersion,
CapabilityRequirement,
current_platform,
)
from tokenspeed_kernel.registry import Priority, error_fn, register_kernel
from tokenspeed_kernel.signature import format_signatures
platform = current_platform()
fp4_quantize = error_fn
flashinfer_quantize_mxfp8 = error_fn
flashinfer_quantize_nvfp4 = error_fn
mxfp8_quantize = error_fn
nvfp4_block_scale_interleave = error_fn
fp8_blockscale_quantize_runner_sm90 = error_fn
if platform.is_nvidia:
from flashinfer import mxfp8_quantize
if platform.is_hopper:
from flashinfer.gemm.gemm_base import (
get_fp8_blockscale_gemm_runner_sm90 as fp8_blockscale_quantize_runner_sm90,
)
@register_kernel(
"quantization",
"mxfp8",
name="flashinfer_quantize_mxfp8",
solution="flashinfer",
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={},
priority=Priority.PERFORMANT,
)
def flashinfer_quantize_mxfp8(
x: torch.Tensor,
enable_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
return mxfp8_quantize(x, False)
if platform.is_nvidia and platform.is_blackwell:
from flashinfer import (
fp4_quantize,
nvfp4_block_scale_interleave,
)
@register_kernel(
"quantization",
"nvfp4",
name="flashinfer_quantize_nvfp4",
solution="flashinfer",
capability=CapabilityRequirement(
min_arch_version=ArchVersion(10, 0),
vendors=frozenset({"nvidia"}),
),
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={
"has_scale": frozenset({True}),
},
priority=Priority.PERFORMANT,
)
def flashinfer_quantize_nvfp4(
x: torch.Tensor,
scale: float | torch.Tensor | None = None,
scale_layout: str = "swizzled",
enable_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
# The public quantization API uses the actual scale; FlashInfer's FP4
# helper expects the inverse scale used before packing.
scale_inv = 1.0 / scale
return fp4_quantize(
x,
global_scale=scale_inv,
sf_vec_size=16,
is_sf_swizzled_layout=scale_layout == "swizzled",
enable_pdl=enable_pdl,
)
__all__ = [
"fp4_quantize",
"mxfp8_quantize",
"nvfp4_block_scale_interleave",
"fp8_blockscale_quantize_runner_sm90",
]
@@ -0,0 +1,484 @@
# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from typing import Optional
import torch
from tokenspeed_kernel._triton import tl, triton
from tokenspeed_kernel.platform import CapabilityRequirement, current_platform
from tokenspeed_kernel.registry import Priority, register_kernel
from tokenspeed_kernel.signature import format_signatures
platform = current_platform()
@triton.jit
def _fp8_quantize_kernel(
x_ptr,
out_ptr,
scale,
M,
N,
x_row_stride,
out_row_stride,
BLOCK_N: tl.constexpr,
EVEN_N: tl.constexpr,
FP8_DTYPE: tl.constexpr,
BLOCK_M: tl.constexpr,
HAS_SCALE: tl.constexpr,
HAS_SCALE_TENSOR: tl.constexpr,
ENABLE_PDL: tl.constexpr,
):
pid = tl.program_id(0)
m_idx = pid * BLOCK_M + tl.arange(0, BLOCK_M)
m_mask = m_idx < M
n_idx = tl.arange(0, BLOCK_N)
# PDL: wait for the producer kernel (e.g., kv_b_proj GEMM) to drain before
# we read its output. No-op when disabled.
if ENABLE_PDL:
tl.extra.cuda.gdc_wait()
if EVEN_N:
load_mask = m_mask[:, None]
else:
load_mask = m_mask[:, None] & (n_idx[None, :] < N)
x_off = m_idx[:, None] * x_row_stride + n_idx[None, :]
x = tl.load(x_ptr + x_off, mask=load_mask)
x = x.to(tl.float32)
if HAS_SCALE:
if HAS_SCALE_TENSOR:
scale = tl.load(scale)
x = x * (1.0 / scale)
x_fp8 = x.to(FP8_DTYPE)
out_off = m_idx[:, None] * out_row_stride + n_idx[None, :]
tl.store(out_ptr + out_off, x_fp8, mask=load_mask)
# PDL: signal that dependents (e.g., FMHA) can begin their preamble.
if ENABLE_PDL:
tl.extra.cuda.gdc_launch_dependents()
def _flatten_to_2d(x: torch.Tensor):
"""Flatten leading dims into a single M, returning (M, N, row_stride).
Requires stride(-1) == 1 and that all leading dims pack contiguously
onto the row stride — i.e. ``stride(d) == shape(d+1) * stride(d+1)`` for
every ``d < ndim - 2``. This holds for fully-contiguous tensors and for
last-dim slices like ``kv[..., qk_nope:]`` where the leading dims still
pack onto a uniform row stride.
"""
assert x.stride(-1) == 1, f"expected stride-1 inner dim, got stride={x.stride(-1)}"
N = x.shape[-1]
if x.ndim == 1:
return 1, N, N
M = x.numel() // N
row_stride = x.stride(-2)
# Validate that every leading dim packs onto the next.
for d in range(x.ndim - 2):
expected = x.shape[d + 1] * x.stride(d + 1)
if x.stride(d) != expected:
raise ValueError(
f"cannot flatten dim {d}: stride={x.stride(d)} but expected "
f"shape[{d+1}]*stride[{d+1}]={expected}. Tensor shape={tuple(x.shape)}, "
f"stride={tuple(x.stride())}."
)
return M, N, row_stride
def fp8_quantize(
x: torch.Tensor,
scale: float | torch.Tensor | None = None,
out: Optional[torch.Tensor] = None,
fp8_dtype: torch.dtype = torch.float8_e4m3fn,
enable_pdl: bool = False,
) -> torch.Tensor:
"""Cast a BF16/FP16 tensor to FP8 with an optional per-tensor scale.
Computes ``out = saturate((x / scale) -> fp8)`` element-wise when scale is
provided. When scale is omitted, this is a pure FP8 cast.
Args:
x: BF16 or FP16 tensor. Must have stride(-1) == 1; leading dims must
pack uniformly onto the row stride (true for contiguous tensors and
for last-dim slice views like ``kv[..., qk_nope:]``).
scale: optional scalar divisor applied before the cast. Python values
are passed as plain kernel args; scalar tensors are loaded on device.
out: optional pre-allocated FP8 output. Same shape as ``x``. If not
provided, allocated as contiguous.
fp8_dtype: ``torch.float8_e4m3fn`` (default), ``torch.float8_e5m2`` or
``torch.float8_e4m3fnuz`` (the bias-8 e4m3 used on AMD CDNA3).
enable_pdl: opt into Programmatic Dependent Launch (Hopper+). Caller
must also pass ``launch_pdl=True`` upstream / downstream as needed.
Returns:
FP8 tensor with the same shape as ``x``.
"""
assert x.dtype in (
torch.bfloat16,
torch.float16,
), f"fp8_quantize input must be bf16/fp16, got {x.dtype}"
assert fp8_dtype in (
torch.float8_e4m3fn,
torch.float8_e5m2,
torch.float8_e4m3fnuz,
), f"fp8_quantize unsupported fp8 dtype: {fp8_dtype}"
has_scale = scale is not None
has_scale_tensor = isinstance(scale, torch.Tensor)
if has_scale_tensor:
assert scale.numel() == 1, "scale tensor must be scalar"
scale = scale.contiguous()
M, N, x_row_stride = _flatten_to_2d(x)
if out is None:
out = torch.empty(x.shape, dtype=fp8_dtype, device=x.device)
else:
assert out.shape == x.shape and out.dtype == fp8_dtype
out_M, _, out_row_stride = _flatten_to_2d(out)
assert out_M == M
if fp8_dtype is torch.float8_e4m3fn:
fp8_dtype_const = tl.float8e4nv
elif fp8_dtype is torch.float8_e5m2:
fp8_dtype_const = tl.float8e5
else:
fp8_dtype_const = tl.float8e4b8
# Block-size heuristic — picked from per-shape best configs in an
# nsys-driven sweep on B200 (kv_a [s,512] and v [s,h,128] for K2.5).
# Pattern: num_warps=4, num_stages=2 win universally; BLOCK_M ramps with
# M to amortize launch as the grid grows.
# See tasks/k2.5_optimization/{tune_fp8_quantize_nsys,parse_tune_fp8_quantize_nsys}.py
if M <= 2048:
block_m = 4
elif M <= 16384:
block_m = 16
else:
block_m = 32
num_warps = 4
num_stages = 2
grid = (triton.cdiv(M, block_m),)
block_n = max(1, triton.next_power_of_2(N))
even_n = block_n == N
# ``launch_pdl`` is a NVIDIA-only Triton runtime kwarg (Hopper+ Programmatic
# Dependent Launch). The HIP backend rejects unknown kwargs, so only forward
# it when PDL is actually requested.
extra_kwargs = {"launch_pdl": True} if enable_pdl else {}
_fp8_quantize_kernel[grid](
x,
out,
1.0 if scale is None else scale,
M,
N,
x_row_stride,
out_row_stride,
BLOCK_N=block_n,
EVEN_N=even_n,
FP8_DTYPE=fp8_dtype_const,
BLOCK_M=block_m,
HAS_SCALE=has_scale,
HAS_SCALE_TENSOR=has_scale_tensor,
ENABLE_PDL=enable_pdl,
num_warps=num_warps,
num_stages=num_stages,
**extra_kwargs,
)
return out
@triton.jit
def _fp8_token_group_quantize_kernel(
x_ptr,
out_ptr,
scale_ptr,
group_size,
eps,
bit8_min,
bit8_max,
BLOCK: tl.constexpr,
):
group_id = tl.program_id(0)
cols = tl.arange(0, BLOCK)
mask = cols < group_size
offsets = group_id.to(tl.int64) * group_size + cols
x = tl.load(x_ptr + offsets, mask=mask, other=0.0).to(tl.float32)
scale = tl.maximum(tl.max(tl.abs(x), axis=0), eps) / bit8_max
out = tl.clamp(x / scale, bit8_min, bit8_max).to(out_ptr.dtype.element_ty)
tl.store(out_ptr + offsets, out, mask=mask)
tl.store(scale_ptr + group_id, scale)
def _fp8_token_group_quantize(
x: torch.Tensor,
group_size: int,
) -> tuple[torch.Tensor, torch.Tensor]:
if x.shape[-1] % group_size != 0:
raise ValueError(
f"the last dimension of x must be divisible by group_size, got "
f"shape={tuple(x.shape)}, group_size={group_size}"
)
if not x.is_contiguous():
raise ValueError("x must be contiguous")
out_dtype = platform.fp8e4m3fn.dtype
out = torch.empty_like(x, device=x.device, dtype=out_dtype)
scales = torch.empty(
x.shape[:-1] + (x.shape[-1] // group_size,),
device=x.device,
dtype=torch.float32,
)
groups = x.numel() // group_size
block = triton.next_power_of_2(group_size)
num_warps = min(max(block // 256, 1), 8)
bit8_max = platform.fp8e4m3fn.max
bit8_min = -bit8_max
_fp8_token_group_quantize_kernel[(groups,)](
x,
out,
scales,
group_size,
1e-10,
bit8_min=bit8_min,
bit8_max=bit8_max,
BLOCK=block,
num_warps=num_warps,
num_stages=1,
)
return out, scales
@register_kernel(
"quantization",
"fp8",
name="triton_quantize_fp8",
solution="triton",
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={"has_scale": frozenset({True, False})},
priority=Priority.PORTABLE,
)
def triton_quantize_fp8(
x: torch.Tensor,
scale: float | torch.Tensor | None = None,
enable_pdl: bool = False,
) -> torch.Tensor:
return fp8_quantize(x, scale=scale, enable_pdl=enable_pdl)
@register_kernel(
"quantization",
"fp8_with_scale",
name="triton_quantize_fp8_with_scale",
solution="triton",
capability=CapabilityRequirement(vendors=frozenset({"amd", "nvidia"})),
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={
"granularity": frozenset({"token_group_128"}),
"scale_encoding": frozenset({"float32"}),
},
priority=Priority.PORTABLE,
)
def triton_quantize_fp8_with_scale(
x: torch.Tensor,
granularity: str = "tensor",
group_size: int | None = None,
scale_encoding: str = "float32",
enable_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
if granularity != "token_group" or group_size != 128:
raise ValueError(
"triton FP8 dynamic quantization currently supports only "
f"granularity='token_group' with group_size=128, got "
f"granularity={granularity!r}, group_size={group_size}."
)
if scale_encoding != "float32":
raise ValueError(
"triton FP8 dynamic quantization currently requires "
f"scale_encoding='float32', got {scale_encoding!r}."
)
return _fp8_token_group_quantize(x.contiguous(), 128)
@triton.jit
def _mxfp4_quantize_block(x):
max_normal: tl.constexpr = 6
min_normal: tl.constexpr = 1
amax = tl.max(tl.abs(x), axis=0)
amax = amax.to(tl.int32, bitcast=True)
amax = (amax + 0x200000).to(tl.uint32, bitcast=True) & 0xFF800000
amax = amax.to(tl.float32, bitcast=True)
scale_e8m0_unbiased = tl.log2(amax).floor() - 2
scale_e8m0_unbiased = tl.clamp(scale_e8m0_unbiased, min=-127, max=127)
scale_byte = scale_e8m0_unbiased.to(tl.uint8) + 127
qx = x * tl.exp2(-scale_e8m0_unbiased)
qx = qx.to(tl.uint32, bitcast=True)
sign = qx & 0x80000000
qx = qx ^ sign
qx_fp32 = qx.to(tl.float32, bitcast=True)
saturate_mask = qx_fp32 >= max_normal
denormal_mask = (not saturate_mask) & (qx_fp32 < min_normal)
normal_mask = not (saturate_mask | denormal_mask)
denorm_exp: tl.constexpr = (127 - 1) + (23 - 1) + 1
denorm_mask_int: tl.constexpr = denorm_exp << 23
denorm_mask_float: tl.constexpr = tl.cast(denorm_mask_int, tl.float32, bitcast=True)
denormal_x = qx_fp32 + denorm_mask_float
denormal_x = denormal_x.to(tl.uint32, bitcast=True)
denormal_x -= denorm_mask_int
denormal_x = denormal_x.to(tl.uint8)
normal_x = qx
mant_odd = (normal_x >> (23 - 1)) & 1
normal_x += 0xC11FFFFF
normal_x += mant_odd
normal_x = normal_x >> (23 - 1)
normal_x = normal_x.to(tl.uint8)
e2m1 = tl.full(x.shape, 0x7, dtype=tl.uint8)
e2m1 = tl.where(normal_mask, normal_x, e2m1)
e2m1 = tl.where(denormal_mask, denormal_x, e2m1)
sign_lp = sign >> (23 + 8 - 1 - 2)
sign_lp = sign_lp.to(tl.uint8)
e2m1 = e2m1 | sign_lp
e2m1 = tl.reshape(e2m1, [16, 2])
evens, odds = tl.split(e2m1)
return evens | (odds << 4), scale_byte
@triton.jit
def _mxfp4_quantize_kernel(
x_ptr,
out_ptr,
scale_ptr,
M,
x_row_stride,
out_row_stride,
scale_row_stride,
N: tl.constexpr,
):
pid_m = tl.program_id(0)
pid_g = tl.program_id(1)
offs_k = pid_g * 32 + tl.arange(0, 32)
x = tl.load(x_ptr + pid_m * x_row_stride + offs_k).to(tl.float32)
packed, scale_byte = _mxfp4_quantize_block(x)
pack_idx = tl.arange(0, 16)
tl.store(out_ptr + pid_m * out_row_stride + pid_g * 16 + pack_idx, packed)
tl.store(scale_ptr + pid_m * scale_row_stride + pid_g, scale_byte)
def mxfp4_quantize(
x: torch.Tensor,
out: Optional[torch.Tensor] = None,
scales: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Quantize a BF16/FP16 tensor to packed MXFP4.
The last dimension is quantized in groups of 32 values. The returned data
packs two E2M1 values per byte and returns one uint8 E8M0 scale per group.
"""
assert x.dtype in (
torch.bfloat16,
torch.float16,
), f"mxfp4_quantize input must be bf16/fp16, got {x.dtype}"
M, N, x_row_stride = _flatten_to_2d(x)
if N % 32 != 0:
raise ValueError("mxfp4_quantize requires the last dimension divisible by 32")
out_shape = (*x.shape[:-1], N // 2)
scale_shape = (*x.shape[:-1], N // 32)
if out is None:
out = torch.empty(out_shape, dtype=torch.uint8, device=x.device)
else:
assert out.shape == out_shape and out.dtype == torch.uint8
if scales is None:
scales = torch.empty(scale_shape, dtype=torch.uint8, device=x.device)
else:
assert scales.shape == scale_shape and scales.dtype == torch.uint8
out_M, _, out_row_stride = _flatten_to_2d(out)
scales_M, _, scale_row_stride = _flatten_to_2d(scales)
assert out_M == M and scales_M == M
grid = (M, N // 32)
_mxfp4_quantize_kernel[grid](
x,
out,
scales,
M,
x_row_stride,
out_row_stride,
scale_row_stride,
N=N,
num_warps=1,
)
return out, scales
@register_kernel(
"quantization",
"mxfp4",
name="triton_quantize_mxfp4",
solution="triton",
capability=CapabilityRequirement(vendors=frozenset({"amd"})),
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={
"scale_size": frozenset({32}),
"scale_layout": frozenset({"linear"}),
"has_global_scale": frozenset({False}),
"scale_encoding": frozenset({"ue8m0"}),
},
priority=Priority.PORTABLE,
)
def triton_quantize_mxfp4(
x: torch.Tensor,
global_scale: float | None = None,
scale_size: int = 32,
scale_layout: str = "linear",
enable_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
if global_scale is not None:
raise ValueError("triton MXFP4 quantization does not support global_scale")
if scale_size != 32:
raise ValueError(
f"triton MXFP4 quantization requires scale_size=32, got {scale_size}"
)
if scale_layout != "linear":
raise ValueError(
"triton MXFP4 quantization requires scale_layout='linear', "
f"got {scale_layout!r}"
)
return mxfp4_quantize(x)
__all__ = [
"fp8_quantize",
"mxfp4_quantize",
"triton_quantize_mxfp4",
"triton_quantize_fp8_with_scale",
]
@@ -0,0 +1,117 @@
# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import annotations
import torch
from tokenspeed_kernel.platform import (
ArchVersion,
CapabilityRequirement,
current_platform,
)
from tokenspeed_kernel.registry import Priority, error_fn, register_kernel
from tokenspeed_kernel.signature import format_signatures
platform = current_platform()
trtllm_fp8_token_group_128 = error_fn
trtllm_fp8_token = error_fn
trtllm_fp8_tensor = error_fn
if platform.is_nvidia:
from tokenspeed_kernel.thirdparty.trtllm import (
per_tensor_quant_fp8 as _trtllm_per_tensor_quant_fp8,
)
from tokenspeed_kernel.thirdparty.trtllm import (
per_token_group_quant_8bit as _trtllm_per_token_group_quant_8bit,
)
from tokenspeed_kernel.thirdparty.trtllm import (
per_token_quant_fp8 as _trtllm_per_token_quant_fp8,
)
_FP8_DTYPE = platform.fp8e4m3fn.dtype
def trtllm_fp8_token_group_128(x: torch.Tensor) -> torch.Tensor:
qweight, _scale = _trtllm_per_token_group_quant_8bit(x, group_size=128)
return qweight.float()
def trtllm_fp8_token(x: torch.Tensor) -> torch.Tensor:
output = torch.empty_like(x, dtype=_FP8_DTYPE)
scale = torch.empty(x.size(0), dtype=torch.float32, device=x.device)
_trtllm_per_token_quant_fp8(x, output, scale)
return output.float()
def trtllm_fp8_tensor(x: torch.Tensor) -> torch.Tensor:
output = torch.empty_like(x, dtype=_FP8_DTYPE)
scale = torch.zeros(1, dtype=torch.float32, device=x.device)
_trtllm_per_tensor_quant_fp8(x, output, scale)
return output.float()
@register_kernel(
"quantization",
"fp8_with_scale",
name="trtllm_quantize_fp8_with_scale",
solution="trtllm",
capability=CapabilityRequirement(
max_arch_version=ArchVersion(10, 9),
vendors=frozenset({"nvidia"}),
),
signatures=format_signatures("x", "dense", {torch.bfloat16, torch.float16}),
traits={
"granularity": frozenset({"tensor", "token", "token_group_128"}),
"scale_encoding": frozenset({"float32", "ue8m0"}),
},
priority=Priority.PERFORMANT,
)
def trtllm_quantize_fp8_with_scale(
x: torch.Tensor,
granularity: str = "tensor",
group_size: int | None = None,
scale_encoding: str = "float32",
enable_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
if granularity in {"tensor", "token"}:
if scale_encoding != "float32":
raise ValueError(f"TRT-LLM {granularity} FP8 requires float32 scales")
q = torch.empty_like(x, dtype=_FP8_DTYPE)
if granularity == "tensor":
scale = torch.empty(1, dtype=torch.float32, device=x.device)
_trtllm_per_tensor_quant_fp8(x, q, scale)
else:
scale = torch.empty(x.shape[:-1], dtype=torch.float32, device=x.device)
_trtllm_per_token_quant_fp8(x, q, scale)
scale = scale.unsqueeze(-1)
return q, scale
if granularity == "token_group":
return _trtllm_per_token_group_quant_8bit(
x,
group_size=group_size,
use_ue8m0=scale_encoding == "ue8m0",
)
raise ValueError(f"unsupported TRT-LLM FP8 granularity: {granularity!r}")
__all__ = [
"trtllm_fp8_token_group_128",
"trtllm_fp8_token",
"trtllm_fp8_tensor",
]