Repository navigation
qwen38: the DeltaNet layer runs on the card (Q38_DN_GPU=1) -- the qwen36 step with a sigmoid gate and a split in_proj - #1870
Merged
Conversation
Qwen3.8's DeltaNet gates its norm with sigmoid(z) where Qwen3.6 uses silu(z), and its in_proj is two matrices (qkv, z) where qwen36 fused them: coli_cuda_dn_create takes gate_sigmoid, coli_cuda_dn_step an optional projz (NULL = fused). Same five entry points, loader and fake follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e handles qwen38's trunk items are dense handles (dnqkv, dnz, dnout), not the fused dnproj tensor qwen36 uploads; this variant joins the layer to those three, all on one device, with the gate mode the engine names. The step uses the tensors recorded at init on either path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d end to end The same hand-over as qwen36's Q36_DN_GPU: for every DeltaNet layer whose dnqkv, dnz and dnout the placer put on one card, the conv ring, the recurrent state (48 x 128 x 128 per layer) and the conv/norm weights go there too; a decode token computes the two gates on the CPU and hands x to qt_dn_gpu_step. The host arrays stay canonical: a prompt, an MTP verify (snap_after takes its snapshot on the CPU path), a pin snapshot and the prompt cache pull first; a reset, a pin restore and a rejected draft's rollback invalidate the card's copy; a failing step turns the layer off and the CPU continues from what the card holds. Opt-in, beside the Vulkan chain's own hooks, which the CUDA tier keeps off. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the layer on the card documented The fixture's oracle with the whole dense trunk on the fake tier and the two DeltaNet layers stepped on the fake card (sigmoid gate, split in_proj): 8/8 tokens, cosine 0.99998; the same run on the CPU for comparison. Runs from qwen38-dn-gpu-check next to qwen38-tier-engine-check in CI. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The follow-up you asked for first in #1784 ("keep this a per-layer step and take it to qwen38"): Qwen3.8 Flash Next has the same gated-delta layer as Qwen3.6 (36 layers of 48 value heads), the CUDA trunk from #1424 already places its
dnqkv,dnzanddnout, and the CPU still ran the convolution, the recurrence and the gated norm between them -- the round trips of #1784, 36 times per token.What changes
Backend (same five entry points):
coli_cuda_dn_createtakes a gate mode -- Qwen3.8's norm multiplies bysigmoid(z)where Qwen3.6 usessilu(z)-- andcoli_cuda_dn_stepan optional second in_proj tensor: qwen38 keepsqkvandzas two matrices where qwen36 fused them. Loader and fake follow; the fake carries both gates.Tier:
qt_dn_gpu_init_densejoins the layer to three dense handles (the engine's own trunk items) on one device, instead of qwen36's fuseddnprojtensor. The step uses the tensors recorded at init on either path.Engine (
Q38_DN_GPU=1, opt-in, beside the Vulkan chain's hooks, which the CUDA tier keeps off): a decode token computes the two gates on the CPU and hands x to the step; conv ring and recurrent state (48 x 128 x 128 per layer, 108 MB) live on the card. The host arrays stay canonical: a prompt, an MTP verify (snap_aftertakes its snapshot on the CPU path, so a verify forward stays there), a--pinsnapshot and the prompt cache pull first; a reset, a pin restore and a rejected draft's rollback invalidate the card's copy; a failing step turns the layer off and the CPU continues from what the card holds.Measured (RTX 3070, FP8 checkpoint, int8 trunk in VRAM = 553 matrices, cache 224/layer, 100 tokens, two runs each)
Q38_DN_GPU=0Q38_DN_GPU=1=0(all four runs agree)The layer gains the same share as on qwen36 (−34 %, 17 ms per token), and on this box that is all it can show: Qwen3.8 is expert-bound here -- 24,576 FP8 experts, 344 resident at 17 % hit rate behind the 4 GB trunk, 350-370 ms of expert reads per 690 ms token -- the R7 finding that the trunk, not the tier, is this model's lever on 8 GB. On a card with room for the experts, or with the int4-g64 sidecar, the 17 ms would be a visible share; not measured here. Unlike qwen36 the output stays byte-identical to the CPU path over 100 greedy tokens (the int8 rows are the same on both paths and no route sat on a tie).
Verified
tests/test_qwen38_dn_gpu.c(make qwen38-dn-gpu-check, in CI next toqwen38-tier-engine-check): the tiny FP8 fixture's oracle with the whole dense trunk on the fake tier and both DeltaNet layers stepped on the fake card -- 8/8 tokens, cosine 0.99998 -- and the same run on the CPU.test_qwen38_tier_engine, every qwen36 tier test andtest_qwen36_dn_gpuunchanged and green; the Makefile VK_OBJ and loader-ABI tripwires pass (no new symbols); CPU-only and CUDA builds of both engines andcolibriclean.--pin, prompt cache and MTP drafting underQ38_DN_GPU=1(the code paths pull or invalidate before touching host arrays; the fake test covers prefill-after-decode).On the CUDA chain mirroring
vk_chain.c: noted, and I will shape its ops likevk_chain.h's (geometry from the caller, one recorder, the engine owning its state) withcoli_cuda_dn_stepas the DeltaNet op; that is the next piece after this one. And yes to running the staged device-local uploads on the 3070 with the launch VBIOS when the PR is up.Thanks to Claude Code for the help along the way.