Files
2026-07-13 12:31:40 +08:00

83 lines
2.5 KiB
Python

# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# To view a copy of this license, visit http://www.apache.org/licenses/LICENSE-2.0
#
# No warranties are given. The work is provided "AS IS", without warranty of any kind, express or implied.
#
# SPDX-License-Identifier: Apache-2.0
import torch
try:
from . import longlive_kv_dequant_cuda # noqa: F401
except ImportError:
import longlive_kv_dequant_cuda # noqa: F401
def _dtype_to_code(dtype: torch.dtype) -> int:
if dtype == torch.bfloat16:
return 0
if dtype == torch.float16:
return 1
if dtype == torch.float32:
return 2
raise ValueError(f"Unsupported fused KV dequant dtype: {dtype}")
def scale_rule_to_fp4_limits(scale_rule) -> tuple[float, float]:
"""Return the dequant denominator limits used by FourOverSix ScaleRule."""
if hasattr(scale_rule, "max_allowed_e2m1_value") and hasattr(
scale_rule, "max_allowed_e4m3_value",
):
return (
float(scale_rule.max_allowed_e2m1_value()),
float(scale_rule.max_allowed_e4m3_value()),
)
normalized = str(scale_rule).lower()
if "." in normalized:
normalized = normalized.rsplit(".", 1)[-1]
normalized = normalized.strip().strip("\"'")
if normalized == "static_4":
return 4.0, 448.0
if normalized == "static_6":
return 6.0, 448.0
if normalized in {"mse", "mae", "l1_norm", "abs_max"}:
return 6.0, 256.0
raise ValueError(f"Unsupported FP4 scale_rule: {scale_rule}")
def dequantize_kv_cache_fp4(
values: list[torch.Tensor],
scale_factors: list[torch.Tensor],
amax: list[torch.Tensor],
*,
num_heads: int,
block_token_size: int,
dtype: torch.dtype,
e2m1_max: float | None = None,
e4m3_max: float | None = None,
scale_rule=None,
) -> torch.Tensor:
"""Dequantize multiple AR KV-cache chunks with one CUDA launch."""
if e2m1_max is None or e4m3_max is None:
if scale_rule is None:
raise ValueError(
"Either e2m1_max/e4m3_max or scale_rule must be provided.",
)
e2m1_max, e4m3_max = scale_rule_to_fp4_limits(scale_rule)
return torch.ops.longlive_kernels.dequantize_kv_cache_fp4.default(
values,
scale_factors,
amax,
num_heads,
block_token_size,
_dtype_to_code(dtype),
e2m1_max,
e4m3_max,
)