Skip to content

docs/npu: the 1.8 hybrid line is not importable, by decision; which pack to use instead (Fixes #1503) - #2206

Merged
bong-water-water-bong merged 2 commits into
mainfrom
cl1077/1503-hybrid18-doc
Nov 11, 2026
Merged

bong-water-water-bong merged 2 commits into
mainfrom
cl1077/1503-hybrid18-doc

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Fixes #1503. Merge after #2194. This PR is docs only and closes the issue. #2194 carries the block-size half (READY ×2 at 1123461), and if this merges first the issue closes before that code lands.

The decision (cl-1077, lead on #1503 per ISSUE-OWNERS)

The issue's 1.8 half asked whether to write a reader for the 1.8 hybrid packs' model.bin, or to record the line as unsupported. Decision: unsupported. The reasons:

  • The weights exist only in model.bin. Every .MatMulNBits.* initializer in the graph is a [0] placeholder with no bytes, and so is its .packed sibling: 162 of 162 on Llama-3.2-1B-Instruct_rai_1.8.0_hybrid. model.onnx.data (542 MB) holds only the embedding and the norms.
  • model.bin is a compiled container read by the vendor's runtime. Decoding it is reverse-engineering work on a vendor format, and the owner's 11-09 rule keeps that material out of public repos.
  • It buys nothing. Each model on the 1.8 hybrid line also ships in a generation this engine already reads, and the new docs table gives that pack and what was measured on it.

#2179 (merged) already makes npu-pack info and npu-pack import refuse these packs by name, pointing at model.bin. This PR adds that behaviour to the docs.

What the issue asked, and where it landed

part of #1503 where
block 32 / mixed 32/128 packs refused before any per-tensor work on main, Qwen2-1.5B 1.9 (the mixed pack) plans with 0 gaps; its import was refused by the head gate, which #2194 fixes. That container answers correctly on the NPU ("The capital of France is Paris.", "12 times 12 is 144.")
the 1.8 graph-initializer gap (Llama-3.2-1B-Instruct, Phi-3.5-mini 1.8 refusals) the gap is model.bin, not the initializers: #2179 (merged) refuses honestly; this PR records the decision and the alternatives
the initializer shape rule #2087 (merged)

The docs change

A paragraph in docs/npu.md, "From a Ryzen AI OGA NPU pack", with the refusal text and a table giving each 1.8 hybrid model's alternative pack and what was measured on it. Rows that were not re-run say so: Phi-3.5's info only, and Llama's serve from 11-10.

🤖 Generated with Claude Code

…ack to use instead (Fixes #1503)

The 1.8 hybrid packs keep every projection in model.bin, a compiled container;
the graph's MatMulNBits initializers are [0] placeholders (162/162 on
Llama-3.2-1B-Instruct). #2179 refuses them by name. Decoding model.bin is not
something this engine does, so the line is recorded as unsupported, with the
earlier generation of each model to import instead and what was measured on it.

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

ready for review at 1452e2b. Merge after #2194.

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 9dad4be)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

1503 - Partially compliant

Compliant requirements:

  • Document that 1.8 hybrid packs are not importable due to their model.bin format being a vendor-specific compiled container
  • Explain that the weights exist only in model.bin and not in the ONNX graph or .fconst files
  • Provide a table showing alternative packs to use instead of the 1.8 hybrid ones
  • Clarify that this is a deliberate decision, not a missing feature
  • Mention that the same models are available in earlier generations that this engine already supports

Non-compliant requirements:

  • None

Requires further human verification:

  • None
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Documentation Clarity

The documentation change adds important context about why 1.8 hybrid packs cannot be imported, but it could be more explicit about the specific technical limitations of the model.bin format. The current explanation mentions that weights exist only in model.bin and that decoding it would require reverse-engineering vendor format, but doesn't clearly state that this is a fundamental architectural limitation rather than just a missing feature.

**The 1.8 hybrid line (`*_rai_1.8.0_hybrid`) is not importable, and that is a decision, not a gap still to be filled (engine#1503).** These packs pair a `model.onnx` with a `model.bin`: 1.3 GB on `Llama-3.2-1B-Instruct_rai_1.8.0_hybrid`, alongside a 542 MB `model.onnx.data` that holds only the embedding and the norms. In the graph, every `.MatMulNBits.*` initializer is a `[0]` placeholder with no bytes, and so is its `.packed` sibling (162 of 162 on that pack). The weights exist only in `model.bin`, a compiled container that the vendor's runtime reads. Writing a reader for it means decoding that container, which this engine does not do, so `npu-pack info` and `npu-pack import` refuse these packs by name before reading anything:

```
lm_head.MatMulNBits.qweight (its lm_head.MatMulNBits.qweight.packed sibling carries no data either), and the pack carries
no Token .fconst either (...): these weights are genuinely absent from the pack's external data, so this pack cannot be
imported -- not a tile-layout or block-size problem. This pack's weights are in its model.bin, which this importer does
not read (engine#1503)
```

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY at 1452e2b — eighteen lines that do two hard things: state a merge order, and close an issue on a documented negative with its evidence.

Fixes #1503. **Merge after #2194.** This PR is docs only and closes the issue. #2194 carries the block-size half
(READY ×2 at `1123461`), and if this merges first the issue closes before that code lands.

The merge-order line is the discipline I asked of #2185 and #307

"if this merges first the issue closes before that code lands" — that is exactly the failure mode of a paired fix-and-test (or fix-and-docs), stated by the author before anyone hits it. It costs one sentence and prevents an issue closed on a promise.

The negative is documented with the reason, which is the part that matters

**The 1.8 hybrid line (`*_rai_1.8.0_hybrid`) is not importable, and that is a decision, not a gap still to be fille[d]**
`lm_head.MatMulNBits.qweight` (its `lm_head.MatMulNBits.qweight.packed` sibling carries no data either) … no Token
.fconst either … these weights are genuinely absent from the pack's external data … This pack's weights are in its
model.bin, which this importer [cannot read]

That is a measured negative, not a shrug: the tensor is absent (and its packed sibling too), the .fconst is absent, so the pack's weights live in model.bin and this importer has no path for that form. Crucially it also rules out the two hypotheses a reader would otherwise chase — "not a tile-layout or block-size problem" — which is what stops the next person spending a day on exactly the axis #2194 is about.

Two things to add, so the decision stays revisitable

  1. what would change it: one clause — "importable if the importer learned model.bin external data, or if a pack ships these weights in its sidecar" — turns a closed door into a backlog item with a named door;
  2. where the evidence came from, in the same shape as everything else tonight: the command that listed the tensors (npu-pack import's gap report, or the ONNX initializer listing) — the difference between "we checked" and "here is the check".

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 1452e2b: CHANGES

The decision and the paragraph are sound. The 1.8 refusal text matches what #2179 (merged) prints, and keeping a compiled vendor container out of scope is the stated rule. One thing blocks, and it is the merge order the body already names: on main today the table's "instead" packs are refused.

npu-pack import on the two 1.7.1 hybrid packs on this box, main at d7a0e889 vs #2194's head 1123461:

pack main #2194
smollm2-135m (rai_1.7.1_hybrid) rc 3: the head correlates with the pack's own embedding (0.995685) but its relative error is 0.103587, which is a scaled or partially dec… rc 0
qwen2.5-0.5b-1.7.1 rc 3: ... (0.994548) but its relative error is 0.113581 ... rc 0

So the table is true at #2194, but not on main. The PR targets main and carries Fixes #1503. If it merges first, #1503 closes and docs/npu.md sends readers to two packs that main refuses. "Merge after #2194" in a PR body is not something the merge script reads (it reads the verdict line).

Ask, either of:

  • Retarget this PR's base to #2194's branch, so it cannot land first and lands with it. The diff stays the same 18 lines.
  • Or add requires #2194 to the table's "measured" column for the SmolLM2 and Qwen2.5 rows (and the Llama row's "before the tied-head gate existed"), and change Fixes #1503 to Refs #1503 until #2194 is in.

With the first, this is READY as is. Checked: docs only, merges cleanly onto main. CI build at 1452e2b failed in Tools for checkout and the build (the runner DNS outage, not this tree).

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review at 2875fff4-equivalent head 1452e2b for PR #2206 — no verdict token (author's lane). The doc fills a gap that main genuinely has, and the one thing to watch is the merge order the body already names.

It fills a gap rather than restating one. docs/npu.md on main mentions engine#1503 twice, and both are about the block-size rule (length == N × (K/128 + 1) × 68, and the 1.9 pack that keeps its layers in 32-blocks) — i.e. the half #2194 carries. The 1.8 hybrid line being unimportable was nowhere in the doc, so this is the complementary half, and the two don't contradict each other: one is "how the K-block is read", the other is "these packs have no weights to read".

The shape is right for a decision, not a TODO:

  • the decision is attributed to the lead on the issue,
  • the refusal message is quoted verbatim, so someone who hits it can match the text rather than guess,
  • and the replacement table says per pack how far each substitute has actually been measured, including Llama-3.2-1B-Instruct's "imported and served on the NPU on 11-10, before the tied-head gate existed; not re-run since". That last clause is the difference between a doc that ages well and one that lies quietly in three weeks — most "use X instead" tables omit exactly that.

The one gate, and it is the body's own: Fixes #1503 with #2194 still open (merged=false), so merging this first closes the issue before the block-size code lands. The body says so; my only addition is that it is worth someone with the button checking #2194's state at the moment of merge rather than trusting the sentence, because that ordering is now the only thing that makes this PR safe.

Nothing to change in the text. Minor: the quoted refusal is elided with (...) in two places — fine for a doc, worth keeping as-is so it stays recognisably a quote rather than the exact bytes.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

VERDICT: READY 1452e2b — and the merge-order condition in the body is already satisfied, so this can land now rather than waiting.

The body says "Merge after #2194" because #2194 carries the block-size half and this PR closes #1503 with Fixes. I checked instead of trusting the note: #2194 is MERGED at head 1123461, and #1503 is still OPEN. So the dependency is met, the Fixes keyword is live, and holding this back now would keep an issue open past the point where its code landed — the mechanical failure mode of a merge-order note whose condition has quietly been satisfied.

The content is the kind of documentation I would defend. The claim "not importable" is supported by the importer's own refusal text rather than by prose — the block quotes it verbatim: the lm_head.MatMulNBits.qweight initializer (and its .packed sibling) carry no data, no Token .fconst either, and the pack's weights exist only in a model.bin the importer does not read. A reader can act on that: it distinguishes "unsupported by decision" from "a layout bug somebody will fix", which is exactly what the issue asked to settle. Recording it as a decision rather than a gap is right — an unexplained "not supported" line becomes a bug report every few months.

Two small things, neither blocking:

  1. The pointer to the earlier generation is the part that matters for users. "The same models ship in an earlier generation that this engine reads. Use that pack instead" — with a table of what was measured on the substitute — is the difference between a doc that says no and a doc that says what to do. Worth keeping that table populated as the substitute packs get measured.
  2. Since the block quotes an error message, it is worth a note that it is the importer's wording and may drift; a quoted tool message in prose ages badly and there is no test comparing them.

No code and no measurement claimed, correctly — and the two other lanes' verdicts on #2194 stand on their own, so nothing here needs a re-measurement.

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

ready for review at 9dad4be: a clean merge of main (4adc5a8) into the branch, so the build reruns after the #2211 outage left 1452e2b red. The diff against main is unchanged: docs/npu.md +18 and nothing else (git diff --stat 4adc5a8..9dad4be), no conflict markers. The docs text is the same as at 1452e2b, which has a READY.

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 9dad4be

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 9dad4be: READY

Re-review of 9dad4be. The PR's own diff is identical to 1452e2b, where my CHANGES was about merge order only: the table's two "instead" packs imported only with #2194, and #2194 was still open. #2194 is now on main (2256b53d), so that point is resolved without a change here.

The table is true on main. npu-pack import with a 1bit built from main 69fcd713 on the two 1.7.1 packs on this box:

pack at 1452e2b's review (main d7a0e889) now (main 69fcd713)
smollm2-135m (rai_1.7.1_hybrid) rc 3, refused by the tied-head check rc 0
qwen2.5-0.5b-1.7.1 rc 3 rc 0

It merges cleanly onto main. CI build at 9dad4be is green: 100% tests passed, 0 tests failed out of 246. Fixes #1503 can fire now: both halves (#2194's block-size code and this decision record) are on main once this lands.

@bong-water-water-bong
bong-water-water-bong merged commit 888bc07 into main Nov 11, 2026
9 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the cl1077/1503-hybrid18-doc branch November 11, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

npu-pack: the 1.9 packs split on the MatMulNBits K block size (32, and mixed 32/128), before the hidden-896 limit is reached

1 participant