Upload web/public/webgpu.js with huggingface_hub
Browse files- web/public/webgpu.js +16 -6
web/public/webgpu.js
CHANGED
|
@@ -271,6 +271,16 @@
|
|
| 271 |
return out;
|
| 272 |
}
|
| 273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
async function initCompute(L) {
|
| 275 |
const cpu = { backend: "cpu", label: "CPU (JS)",
|
| 276 |
matmulInt8: (Xq, Wq, m, k, n, LL) => root.Verified.lutMatmulJS(Xq, Wq, m, k, n, LL) };
|
|
@@ -342,8 +352,8 @@
|
|
| 342 |
for (let i = 0; i < refAccC.length; i++) if (accC[i] !== refAccC[i]) throw new Error(`ctx accumulator mismatch @${i} shape ${JSON.stringify(d0)}`);
|
| 343 |
const refS = root.Verified.attScoresJS(qq, kq, qs, ks, d0, L);
|
| 344 |
const refC = root.Verified.attCtxJS(aq, vq, as, vs, d0, L);
|
| 345 |
-
for (let i = 0; i < refS.length; i++) if (hwS[i]
|
| 346 |
-
for (let i = 0; i < refC.length; i++) if (hwC[i]
|
| 347 |
}
|
| 348 |
} catch (e) {
|
| 349 |
console.warn("fused attention kernels failed verification — using CPU LUT mirrors:", e.message);
|
|
@@ -389,7 +399,7 @@
|
|
| 389 |
const hw = await bgFn(Xq, Wq, rs, cs, d0);
|
| 390 |
const ref = root.Verified.bgemmJS(Xq, Wq, rs, cs, d0, L);
|
| 391 |
for (let i = 0; i < ref.length; i++)
|
| 392 |
-
if (hw[i]
|
| 393 |
}
|
| 394 |
return null;
|
| 395 |
}
|
|
@@ -412,9 +422,9 @@
|
|
| 412 |
const ref = await root.Verified.vmlpBlock(Xf, W1, W2, d0, L, null, null);
|
| 413 |
const shape = `${d0.m}x${d0.k}x${d0.h}x${d0.n}`;
|
| 414 |
for (let i = 0; i < ref.h1.length; i++)
|
| 415 |
-
if (hw.h1[i]
|
| 416 |
for (let i = 0; i < ref.out.length; i++)
|
| 417 |
-
if (hw.out[i]
|
| 418 |
}
|
| 419 |
// DISCRIMINATING case: the sweep above passes vacuously if no value
|
| 420 |
// lands on a rounding boundary — the old round(x/scale) spec would
|
|
@@ -439,7 +449,7 @@
|
|
| 439 |
const refNew = V.bgemmJS(qNew, w2.q, sc.scale, w2.s, { m: d1.m, k: d1.h, n: d1.n, batch: 1 }, L);
|
| 440 |
const refOld = V.bgemmJS(qOld, w2.q, sc.scale, w2.s, { m: d1.m, k: d1.h, n: d1.n, batch: 1 }, L);
|
| 441 |
let eqNew = true, eqOld = true;
|
| 442 |
-
for (let i = 0; i < refNew.length; i++) { if (gpu.out[i]
|
| 443 |
if (!eqNew) return "discriminating boundary case: GPU chain does not match the respec mirror";
|
| 444 |
if (eqOld) return "discriminating boundary case: GPU chain matches the OLD quantize spec";
|
| 445 |
return null; // proven: respec, not merely gate-compatible
|
|
|
|
| 271 |
return out;
|
| 272 |
}
|
| 273 |
|
| 274 |
+
// f32 gate equality AT THE BIT LEVEL. JS `!==` says -0 === 0, but the fleet
|
| 275 |
+
// compares devices by hashing raw bit patterns (FNV over the byte buffer), so
|
| 276 |
+
// a kernel that flushes -0 to +0 — real hardware has instructions that do
|
| 277 |
+
// exactly this (RDNA2 output modifiers and DX9-legacy multiplies are
|
| 278 |
+
// documented as "not IEEE compatible: -0 is flushed to +0") — would pass a
|
| 279 |
+
// `!==` gate and still fork the weights at the sync guard. The gates must
|
| 280 |
+
// compare the same thing the hash sees: the bits.
|
| 281 |
+
const _fb = new Float32Array(1), _ub = new Uint32Array(_fb.buffer);
|
| 282 |
+
function bitDiff(a, b) { _fb[0] = a; const u = _ub[0]; _fb[0] = b; return u !== _ub[0]; }
|
| 283 |
+
|
| 284 |
async function initCompute(L) {
|
| 285 |
const cpu = { backend: "cpu", label: "CPU (JS)",
|
| 286 |
matmulInt8: (Xq, Wq, m, k, n, LL) => root.Verified.lutMatmulJS(Xq, Wq, m, k, n, LL) };
|
|
|
|
| 352 |
for (let i = 0; i < refAccC.length; i++) if (accC[i] !== refAccC[i]) throw new Error(`ctx accumulator mismatch @${i} shape ${JSON.stringify(d0)}`);
|
| 353 |
const refS = root.Verified.attScoresJS(qq, kq, qs, ks, d0, L);
|
| 354 |
const refC = root.Verified.attCtxJS(aq, vq, as, vs, d0, L);
|
| 355 |
+
for (let i = 0; i < refS.length; i++) if (bitDiff(hwS[i], refS[i])) throw new Error(`scores epilogue mismatch @${i}`);
|
| 356 |
+
for (let i = 0; i < refC.length; i++) if (bitDiff(hwC[i], refC[i])) throw new Error(`ctx epilogue mismatch @${i}`);
|
| 357 |
}
|
| 358 |
} catch (e) {
|
| 359 |
console.warn("fused attention kernels failed verification — using CPU LUT mirrors:", e.message);
|
|
|
|
| 399 |
const hw = await bgFn(Xq, Wq, rs, cs, d0);
|
| 400 |
const ref = root.Verified.bgemmJS(Xq, Wq, rs, cs, d0, L);
|
| 401 |
for (let i = 0; i < ref.length; i++)
|
| 402 |
+
if (bitDiff(hw[i], ref[i])) return `epilogue mismatch @${i} (${shape}): ${hw[i]} vs ${ref[i]}`;
|
| 403 |
}
|
| 404 |
return null;
|
| 405 |
}
|
|
|
|
| 422 |
const ref = await root.Verified.vmlpBlock(Xf, W1, W2, d0, L, null, null);
|
| 423 |
const shape = `${d0.m}x${d0.k}x${d0.h}x${d0.n}`;
|
| 424 |
for (let i = 0; i < ref.h1.length; i++)
|
| 425 |
+
if (bitDiff(hw.h1[i], ref.h1[i])) return `h1 mismatch @${i} (${shape}): ${hw.h1[i]} vs ${ref.h1[i]}`;
|
| 426 |
for (let i = 0; i < ref.out.length; i++)
|
| 427 |
+
if (bitDiff(hw.out[i], ref.out[i])) return `out mismatch @${i} (${shape}): ${hw.out[i]} vs ${ref.out[i]}`;
|
| 428 |
}
|
| 429 |
// DISCRIMINATING case: the sweep above passes vacuously if no value
|
| 430 |
// lands on a rounding boundary — the old round(x/scale) spec would
|
|
|
|
| 449 |
const refNew = V.bgemmJS(qNew, w2.q, sc.scale, w2.s, { m: d1.m, k: d1.h, n: d1.n, batch: 1 }, L);
|
| 450 |
const refOld = V.bgemmJS(qOld, w2.q, sc.scale, w2.s, { m: d1.m, k: d1.h, n: d1.n, batch: 1 }, L);
|
| 451 |
let eqNew = true, eqOld = true;
|
| 452 |
+
for (let i = 0; i < refNew.length; i++) { if (bitDiff(gpu.out[i], refNew[i])) eqNew = false; if (bitDiff(gpu.out[i], refOld[i])) eqOld = false; }
|
| 453 |
if (!eqNew) return "discriminating boundary case: GPU chain does not match the respec mirror";
|
| 454 |
if (eqOld) return "discriminating boundary case: GPU chain matches the OLD quantize spec";
|
| 455 |
return null; // proven: respec, not merely gate-compatible
|