Repository navigation
tenstorrent: f32-out matmul must not land on the bf16 grid; the kolibri residue is chain drift through a high-gain router - #3444
Conversation
localai-org-maint-bot
left a comment
There was a problem hiding this comment.
@mudler @richiejp One source-level blocker in the added diagnostic path at 1bf1e5c:
In kolibri1_tt_forward.cpp::MoeBlock, the StageDumpOn() && l3dbg(layer) block indexes g_kolibri1_dbg_route_logits[k] unconditionally while iterating over href. That global starts empty and is populated only by the CPU forward path's RouteDump. Running TT alone with VT_KOLIBRI1_TT_STAGE_DUMP=1 therefore reads out of bounds; a prior CPU run with a shorter token batch also leaves it too small. The size check in TT RouteDump runs later and does not protect this earlier loop.
Please separate the same-input host-reference comparison from the optional CPU comparison, and require matching reference dimensions before reading the latter. The reference also needs to identify the same layer/prefix; a process-global last CPU layer cannot establish layer-by-layer parity by itself. A diagnostic test should cover TT-only execution and mismatched reference sizes.
This is a focused source finding, not acceptance of the stacked TT changes. I could not run the hardware/model gates on this host, so I have not pushed an unvalidated alteration to this branch.
a0250cb to
456f6ee
Compare
amplification of the upstream bf16 drift class — and fix the f32-out GEMM contract the instrument caught The layer-1 moe divergence after the slot-dequant fix is NOT a stride/staging/accounting defect. The teacher-forced instrument (stage bit-hashes, the router dump on both arms, the router weight hash probe, host-reference logits for both arms' router GEMMs, the element-level L0 dhn diff) proves the chain: the first diverging quantity is the L0 input rms_norm output at step 0 (1 bf16 ULP class); by L0 dh2 the drift carries outlier element diffs (~0.4% rms, 3 ULP on a 48-magnitude element); the router gate weight is byte-identical across arms and BOTH router GEMMs match host reference logits computed from their own inputs (CPU 1.4e-5, TT 0.15 max) — and the kolibri router row has ||w||_2 ~ 1 over K=2560 against logits of scale O(5), so that sub-ULP-class drift injects O(1-5) ABSOLUTE logit noise and flips the near-tie top-6-of-384 selection at every layer including L0. The ~3% L1 moe divergence IS the flipped mixture. Classification: selection flips DRIVEN by continuous precision drift — the upstream adjudication decision, not a local patch. The instrument did catch one contract defect, fixed here: the TT kMatmul/kMatmulBT default produced a BF16 tensor upcast on commit for f32-out callers — all 384 router logits sat on the bf16 grid (bf16grid=384/384) with bf16 partial sums, violating the CPU row's LinearBTRaw f32 contract. f32-out now requests dtype FLOAT32 plus fp32_dest_acc_en; post-fix bf16grid=0/384. The device token gate (ON arm, clean reset) keeps 4 HARD flips at the same positions (gaps -5.62 / -3.85 / -14.76 / -3.75 vs -5.92 / -4.56 / -13.35 / -3.06) and the same deterministic memoized-expert DRAM exhaustion abort: the contract fix does not clear the flips because the drift class drives them. Recorded in ISSUE-LOCAL-01M4ER0E9HHM95YZYJB7T5FECN with the full evidence chain; the OFF arm was not re-gated (it aborts on the same OOM before completing). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:zai/glm-5.3-flash [maki]
global unconditionally — TT-only execution with VT_KOLIBRI1_TT_STAGE_DUMP=1 read an EMPTY process-global out of bounds The maintainer review on 1bf1e5c was right, and the tree proves it: the b2ii device token gate TT-only with the dump env set SEGFAULTS at layer 0, immediately after the router_gate hash line and before any router_href line (exit 139, /tmp/red-tt-only-prefix.log) — the MoeBlock dump block iterated the host reference and indexed g_kolibri1_dbg_route_logits[k] unconditionally, and the empty vector's null data derefs. A prior CPU run with a SHORTER token batch left the global too small for the same out-of-bounds read, and the size check in the TT RouteDump runs later and cannot protect this earlier loop. The fix separates the two comparisons the block conflated. The HOST-REFERENCE leg (device logits vs host-computed reference logits for the SAME inputs) stands on its own and is bounds-checked over the two local vectors. The CPU leg is now OPTIONAL and runs only through Kolibri1DebugRouteCompare (declared in kolibri1_tt_forward.h, defined out of the TU's anonymous namespace so the host-side tests reach it) when the stashed CPU reference's layer identity AND element size match the current call — a process-global "last CPU layer" cannot establish layer-by-layer parity, so the CPU arm now tags its stash with the layer (g_kolibri1_dbg_route_layer, g_kolibri1_dbg_dhn_layer) and the TT side checks identity before every global read (RouteDump's route_diff and the layer-0 dhn diff included). TT-only, wrong-layer, and short-batch all print cpu_ref=skipped and move on. New device-free cases in test_kolibri1_tt_b2ii.cpp pin the guard: TT-only execution with an empty CPU global (no read, cpu_compared false, the device leg still computed), a shorter prior CPU batch (the exact pre-fix OOB shape), and a different-layer reference (skipped; the same-layer same-size case still compares and reports maxdiff_cpu). On device, post-fix: the TT-only dump run completes the router_href leg on every layer — 50 cpu_ref=skipped lines, no crash. Gate verdicts UNCHANGED (both arms, clean reset per leg): ON 4 HARD flips at the same positions ('der Mond' step 7, 'Australia' step 5, 'Wissen ist Macht' step 8, 'x1 = 3' step 22) then the deterministic memoized-expert DRAM exhaustion abort; host-free OFF 3 HARD flips then the same abort. TT unit suite: only the two known failures (kGdnDecode, kMatmulBTQuantGrouped). FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:zai/glm-5.3-flash [maki]
456f6ee to
0ebb922
Compare
Two results from the L1-moe localization (the ~3% relative divergence that remained after #3443's dequant fix).
A real contract defect, fixed: TT
kMatmul/kMatmulBTproduced a bf16-upcast tensor on commit for f32-out callers — all 384 kolibri router logits sat on the bf16 grid with bf16 partial sums. F32-out now requests dtype FLOAT32 withfp32_dest_acc_en(bf16grid 0/384 post-fix, instrumentation committed behindVT_KOLIBRI1_TT_STAGE_DUMP).The residue classified — STOP class: with the router GEMM now correct (both arms match host-reference logits computed from their own inputs: CPU 1.4e-5, TT 0.15), the remaining hard flips are continuous precision drift driving discrete selection flips. The L0 input norm differs by 1 bf16 ULP class (substrate-adjudicated drift); by the L0 moe input that carries ~0.4% rms outliers; and the kolibri router (norm-weighted, K=2560, logits O(5)) amplifies that into O(1–5) absolute logit noise, flipping the near-tie top-6-of-384 selection at every layer. The hard flips (4 ON / 3 OFF, same positions) are this amplifier, not an op bug — the router gate weights are byte-identical across arms and both GEMMs are verifiably correct.
The endgame is therefore an adjudication decision, not a local patch: either the device attention/norm chain goes f32 (a perf and substrate-capability question), or the device gate's standard moves to the near-tie instrument's terms (band + zero-hard under teacher forcing, with a re-captured device golden), exactly mirroring the CPU #3438 discussion. The instrument to verify either path is merged (#3442).
Issue: ISSUE-LOCAL-01M4ER0E9HHM95YZYJB7T5FECN (full evidence chain; probes committed behind VT_KOLIBRI1_TT_STAGE_DUMP).
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:zai/glm-5.3-flash [maki]