changh95's picture
Add files using upload-large-folder tool
0190e6b verified
Raw History Blame Contribute Delete
2.76 kB
"""Pure-torch reference of one Qwen3-VL text decoder layer (fp32 math, real checkpoint weights).
Used as the layer-level oracle before/besides the CPU golden run. Follows modeling_qwen3_vl.py exactly
(RMSNorm in fp32, per-head q/k norm before rope, HF rotate_half rope, GQA causal attention, SwiGLU).
"""
from __future__ import annotations
import math
import torch
from .config import TextConfig
def rms_norm(x: torch.Tensor, w: torch.Tensor, eps: float) -> torch.Tensor:
xf = x.float()
xf = xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps)
return (w.float() * xf).to(x.dtype)
def rotate_half(x):
x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2:]
return torch.cat((-x2, x1), dim=-1)
def ref_layer(x: torch.Tensor, w: dict, cos: torch.Tensor, sin: torch.Tensor, tc: TextConfig,
dtype: torch.dtype = torch.float32, return_kv: bool = False):
"""x: [1, L, hidden]; w: Checkpoint.text_layer(i) dict (HF names); cos/sin: [L, head_dim].
Computes in `dtype` (float32 default = tight oracle; bfloat16 mimics the HF CPU run)."""
L = x.shape[1]
H, KV, D = tc.n_heads, tc.n_kv_heads, tc.head_dim
x = x.to(dtype)
W = {k: v.to(dtype) for k, v in w.items()}
h = rms_norm(x, W["input_layernorm.weight"], tc.rms_eps)
q = (h @ W["self_attn.q_proj.weight"].t()).view(1, L, H, D)
k = (h @ W["self_attn.k_proj.weight"].t()).view(1, L, KV, D)
v = (h @ W["self_attn.v_proj.weight"].t()).view(1, L, KV, D)
q = rms_norm(q, W["self_attn.q_norm.weight"], tc.rms_eps).transpose(1, 2) # [1, H, L, D]
k = rms_norm(k, W["self_attn.k_norm.weight"], tc.rms_eps).transpose(1, 2)
v = v.transpose(1, 2)
c, s = cos.to(dtype)[None, None], sin.to(dtype)[None, None]
q = q * c + rotate_half(q) * s
k = k * c + rotate_half(k) * s
rep = H // KV
kk = k[:, :, None].expand(1, KV, rep, L, D).reshape(1, H, L, D)
vv = v[:, :, None].expand(1, KV, rep, L, D).reshape(1, H, L, D)
att = (q.float() @ kk.float().transpose(-1, -2)) / math.sqrt(D)
mask = torch.full((L, L), float("-inf")).triu(1)
att = torch.softmax(att + mask, dim=-1).to(dtype)
o = (att @ vv).transpose(1, 2).reshape(1, L, H * D)
o = o @ W["self_attn.o_proj.weight"].t()
x = x + o
h = rms_norm(x, W["post_attention_layernorm.weight"], tc.rms_eps)
g = torch.nn.functional.silu(h @ W["mlp.gate_proj.weight"].t())
u = h @ W["mlp.up_proj.weight"].t()
x = x + (g * u) @ W["mlp.down_proj.weight"].t()
if return_kv:
return x, k, v
return x
def pcc(a: torch.Tensor, b: torch.Tensor) -> float:
a = a.double().flatten()
b = b.double().flatten()
a = a - a.mean()
b = b - b.mean()
return float((a @ b) / (a.norm() * b.norm() + 1e-12))