Ilikemechuri commited on
Commit
0ef0d8f
·
verified ·
1 Parent(s): 0d72ea4

Update verify.py

Browse files
Files changed (1) hide show
  1. verify.py +51 -4
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) Backward pass (gradients flow through kernel)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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("5) generate()")
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")