Upload web/public/webgpu.js with huggingface_hub
Browse files- web/public/webgpu.js +29 -2
web/public/webgpu.js
CHANGED
|
@@ -491,8 +491,35 @@
|
|
| 491 |
let mlpDp4 = (xq, w1q, w2q, xs, w1s, w2s, d) => gpuMlpChain(device, dp4MlpEnv, xq, w1q, w2q, xs, w1s, w2s, d);
|
| 492 |
const mlpDp4Bad = await gateMlp(mlpDp4);
|
| 493 |
if (mlpDp4Bad) { console.warn("B2B MLP chain (DP4A) failed verification — using the LUT chain:", mlpDp4Bad); mlpDp4 = mlpLut; }
|
| 494 |
-
|
| 495 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
} catch (e) { console.warn("WebGPU init failed, CPU fallback:", e); return cpu; }
|
| 497 |
}
|
| 498 |
|
|
|
|
| 491 |
let mlpDp4 = (xq, w1q, w2q, xs, w1s, w2s, d) => gpuMlpChain(device, dp4MlpEnv, xq, w1q, w2q, xs, w1s, w2s, d);
|
| 492 |
const mlpDp4Bad = await gateMlp(mlpDp4);
|
| 493 |
if (mlpDp4Bad) { console.warn("B2B MLP chain (DP4A) failed verification — using the LUT chain:", mlpDp4Bad); mlpDp4 = mlpLut; }
|
| 494 |
+
|
| 495 |
+
// Both backends are exact-gated bit-identical, so WHICH one runs is a
|
| 496 |
+
// free choice. On our NVIDIA part they TIE on the shipped float path
|
| 497 |
+
// (packing overhead cancels the dot-throughput win at these sizes) and
|
| 498 |
+
// DP4A is ~12% faster in int8-backward mode — but the ordering is
|
| 499 |
+
// device-dependent in principle (a driver with slow dot4I8Packed or a
|
| 500 |
+
// fast cache path for the LUT flips it). The race below costs ~40ms at
|
| 501 |
+
// init and self-calibrates per device instead of trusting one machine's
|
| 502 |
+
// benchmark. First run of a fresh build is warm-up-skewed; the race
|
| 503 |
+
// warms both before timing.
|
| 504 |
+
const dp4 = { backend: "webgpu", label: `${gpuName} (DP4A int8 dot · exact-gated vs units)`,
|
| 505 |
+
bgemm: bg, att, fgemm, mlp: mlpDp4 };
|
| 506 |
+
try {
|
| 507 |
+
const d0 = { m: 256, k: 32, n: 32, batch: 3, relu: false };
|
| 508 |
+
const rnd8 = (len) => { const a = new Int8Array(len); for (let i = 0; i < len; i++) a[i] = (Math.random() * 256 - 128) | 0; return a; };
|
| 509 |
+
const Xq = rnd8(d0.batch * d0.m * d0.k), Wq = rnd8(d0.batch * d0.k * d0.n);
|
| 510 |
+
const rs = Float32Array.from({ length: d0.batch * d0.m }, () => Math.random() + 0.5);
|
| 511 |
+
const cs = Float32Array.from({ length: d0.batch * d0.n }, () => Math.random() + 0.5);
|
| 512 |
+
const time = async (fn) => {
|
| 513 |
+
await fn(Xq, Wq, rs, cs, d0); await fn(Xq, Wq, rs, cs, d0); // warm
|
| 514 |
+
const t0 = performance.now();
|
| 515 |
+
for (let r = 0; r < 6; r++) await fn(Xq, Wq, rs, cs, d0); // serialized, like training
|
| 516 |
+
return performance.now() - t0;
|
| 517 |
+
};
|
| 518 |
+
const tLut = await time(bgLut), tDp4 = await time(bg);
|
| 519 |
+
const winner = tDp4 <= tLut ? dp4 : viaLUT;
|
| 520 |
+
winner.label += ` · won init race ${Math.min(tLut, tDp4).toFixed(0)}ms vs ${Math.max(tLut, tDp4).toFixed(0)}ms`;
|
| 521 |
+
return winner;
|
| 522 |
+
} catch (e) { return dp4; }
|
| 523 |
} catch (e) { console.warn("WebGPU init failed, CPU fallback:", e); return cpu; }
|
| 524 |
}
|
| 525 |
|