#!/usr/bin/env python """Issue 5 round two: isolate the compressed-tensors W8A8-int8-dynamic path. Mirrors marlin_isolate.py but for the int-quantized W8A8 dynamic scheme (int8 weights, static per-output-channel scales, dynamic symmetric per-token int8 activations) whose kernel on sm_86 is the cutlass int8 scaled-MM — no Marlin in the path. Loads synthetic int8 tensors through the production weight-loader machinery and compares layer(x) against a float32 reference computed from the same dequantized weights with per-token dynamic int8 activation quantization applied to the reference input. Expected rel-L2 when the chain is correct: a few percent (int8 weight error ~1% plus int8 per-token activation rounding). Usage: w8a8_isolate.py [--block N] """ from __future__ import annotations import argparse import json import torch def synth(out: int, inp: int, ones: bool = False) -> tuple[torch.Tensor, torch.Tensor]: """Per-channel symmetric int8 weight + scale, mirroring the artifact builder. ones=True emits an analytically known weight (q=127, scale=1/127 -> W=1): with an all-ones input row the layer output must be exactly in_features. """ if ones: q = torch.full((out, inp), 127, dtype=torch.int8) return q, torch.full((out, 1), 1.0 / 127.0, dtype=torch.float32) w = torch.randn(out, inp, dtype=torch.float32) scale = w.abs().amax(dim=1, keepdim=True).clamp_min(1e-12) / 127.0 q = torch.round(w / scale).clamp(-127, 127).to(torch.int8) return q, scale.to(torch.float32) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--block", type=int, default=0) parser.add_argument("--ones", action="store_true", help="analytic weights (W=1) and ones input; output must equal in_features") parser.add_argument("--act-dtype", choices=("bfloat16", "float16"), default="bfloat16") args = parser.parse_args() import vllm.distributed from vllm.config import VllmConfig, set_current_vllm_config from vllm.distributed import ( destroy_distributed_environment, destroy_model_parallel, initialize_model_parallel, ) from vllm.model_executor.layers.linear import QKVParallelLinear, RowParallelLinear from compressed_tensors.quantization import ( QuantizationArgs, QuantizationConfig, QuantizationScheme, QuantizationStatus, QuantizationStrategy, QuantizationType, ) from compressed_tensors.config import CompressionFormat from vllm_omni.quantization import build_quant_config, resolve_component_quant_config weights = QuantizationArgs(num_bits=8, type=QuantizationType.INT, symmetric=True, strategy=QuantizationStrategy.CHANNEL, dynamic=False, observer="minmax") acts = QuantizationArgs(num_bits=8, type=QuantizationType.INT, symmetric=True, strategy=QuantizationStrategy.TOKEN, dynamic=True) scheme = QuantizationScheme(targets=["Linear"], weights=weights, input_activations=acts) disk = QuantizationConfig( config_groups={"group_0": scheme}, format=CompressionFormat.int_quantized, ignore=["img_in", "txt_in", "time_text_embed", "modulation", "norm_out", "proj_out"], quant_method="compressed-tensors", quantization_status=QuantizationStatus.FROZEN, ).to_dict() quant_config = resolve_component_quant_config( build_quant_config({"transformer": disk}), "transformer" ) vllm.distributed.init_distributed_environment( backend="gloo", world_size=1, rank=0, local_rank=0, distributed_init_method="tcp://127.0.0.1:29602", ) with set_current_vllm_config(VllmConfig()): initialize_model_parallel(tensor_model_parallel_size=1) device = torch.device("cuda") torch.manual_seed(2301) tensors = { "q": synth(4096, 4096, args.ones), "k": synth(4096, 4096, args.ones), "v": synth(4096, 4096, args.ones), "to_out": synth(4096, 4096, args.ones), } b = args.block p = f"transformer.transformer_blocks.{b}" results = [] with torch.device(device.type): to_qkv = QKVParallelLinear( hidden_size=4096, head_size=128, total_num_heads=32, bias=False, quant_config=quant_config, prefix=f"{p}.attn.to_qkv", ) for part, shard in (("q", "q"), ("k", "k"), ("v", "v")): q, s = tensors[part] to_qkv.weight.weight_loader(to_qkv.weight, q.to(device), shard) to_qkv.weight_scale.weight_loader(to_qkv.weight_scale, s.to(device), shard) to_qkv.quant_method.process_weights_after_loading(to_qkv) to_out = RowParallelLinear( 4096, 4096, bias=False, input_is_parallel=True, return_bias=False, quant_config=quant_config, prefix=f"{p}.attn.to_out.0", ) q, s = tensors["to_out"] to_out.weight.weight_loader(to_out.weight, q.to(device)) to_out.weight_scale.weight_loader(to_out.weight_scale, s.to(device)) loaded_bitwise_ok = bool(torch.equal(to_out.weight.detach().cpu(), q)) loaded_scale_ok = bool(torch.allclose(to_out.weight_scale.detach().float().cpu(), s)) to_out.quant_method.process_weights_after_loading(to_out) for name, layer, parts, in_features in ( ("attn.to_qkv (fused q/k/v)", to_qkv, ("q", "k", "v"), 4096), ("attn.to_out.0 (row)", to_out, ("to_out",), 4096), ): if args.ones: x = torch.ones(4, in_features, dtype=getattr(torch, args.act_dtype), device=device) else: x = torch.randn(512, in_features, dtype=getattr(torch, args.act_dtype), device=device) result = layer(x) out = (result[0] if isinstance(result, tuple) else result).float() if args.ones: expected = torch.full_like(out, float(in_features)) rel = float((out - expected).norm() / expected.norm()) finite = bool(torch.isfinite(out).all()) results.append({ "layer": name, "rel_l2": round(rel, 6) if finite else "NaN", "out_finite": finite, "out_row0_first8": [round(v, 2) for v in out[0, :8].tolist()], }) continue ref_w = torch.cat([tensors[k][0].float() * tensors[k][1] for k in parts], dim=0) # Reference with the same dynamic per-token symmetric int8 activation # quantization the kernel applies (dequantized acts, dequantized weights). xs = x.float() act_scale = xs.abs().amax(dim=1, keepdim=True).clamp_min(1e-12) / 127.0 x_dq = torch.round(xs / act_scale).clamp(-127, 127) * act_scale ref = x_dq @ ref_w.T.to(device) finite = bool(torch.isfinite(out).all()) rel = float((out - ref).norm() / ref.norm()) row = {"layer": name, "rel_l2": round(rel, 5) if finite else "NaN", "out_finite": finite} if name.startswith("attn.to_out"): row["loaded_bitwise_ok"] = loaded_bitwise_ok row["loaded_scale_ok"] = loaded_scale_ok # Reference computed from the layer's own post-repack weight # parameter ((K, N) after the transpose) and scales. w_layer = to_out.weight.detach().float() # (K, N) s_layer = to_out.weight_scale.detach().float().squeeze(1) # (N,) ref_layer = x_dq @ (w_layer * s_layer.unsqueeze(0)).to(device) row["rel_l2_vs_layer_weight"] = round(float((out - ref_layer).norm() / ref_layer.norm()), 5) results.append(row) destroy_model_parallel() destroy_distributed_environment() print(json.dumps(results, indent=1)) return 0 if __name__ == "__main__": raise SystemExit(main())