Repository navigation
ricursive: Ripple-65B-Preview on native Metal (NVFP4 and bf16 releases) - #2231
BobClawblaw wants to merge 6 commits into
Conversation
|
Thanks @BobClawblaw. This is a thorough first PR for a new family: bit-identical chunks and windows, 15 planted controls all red, and the NVFP4 cost measured against both float64 passes, which shows it's the publisher's quantization rather than ours. The family itself still needs a yes on #2171, so this is a review of the PR against its plan, not an acceptance. Three things:
One question as well: |
1f52099 to
3a5954f
Compare
|
Thanks, Ash. All three are done, and the question is answered below. The branch is rebased on main 1. Context capped. That is 2. The
The engine is as close to the release's own bf16 forward as the float64 pass is: what remains is bf16 rounding order 3. bf16 through the harness (the same build;
Cold prompts on a fresh server: 2,206 tokens 519 tok/s (4.3 s), 8,830 596 (14.8 s), 34,931 586 (59.6 s), 139,870 The question. Yes. The family was written from the config and weights, but it follows Understood on #2171: this waits for your yes on the family and on adding the NVFP4 release. Checks, each exit 0 (the full set on the first two commits, |
|
Thanks @BobClawblaw. The context cap refuses by name, the engine is as close to the release's own bf16 forward as the float64 pass is, and the bf16 speed row is in, so all three gaps are closed. Thanks also for the notices entry. The family itself, and adding the NVFP4 release, still need a decision on #2171, and we'll answer there. |
3a5954f to
09dd4a4
Compare
|
Rebased onto main |
|
Thanks @BobClawblaw for the rebase and for moving H3 into its own |
09dd4a4 to
70c1867
Compare
|
Thanks @ashhart. Rebased on today's main (
CI steps exit 0 on this head: fmt, lean (0 new), Since #2313 changed how tool calls before the think close are returned, the recipe harness's structured plan ran on the NVFP4 release served from this Ripple code: structured 18/18, drafted == plain 12/12, tools 5/5. Still waiting on #2171. #2260 is restacked on this head ( |
|
Thanks @BobClawblaw. The rebase keeps main's |
…ig stays at 600 lines or fewer
ricursiveAI's Ripple-65B-Preview (model_type ricursive) served from the publisher's own releases as published, read in place from their shards: the NVFP4 release (ModelOpt NVFP4 MLPs, bf16 attention, 53 GiB) and the bf16 release (121 GiB). - Family in zig/src/families/ricursive and kernels in zig/kernels/metal/ricursive: PeriNorm, q/k norms, RoPE on sliding layers (1,024-key window, 3,072-slot ring), NoPE global layers every fifth, fp32 sigmoid gate, value residual, clamped SwiGLU. - NVFP4 MLPs: E2M1 nibbles, E4M3 block scales and the fp32 global, applied exactly; activations stay bf16 (the publisher's SGLang serving is W4A4; disclosed in the doc). - Exact bf16 caches; prompt chunks planned on one 2,048-row grid, so resumed == fresh. - Every kernel registered with the kernel contract: 36 pass gates 1-4, 15 controls red. - Server: replies are always read for a think block when the model decides itself whether to think (Info.reasoning_optional); a thinking budget and logprobs are refused, since Ripple's think markers are spelled from several tokens. - tools/zig/ricursive_reference.py: the float64 / bf16-point CPU reference. - docs/recipes/ripple-65b-metal.md: correctness (KL), harness speed and serving checks.
…release code Longer contexts are refused by name until a run at that length qualifies them. THIRD_PARTY_NOTICES names modeling_ricursive.py and the release's SGLang model, which the family follows for its layer order and rounding points.
…ase through the harness
70c1867 to
c244847
Compare
|
Rebased onto main |
What this changes
Adds the
ricursivefamily on the native Metal engine: ricursiveAI's Ripple-65B-Preview served from the publisher's ownreleases as published, read in place from their shards, nothing converted. Before,
ricursivecheckpoints wererefused as having no backend.
ricursiveAI/Ripple-65B-Preview-NVFP4at99eea4477a001a41b86914e41feb4b2ed86105e5(53 GiB): ModelOpt NVFP4 MLPs; attention, embeddings and head bf16.ricursiveAI/Ripple-65B-Previewat240d5966cbe00f0627c699e59ef58560b60303cf(121 GiB): the bf16 release.The full account is
docs/recipes/ripple-65b-metal.md.for caches on one Mac).
c70d67bb2), six commits: H3's contract registration moved into its own Suite (sotests/contract/metal_main.zigstays at 600 lines or fewer, now 597 beside main'smasked_valuessuite), the family,the context cap and its notice, the doc rows from review, the contract at o_proj's reduction, and the CHANGELOG line.
atc overlap --json: no conflict with main. Shared hub files overlap with other open PRs (contract registry,native/metal.zig,tests/contract/metal_main.zig); Implement GLP control vectors with a fused Metal kernel for Qwen3.8-27B #1835, kimi: K3 and K3.1 through the native server on Metal #2221 and kimi: experimental K3.1 index operators on Metal, native serving stays capped #2228 would conflict there, whichever landssecond rebases. No conflict resolved in this branch.
Things to say up front
flashinfer_cutlass, which alsoquantizes activations to fp4 (W4A4). This engine runs the release's NVFP4 weights exactly (E2M1 × unsigned E4M3 per
16 × fp32 global, the global applied to the fp32 sum before the one bf16 rounding) with bf16 activations and fp32
sums, so the numbers here are that model, not the publisher's W4A4 kernels.
mean KL 0.0060, top-1 96.1%; the NVFP4 checkpoint's own float64 pass against the same, 0.0059 and 95.8%. The cost is
the publisher's quantization; the engine's own rounding is 0.0007 (prompt) / 0.0011 (decode) against the NVFP4
float64 pass, and 0.00086 / 0.00073 for bf16. Against the release's own
modeling_ricursive.pyin bf16 (thereference's
--releasemode), the bf16 engine's mean KL is 0.00073 (prompt, top-1 98.7%) / 0.00069 (decode,98.8%), against 0.00076 for the float64 pass.
float64 (float64
000at 0.645, decode000at 0.621, the prompt path096at 0.855). It traces to the shared bf16tensor-unit GEMM on the attention projections, which matches MLX bit for bit and passes the contract at these shapes;
bf16 does not flip there. Details in the doc.
every fifth layer is global (NoPE). 16.75 GiB a stream at 262,144 tokens.
--contextdefaults to and stops at 262,144, the longest checked (needles to 258,039 tokens); longervalues, the card's 1M among them, are refused by name until a run at that length qualifies them.
<think>,</think>and<tool_call>are spelledfrom several BPE tokens, not single tokens. So a
thinking_budgetandlogprobsare refused by name for this family,and
reasoning_tokensreads 0.Shared code
All outside the family folders, each inert unless the model is
ricursive:engine_api.Info.reasoning_optional(default false; only Ripple sets it) →reply_text.Markers.optional: a replythat does not open a think block is all answer.
server/chat.zigreads replies for a think block whenever that flagis set, whatever
enable_thinkingrenders (the template has no switch). With the flag false, both expressions reduceto the previous ones;
test-goldenis unchanged (322/335 equal, 0 unexpected).native/metal.zig: the family entry, the open dispatch and the model name in two refusal strings.tests/contract/metal_llama*.zig,metal_limits.zig,registry.zig: llama's row projections, merge, argmax andGEMM retargeted at Ripple's shapes through new optional fields; llama's own cases keep their defaults.
sources.zig,metal_targets.zig,cli/hub.zig,tensorfold.zig,server/server.zig: registration lines.THIRD_PARTY_NOTICES.md: the family followsmodeling_ricursive.pyand the release's SGLang model (Apache-2.0).Checks on this head
c244847b6(on mainc70d67bb2;70c1867b5rebased, withCHANGELOG.mdthe only conflict and the other five commits' patches unchanged bygit range-diff). ricursive: the publisher's DFlash2 drafter for Ripple-65B (stacked on #2231) #2260's head8843987e8sits on this one.zig fmt --check build.zig zig,zig build test --test-timeout 10m,test-kernel-contract,test-golden(322/335 and 55/55 equal to server goldens, 0 unexpected differences),test-server-security test-pull-security(24 passed, 0 failed, 0 skipped),check-release-paths,fuzz-cortheonand
dev-tools.tf-kernel-contract --only ricursiveon ricursive: the publisher's DFlash2 drafter for Ripple-65B (stacked on #2231) #2260's head: 75 kernels pass gates 1-4, 25 controls red as planted, 0 limit problems.on the NVFP4 release, served from
630f1fc4f(this head's Ripple code, before main's last 34 commits, which touchneither the server nor Metal): structured 18/18 obey, drafted == plain 12/12, a bad regex 400; tools 5/5.
untested.
Receipt
above.
CUDA, HIP and pre-M5 Macs are not reached.
one-row steps bit for bit (both releases). Serving, through the recipe harness's quick plan on
e2ca8c387: seededsampling 9/9 equal on repeat and undrafted; drafted == plain 12/12; 12 concurrent replies and a 60-turn soak each equal
to the request alone; a resumed turn equal to the cold one after a restart. Structured 18/18 and tools 5/5 rerun on
68e1993d9.--context 262145is refused by name.--context 262144 --parallel 2, greedy 256-token replies, recipe harnessrather than
bench_openai.py): 1 stream 10.1-10.2 tok/s, 99 ms a round, TTFT 0.61-0.74 s; 2 streams 18.6-19.1 tok/stotal, 107 ms a round.
35,015 587 (59.6 s), 139,723 434 (322 s). A resumed third turn (4,513 of 4,597 cached) starts in 0.67 s against 8.2 s
cold. A passphrase a third of the way into 120,041- and 258,039-token prompts comes back exactly (273 s and 790 s).
a round. Cold prompts with thinking requested: 2,206 tokens 519 tok/s (4.3 s), 8,830 596 (14.8 s), 34,931 586
(59.6 s), 139,870 459 (305 s); without thinking requested Ripple opened a think block itself on all four, so the
plan's 8-token replies had no answer token to time. A resumed third turn starts in 0.59 s against 7.5 s cold.
Kernel contract
attention for sliding and global layers, the NVFP4 row kernels (1-32 rows), dequantization and GEMM, plus llama's row
projections, merge, argmax and GEMM at Ripple's shapes, every reduction it runs (k 5,120, 10,240 for the attention
output, and 40,960) (
zig/tests/contract/metal_ricursive*.zig). None replaces an existing kernel.tf-kernel-contract --only ricursive, M5 Ultra, exit 0, with the k 10,240 cases (the run quoted in the doc):