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

297 lines
9.4 KiB
Python

import hashlib
import logging
import time
from typing import Dict, Iterable, NamedTuple, Optional, Set
import torch
import torch.distributed as dist
from pydantic import BaseModel, ConfigDict
from sglang.srt.managers.mm_utils import tensor_hash
from sglang.srt.utils.weight_checker_comparator import (
CHUNK_NUMEL,
ComparableWeight,
RawComparable,
compare_weights,
select_comparable_weight,
)
logger = logging.getLogger(__name__)
class _StrictBaseModel(BaseModel):
model_config = ConfigDict(extra="forbid")
class ParallelismInfo(_StrictBaseModel):
tp_rank: int
tp_size: int
dp_rank: int
dp_size: int
pp_rank: int
pp_size: int
rank: int
size: int
class ChecksumInfo(_StrictBaseModel):
checksums: Dict[str, str]
per_gpu_checksum: str
parallelism_info: ParallelismInfo
class CheckEntry(NamedTuple):
name: str
should_compare: bool
comparable: ComparableWeight
class QuantizedWeight(NamedTuple):
comparable_cls: type[ComparableWeight]
scale_name: str
_NON_PERSISTENT_BUFFER_PATTERNS = (
"cos_sin_cache",
"inv_freq",
"freqs_cis",
"_weight_fp32",
)
def _is_non_persistent_buffer_name(name: str) -> bool:
return any(pat in name for pat in _NON_PERSISTENT_BUFFER_PATTERNS)
class WeightChecker:
def __init__(self, model_runner):
self._model_runner = model_runner
self._snapshot_tensors = None
def handle(self, action: str, allow_quant_error: bool = False) -> Optional[Dict]:
logger.info(
f"[WeightChecker] handle action={action} allow_quant_error={allow_quant_error}"
)
if action == "snapshot":
return self._snapshot()
elif action == "reset_tensors":
return self._reset_tensors()
elif action == "compare":
return self._compare(allow_quant_error=allow_quant_error)
elif action == "checksum":
return self._compute_checksum()
else:
raise Exception(f"Unsupported {action=}")
def _snapshot(self):
named_tensors = [
(name, param.data.detach().cpu()) for name, param in self._model_state()
]
self._snapshot_tensors = dict(named_tensors)
assert len(self._snapshot_tensors) == len(
named_tensors
), f"should not have duplicated tensor name"
def _reset_tensors(self):
for name, param in self._model_state():
if _is_non_persistent_buffer_name(name):
continue
param.copy_(_random_like(param))
def _compare(self, allow_quant_error: bool = False):
assert self._snapshot_tensors is not None
quantized_set = _build_quantized_set(self._model_runner.model)
skip_compare_names = {
name
for name, param in self._model_state()
if getattr(param, "_skip_weight_check", False)
}
_check_tensors(
expect_tensors=_build_check_entries(
self._snapshot_tensors, skip_compare_names, quantized_set
),
actual_tensors=_build_check_entries(
dict(self._model_state()), skip_compare_names, quantized_set
),
allow_quant_error=allow_quant_error,
)
def _compute_checksum(self) -> Dict:
torch.cuda.synchronize()
start = time.perf_counter()
quantized_set = _build_quantized_set(self._model_runner.model)
skip_compare_names = {
name
for name, param in self._model_state()
if getattr(param, "_skip_weight_check", False)
}
# Hash the dequantized weight so two (qweight, scale) pairs with the same
# bf16 hash equal.
checksums = {}
for name, should_compare, comparable in _build_check_entries(
dict(self._model_state()), skip_compare_names, quantized_set
):
if should_compare:
checksums[name] = _hash_tensor(comparable.dequantize().data)
h = hashlib.sha256()
for name in sorted(checksums):
h.update(name.encode())
h.update(checksums[name].encode())
overall = h.hexdigest()
torch.cuda.synchronize()
elapsed = time.perf_counter() - start
logger.info(
f"[WeightChecker] checksum computed for {len(checksums)} tensors in {elapsed:.3f}s"
)
info = ChecksumInfo(
checksums=checksums,
per_gpu_checksum=overall,
parallelism_info=self._parallelism_info(),
)
return info.model_dump()
def _parallelism_info(self) -> ParallelismInfo:
mr = self._model_runner
return ParallelismInfo(
tp_rank=mr.tp_rank,
tp_size=mr.tp_size,
dp_rank=mr.dp_rank if mr.dp_rank is not None else 0,
dp_size=mr.dp_size,
pp_rank=mr.pp_rank,
pp_size=mr.pp_size,
rank=dist.get_rank() if dist.is_initialized() else 0,
size=dist.get_world_size() if dist.is_initialized() else 1,
)
def _model_state(self):
yield from self._model_runner.model.named_parameters()
yield from self._model_runner.model.named_buffers()
def _hash_tensor(t: torch.Tensor) -> str:
return f"{tensor_hash(t):016x}"
def _check_tensors(
expect_tensors: Iterable[CheckEntry],
actual_tensors: Iterable[CheckEntry],
allow_quant_error: bool = False,
):
good_names = []
error_messages = []
info_messages = []
for (expect_name, should_compare, expect_comparable), (
actual_name,
actual_should_compare,
actual_comparable,
) in zip(expect_tensors, actual_tensors, strict=True):
assert expect_name == actual_name, f"{expect_name=} {actual_name=}"
assert (
should_compare == actual_should_compare
), f"{should_compare=} {actual_should_compare=}"
name = expect_name
try:
equal, max_abs_err, mean_abs_err, num_exceed = compare_weights(
expect_comparable, actual_comparable
)
except Exception as e:
e.add_note(
f"when handling {name=} expect={expect_comparable!r} actual={actual_comparable!r}"
)
raise
if equal:
good_names.append(name)
continue
msg = (
f"name={name} "
f"max_abs_err={max_abs_err} "
f"mean_abs_err={mean_abs_err} "
f"num_exceed={num_exceed} "
f"expect={expect_comparable!r} actual={actual_comparable!r} "
)
if not should_compare:
info_messages.append(msg)
elif allow_quant_error and num_exceed == 0:
info_messages.append(msg + "(within quantization ULP tolerance)")
else:
error_messages.append(msg)
logger.info(f"[check_tensors] equal tensors: {good_names}")
if len(info_messages) > 0:
logger.info(f"[check_tensors] info: {info_messages}")
if len(error_messages) > 0:
raise Exception(f"check tensor equality failed:\n" + "\n".join(error_messages))
def _random_like(t: torch.Tensor):
device = t.device
shape = t.shape
dtype = t.dtype
if dtype.is_floating_point:
out = torch.empty(shape, device=device, dtype=dtype)
for chunk in out.view(-1).split(CHUNK_NUMEL):
chunk.copy_(
torch.rand(chunk.shape, device=device, dtype=torch.float32).to(dtype)
)
return out
if dtype == torch.bool:
return torch.rand(shape, device=device) > 0.5
info = torch.iinfo(dtype)
return torch.randint(
low=int(info.min), high=int(info.max), size=shape, device=device, dtype=dtype
)
def _build_quantized_set(model) -> Dict[str, QuantizedWeight]:
"""Run the router over the model: {weight_name: QuantizedWeight} for each
quantized weight; weights absent from the set compare raw."""
quantized_set = {}
for module_name, module in model.named_modules():
comparable_cls = select_comparable_weight(getattr(module, "quant_method", None))
if comparable_cls is None:
continue
prefix = f"{module_name}." if module_name else ""
own = {name for name, _ in module.named_parameters(recurse=False)}
for name in own:
scale = name.replace("weight", "weight_scale_inv")
if name.endswith("weight") and scale in own:
quantized_set[prefix + name] = QuantizedWeight(
comparable_cls, prefix + scale
)
return quantized_set
def _build_check_entries(
raw: Dict[str, torch.Tensor],
skip_compare_names: Set[str],
quantized_set: Optional[Dict[str, QuantizedWeight]] = None,
) -> Iterable[CheckEntry]:
"""Yields a CheckEntry per weight; quantized weights consume their scale, everything
else is raw."""
skip_compare_names = set(skip_compare_names)
quantized_set = quantized_set or {}
scale_names = {qw.scale_name for qw in quantized_set.values()}
for name, tensor in raw.items():
if name in scale_names:
continue # compared via its weight's comparable
if name in quantized_set:
qw = quantized_set[name]
yield CheckEntry(name, True, qw.comparable_cls(tensor, raw[qw.scale_name]))
else:
should_compare = name not in skip_compare_names and (
not _is_non_persistent_buffer_name(name)
)
yield CheckEntry(name, should_compare, RawComparable(tensor))