Quazim0t0 commited on
Commit
728ce28
·
verified ·
1 Parent(s): 6c73e9a

Upload web/public/webgpu.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. web/public/webgpu.js +42 -1
web/public/webgpu.js CHANGED
@@ -940,6 +940,43 @@
940
  const cs = Float32Array.from({ length: batch * n }, () => 1);
941
  return { Xq, Wq, rs, cs, d: { ...PROBE, acc: true } };
942
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
943
  async function kernelProbe(compute, L) {
944
  const { Xq, Wq, rs, cs, d } = probeInputs();
945
  const out = compute && compute.bgemm
@@ -948,8 +985,12 @@
948
  let h = 0x811c9dc5; // FNV-1a over the exact int32 results
949
  const b = new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
950
  for (let i = 0; i < b.length; i++) { h ^= b[i]; h = Math.imul(h, 0x01000193); }
 
 
 
 
951
  return h >>> 0;
952
  }
953
 
954
- root.Compute = { initCompute, loadLUTs, kernelProbe };
955
  })(self);
 
940
  const cs = Float32Array.from({ length: batch * n }, () => 1);
941
  return { Xq, Wq, rs, cs, d: { ...PROBE, acc: true } };
942
  }
943
+ // ---- transcendental probe ---------------------------------------------------
944
+ // The kernel probe covers int8 GEMM arithmetic. It does NOT cover the JS
945
+ // transcendentals, and ECMA-262 does not require Math.exp/log/cos/sin to be
946
+ // correctly rounded — it calls them "implementation-approximated", so V8,
947
+ // SpiderMonkey and JSC are all permitted to return different bits.
948
+ //
949
+ // One use of them can fork a fleet: weight INIT. Peers build their own
950
+ // starting weights from a shared seed rather than broadcasting them
951
+ // (Box-Muller, so Math.log/cos/sin), and one ulp of engine disagreement
952
+ // means peers begin from different models. The per-step uses (softmax, loss)
953
+ // cannot fork anything — every peer averages the same received gradient
954
+ // BYTES, so a differently-rounded local gradient is still a gradient the
955
+ // whole group then agrees on.
956
+ //
957
+ // This hashes the exact f64 bits of those four functions over a fixed grid,
958
+ // so a browser whose math library differs is IDENTIFIED instead of showing
959
+ // up later as an unexplained weight-hash mismatch. Cost: microseconds, once.
960
+ // Detection, not correction — pinning the algorithms would be a fleet-wide
961
+ // numerics change, and is only worth doing if this ever reports a mismatch.
962
+ function mathProbe() {
963
+ const buf = new ArrayBuffer(8), dv = new DataView(buf);
964
+ let h = 0x811c9dc5;
965
+ const eat = (x) => {
966
+ dv.setFloat64(0, x);
967
+ for (let i = 0; i < 8; i++) { h ^= dv.getUint8(i); h = Math.imul(h, 0x01000193); }
968
+ };
969
+ for (let i = 1; i <= 400; i++) {
970
+ const u = i / 401; // (0,1): the Box-Muller domain
971
+ eat(Math.log(u));
972
+ eat(Math.cos(2 * Math.PI * u));
973
+ eat(Math.sin(2 * Math.PI * u));
974
+ eat(Math.sqrt(-2 * Math.log(u))); // the exact composite randn uses
975
+ eat(Math.exp(-u * 12)); // the softmax domain
976
+ }
977
+ return h >>> 0;
978
+ }
979
+
980
  async function kernelProbe(compute, L) {
981
  const { Xq, Wq, rs, cs, d } = probeInputs();
982
  const out = compute && compute.bgemm
 
985
  let h = 0x811c9dc5; // FNV-1a over the exact int32 results
986
  const b = new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
987
  for (let i = 0; i < b.length; i++) { h ^= b[i]; h = Math.imul(h, 0x01000193); }
988
+ // fold in the transcendental hash: same question ("is your arithmetic the
989
+ // same as mine?"), same broadcast slot, no wire-format change
990
+ const mh = mathProbe();
991
+ for (let i = 0; i < 4; i++) { h ^= (mh >>> (i * 8)) & 0xFF; h = Math.imul(h, 0x01000193); }
992
  return h >>> 0;
993
  }
994
 
995
+ root.Compute = { initCompute, loadLUTs, kernelProbe, mathProbe };
996
  })(self);