Skip to content

dasLLAMA: Qwen 3.5/3.6 support (qwen35/qwen35moe — Gated DeltaNet hybrid)#3448

Merged
borisbat merged 10 commits into
masterfrom
bbatkin/dasllama-qwen35
Jul 12, 2026
Merged

dasLLAMA: Qwen 3.5/3.6 support (qwen35/qwen35moe — Gated DeltaNet hybrid)#3448
borisbat merged 10 commits into
masterfrom
bbatkin/dasllama-qwen35

Conversation

@borisbat

@borisbat borisbat commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Qwen 3.5/3.6 support in dasLLAMA: the qwen35/qwen35moe hybrid architecture — 3:1 Gated DeltaNet (linear attention, recurrent state, no KV) : gated full attention (GQA head_dim 256, partial RoPE 64/256, sigmoid output gate), 248k vocab, MoE variant with 256 experts + shared expert. Unlocks the whole Qwen3.5 open lineup (0.8B/4B/9B/27B) plus Qwen3.6-35B-A3B / 27B.

One PR, staged commits:

  • Tokenizerpre="qwen35": letter runs absorb combining marks ([\p{L}\p{M}]+); cpt_is_mark + marks flag in pretok_split; byte-exact vs llama.cpp ggml-vocab-qwen35 corpus, existing corpora unchanged (6/6)
  • Dense qwen35 — per-layer recurrent mask (recr_mask, zero KV via layer_n_kv_heads), partial NEOX rope (direct + table leaves), 2×-wide gated Q, Session-resident conv/delta f32 state (forward-only, rewind-guarded), deltanet kernels matching ggml's float-accumulation order, prefix-cache refusal for hybrids. Bit-exact on Qwen3.5-0.8B-Q8_0: 40/40 vs simple_ids on the frozen counting fixture, the high-entropy "Once upon a time" prompt, and the both-sides-q8_0-KV arm; full parity suite 42 tests / 0 failed
  • qwen35moe — existing top-8 softmax+renorm router + sigmoid-gated shared expert; optional feed_forward_length (pure-MoE files), F32 ssm_beta/ssm_alpha fp32 matmul rail, modulo GQA-repeat (32 v-heads over 16 k-heads). Bit-exact on Qwen3.6-35B-A3B-UD-Q4_K_M: 40/40, fixture frozen running both MoE prefill paths (K-quant expert stacks on the native kq tier)
  • Perf — chunked deltanet prefill (llama.cpp's CS=64 form: in-chunk deltas solved as a unit-lower triangular system, outputs/state-advance as register-tiled gemm_f32, f32 state touched once per chunk instead of per token) behind set_deltanet_prefill_mode — chunked is the runtime default like llama.cpp, the parity fixtures pin recurrent (the bit-exact ggml float order) and every hybrid fixture runs an explicit chunked arm; batched causal conv (tap-major weights, float4 rows, history handled at both seams); decode delta rule threaded work-proportionally over v-heads. New test_deltanet.das proves chunked==recurrent on a 150-token multi-chunk window (argmax + 8-token greedy lockstep across the state handoff into decode). Also: jobque worker affinity now off by default (DAS_JOBQUE_AFFINITY=1|2 opts in).

Perf at 16 threads on the 3990X, vs llama.cpp -t 16 (fdb1db877) on the same files — spreads are the placement lottery with affinity off; DAS_JOBQUE_AFFINITY=1 lands the top of the range:

model metric before after llama.cpp
Qwen3.5-0.8B Q8_0 pp512 225 756–833 520
Qwen3.5-0.8B Q8_0 tg64 40.5 53–54 41.2
Qwen3.6-35B-A3B UD-Q4_K_M pp512 65 90–97 105
Qwen3.6-35B-A3B UD-Q4_K_M tg64 12.3 14.7–16.4 12.7

The 35B prefill residual vs llama.cpp is the MoE expert GEMMs (mm_gemm 55% of the profile), not deltanet — that's kq-tier territory (#3444 follow-ups). Deferred beyond the arc: MTP self-spec decode, vision mmproj, prefix-cache state snapshots for hybrids, YaRN long-ctx.

🤖 Generated with Claude Code

Qwen 3.5/3.6 ships tokenizer.ggml.pre="qwen35": qwen2 single-digit splitting,
but letter runs are [\p{L}\p{M}]+ and the punctuation class excludes \p{M}
(llama.cpp unicode_regex_split_custom_qwen35). Adds cpt_is_mark (the 0x10
accent-mark flag was already in the RANGES transcode), threads a `marks` flag
through pretok_split's letter and punctuation rules, dispatches on pre=="qwen35",
and gates against the llama.cpp ggml-vocab-qwen35 corpus.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 15:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds support in dasLLAMA’s BPE pre-tokenizer for the Qwen 3.5/3.6 regex variant where letter runs absorb Unicode combining marks (i.e., [\p{L}\p{M}]+), matching llama.cpp’s unicode_regex_split_custom_qwen35. This extends the existing shared llama3/qwen2 pre-tokenizer logic while keeping existing pre-tokenizers byte-identical by default.

Changes:

  • Introduces cpt_is_mark (\p{M}) in dasllama_unicode.das based on the existing range-flag table.
  • Threads a marks switch through the shared pretok_split letter + punctuation rules, and dispatches it for tk.pre == "qwen35".
  • Adds a tokenizer corpus gate test for ggml-vocab-qwen35.gguf fixtures.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
tests/dasLLAMA/test_tokenizer.das Adds a new corpus gate test for the qwen35 tokenizer fixtures.
modules/dasLLAMA/dasllama/dasllama_unicode.das Adds cpt_is_mark to classify Unicode combining marks via the transcoded range flags.
modules/dasLLAMA/dasllama/dasllama_bpe.das Extends the shared pre-tokenizer split logic with a marks mode and enables it for pre == "qwen35".

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/dasLLAMA/dasllama/dasllama_unicode.das
@borisbat borisbat changed the title dasLLAMA: qwen35 pre-tokenizer (letter runs absorb combining marks) dasLLAMA: Qwen 3.5/3.6 support (qwen35/qwen35moe — Gated DeltaNet hybrid) Jul 12, 2026
@borisbat
borisbat marked this pull request as draft July 12, 2026 15:41
borisbat and others added 2 commits July 12, 2026 09:14
…0.8B

The qwen35 arch (Qwen 3.5/3.6): 3 of every 4 layers are Gated-DeltaNet
recurrent linear attention (causal conv1d k=4 + SiLU, per-v-head delta rule
on f32 128x128 state, z-gated RMSNorm out), the rest full attention with a
2x-wide [q|gate] projection (out ⊙ σ(gate) before wo) and partial NEOX rope
(64 of 256 dims; text-only M-RoPE degenerates per the qwen3vl precedent).

- Config: recr_mask/rope_dim/q_gated + ssm geometry, arch opt-ins
  hybrid_deltanet/partial_rope; layer_n_kv_heads = 0 on recurrent layers
  makes every KV prefix walk (session slabs, pool blobs, q8 validation)
  allocate zero bytes for them
- Loader: recurrent-layers mask (array or full_attention_interval),
  partial-rotary opt-in (others still refuse), ssm_* tensors, panic on MTP
  tensors; per-layer q8 repack covers the deltanet matrices and skips -1
  attention slots (both repack walks)
- Session: per-recurrent-layer conv history + S state (forward-only; dn_pos
  guards rewind, position 0 resets); prefix cache refuses hybrid models
- Kernels: softplus/l2_norm_rows (ggml-exact), partial-rope leaves
  (direct + table), dn_conv_step / dn_delta_head matching ggml's float
  accumulation order; eval_batch rides the attn_is_std=false fallback
- qwen35moe_blocks pre-wired (registration lands with the 35B stage)

Parity vs llama.cpp simple_ids on Qwen3.5-0.8B-Q8_0: 40/40 token-for-token
on the counting fixture (frozen in test_parity), the high-entropy
"Once upon a time" prompt, and the both-sides-q8_0-KV arm. Full suite
42 tests / 0 failed — existing arches undisturbed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Registers qwen35moe: the qwen35 hybrid attention + the existing routed-MoE
FFN (softmax top-8-of-256 renormalized + the qwen2moe-style sigmoid-gated
shared expert, both metadata/tensor-detected). Loader deltas the 35B file
surfaced: feed_forward_length is optional for pure-MoE arches (every FFN is
router + experts), and F32-on-disk ssm_beta/ssm_alpha stay fp32 in fblob and
matmul via mm_fblob (llama.cpp matmuls them f32; the q8 path remains for
quantized files like the 0.8B). First model with v-heads (32) != k-heads
(16), exercising the modulo GQA-repeat.

Parity vs llama.cpp simple_ids on Qwen3.6-35B-A3B-UD-Q4_K_M (Q4_K/Q5_K/Q6_K
kq tier, x64-gen grp8 repack): 40/40 token-for-token; fixture frozen in
test_parity running BOTH MoE prefill paths (grouped + reference). 0.8B
fixture stays green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread modules/dasLLAMA/dasllama/dasllama_common.das
borisbat and others added 2 commits July 12, 2026 11:16
DAS_JOBQUE_AFFINITY unset now means 0 (no placement) instead of 1
(ideal-CPU hint) — a library should not impose thread placement on host
processes by default; boxes that want the SMT-pair spread opt in with
DAS_JOBQUE_AFFINITY=1 (hint) or 2 (hard mask).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…35 perf)

