Upload web/TEST_RESULTS.md with huggingface_hub
Browse files- web/TEST_RESULTS.md +41 -0
web/TEST_RESULTS.md
CHANGED
|
@@ -153,6 +153,47 @@ path runs. A note on method: the init backend race makes step totals vary
|
|
| 153 |
run-to-run (LUT vs DP4A can win), so uncontrolled before/after numbers are
|
| 154 |
not comparable — hence the same-session A/B.
|
| 155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
## Fixing the audit's coverage (the weak spot, named and closed)
|
| 157 |
|
| 158 |
The live audit's two constants — `cells: 6`, `due: 2% of GEMMs` — were chosen
|
|
|
|
| 153 |
run-to-run (LUT vs DP4A can win), so uncontrolled before/after numbers are
|
| 154 |
not comparable — hence the same-session A/B.
|
| 155 |
|
| 156 |
+
## Two gaps found by auditing the verification itself
|
| 157 |
+
|
| 158 |
+
Reviewing the instruments (rather than the kernels) turned up two places where
|
| 159 |
+
the standard applied everywhere else had not been applied.
|
| 160 |
+
|
| 161 |
+
**1. The attention kernels had no live audit.** Every other GPU kernel is
|
| 162 |
+
recomputed against the units at *live* shapes; `att.scores` and `att.ctx` had
|
| 163 |
+
exact init gates and nothing after — the precise gap the audit exists to close,
|
| 164 |
+
left open on the kernels with the trickiest indexing (head-strided gather,
|
| 165 |
+
scatter write-back). `auditAttScores` / `auditAttCtx` now recompute individual
|
| 166 |
+
cells, stratified like the GEMM audit (last head, last token pair, last
|
| 167 |
+
channel first). Both reject a corrupted last-head/last-channel cell and accept
|
| 168 |
+
the clean kernel; a live 300-step run audits every attention dispatch with no
|
| 169 |
+
false positives.
|
| 170 |
+
|
| 171 |
+
**2. The f32 backward GEMM was gated by `allclose`** (`1e-3`) — the last
|
| 172 |
+
tolerance in a shipped path, and this suite's own mutation test shows allclose
|
| 173 |
+
waving through a real rounding bug. The reason was legitimate: split-K
|
| 174 |
+
accumulates in a different order than a naive reference, so bit-equality
|
| 175 |
+
against *that* reference is impossible. So the reference was rewritten instead:
|
| 176 |
+
`fgemmMirror` reproduces split-K's partition and accumulation order exactly,
|
| 177 |
+
and the gate now compares with `!==`.
|
| 178 |
+
|
| 179 |
+
That raised a question the code could not answer by reasoning: WGSL permits a
|
| 180 |
+
compiler to contract `s + a*b` into a fused multiply-add (one rounding instead
|
| 181 |
+
of two), which would change the result. Rather than assume, the gate tries both
|
| 182 |
+
schedules and reports which the device implements — and refuses the kernel if
|
| 183 |
+
**neither** matches, since a backward GEMM that is not bit-reproducible sets
|
| 184 |
+
weights the whole fleet is hashed against. Measured here:
|
| 185 |
+
|
| 186 |
+
```
|
| 187 |
+
split-K f32 GEMM is bit-exact (two-rounding multiply-add schedule)
|
| 188 |
+
```
|
| 189 |
+
|
| 190 |
+
So this driver does not contract, and the f32 backward is now exactly gated.
|
| 191 |
+
The two schedules are not a distinction without a difference — they disagree
|
| 192 |
+
on 22/24 cells at the gate shape, so the gate is choosing between real
|
| 193 |
+
alternatives. (The same measurement shows split-K disagreeing with a naive
|
| 194 |
+
matmul on 22/24 cells, which is exactly why the tolerance was there and why
|
| 195 |
+
the mirror had to be written.)
|
| 196 |
+
|
| 197 |
## Fixing the audit's coverage (the weak spot, named and closed)
|
| 198 |
|
| 199 |
The live audit's two constants — `cells: 6`, `due: 2% of GEMMs` — were chosen
|