Download offload/dspark/native/tests/test_ops.py from ProprietaryLegal/dsv41-offload: direct link, hf CLI and curl.
- Browser
- Download file 6.83 kB
-
https://huggingface.co/ProprietaryLegal/dsv41-offload/resolve/main/offload/dspark/native/tests/test_ops.py
- Command line
-
hf download hf://ProprietaryLegal/dsv41-offload/offload/dspark/native/tests/test_ops.py
-
curl -L -o test_ops.py https://huggingface.co/ProprietaryLegal/dsv41-offload/resolve/main/offload/dspark/native/tests/test_ops.py
6.83 kB
| """The native GPU ops against formats.py / reference.py on the real official tensors. | |
| GPU: CUDA_VISIBLE_DEVICES=GPU-7744b44b-... python -m pytest -q offload/dspark/native/tests/test_ops.py | |
| CPU: TRITON_INTERPRET=1 python -m pytest -q offload/dspark/native/tests/test_ops.py (Triton interpreter; slow) | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import pytest | |
| import torch | |
| from offload.dspark.native import formats as F | |
| from offload.dspark.native import ops as NO | |
| from offload.dspark.native import reference as R | |
| from offload.dspark.native.loader import LoadStats, load_dense, load_expert_banks | |
| from offload.dspark.native.official import OfficialShards | |
| ROOT = os.environ.get("NATIVE_1017_ROOT", "/opt/dsv41/x86host-data/native-1017") | |
| HAVE = os.path.exists(os.path.join(ROOT, "model-00044-of-00048.safetensors")) | |
| INTERP = os.environ.get("TRITON_INTERPRET") == "1" | |
| DEV = torch.device("cpu") if INTERP or not torch.cuda.is_available() else torch.device("cuda") | |
| pytestmark = pytest.mark.skipif(not INTERP and not torch.cuda.is_available(), reason="needs a GPU or the interpreter") | |
| def test_act_qdq_bit_identical(): | |
| g = torch.Generator().manual_seed(0) | |
| x = (torch.randn(9, 640, generator=g) * torch.logspace(-7, 4, 640)).to(torch.bfloat16) | |
| x[0, :32] = 0 | |
| x[1, 32:64] = 448.0 | |
| x[2, 64:96] = -448.0 * 2 ** -5 | |
| x[3] = x[3] * 1e-30 | |
| want = F.act_qdq(x) | |
| got = NO.act_qdq(x.to(DEV)).cpu() | |
| assert torch.equal(got.view(torch.int16), want.view(torch.int16)) | |
| def test_dense_matches_reference(kind): | |
| sh = OfficialShards(ROOT) | |
| st = LoadStats() | |
| d = load_dense(sh, "mtp.1.attn.wkv", DEV, kind, st) | |
| w, s = sh.get("mtp.1.attn.wkv.weight"), sh.get("mtp.1.attn.wkv.scale") | |
| g = torch.Generator().manual_seed(3) | |
| x = torch.randn(5, 5120, generator=g).to(torch.bfloat16) | |
| want = R.linear_fp8(x, w, s, "f64").float() | |
| xq = NO.act_qdq(x.to(DEV)) | |
| got = d(xq).cpu().float() | |
| tol = torch.finfo(torch.bfloat16).eps * want.abs().amax() | |
| assert (got - want).abs().max() <= tol | |
| assert (got == want).float().mean() > 0.97 | |
| got32 = d(xq, out_f32=True).cpu() | |
| ref32 = (F.act_qdq(x).double() @ F.decode_fp8_block(w, s).double().t()).float() | |
| assert ((got32 - ref32).abs() <= 1e-5 * ref32.abs().amax()).all() | |
| if kind == "bf16" and DEV.type == "cuda": # the Triton kernel on bf16 weights agrees too | |
| dt = NO.NativeDense("wkv-triton", "bf16", d.w, None, backend="triton") | |
| assert (dt(xq).cpu().float() - want).abs().max() <= tol | |
| assert ((dt(xq, out_f32=True).cpu() - ref32).abs() <= 1e-5 * ref32.abs().amax()).all() | |
| # a row shard keeps the full tensor's scale blocks | |
| d2 = load_dense(sh, "mtp.1.attn.wkv", DEV, kind, st, rows=(256, 512)) | |
| assert torch.equal(d2(xq).cpu(), d(xq).cpu()[:, 256:512]) or kind == "bf16" | |
| def test_expert_slots_match_reference(kind): | |
| sh = OfficialShards(ROOT) | |
| E = 6 | |
| banks = load_expert_banks(sh, 2, [(0, DEV), (1, DEV)], 2, kind, LoadStats(), verify_sample=2, n_experts=E) | |
| g = torch.Generator().manual_seed(4) | |
| T = 2 | |
| x = (torch.randn(T, 5120, generator=g) * 0.7).to(torch.bfloat16) | |
| ids = torch.tensor([[0, 5, 3], [2, 0, 4]], dtype=torch.int64) | |
| rw = torch.rand(T, 3, generator=g) | |
| xq = F.act_qdq(x) | |
| full = torch.zeros(T, 3, 5120, dtype=torch.float32) | |
| hs = {} | |
| for r in (0, 1): | |
| h = torch.empty(T * 3, 1152, dtype=torch.bfloat16, device=DEV) | |
| full += banks[r].forward_slots(xq.to(DEV), ids.to(DEV), rw.to(DEV), h=h).cpu() | |
| hs[r] = h.cpu() | |
| for t in range(T): | |
| for j in range(3): | |
| e = int(ids[t, j]) | |
| p = f"mtp.2.ffn.experts.{e}." | |
| w1, s1, w3, s3, w2, s2 = (sh.get(p + n) for n in ("w1.weight", "w1.scale", "w3.weight", "w3.scale", | |
| "w2.weight", "w2.scale")) | |
| gg = R.linear_fp4(x[t:t + 1], w1, s1) | |
| uu = R.linear_fp4(x[t:t + 1], w3, s3) | |
| hq = F.act_qdq(R.swiglu(gg, uu, rw[t:t + 1, j:j + 1])) | |
| got_h = torch.cat([hs[0][t * 3 + j], hs[1][t * 3 + j]]) | |
| frac = (got_h == hq[0]).float().mean().item() | |
| assert frac > 0.995, frac # bf16 g/u ties may flip by fp32 order: a few elements | |
| y = (hq.double() @ F.decode_fp4(w2, s2).double().t()).float()[0] | |
| rel = ((full[t, j] - y).norm() / y.norm()).item() | |
| assert rel < 5e-3, rel | |
| def test_official_combine_order(): | |
| parts = torch.randn(2, 3, 8) * 100 | |
| ids = torch.tensor([[7, 1, 4], [0, 9, 2]]) | |
| sh = torch.randn(2, 8) | |
| got = NO.moe_combine_official(parts, sh, ids) | |
| want = torch.zeros(2, 8) | |
| for t in range(2): | |
| for j in ids[t].argsort().tolist(): | |
| want[t] += parts[t, j].to(torch.bfloat16).float() | |
| want = (want + sh.to(torch.bfloat16).float()).to(torch.bfloat16) | |
| assert torch.equal(got, want) | |
| def test_markov_logits_fp32_exact_bias(): | |
| g = torch.Generator().manual_seed(6) | |
| V, Vr, Rk = 1000, 300, 256 | |
| w1 = (torch.randn(V, Rk, generator=g) * 0.05).to(torch.bfloat16) | |
| w2 = (torch.randn(Vr, Rk, generator=g) * 0.05).to(torch.bfloat16) | |
| base = torch.randn(3, Vr, generator=g) * 4 | |
| prev = torch.tensor([5, 999, 0]) | |
| got = NO.markov_logits_fp32(base.to(DEV), prev.to(DEV), w1.to(DEV), w2.to(DEV)).cpu() | |
| want = (base.double() + w1[prev].double() @ w2.double().t()).float() | |
| assert ((got - want).abs() <= 1e-5 * want.abs().amax()).all() | |
| def test_markov_hot_rows_bit_identical_to_computed(): | |
| g = torch.Generator().manual_seed(7) | |
| V, Vr = 700, 260 | |
| w1 = (torch.randn(V, 256, generator=g) * 0.05).to(torch.bfloat16).to(DEV) | |
| w2 = (torch.randn(Vr, 256, generator=g) * 0.05).to(torch.bfloat16).to(DEV) | |
| base = (torch.randn(3, Vr, generator=g) * 4).to(DEV) | |
| prev = torch.tensor([5, 699, 17]).to(DEV) | |
| rows = NO.MarkovRowsFP32(w1, w2, [17, 5, 3], rows=2) # 5 and 17 cached, 699 computed | |
| assert rows.rows == 2 | |
| a = NO.markov_logits_fp32(base, prev, w1, w2, rows).cpu() | |
| b = NO.markov_logits_fp32(base, prev, w1, w2, None).cpu() | |
| assert torch.equal(a, b) | |
| def test_swiglu_qdq_matches_reference(): | |
| g_ = torch.Generator().manual_seed(8) | |
| T, I = 4, 1152 | |
| g = torch.randn(T, 3, I, generator=g_) * 6 | |
| u = torch.randn(T, 3, I, generator=g_) * 6 | |
| rw = torch.rand(T, 3, generator=g_) | |
| got = NO.swiglu_qdq(g.to(DEV), u.to(DEV), rw.to(DEV)).cpu() | |
| want = F.act_qdq(R.swiglu(g.to(torch.bfloat16), u.to(torch.bfloat16), rw.reshape(T, 3, 1))).view(T * 3, I) | |
| assert (got == want).float().mean() > 0.999 | |