Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

169 lines
6.2 KiB
Python

from typing import Iterable, NamedTuple, Optional, Tuple
import torch
from sglang.srt.layers.quantization.fp8 import Fp8LinearMethod, Fp8MoEMethod
from sglang.srt.layers.quantization.fp8_utils import (
block_quant_dequant,
inverse_transform_scale_ue8m0,
)
from sglang.srt.layers.quantization.modelopt_quant import (
ModelOptFp4LinearMethod,
ModelOptNvFp4FusedMoEMethod,
)
# chunk to avoid too high GPU memory peak
CHUNK_NUMEL = 64 * 1024 * 1024
class CompareResult(NamedTuple):
equal: bool
max_abs_err: float
mean_abs_err: float
num_exceed: int # elements past the combined per-side tolerance
class ComparableWeight:
"""Base comparable-weight class; one subclass per precision or raw tensor."""
@staticmethod
def _quant_ulp(w_q: torch.Tensor) -> torch.Tensor:
"""Per-element ULP of w_q in its own dtype."""
finfo = torch.finfo(w_q.dtype)
x = w_q.to(torch.float32).abs()
# frexp: x = m * 2^e, m in [0.5, 1), so 2^(e-1) is x's binade base.
_, exponent = torch.frexp(x)
binade = torch.exp2((exponent - 1).to(torch.float32))
# Zeros and subnormals share the spacing of the smallest normal binade.
binade = binade.masked_fill(x < finfo.smallest_normal, finfo.smallest_normal)
return binade * finfo.eps
def iter_chunks(self) -> Iterable[Tuple[torch.Tensor, Optional[torch.Tensor]]]:
raise NotImplementedError
def dequantize(self, dtype: torch.dtype = torch.bfloat16) -> torch.Tensor:
raise NotImplementedError
class Fp8BlockComparable(ComparableWeight):
"""Deepseek-style FP8 quantization."""
def __init__(self, w_q: torch.Tensor, w_s: torch.Tensor):
self.w_q = w_q
self.w_s = w_s
def __repr__(self) -> str:
return f"fp8_block(shape={tuple(self.w_q.shape)} dtype={self.w_q.dtype})"
@staticmethod
def _normalize_scale(w_q: torch.Tensor, w_s: torch.Tensor) -> torch.Tensor:
if w_s.dtype == torch.int32:
w_s = inverse_transform_scale_ue8m0(w_s, mn=w_q.shape[-2])
# ue8m0 packing aligns k to a multiple of 4; drop the padding blocks.
w_s = w_s[..., : -(-w_q.shape[-1] // 128)]
return w_s.to(torch.float32)
@staticmethod
def _infer_block_size(w_q: torch.Tensor, w_s: torch.Tensor) -> list:
k, s_k = w_q.shape[-1], w_s.shape[-1]
assert k % s_k == 0, f"cannot infer block size from {w_q.shape=} {w_s.shape=}"
block = k // s_k
return [block, block]
@staticmethod
def _iter_quant_chunks(w_q: torch.Tensor, w_s: torch.Tensor, block_n: int):
"""Yields block-row-aligned (q_slice, s_slice) pairs of bounded size."""
q3 = w_q.reshape(-1, *w_q.shape[-2:])
s3 = w_s.reshape(-1, *w_s.shape[-2:])
n, k = q3.shape[-2:]
rows = max(block_n, CHUNK_NUMEL // k // block_n * block_n)
for b in range(q3.shape[0]):
for r0 in range(0, n, rows):
r1 = min(r0 + rows, n)
yield q3[b, r0:r1], s3[b, r0 // block_n : -(-r1 // block_n)]
def _scale_and_block_size(self):
s = self._normalize_scale(self.w_q, self.w_s)
return s, self._infer_block_size(self.w_q, s)
def iter_chunks(self):
s, block_size = self._scale_and_block_size()
for q, s_chunk in self._iter_quant_chunks(self.w_q, s, block_size[0]):
q, s_chunk = q.cuda(), s_chunk.cuda()
yield (
block_quant_dequant(q, s_chunk, block_size, dtype=torch.bfloat16),
block_quant_dequant(
self._quant_ulp(q), s_chunk, block_size, dtype=torch.float32
),
)
def dequantize(self, dtype: torch.dtype = torch.bfloat16) -> torch.Tensor:
s, block_size = self._scale_and_block_size()
return block_quant_dequant(self.w_q, s, block_size, dtype=dtype)
class RawComparable(ComparableWeight):
"""Bitwise equal compare on raw tensor."""
def __init__(self, tensor: torch.Tensor):
self.tensor = tensor
def __repr__(self) -> str:
return f"raw(shape={tuple(self.tensor.shape)} dtype={self.tensor.dtype})"
def iter_chunks(self):
flat = self.tensor.reshape(-1)
for start in range(0, flat.numel(), CHUNK_NUMEL):
yield flat[start : start + CHUNK_NUMEL].cuda(), None
def dequantize(self, dtype: torch.dtype = torch.bfloat16) -> torch.Tensor:
return self.tensor
def compare_weights(
expect: ComparableWeight, actual: ComparableWeight
) -> CompareResult:
"""Chunked element-wise compare in ComparableWeight space."""
equal = True
max_abs_err = torch.zeros((), dtype=torch.float32)
sum_abs_err = 0.0
num_exceed = 0
numel = 0
for (expect_dq, expect_tol), (actual_dq, actual_tol) in zip(
expect.iter_chunks(), actual.iter_chunks(), strict=True
):
assert (
expect_dq.shape == actual_dq.shape
), f"{expect_dq.shape=} {actual_dq.shape=}"
numel += expect_dq.numel()
abs_diff = (actual_dq.float() - expect_dq.float()).abs()
if torch.all(abs_diff == 0):
continue
equal = False
# |actual_dq - expect_dq| ≤ |actual_dq - w| + |expect_dq - w| ≤ actual_tol + expect_tol
tol = (
0.0 if expect_tol is None or actual_tol is None else expect_tol + actual_tol
)
max_abs_err = torch.maximum(max_abs_err, abs_diff.max().cpu())
sum_abs_err += abs_diff.sum().item()
# `~(diff <= tol)` instead of `diff > tol` so NaN counts as exceeding.
num_exceed += int((~(abs_diff <= tol)).sum())
return CompareResult(
equal, max_abs_err.item(), sum_abs_err / max(numel, 1), num_exceed
)
def select_comparable_weight(quant_method) -> Optional[type]:
"""Map a module's quant_method to its ComparableWeight. None means raw (bitwise equal) compare."""
if (
isinstance(quant_method, (Fp8LinearMethod, Fp8MoEMethod))
and quant_method.block_quant
and not quant_method.use_mxfp8
):
return Fp8BlockComparable
if isinstance(quant_method, (ModelOptFp4LinearMethod, ModelOptNvFp4FusedMoEMethod)):
raise NotImplementedError(
f"weight checker has no ComparableWeight for {type(quant_method).__name__}"
)
return None