Upload web/docs/VERIFICATION.md with huggingface_hub
Browse files- web/docs/VERIFICATION.md +106 -0
web/docs/VERIFICATION.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Verification — why you can trust the numbers
|
| 2 |
+
|
| 3 |
+
DaisyChain-Web's core claim is strong: **every device — any GPU, any driver,
|
| 4 |
+
or plain CPU — computes bit-identical results**, so replicas can be compared
|
| 5 |
+
by hashing raw bytes. This document explains the layers that make that claim
|
| 6 |
+
*checked by things that run*, not argued. Full current results:
|
| 7 |
+
[TEST_RESULTS.md](../TEST_RESULTS.md).
|
| 8 |
+
|
| 9 |
+
## The verified INT8 units
|
| 10 |
+
|
| 11 |
+
All model multiplies run through one primitive: a **block-scaled int8 GEMM**.
|
| 12 |
+
|
| 13 |
+
1. Inputs are quantized per row / per column: `scale = max(|row|)/127`
|
| 14 |
+
(floored at 1e-8), values to int8.
|
| 15 |
+
2. Products come from `mul_lut` — a 65536-entry table of **exact** int8
|
| 16 |
+
products — accumulated in **int32** (exact; no overflow at these sizes).
|
| 17 |
+
3. The float epilogue is fixed to a bit-exact rounding schedule:
|
| 18 |
+
`epi(s,a,b) = f32(f32(f32(s)·a)·b)` — round to f32 after the int→float
|
| 19 |
+
conversion and after **each** multiply.
|
| 20 |
+
|
| 21 |
+
Steps 1–2 are integer-exact everywhere by construction. Step 3 is where
|
| 22 |
+
"bit-identical across devices" is usually lost — so it is pinned to WGSL's
|
| 23 |
+
guarantees (add/multiply are correctly rounded; division is not, so **no
|
| 24 |
+
division ever runs on the GPU** — scales are derived in JS f64, which is
|
| 25 |
+
exactly rounded and device-identical).
|
| 26 |
+
|
| 27 |
+
## Layer 1: exact init gates (every device, every boot)
|
| 28 |
+
|
| 29 |
+
No kernel computes a single training value before passing its gate: run the
|
| 30 |
+
kernel and the JS mirror on a sweep of shapes (ragged ones included) and
|
| 31 |
+
compare — int32 accumulators exactly, f32 outputs **at the bit level**. Any
|
| 32 |
+
mismatch demotes the device to the CPU mirror. Bit-level matters: JS `!==`
|
| 33 |
+
treats `-0 === 0`, but real ISAs have non-IEEE modes that flush −0 to +0, and
|
| 34 |
+
the replica hash *would* see that. The gates compare exactly what the hash
|
| 35 |
+
sees.
|
| 36 |
+
|
| 37 |
+
Gates re-run at **every** init because floating-point behavior is runtime
|
| 38 |
+
state on real hardware (rounding mode and denorm flushing are per-wave MODE
|
| 39 |
+
registers on RDNA2, set by the driver) — a device model can't be trusted
|
| 40 |
+
across boots; a fresh gate can.
|
| 41 |
+
|
| 42 |
+
Some gates additionally **gate the gate**: the B2B chain gate hunts for an
|
| 43 |
+
input where the old and new quantize specs actually disagree and requires the
|
| 44 |
+
GPU to match the new one — so a pass is something the old spec would fail,
|
| 45 |
+
not a vacuous agreement.
|
| 46 |
+
|
| 47 |
+
## Layer 2: continuous audit (every run, live shapes)
|
| 48 |
+
|
| 49 |
+
Init gates use test shapes; the **audit** samples random output cells of the
|
| 50 |
+
*live* GEMMs during training and recomputes them through the units. A kernel
|
| 51 |
+
that is correct at gate shapes but wrong at live shapes (stride bugs, padding
|
| 52 |
+
bugs) is caught while it trains.
|
| 53 |
+
|
| 54 |
+
## Layer 3: the kernel probe (every step, cross-device)
|
| 55 |
+
|
| 56 |
+
The weight hash cannot catch a device whose *kernel* is wrong — weights only
|
| 57 |
+
depend on the gradient bytes everyone receives. So each step every device
|
| 58 |
+
also publishes a **probe hash**: the same seeded int8 GEMM through its live
|
| 59 |
+
kernel. Same math ⇒ same hash, on every honest device, any backend.
|
| 60 |
+
|
| 61 |
+
## Layer 4: the referee — an IEEE-754 oracle
|
| 62 |
+
|
| 63 |
+
Who checks the JS mirror? `test_ieee.js` builds a binary32 oracle **from the
|
| 64 |
+
IEEE-754 definition in exact BigInt arithmetic** — no `Math.fround` anywhere
|
| 65 |
+
in it, round-to-nearest-even, subnormals, signed zero. The mirror's epilogue
|
| 66 |
+
agrees with the oracle on 500k+ checks, including a tie-to-even ladder around
|
| 67 |
+
2²⁴ — and the oracle **rejects** the older round-once mirror on 34% of
|
| 68 |
+
inputs, which is what makes the agreement meaningful.
|
| 69 |
+
|
| 70 |
+
## Layer 5: properties and mutation scores
|
| 71 |
+
|
| 72 |
+
`test_metamorphic.js` holds correctness properties that need **no reference
|
| 73 |
+
implementation**: relations (permuting rows permutes outputs; a zero row
|
| 74 |
+
yields zeros; batches decompose; single-cell sensitivity) plus two
|
| 75 |
+
**definitional absolutes** — fused-ReLU output can never be negative, and at
|
| 76 |
+
unit scales the output must equal the exact integer dot product. The split is
|
| 77 |
+
principled: if `out` satisfies every relation, so does `2·out` — relations are
|
| 78 |
+
provably blind to value bugs, absolutes are not.
|
| 79 |
+
|
| 80 |
+
`test_corpus.js` then **mutation-scores the checkers themselves** against an
|
| 81 |
+
externally authored bug taxonomy
|
| 82 |
+
([dipankarsarkar/gpuemu-corpus](https://huggingface.co/datasets/dipankarsarkar/gpuemu-corpus)):
|
| 83 |
+
each ported bug must be caught (4/4 properties, 4/4 differential), and a
|
| 84 |
+
control run must stay clean. A checker that has never rejected anything is
|
| 85 |
+
decoration; these have a scoreboard.
|
| 86 |
+
|
| 87 |
+
## Hardware ground truth (RDNA2 ISA audit)
|
| 88 |
+
|
| 89 |
+
Reading a real GPU ISA against the assumptions confirmed on silicon:
|
| 90 |
+
`V_DOT4_I32_I8` is an exact packed int8 dot (the DP4A path is exact by ISA
|
| 91 |
+
guarantee); f32 add/mul are 0.5 ULP; reciprocal is 1 ULP (division stays off
|
| 92 |
+
the GPU). It also produced two hardenings: the bit-level gate comparisons
|
| 93 |
+
above, and a proof that FMA contraction of the quantize's `x·inv + 0.5`
|
| 94 |
+
(one rounding instead of two — a choice WGSL leaves to the compiler) is
|
| 95 |
+
**floor-invisible by construction**: last-ulp anomalies occur at binade
|
| 96 |
+
edges, but RNE tie parity keeps both rounding schedules on the same side of
|
| 97 |
+
every integer, so the quantized int8 is identical either way. Since no gate
|
| 98 |
+
can forbid a compiler an fma, that one had to be a theorem, not a check —
|
| 99 |
+
`test_b2b.js` asserts both halves (anomalies exist; zero survive `floor`).
|
| 100 |
+
|
| 101 |
+
## What this does NOT protect against
|
| 102 |
+
|
| 103 |
+
A **malicious** peer that runs the correct math but *lies* — sends a crafted
|
| 104 |
+
gradient — is not caught by any of this; there is no gradient authentication.
|
| 105 |
+
The verification stack proves the *computation* is right on every honest
|
| 106 |
+
device. Trust in the *participants* is still yours to establish.
|