Quazim0t0 commited on
Commit
1bdb0bb
·
verified ·
1 Parent(s): 867cc7f

Upload web/test_gates.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. web/test_gates.js +53 -0
web/test_gates.js CHANGED
@@ -9,6 +9,7 @@
9
  const fs = require("fs");
10
  const path = require("path");
11
  const V = require("./public/verified_core.js");
 
12
 
13
  const mul = new Int16Array(fs.readFileSync(path.join(__dirname, "public", "mul_lut.bin")).buffer.slice(0));
14
  const L = { mul };
@@ -181,6 +182,58 @@ console.log("\nthe audit must catch a LAST-COLUMN bug (uniform sampling cannot):
181
  ok(fp === 0, `no false positives on the clean kernel (${TRIALS} audits)`);
182
  }
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  console.log(pass ? "\nGATE TEST PASSED — the gate rejects real bugs and accepts the real kernel."
185
  : "\nGATE TEST FAILED");
186
  process.exit(pass ? 0 : 1);
 
9
  const fs = require("fs");
10
  const path = require("path");
11
  const V = require("./public/verified_core.js");
12
+ const TC = require("./public/traincore.js");
13
 
14
  const mul = new Int16Array(fs.readFileSync(path.join(__dirname, "public", "mul_lut.bin")).buffer.slice(0));
15
  const L = { mul };
 
182
  ok(fp === 0, `no false positives on the clean kernel (${TRIALS} audits)`);
183
  }
184
 
185
+ // ---- the attention kernels now get a LIVE audit too --------------------------
186
+ // They had exact init gates but nothing at live shapes — the same gap the GEMM
187
+ // audit exists to close. These must reject a corrupted attention output and
188
+ // accept a clean one, at a shape the init gate never sees.
189
+ console.log("\nthe attention audits must reject corrupted output:");
190
+ {
191
+ const d = { B: 2, T: 24, heads: 3, hd: 8 }; // not one of the gate's shapes
192
+ const C = d.heads * d.hd, BH = d.B * d.heads;
193
+ const qq = rnd(d.B * d.T * C, () => (Math.random() * 256 - 128) | 0);
194
+ const kq = rnd(d.B * d.T * C, () => (Math.random() * 256 - 128) | 0);
195
+ const qs = Float32Array.from({ length: d.B * d.T * d.heads }, () => Math.random() + 0.5);
196
+ const ks = Float32Array.from({ length: d.B * d.T * d.heads }, () => Math.random() + 0.5);
197
+ const good = V.attScoresJS(qq, kq, qs, ks, d, L);
198
+ ok(V.auditAttScores(qq, kq, qs, ks, d, good, L, 12) === null, "att.scores audit accepts the clean kernel");
199
+ // corrupt the LAST head's last token pair — the classic head-stride bug
200
+ const badS = Float32Array.from(good);
201
+ badS[((d.B * d.heads - 1) * d.T + (d.T - 1)) * d.T + (d.T - 1)] = 0;
202
+ ok(V.auditAttScores(qq, kq, qs, ks, d, badS, L, 12) !== null, "att.scores audit rejects a corrupted last head/token");
203
+
204
+ const aq = rnd(BH * d.T * d.T, () => (Math.random() * 127) | 0);
205
+ const vq = rnd(d.B * d.T * C, () => (Math.random() * 256 - 128) | 0);
206
+ const as = Float32Array.from({ length: BH * d.T }, () => Math.random() + 0.5);
207
+ const vs = Float32Array.from({ length: BH * d.hd }, () => Math.random() + 0.5);
208
+ const goodC = V.attCtxJS(aq, vq, as, vs, d, L);
209
+ ok(V.auditAttCtx(aq, vq, as, vs, d, goodC, L, 12) === null, "att.ctx audit accepts the clean kernel");
210
+ const badC = Float32Array.from(goodC); // last channel of the last head
211
+ badC[((d.B - 1) * d.T + (d.T - 1)) * C + (d.heads - 1) * d.hd + (d.hd - 1)] = 0;
212
+ ok(V.auditAttCtx(aq, vq, as, vs, d, badC, L, 12) !== null, "att.ctx audit rejects a corrupted last channel (scatter write-back)");
213
+ }
214
+
215
+ // ---- the f32 backward GEMM is no longer gated by a tolerance -----------------
216
+ // fgemmMirror reproduces split-K's partition and accumulation order, so the
217
+ // gate can compare with `!==`. This checks the mirror is self-consistent and
218
+ // that the two rounding schedules it offers are genuinely different (i.e. the
219
+ // gate is choosing between real alternatives, not two names for one thing).
220
+ console.log("\nthe split-K mirror is exact and discriminating:");
221
+ {
222
+ const m0 = 6, k0 = 5000, n0 = 4; // k > 4096 exercises split-K
223
+ const A = Float32Array.from({ length: m0 * k0 }, () => Math.random() - 0.5);
224
+ const Bm = Float32Array.from({ length: k0 * n0 }, () => Math.random() - 0.5);
225
+ const dG = { m: m0, k: k0, n: n0 };
226
+ const stepped = V.fgemmMirror(A, Bm, dG, false), fused = V.fgemmMirror(A, Bm, dG, true);
227
+ ok(V.fgemmMirror(A, Bm, dG, false).every((v, i) => !V.bitDiff(v, stepped[i])), "mirror is deterministic");
228
+ let diff = 0;
229
+ for (let i = 0; i < stepped.length; i++) if (V.bitDiff(stepped[i], fused[i])) diff++;
230
+ ok(diff > 0, `the two rounding schedules really differ (${diff}/${stepped.length} cells) — the gate picks between real alternatives`);
231
+ const naive = TC.matmul(A, Bm, m0, k0, n0);
232
+ let vsNaive = 0;
233
+ for (let i = 0; i < naive.length; i++) if (V.bitDiff(naive[i], stepped[i])) vsNaive++;
234
+ console.log(` note split-K order differs from a naive matmul on ${vsNaive}/${naive.length} cells — which is why the old gate had to use a tolerance, and why the mirror had to be written`);
235
+ }
236
+
237
  console.log(pass ? "\nGATE TEST PASSED — the gate rejects real bugs and accepts the real kernel."
238
  : "\nGATE TEST FAILED");
239
  process.exit(pass ? 0 : 1);