The deltanet prefill gets llama.cpp's chunked form (its own prefill default,
CS=64) behind set_deltanet_prefill_mode: per chunk the in-chunk delta
interactions solve as a unit-lower triangular system (forward substitution),
outputs and the state advance become register-tiled gemm_f32 calls, and the
f32 state is touched once per chunk instead of per token. The causal conv
batches over the window (tap-major weights, float4 rows) with the persistent
history handled at both seams. Per-v-head slabs, threaded over heads.
Chunked is the runtime default (matching llama.cpp); the parity fixtures pin
recurrent (the ggml-float-order bit-exact form) and every hybrid fixture adds
an explicit chunked arm. Decode: the per-token delta rule now threads over
v-heads work-proportionally — heads own disjoint state slabs, and keeping
workers hot through the formerly-serial section speeds the surrounding
dispatches too.

16 threads on the 3990X (llama-bench -t 16 as reference):
- Qwen3.5-0.8B-Q8:      pp512 225 -> 756 tok/s (llama.cpp 520), tg64 40.5 -> 54 (41.2)
- Qwen3.6-35B-A3B-Q4KM: pp512  65 ->  97 tok/s (llama.cpp 105), tg64 12.3 -> 16.4 (12.7)

tests/dasLLAMA/test_deltanet.das: chunked==recurrent on a 150-token
multi-chunk window (argmax + 8-token greedy lockstep, proving the state
handoff into decode); logit divergence measured in-family with the accepted
flash-vs-classic attention spread. test_kv_paged stack bump: the Stage-2
Session dn_* fields tipped the eval_batch frame over 64K (pre-existing on
the branch, surfaced by the full-directory sweep).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Comment thread modules/dasLLAMA/dasllama/dasllama_common.das
Comment thread modules/dasLLAMA/dasllama/dasllama_common.das
@borisbat
borisbat marked this pull request as ready for review July 12, 2026 18:38
recurrent_layers array length now validated like feed_forward_length;
full_attention_interval must be positive (a zero from a malformed file was
a % 0 — hardware exception under JIT, not a clean panic); conv_dim must be
a multiple of 4 at load (the batched conv reads float4 rows through raw
pointers, outside das bounds checks). Plus the RANGES bit legend gains the
0x10 mark flag cpt_is_mark reads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 18:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment thread modules/dasLLAMA/dasllama/dasllama_common.das
group_count 0 in a malformed file was another % 0 in the geometry check;
state_size/group_count/time_step_rank now validate positive first, closing
the class — no unvalidated metadata feeds a modulo in the hybrid block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 19:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment thread modules/dasLLAMA/benchmarks/prefill_perf.das Outdated
Copilot AI review requested due to automatic review settings July 12, 2026 19:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

…en35

# Conflicts:
#	modules/dasLLAMA/benchmarks/prefill_perf.das
Copilot AI review requested due to automatic review settings July 12, 2026 19:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment thread modules/dasLLAMA/dasllama/dasllama_common.das
A pure-MoE file (feed_forward_length absent, hidden 0) that also omitted the
expert_feed_forward_length / expert_shared_feed_forward_length keys failed
open to zero-width experts through the hidden-derived fallbacks; both widths
now validate positive with a clear panic. 35B load smoke: n_ff_exp=512,
n_ff_shexp=512 unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 12, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@borisbat
borisbat merged commit f79afc5 into master Jul 12, 2026
38 checks passed
pull Bot pushed a commit to forksnd/daScript that referenced this pull request Jul 13, 2026
…GaijinEntertainment#3448)

Every dasLLAMA test that requires the transformer umbrella failed the full
AOT sweep with error[50101] on dasllama_arch_qwen35 symbols — the module
landed without its tests/aot/CMakeLists.txt registration (per-PR CI only
builds the tests/language subset, so the gap was invisible until the
nightly/preflight full sweep).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants