WIP: goal 7: Ornith-1.5-35B-A3B MoE bring-up (Adartras bundle, FP8 loader, ttl shim) #16
No reviewers
Labels
No labels
human-approved
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
bitpartner/tt-stack!16
Loading…
Reference in a new issue
No description provided.
Delete branch "agent/claude-auth/ornith-moe"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Tier T1 (serving image + docs; no host config).
Goal 7 bring-up: docs/GOAL-ORNITH-MOE.md, the Ornith-1.5-35B-A3B MoE (27B programme dropped for the MoE).
Phase 0 scouting + Phase 1 image. Recipe: HF Adartras/qwen3.6-a3b-blackhole tt-kernel vLLM bundle (single p150, 32.5 tok/s external), loaded via our plugin's EXTRA_MODELS_DIR hook. Deviations: ttl (tt-lang) import shim (cp312-only wheel, pins ttnn 0.74, so GDN decode runs the bundle's ttnn scan fallback), FP8 compressed-tensors loader patch with per-expert -> fused assembly (verified offline: bf16 fused vs FP8 dequant cosine 0.9996/0.9997), hand-written vllm_metadata.json, serve/smoke scripts. Image vllm-tt:ornith built and import-verified on nixos.
Device run is done (2026-09-06 00:40), not pending. All measured on cfx-llm2, 2× Blackhole p150a, (1,2) mesh:
DP-2 both cards: 66.4/66.1/64.5/63.7 tok/s aggregate at 128/1k/4k/16k, zero per-card loss. All 21 no-code knobs spent (none adopted beyond the serving-path switch); everything from here is code.
Open levers, in order: traced prefill (B7 wedges on a padded 1k bucket), fused GDN decode kernel (needs tt-lang or a hand kernel; also unblocks MTP), grouped top-k MoE prefill (lever 2.8), sparse batched MoE (lever 2.1).
Branch was cut from agent/claude-auth/goal-4-nvfp4-single-card and carries its parked 27B commits; the Ornith diff is ornith/, docker/ornith, docs/GOAL-ORNITH-MOE.md.
Every MBU figure in this repo took 27.49 GiB from the external report. Summing our own tensor-cache files by name group says that is wrong, because two of the largest cached tensors are not read per token: mlp.gate_up.weight.swiglu.tp 5.98 GiB packed [gate|up] for the fused PREFILL agmm -- the source says decode keeps w1/w3 tok_embeddings.weight 2.37 GiB a row lookup, not a matmul The corrected read is 20.17 GiB, and it moves both numbers in opposite directions: the 100%-MBU ceiling rises from 29.1 to 39.7 tok/s, and our measured 14.42 tok/s is 36% of DRAM rather than 49%. That is better news and worse news, and the worse half is the interesting one. More headroom exists than documented. But a decode that is ALREADY TRACED, with a p99/p50 of 1.18 and no episodic tail, sitting at 36% MBU, has something systematic in front of every token -- which is not the conclusion the previous revision drew when it said the dispatch levers were spent. Three candidates are now written down with the evidence for each: host round-trips (_ondev_argmax is False, so logits cross PCIe Gen3 x4 every token), M=1 matmul efficiency on a path tuned for 1 and 4 cards, and the per-layer CCL at a TP=2 that falls back to TP=4 constants. It also changes the goal 3 projection from a miss to a pass: at a constant 36% MBU, down_proj at bfloat4_b lands at 16.6 tok/s against the > 16.0 gate rather than the ~15.9 the old divisor predicted. Whether MBU holds constant is the open question, which is the argument for measuring instead of projecting.layer.py branches on num_devices > 1, so a (1,1) mesh takes the NON-TP modules, and those call load_gdn_weights, which raises "DeltaNet layer requires the combined qkv_proj weight". Both lazy loaders deliberately keep GDN linear_attn.* raw -- fused in_proj_qkv, fused conv1d -- because the TP loaders shard those themselves. Goals 1-3 ran entirely at TP=2 and could not have found this; it would have surfaced as a crash after a multi-hour cold cache build. as_single_device() supplies the remap_qwen36_state_dict layout without giving up laziness: in_proj_qkv renamed to qkv_proj, conv1d recorded as three slice specs that slice on read. 851 keys become 947 (+96 = 48 GDN layers x 2 extra conv keys), the NVFP4 and FP8 single-device key sets are identical, the split reassembles to the original tensor exactly, and the spec shapes match the actual reads -- which matters because the warm-cache marker trusts them. Peak RSS 1.60 GB. model_config passes single_device=(num_devices == 1), so two cards are untouched. I first read LINEAR_Q_DIM/LINEAR_K_DIM = 2048 as hardcoded for the 9B and therefore wrong here. They are not: that is linear_num_key_heads x linear_key_head_dim, 16 x 128 in both models, and V is taken as the remainder -- 6144 here against the 9B's 4096. The stale constant in that block is FULL_ATTENTION_LAYERS = {3..31}, and it is dead code.Closing: the branch
agent/claude-auth/ornith-moeis fully merged into master (ancestor), and the project chose Qwen3.8-27B / ThinkingCap over this goal. It is being archived as tagarchive/agent/claude-auth/ornith-moe.Ornith-1.5-35B-A3B remains a candidate for the new 1-card target, tracked on #69. Its 32.5 tok/s single-P150 figure is third-party and was never measured here.
agent-gateway closeout (closed): cleared
agent:*labels.Hermes kanban card (if any) is left for Hermes to archive/complete.
Pull request closed