Update verify.py
Browse files
verify.py
CHANGED
|
@@ -32,7 +32,6 @@ model.config.use_cuda_kernel = False
|
|
| 32 |
with torch.no_grad():
|
| 33 |
out_f = model(ids).logits
|
| 34 |
model.config.use_cuda_kernel = True
|
| 35 |
-
|
| 36 |
diff = (out_k.float() - out_f.float()).abs()
|
| 37 |
print(f" max abs diff kernel vs fallback: {diff.max().item():.4e}")
|
| 38 |
print(f" mean abs diff: {diff.mean().item():.4e}")
|
|
@@ -41,7 +40,38 @@ print(" kernel top-1 next id:", out_k[0, -1].argmax().item(),
|
|
| 41 |
"| fallback:", out_f[0, -1].argmax().item())
|
| 42 |
|
| 43 |
print("=" * 70)
|
| 44 |
-
print("4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
model.train()
|
| 46 |
ids2 = tok("Backward test sentence for gradient check.", return_tensors="pt").input_ids.cuda()
|
| 47 |
out = model(ids2, labels=ids2)
|
|
@@ -57,12 +87,29 @@ print(f" blocks.6.att.w1 (decay-lora) grad norm: {g_w1.float().norm().item():.
|
|
| 57 |
n_with_grad = sum(1 for p in model.parameters() if p.grad is not None and p.grad.abs().sum() > 0)
|
| 58 |
n_total = sum(1 for _ in model.parameters())
|
| 59 |
print(f" params with non-zero grad: {n_with_grad}/{n_total}")
|
|
|
|
| 60 |
|
| 61 |
print("=" * 70)
|
| 62 |
-
print("
|
| 63 |
model.eval()
|
| 64 |
with torch.no_grad():
|
| 65 |
gen = model.generate(ids, max_new_tokens=10, do_sample=False)
|
| 66 |
print(" generated:", tok.decode(gen[0]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
print("=" * 70)
|
| 68 |
-
print("ALL CHECKS DONE")
|
|
|
|
| 32 |
with torch.no_grad():
|
| 33 |
out_f = model(ids).logits
|
| 34 |
model.config.use_cuda_kernel = True
|
|
|
|
| 35 |
diff = (out_k.float() - out_f.float()).abs()
|
| 36 |
print(f" max abs diff kernel vs fallback: {diff.max().item():.4e}")
|
| 37 |
print(f" mean abs diff: {diff.mean().item():.4e}")
|
|
|
|
| 40 |
"| fallback:", out_f[0, -1].argmax().item())
|
| 41 |
|
| 42 |
print("=" * 70)
|
| 43 |
+
print("4) Cached vs uncached parity (prefill + stateful decode vs full recompute)")
|
| 44 |
+
# The stateful path always runs on the PyTorch implementation; compare against a
|
| 45 |
+
# full PyTorch-fallback forward so both sides share the same numerics (fp32
|
| 46 |
+
# internal, sequential over time) -> should match (near-)exactly.
|
| 47 |
+
SPLIT = 4 # decode the last SPLIT tokens one at a time
|
| 48 |
+
assert ids.shape[1] > SPLIT
|
| 49 |
+
model.config.use_cuda_kernel = False
|
| 50 |
+
with torch.no_grad():
|
| 51 |
+
full = model(ids).logits
|
| 52 |
+
pre = model(ids[:, :-SPLIT], use_cache=True) # prefill -> state
|
| 53 |
+
st, chunks = pre.state, [pre.logits]
|
| 54 |
+
for t in range(ids.shape[1] - SPLIT, ids.shape[1]):
|
| 55 |
+
o = model(ids[:, t:t + 1], state=st) # passing state implies use_cache
|
| 56 |
+
st, chunks = o.state, chunks + [o.logits]
|
| 57 |
+
inc = torch.cat(chunks, dim=1)
|
| 58 |
+
model.config.use_cuda_kernel = True
|
| 59 |
+
diff_c = (inc.float() - full.float()).abs()
|
| 60 |
+
print(f" max abs diff cached vs uncached: {diff_c.max().item():.4e}")
|
| 61 |
+
print(f" mean abs diff: {diff_c.mean().item():.4e}")
|
| 62 |
+
assert torch.allclose(inc.float(), full.float(), atol=1e-3, rtol=0), \
|
| 63 |
+
"cached (prefill+decode) logits diverge from full recompute"
|
| 64 |
+
# also check against the kernel forward with a looser bf16 tolerance
|
| 65 |
+
diff_ck = (inc.float() - out_k.float()).abs()
|
| 66 |
+
print(f" max abs diff cached vs kernel: {diff_ck.max().item():.4e}")
|
| 67 |
+
ax, wkv, fx = st[0]
|
| 68 |
+
print(" state[0] shapes:",
|
| 69 |
+
"att_x_prev", tuple(ax.shape), ax.dtype, "|",
|
| 70 |
+
"wkv", tuple(wkv.shape), wkv.dtype, "|",
|
| 71 |
+
"ffn_x_prev", tuple(fx.shape), fx.dtype)
|
| 72 |
+
|
| 73 |
+
print("=" * 70)
|
| 74 |
+
print("5) Backward pass (gradients flow through kernel)")
|
| 75 |
model.train()
|
| 76 |
ids2 = tok("Backward test sentence for gradient check.", return_tensors="pt").input_ids.cuda()
|
| 77 |
out = model(ids2, labels=ids2)
|
|
|
|
| 87 |
n_with_grad = sum(1 for p in model.parameters() if p.grad is not None and p.grad.abs().sum() > 0)
|
| 88 |
n_total = sum(1 for _ in model.parameters())
|
| 89 |
print(f" params with non-zero grad: {n_with_grad}/{n_total}")
|
| 90 |
+
model.zero_grad(set_to_none=True)
|
| 91 |
|
| 92 |
print("=" * 70)
|
| 93 |
+
print("6) generate() through the state cache")
|
| 94 |
model.eval()
|
| 95 |
with torch.no_grad():
|
| 96 |
gen = model.generate(ids, max_new_tokens=10, do_sample=False)
|
| 97 |
print(" generated:", tok.decode(gen[0]))
|
| 98 |
+
|
| 99 |
+
# generate() must equal a manual RNN-mode greedy loop (same state-cache path)
|
| 100 |
+
with torch.no_grad():
|
| 101 |
+
o = model(ids, use_cache=True)
|
| 102 |
+
cur = o.logits[:, -1].argmax(-1, keepdim=True)
|
| 103 |
+
st, toks = o.state, [cur]
|
| 104 |
+
for _ in range(9):
|
| 105 |
+
o = model(cur, state=st)
|
| 106 |
+
st = o.state
|
| 107 |
+
cur = o.logits[:, -1].argmax(-1, keepdim=True)
|
| 108 |
+
toks.append(cur)
|
| 109 |
+
manual = torch.cat(toks, dim=1)
|
| 110 |
+
match = bool((gen[:, ids.shape[1]:] == manual).all())
|
| 111 |
+
print(" generate == manual stateful greedy:", match)
|
| 112 |
+
assert match, "generate() output diverges from manual stateful greedy decode"
|
| 113 |
+
|
| 114 |
print("=" * 70)
|
| 115 |
+
print("ALL CHECKS DONE")
|