Add DeepSeek V4 Flash CPU inference with NVMe expert streaming - #165
Add DeepSeek V4 Flash CPU inference with NVMe expert streaming#165DrewZt wants to merge 13 commits into
Conversation
rajpratham1
left a comment
There was a problem hiding this comment.
This is a very impressive contribution and clearly represents a significant amount of engineering work. The implementation covers a complete DeepSeek V4 CPU inference pipeline including runtime, expert streaming, quantization, safetensors loading, CLI tooling, documentation, and an extensive unit test suite.
Because this PR introduces an entirely new inference stack across many core components, I'd prefer additional review before approval.
Some areas that would benefit from closer review include:
- Long-term API stability for the new DeepSeek V4 interfaces.
- Memory ownership and lifetime throughout the expert streaming/runtime pipeline.
- Performance characteristics of the NVMe streaming implementation under sustained inference.
- Cross-platform compatibility (Windows/Linux/macOS) for filesystem and I/O paths.
- Validation against larger real-world models beyond the included unit tests.
Overall the direction looks very promising, but given the size and architectural impact of this change, I think it should receive another maintainer review before merging.
|
Thanks for the thoughtful review. I agree that another maintainer review is appropriate given the size of the change. A few clarifications on the areas you mentioned: API stability: the new interfaces are currently scoped to the DeepSeek V4 engine and should be considered experimental. They are not intended to establish a stable generic model API at this stage. I’m happy to address targeted follow-up findings, add more validation, or split parts of the implementation into staged PRs if the maintainers feel that would make review and long-term maintenance easier. |
|
I pushed a follow-up series through The main changes are:
The latest changes pass: The remaining validation work is focused on sustained NVMe behavior and broader full-model comparison against the official Transformers implementation. Those limitations remain documented in the PR and do not represent unresolved API or resource-lifetime issues. I’m marking the PR ready for review and would appreciate another maintainer look, particularly at the revised API boundary and ownership model. |
|
First full-model validation on Linux/x86-64 — plus a build fix and an AVX2 kernel series, branch ready to pull: steve-m/colibri@v4-avx2-kernels (5 commits on top of this PR's Hardware: Ryzen 9 3900X (Zen 2, 12C/24T, AVX2 no AVX-512), 62 GiB RAM, NVMe ~6 GB/s, Manjaro, gcc 15. Model: Build fix you'll want regardless: two amalgam units ( Kernel series (all behind a
Measured, 48-token free-form decode, OMP_NUM_THREADS=12: 0.53 tok/s (PR defaults) → 0.62 (threads = physical cores; SMT only adds barrier traffic) → 0.78 (FP4 int8) → 0.99 (head) → 1.12 tok/s (FP8). Verify phase −27%, TTFT 20 → 16.7 s. Validation at every step: your oracle tool's Also on the branch, off by default: a dual-SSD mirror ( Happy to split any of this into separate PRs against your |
This is extremely helpful — thank you for doing the first independent full-model Linux/x86-64 validation and for documenting the performance progression in such detail. The Ryzen 3900X result directly addresses one of the main remaining validation gaps for this PR, and the 0.53 → 1.12 tok/s breakdown makes it much easier to see where the current bottlenecks are. I checked the branch history and it looks like Those later commits include the revised public/internal API separation, engine/session lifetime accounting, failure-path cleanup, isolated ownership-test objects, and V4 session tokenizer cleanup. The optimization work is still very valuable, but it should be rebased onto One clarification regarding the pthread build issue: I had already addressed the missing declaration problem in Your source-level includes may still be a cleaner and more localized solution, but the issue itself no longer needs a separate build-fix PR. When rebasing, please either drop the overlapping build-fix commit or call out why replacing the current compiler-level include with explicit includes in the two amalgam units would be preferable. For the remaining work, I suggest splitting it into two focused follow-ups:
I also noticed that the branch diff appears to include generated test binaries such as: Please drop those artifacts when preparing the follow-up PRs. After rebasing, please rerun the full-model correctness and performance validation because the runtime and ownership code has changed since The current benchmark result is already valuable as independent validation of the earlier implementation. Once the rebased kernel series is reviewed, I’d be happy to add the reproducible Linux/x86-64 measurements to the documentation with credit to you and the exact hardware and commands. Thanks again — this is a substantial and very useful contribution. Rebasing and splitting it should let us preserve the recent API and ownership work while giving the kernels and storage experiment the focused review they deserve. |
|
Follow-up for @JustVugg: head af86de1 closes the remaining validation findings. The safetensors index now requires payload bytes to equal dtype width times shape numel; V4 config integers, floats, and compress ratios now have finite/integer/range checks. I also removed the dense-cache borrowed config pointer in favor of the engine-owned canonical config and made the DSpark oracle require exact output lengths on both paths. Fresh validation passed make check (all C tests plus 71 Python tests), x86-64-v3/native builds, ASan+UBSan+LSan, and the 48-shard MEMORY_GB=32 oracle (19/19 teacher forcing, 8/8 greedy, 8/8 continuation self-check, exact DSpark on/off identity). This supersedes my earlier blocker summary; AVX2 and dual-SSD work remain out of scope. Could you please review when convenient? |
|
Pushed the rebased AVX2 kernel series to Two changes from the old
The three commits, all behind the
Validation on the rebased branch — Ryzen 9 3900X (Zen 2, AVX2 no AVX-512), 62 GiB, gcc 16.1.1,
Perf — AVX2 on vs the Kernel-only isolation, DSpark disabled (
For reference, DSpark on (same prompt): decode 0.62 → 0.85 tok/s (+36%), TTFT 43.6 → 30.3 s (−30%) — but that pass had asymmetric acceptance (on 3/10 vs off 1/10 speculative tokens), so the isolated The float-path baseline matches the known physical-cores number, so the kill-switch cleanly isolates the kernel gain. TTFT is stable across the DSpark condition (~31 s on / ~48 s off), as expected — the first token is prefill + first decode, before any speculation. (Absolute tok/s is workload-dependent — this was a heavy ~80 GB-streaming pass; a lighter/warmer pass on this box peaks around 1.12 tok/s. The on/off ratio is the stable claim.) |
This looks excellent — thank you for rebasing the series carefully and for preserving the API and ownership work underneath it. The updated scope is exactly what I was hoping for:
I also appreciate the distinction between the DSpark-enabled result and the The zero-copy resident-head path being exercised by the full-model oracle is also useful confirmation that the new path is covered rather than only compiled. Since the kernel branch is stacked on top of #165, I think the cleanest next step is to keep the branch as-is for now and open a dedicated follow-up PR after #165 is merged. At that point it can be rebased onto the resulting upstream Please preserve the current commit separation and validation details in that PR. In particular, the Thanks again — this is a strong follow-up series, and the careful validation and honest performance attribution make it much easier to review. |
|
Pushed follow-up stability fix
Validation:
|
|
I'm interested in this — DeepSeek V4 Flash on CPU with NVMe expert streaming is squarely what colibrì is for, and I'd like it in. The one condition is that I need to run it on my own machine first. Not as a gate to be difficult: it's the rule I've had to learn the hard way this week. So: as soon as I can get a checkpoint on this box, I'll test it and we'll work on it together. That's not a "no" parked forever — it's the next thing I want to do on this front. Two things that would make it land sooner, and I'd rather ask than have you guess:
I saw the stability fix you pushed ( Keeping this open. Let's keep going. |
Thanks — this gives me a clear integration path. I’ll make the tiny DeepSeek V4 fixture the immediate priority. The goal will be a deterministic, independently generated checkpoint and reference that The initial test contract will cover:
The generator will remain available so the fixture is reproducible rather than an opaque committed artifact, while CI itself will use the checked-in tiny checkpoint and reference. I’ll also continue removing local duplication where that does not change runtime or kernel boundaries. For the deeper shared-I/O work—particularly consolidating the streaming read path with the existing DIRECT/URING infrastructure—I would prefer to do that as a focused follow-up after this base engine and the already prepared AVX2 series land. That keeps the current correctness and performance baselines stable, avoids repeatedly invalidating the AVX2 branch, and lets the tiny token-exact oracle protect the later refactor across both scalar and optimized paths. I’ll keep AVX2 and the dual-SSD experiment out of this PR, and I’ll document the shortest full-checkpoint smoke-test path for your machine alongside the tiny fixture. |
|
Implemented the requested deterministic tiny DeepSeek V4 + DSpark oracle at head
Manual local validation (from the repository root): # Dedicated tiny target + DSpark token-exact oracle
make -C c deepseek-v4-tiny-check ARCH=x86-64-v3
# Or run the complete dependency-free check suite
make -C c checkTo exercise the normal runtime explicitly with drafting disabled: cd c
make deepseek-v4 ARCH=x86-64-v3
./deepseek_v4 deepseek_v4_tiny '<t005><t007><t009>' \
--raw-prompt --draft-model deepseek_v4_tiny/dspark --no-dsparkThe generator and regeneration package versions are documented in |
sorry what?! That's impressive for NVMe. |
The prompt 'What is the capital of France' have some uniqueness, the answer token got 100% dspark acceptance rate, that is the fastest speed boost. |
|
On your own Pc, Vincent, how does it compare to GLM in speed if you don't mind me asking (And what are the specs of yours , and what OS) 🤔From: DrewZt ***@***.***>Sent: Saturday, July 18, 2026 12:07:24 pmTo: JustVugg/colibri ***@***.***>Cc: Maikel Frias Mosquea ***@***.***>; Comment ***@***.***>Subject: Re: [JustVugg/colibri] Add DeepSeek V4 Flash CPU inference with NVMe expert streaming (PR #165)DrewZt left a comment (JustVugg/colibri#165)1.12 tok/s (FP8).sorry what?! That's impressive for NVMe.The prompt 'What is the capital of France' have some uniqueness, the answer token got 100% dspark acceptance rate, that is the fastest speed boost.
For another 0% dspark acceptance rate special case 'hello', decode speed will drop to 0.59tok/s, which is slower than no-dspark situation—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.
|
My pc is ai max 395+128gb ram+6gb/s ssd, tested glm with config think=0 and mtp=1, got around 0.7 tok/s |
|
Status check: |
Yes, I’m still actively working on this. Please keep the PR open. I reviewed the impact of the current I’m going to treat this as a minimal forward port onto current Work I will complete before merging #165
I had already done additional local work around redundant expert reads and the streamed I/O path, but I intentionally did not push it onto #165. At that point the branch had a stable correctness baseline and Steve’s AVX2 series was stacked on top of it; changing the I/O and cache boundaries again would have invalidated both his branch and the existing measurements. Work planned after #165 merges
So the immediate objective is to restore #165 on current |
|
The forward port is now pushed. PR #165 now points to The main Local The new PR workflows are currently waiting for maintainer approval. Could you approve them so the checks can run? |
|
approved! |
|
CI is green — both workflows, all jobs. Sorry that took a day: GitHub holds workflow runs from contributors whose first PR here hasn't merged yet, and I hadn't spotted how many were queued behind that setting. Nothing to do with your code. So the state now: 20,780 lines, forward-ported onto current dev, and our own gates pass on it for the first time. That plus the fact that it touches neither I owe you a real read of the engine before merging, which is the part I can't rush. Two things that would help while I do that:
Thanks for staying with this through a refactor that would have killed most PRs. |
Thanks — and yes, the target engine is intended to be config-driven rather than tied to the Flash dimensions. Layer count, hidden size, attention ranks, expert count, MoE width, compression schedule, and tensor shapes are all derived from One important current limitation: please use the DeepSeek-V4-Flash-DSpark checkpoint for testing, not the plain Flash checkpoint. I found a checkpoint read issue yesterday, and the current branch only loads the DSpark-packaged layout correctly. Target-only execution can still be tested with --no-dspark; the limitation is the checkpoint package being loaded. I have not fixed the plain-checkpoint path yet. I have not tested a Pro checkpoint yet, so I would treat that as expected compatibility rather than confirmed support. The main things to verify are tensor names, compression ratios, tokenizer/prompt format, memory planning, and the Pro DSpark stage layout if a draft checkpoint is available. The most useful places to review first are:
One additional note: the implementation still contains a non-trivial number of reference, fallback, and experimental paths that emerged during development. Some are useful correctness baselines or low-memory fallbacks; others may now duplicate the preferred path. I avoided broad pruning during the forward port to keep the validated behavior stable. After Flash and Pro validation, I’d like to classify them explicitly: retain tested fallbacks, isolate research-only variants, and remove purely historical duplication. |
|
Pushed two follow-up commits, now at b09ab5: --no-dspark is now a true target-only mode and no longer requires or initializes a DSpark checkpoint. Initial V4-Pro target-only performance under the current test configuration: 16 GiB memory limit: 0.087 tok/s V4-Pro DSpark support has not been implemented; Pro currently requires --no-dspark. |
|
Tested this PR on aarch64 — first datapoint outside x86-64, I believe: NVIDIA DGX Spark GB10 (Grace, 10× Cortex-X925 + 10× Cortex-A725, 121 GB unified LPDDR5x), Ubuntu 24.04, gcc 13.3.0. The engine core is genuinely portable: with the platform gates bypassed, 41 of 43 amalgam TUs compile clean on aarch64 with zero warnings. The only x86 dependencies were the two unconditional I put up a small branch on top of this PR's current head (2 commits, 6 files, +197/−15): whale-agent-lab#1. It:
Validation on the GB10, on top of b09ab5d:
Kernel bench at the real V4-Flash expert shapes (hidden 4096 × moe_inter 2048, FP4), flat OMP scalar (
Pack cost is ~2.9 ms per 4 MiB matrix, once per pinned expert. These are kernel-level numbers only — no full-model tokens/s yet (checkpoint download pending on this box). Happy to split the build enablement from the NEON kernels if you'd rather keep this PR x86-only — whichever is easier. |
Summary
This PR adds a separate, model-specific DeepSeek V4 Flash + DSpark CPU engine for x86-64 Linux and Windows/MSYS2. It streams routed FP4 experts directly from the original safetensors checkpoint on NVMe and allocates available memory between resident target tensors, DSpark stages, the output head, and per-layer expert caches.
The implementation includes:
make deepseek-v4target and standard-library-onlyc/v4launcher;The DeepSeek implementation remains a separate model-specific engine and does not modify the main
c/colibri.cinference or storage paths.; the default GLM build and unsupported-platform test path remain intact.Merge hardening
This branch was reconstructed as a fresh forward port onto current upstream
dev, rather than replaying the obsolete pre-#391 commit history. and integrates V4 targets with the upstream target-triplet detection,tools/run_tests.py, andtools/clean.pyflow.The safetensors index now:
dtype width ? shape numel, preventing undersized reads and oversized writes.Malformed fixtures cover bad header lengths, wrong JSON types, invalid offsets, invalid dimensions/rank, arithmetic overflow, dtype/shape/payload-size mismatches, and repeated open/close under LSan. The same JSON-tree ownership fix was applied to V4 config parsing after sanitizer validation exposed it.
V4 config integer fields and
compress_ratiosnow require finite, integral values in the Cintrange. Floating-point fields require finite values representable asfloat.The full-model oracle launcher resolves its local binary path correctly and requires exact output length and token identity for both DSpark-on and DSpark-off runs. The resident dense cache always uses the engine-owned canonical config and no longer retains a borrowed config pointer.
Validation
make -C c check- all C tests and 71 Python tests passmake -C c deepseek-v4 ARCH=x86-64-v3make -C c deepseek-v4 ARCH=nativetest_safetensors_index,test_deepseek_v4,test_v4_ownershipMEMORY_GB=32DeepseekV4ForCausalLMmake checkpassed; portable V4 infrastructure tests ran, whilethe x86-64-only V4 engine and tiny runtime oracle were explicitly gated off
The full-model fixture uses
source=coli-self: it validates deterministic target-token reproduction and DSpark losslessness, not independent Hugging Face parity.CUDA validation is not applicable because this PR does not add or modify a CUDA backend.
Scope
This PR intentionally does not include the proposed AVX2 kernel or dual-SSD mirror work; those should be reviewed separately.
Compatibility