#!/usr/bin/env python3 """Validate the SDQ paged MoE kernel for Ling-3.0-flash (bailingmoe3) with pure NumPy. The weights are read straight out of the sharded GGUF, dequantized with ggml's definitions, and the SiLU-gated expert forward pass is recomputed in fp32. The result is compared against `sdq-chat --selftest IL:IE:SEED:OUT.bin`. Ling-3.0-flash expert tensors (Q4_K_M): ffn_gate_exps [n_embd=2560, n_ff_exp=768, n_expert=512] q4_K ffn_up_exps [2560, 768, 512] q4_K ffn_down_exps [768, 2560, 512] q4_K or q6_K """ import os import struct import sys import numpy as np QK_K = 256 MODEL = os.environ.get('MODEL', '/root/app/ling/tiny/models/Ling-3.0-tiny-Q4_K_M.gguf') SHARDS = [MODEL.replace('00001-of', f'{i:05d}-of') for i in (1, 2)] TS = {0: 1, 1: 1, 2: 2, 3: 2, 4: 4, 5: 4, 6: 4, 7: 1, 10: 8, 11: 8, 12: 8} BLK = {12: (256, 144), 13: (256, 176), 14: (256, 210), 7: (32, 24), 8: (32, 34), 2: (32, 18), 3: (32, 20), 6: (32, 22), 0: (1, 4), 1: (1, 2)} FMT = {0: '> 6) << 4)) m1 = int((sc[is_ + 4] >> 4) | ((sc[is_] >> 6) << 4)) sc2 = int((sc[is_ + 5] & 0xF) | ((sc[is_ - 3] >> 6) << 4)) m2 = int((sc[is_ + 5] >> 4) | ((sc[is_ + 1] >> 6) << 4)) q = qs[j // 2: j // 2 + 32] out[base + j: base + j + 32] = d * sc1 * (q & 0xF) - dmin * m1 out[base + j + 32: base + j + 64] = d * sc2 * (q >> 4) - dmin * m2 is_ += 2 return out def dequant_q6_K(raw, n): nb = n // QK_K out = np.empty(n, dtype=np.float32) for i in range(nb): b = raw[i * 210:(i + 1) * 210] d = fp16(b[208:210]) ql = np.frombuffer(b, dtype=np.uint8, count=128, offset=0) qh = np.frombuffer(b, dtype=np.uint8, count=64, offset=128) sc = np.frombuffer(b, dtype=np.int8, count=16, offset=192) base = i * QK_K for g in range(2): # two 128-element groups per block for l in range(32): is_ = l // 16 q1 = ((ql[g * 64 + l] & 0xF) | (((qh[g * 32 + l] >> 0) & 3) << 4)).astype(np.int16) - 32 q2 = ((ql[g * 64 + l + 32] & 0xF) | (((qh[g * 32 + l] >> 2) & 3) << 4)).astype(np.int16) - 32 q3 = ((ql[g * 64 + l] >> 4) | (((qh[g * 32 + l] >> 4) & 3) << 4)).astype(np.int16) - 32 q4 = ((ql[g * 64 + l + 32] >> 4) | (((qh[g * 32 + l] >> 6) & 3) << 4)).astype(np.int16) - 32 off0 = base + g * 128 out[off0 + l] = d * sc[g * 8 + is_] * q1 out[off0 + l + 32] = d * sc[g * 8 + is_ + 2] * q2 out[off0 + l + 64] = d * sc[g * 8 + is_ + 4] * q3 out[off0 + l + 96] = d * sc[g * 8 + is_ + 6] * q4 return out def dequant(raw, n, tt): if tt == 12: return dequant_q4_K(raw, n) if tt == 14: return dequant_q6_K(raw, n) raise ValueError(f'unsupported type {tt} ({NAME.get(tt, tt)})') def row_bytes(n, tt): bs, ts = BLK[tt] return n // bs * ts def read_expert(tensors, il, ie): def seg(name): si, off, dims, tt = tensors[f'blk.{il}.{name}'] nrow = row_bytes(dims[0], tt) n = dims[1] * nrow with open(SHARDS[si], 'rb') as f: f.seek(off + ie * n) return f.read(n), nrow, tt, dims[0] g = seg('ffn_gate_exps.weight') u = seg('ffn_up_exps.weight') d = seg('ffn_down_exps.weight') return g, u, d def load_matrix(seg, n_rows): raw, nrow, tt, ne0 = seg return np.stack([dequant(raw[r * nrow:(r + 1) * nrow], ne0, tt) for r in range(n_rows)]) def main(): cases = [] for path in sys.argv[1:]: # st_le.bin base = os.path.basename(path) body = base[len('st_l'):-len('.bin')] il, ie = body.split('e') cases.append((int(il), int(ie), path)) if not cases: print('usage: verify_ling.py st_le.bin ...') return 1 kv, tensors = parse_headers() n_embd = int(kv['bailingmoe3.embedding_length']) n_ff = int(kv['bailingmoe3.expert_feed_forward_length']) print(f"arch=bailingmoe3 n_expert={int(kv['bailingmoe3.expert_count'])} " f"n_expert_used={int(kv['bailingmoe3.expert_used_count'])} " f"n_embd={n_embd} n_ff_exp={n_ff}") all_ok = True for il, ie, path in cases: raw = open(path, 'rb').read() n_tok = len(raw) // 4 // (2 * n_embd) got = np.frombuffer(raw[:n_tok * n_embd * 4], dtype=np.float32).reshape(n_tok, n_embd) x = np.frombuffer(raw[n_tok * n_embd * 4:], dtype=np.float32).reshape(n_tok, n_embd) g_seg, u_seg, d_seg = read_expert(tensors, il, ie) Wg = load_matrix(g_seg, n_ff) Wu = load_matrix(u_seg, n_ff) Wd = load_matrix(d_seg, n_embd) rels, corrs = [], [] for t in range(n_tok): xt = x[t] g = Wg @ xt u = Wu @ xt h = (g / (1.0 + np.exp(-g))) * u ref = Wd @ h denom = max(float(np.abs(ref).max()), 1e-9) rels.append(float(np.abs(got[t] - ref).max()) / denom) corrs.append(float(np.corrcoef(got[t], ref)[0, 1])) rel = max(rels) corr = min(corrs) ok = rel < 0.05 and corr > 0.99 all_ok &= ok print(f'L{il} E{ie}: gate={NAME[g_seg[2]]} up={NAME[u_seg[2]]} down={NAME[d_seg[2]]}' f' | max_rel_err={rel:.4f} corr={corr:.6f} | {"PASS" if ok else "FAIL"}') print('\nALL PASS' if all_ok else '\nSOME FAILED') return 0 if all_ok else 1 if __name__ == '__main__': sys.exit(main())