From ec6cc5e0794c544dc48155081e717c3883d7d7a1 Mon Sep 17 00:00:00 2001 From: pi-mosaic Date: Tue, 10 Nov 2026 23:01:57 -0400 Subject: [PATCH 1/2] npu-pack: a tied head must correlate AND not be mis-scaled, or it imports cleanly and answers nonsense (engine#1503) Two gemma-2-2b hybrid packs measured on this box import with every check green and serve garbage: pack corr rel_err serves Qwen-2.5_1.5B_Instruct_rai_1.9.0_npu 0.996901 0.000000 'The capital of France is Paris.' x3 gemma-2-2b-onnx-ryzenai-hybrid 0.991539 0.136140 'myself myself ...' x3 gemma-2-2b-awq-...-g32-fp16-onnx-hybrid 0.996053 0.094874 'myselfGetBytes...' x3 A head that is a SCALED copy of its own embedding still correlates, so the correlation-only check passes it -- and the import printed the number that distinguishes them (rel_err) as an advisory field next to the correlation it gated on. Both packs cost a device ticket to discover. - one predicate, selfcheck_head_ok(corr, rel), so the four sites that set selfcheck_tied cannot drift; - kSelfcheckRelMax = 0.02, the measured gap: 0.000000 on the pack that serves, 0.095/0.136 on the two that do not; - Report::selfcheck_scaled, set at all four sites next to selfcheck_tied; - main() refuses on it and NAMES both numbers and the threshold. --allow-incomplete does not override: that flag means 'write the tensors I could not represent', and this is 'the tensors I wrote do not decode'. Verified: both translation units pass g++ -fsyntax-only (the json header from a neighbour build), and the predicate's six arms pass against the three measured triples plus a control, a no-correlation case and the inclusive boundary (~ /wt/relcheck.cpp, run). NOT verified here: the full npu_pack_import_test binary and any container import -- that needs a configured build, which the disk floor did not allow at the time; the two test arms are written for CI. --- npu/pack_import.cpp | 30 ++++++++++++++++++++++++++++++ npu/pack_import.h | 11 +++++++++++ tests/npu_pack_import_test.cpp | 16 ++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/npu/pack_import.cpp b/npu/pack_import.cpp index d1e844bc7..52f0e8e5f 100644 --- a/npu/pack_import.cpp +++ b/npu/pack_import.cpp @@ -498,6 +498,11 @@ const uint8_t* at(const Fconst& f, int64_t off, int64_t len) { // field, the readout and the note all have to agree on it: three copies of 0.99 is how they drifted apart before. constexpr double kTieCorr = 0.99; +// engine#1503: tied AND not mis-scaled. Correlation alone passes a head that is a scaled copy of the embedding -- two +// packs on this box report corr 0.9915/0.9961 with rel_err 0.095/0.136 and serve garbage, while the pack that serves +// correctly reports rel_err 0.000000. One predicate, so the four sites that set selfcheck_tied cannot drift apart. + + // Every entry was measured by diffing the 1.9 pack against the 1.8 pack of the SAME model: the bundle's tile shape and // its rotation are not derivable from the pack, and neither is `prefix`. It was tempting to read the extra bytes as // Qwen3's per-head QK norm gains, but Llama-3.2-1B -- which has no QK norms at all -- carries the same +4,352 at hidden @@ -5011,6 +5016,8 @@ Report import_pack(const std::string& pack_dir, const std::string& out_dir, cons // `tied` is false there while the head plainly reproduces its embedding, and the readout used to call those // packs untied while the container it wrote said tied. Same threshold the container's own decision uses. r.selfcheck_tied = r.lmhead_corr > kTieCorr; + + r.selfcheck_scaled = r.selfcheck_tied && !selfcheck_head_ok(r.lmhead_corr, r.lmhead_rel); const Q4 swap = decode_matmulnbits(bytes_of(wt, qw_need), scales.data(), zp, int(mm.N), int(mm.K), mm.block, /*swap_nibbles*/ true, false); const Q4 nozp = decode_matmulnbits(bytes_of(wt, qw_need), scales.data(), nullptr, int(mm.N), int(mm.K), @@ -5098,6 +5105,8 @@ Report import_pack(const std::string& pack_dir, const std::string& out_dir, cons } r.selfcheck_reference = true; r.selfcheck_tied = c32 > kTieCorr; + + r.selfcheck_scaled = r.selfcheck_tied && !selfcheck_head_ok(r.lmhead_corr, r.lmhead_rel); double sxy = 0, sx = 0, sy = 0, sxx = 0, syy = 0; const int nsh = std::min(2048, int(V) - 1); for (int rr = 0; rr < nsh; ++rr) @@ -5311,6 +5320,8 @@ Report import_pack(const std::string& pack_dir, const std::string& out_dir, cons r.lmhead_corr = corr(q, embed_tbl, q.N); r.selfcheck_reference = true; r.selfcheck_tied = r.lmhead_corr > kTieCorr; + + r.selfcheck_scaled = r.selfcheck_tied && !selfcheck_head_ok(r.lmhead_corr, r.lmhead_rel); double sxy = 0, sx = 0, sy = 0, sxx = 0, syy = 0; const int nsh = std::min(2048, q.N - 1); for (int rr = 0; rr < nsh; ++rr) @@ -5423,6 +5434,8 @@ Report import_pack(const std::string& pack_dir, const std::string& out_dir, cons r.lmhead_corr = corr(q, embed_tbl, q.N); r.selfcheck_reference = true; r.selfcheck_tied = r.lmhead_corr > kTieCorr; + + r.selfcheck_scaled = r.selfcheck_tied && !selfcheck_head_ok(r.lmhead_corr, r.lmhead_rel); // The control this path can actually run: the same tiles and the same decoder, with each // head row matched against the NEXT embedding row. If a misaligned head still correlated, // the number above would be measuring the vocabulary's mean brightness rather than the @@ -6020,6 +6033,19 @@ int run(int argc, char** argv) { } const Report r = import_pack(dir, out, Options{allow, layout}); + // engine#1503: a head that correlates but is mis-scaled imports cleanly and answers nonsense on the device (two + // packs measured: rel_err 0.095 and 0.136 against 0.000000 on the pack that serves). `--allow-incomplete` is not an + // override here: that flag means "write the tensors I could not represent", and this is "the tensors I wrote do not + // decode", which no amount of writing fixes. + if (r.selfcheck_scaled) { + std::fprintf(stderr, + "1bit npu-pack: refusing to import %s: the head correlates with the pack's own embedding (%.6f) but " + "its relative error is %.6f, which is a scaled or partially decoded head rather than a rounding " + "difference (the threshold is %.3f). A pack in this state imports cleanly and answers garbage on " + "the device; --allow-incomplete does not override this.\n", + dir.c_str(), r.lmhead_corr, r.lmhead_rel, kSelfcheckRelMax); + return 3; + } if (!r.refused.empty() && !allow) { std::fprintf(stderr, "1bit npu-pack: refusing to import %s: %zu of the pack's tensors cannot be " @@ -6273,5 +6299,9 @@ void sweep_fconst_scratch_dirs(const std::vector& dirs, const std:: } } +// engine#1503: the tied-head rule, defined here so it is the namespace-scope function the header declares (a file-local +// copy is ambiguous with it at every call site). Correlated AND not a scaled copy of the embedding -- the two states this +// box measures are rel_err 0.000000 (serves) and 0.095/0.136 (imports cleanly, answers garbage). +bool selfcheck_head_ok(double corr, double rel) { return corr > kTieCorr && rel <= kSelfcheckRelMax; } } // namespace onebit::npu::pack_import diff --git a/npu/pack_import.h b/npu/pack_import.h index 513025dbf..48a47a6bc 100644 --- a/npu/pack_import.h +++ b/npu/pack_import.h @@ -442,6 +442,11 @@ struct Report { // check; an untied pack's head and embedding are separate matrices by construction, and the same number is // meaningless -- reported as such rather than left looking like a failed import. bool selfcheck_tied = false; + // engine#1503: tied, correlated -- but MIS-SCALED. Correlation alone passes a head that is a scaled copy of the + // embedding: two packs measured on this box report corr 0.9915/0.9961 with rel_err 0.095/0.136 and serve garbage + // ("myself" forever), while the pack that serves correctly reports rel_err 0.000000. A pack in this state imports + // cleanly and answers nonsense, so it is refused rather than reported. + bool selfcheck_scaled = false; double lmhead_corr = 0, lmhead_rel = 0, ctrl_corr_nibble = 0, ctrl_corr_nozp = 0; // The tail (.fconst) path has no MatMulNBits bytes to mis-decode, so its control is an ALIGNMENT one: the same // tiles, the same decoder, rows matched against the neighbouring embedding row. A correct decode correlates ~1 @@ -772,6 +777,12 @@ bool fconst_scratch_ready(const std::string& dir); const Fconst19Rule* select_fconst19_rule_from(const Fconst19Rule* rules, int count, int hidden, int heads, int layers, std::string* why); +// engine#1503: the tied-head rule, as ONE predicate so the four call sites cannot drift: the head must reproduce the +// embedding (corr) AND not be a scaled copy of it (rel_err). The constant is the measured gap between the two states -- +// 0.000000 for the pack that serves, 0.095/0.136 for the two that do not -- so 0.02 sits far from both. +inline constexpr double kSelfcheckRelMax = 0.02; +bool selfcheck_head_ok(double corr, double rel); + int64_t attn_tile_bytes(int64_t k); // Pearson correlation between a quantised head and a bf16 embedding table (engine#1690; the self-check's own statistic, // exported so a test can pin the buffer width it decodes). diff --git a/tests/npu_pack_import_test.cpp b/tests/npu_pack_import_test.cpp index 57e3e8862..6adfb4230 100644 --- a/tests/npu_pack_import_test.cpp +++ b/tests/npu_pack_import_test.cpp @@ -5665,7 +5665,23 @@ void test_header_witness_refusal() { std::printf(" header witness: 8 arms (one-header vote vs declaration refuses; 3/1-without-declaration/0 allowed)\n"); } +// engine#1503: the tied-head rule as ONE predicate -- correlated AND not mis-scaled. Two packs on this box correlate +// (0.9915 / 0.9961) while being scaled copies of their own embedding (rel_err 0.1361 / 0.0949): they import cleanly and +// serve garbage, where the pack that serves correctly reports rel_err 0.000000. Correlation alone cannot tell them apart, +// which is why the correlation-only check passed both and cost two device tickets. +static void selfcheck_head_rule_arms() { + check(pi::selfcheck_head_ok(0.996901, 0.000000), "head rule: the pack that serves correctly passes (corr .9969, rel 0)"); + check(!pi::selfcheck_head_ok(0.991539, 0.136140), "head rule: a correlated but scaled head is refused (corr .9915, rel .1361)"); + check(!pi::selfcheck_head_ok(0.996053, 0.094874), "head rule: the second measured pack is refused too (corr .9961, rel .0949)"); + check(pi::selfcheck_head_ok(0.996053, 0.000000), + "head rule: correlated and unscaled passes -- the rule is not 'refuse everything'"); + check(!pi::selfcheck_head_ok(0.50, 0.000000), "head rule: an uncorrelated head is still refused on correlation"); + check(pi::selfcheck_head_ok(0.996053, pi::kSelfcheckRelMax), "head rule: exactly at the threshold passes (inclusive bound)"); + std::printf(" head rule: 6 arms (two measured bad packs, the serving one, the unscaled control, no-corr, boundary)\n"); +} + int main(int argc, char** argv) { + selfcheck_head_rule_arms(); // engine#1907: every crafted 1.9 import writes a canonical copy into the scratch cache. Without this the suite left 0-byte // copies in the user's real ~/.cache/1bit/fconst19 and in /tmp on every run. Give the run its own directory, removed at exit. const fs::path run_scratch = ::onebit::test::tmp_root() / ("1bit-pack-test-scratch-" + std::to_string(::getpid())); From f075d939bdb56f7b80323ed686e11d0987a2a849 Mon Sep 17 00:00:00 2001 From: pi-mosaic Date: Tue, 10 Nov 2026 23:27:26 -0400 Subject: [PATCH 2/2] npu-pack: name the partial output in the mis-scaled-head refusal (engine#1503) Demonstrated on the real pack, not argued from the fixture: importing ~/scratch-packs/gemma22b (gemma-2-2b-onnx-ryzenai-hybrid, the pack that served 'myself myself ...' for 16 tokens) now stops at refusing to import ...: the head correlates with the pack's own embedding (0.991539) but its relative error is 0.136140, which is a scaled or partially decoded head rather than a rounding difference (the threshold is 0.020). A pack in this state imports cleanly and answers garbage on the device; --allow-incomplete does not override this. That run also showed the check happens after import_pack() has already copied the text artifacts and written model.q4nx, so a refusal left five files behind. An importer must not delete a directory the caller named, so the message now says the partial output exists and is not servable -- the operator deletes it before retrying. Verified by rebuilding onebit and re-running the same import, and the test target still passes its six arms. --- npu/pack_import.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/npu/pack_import.cpp b/npu/pack_import.cpp index 52f0e8e5f..01bcc0e67 100644 --- a/npu/pack_import.cpp +++ b/npu/pack_import.cpp @@ -6042,8 +6042,9 @@ int run(int argc, char** argv) { "1bit npu-pack: refusing to import %s: the head correlates with the pack's own embedding (%.6f) but " "its relative error is %.6f, which is a scaled or partially decoded head rather than a rounding " "difference (the threshold is %.3f). A pack in this state imports cleanly and answers garbage on " - "the device; --allow-incomplete does not override this.\n", - dir.c_str(), r.lmhead_corr, r.lmhead_rel, kSelfcheckRelMax); + "the device; --allow-incomplete does not override this. The partial output this run already\n" + "wrote under %s is not servable -- delete it before retrying.\n", + dir.c_str(), r.lmhead_corr, r.lmhead_rel, kSelfcheckRelMax, out.c_str()); return 3; } if (!r.refused.empty() && !allow) {