feat(dsv4): DeepSeek V4 Flash support — CUDA/VRAM expert tiering, DSML tool use, cross-session KV persistence - #1031
feat(dsv4): DeepSeek V4 Flash support — CUDA/VRAM expert tiering, DSML tool use, cross-session KV persistence#1031rafpigna wants to merge 21 commits into
Conversation
- Port arch-agnostic DS4 CUDA kernels (backend_cuda_dsv4.cu/.h, dsv4_mhc.h, dsv4_quant.h) from ZacharyZcR/colibri; fp4 experts + fp8 dense, sm_86-capable - Makefile.deepseek-v4: CUDA=1 -> compile backend_cuda_dsv4.o w/ nvcc, link -lcudart -lcublasLt, define COLI_DSV4_CUDA; c/Makefile forwards CUDA/CUDA_ARCH to the sub-make - deepseek_v4.c: VRAM tier grafted onto the existing V4HotPolicy (pin/LRU/repin): top-M pinned experts per layer stay resident on GPU (dsv4_cuda_upload_fp4), tiered per-expert dispatch (dsv4_cuda_expert_group) with silent CPU fallback, VRAM window follows .coli_usage repin; dense/attention remain CPU in v1 - Numerics verified identical to CPU-only on RTX 3080 (sm_86): "Hello! How can" == "Hello! How can"; 8-token output coherent - gitignore backend_cuda_dsv4.o
…oli TUI & flag fixes - backend_loader_dsv4.c: MinGW loader for coli_dsv4_cuda.dll (LoadLibrary/GetProcAddress), silent CPU fallback; deepseek_v4.c untouched (CUDA_DLL=1 pattern like GLM). - backend_cuda_dsv4.h: COLI_DSV4_CUDA_DLLEXPORT on the 5 engine-facing decls. - Makefile.deepseek-v4: Windows arm links the loader, dsv4-cuda-dll target (nvcc -shared -arch=sm_86). - coli: chat_ngen caps interactive max_tokens at CTX-256 (fix 400 context_length_exceeded); --gpu/--vram/--ram unification for DS4 in env_for_engine; native cmd_chat_v4 serve-protocol TUI (clean console, tok/s-hit-RSS-elapsed metrics); v4_submit wire format fix (6 fields + trailing newline, matching openai_server) - without it the engine never responds on Windows.
…roject docs out of the repo - new docs/deepseek-v4-cuda-tiering.md: user-facing guide (scope, build for Linux and Windows, one-line chat/serve usage, not-wired-up limitations). - remove the internal project docs (dsv4-cuda-tiering.md, dsv4-cuda-tiering-windows.md) from the repo; they live in the local workdir only (.gitignore guard added).
openai_server.py: render_chat_v4 now renders the checkpoint's native DSML tool format (byte-exact port of encoding/encoding_dsv4.py TOOLS_TEMPLATE): declarations on the leading system message, assistant tool_calls history as <|DSML|>tool_calls blocks, role=tool results merged into user turns as <tool_result>; tool_choice none/auto/required/forced. parse_tool_calls dispatches ARCH==deepseek_v4 to a tolerant DSML parser (covers non-streaming, streaming and the Anthropic /v1/messages path); streaming suppresses the DSML marker with a marker-length hold-tail. Python-only, engine untouched. Verified: 25/25 unit checks + 14/14 E2E via coli serve (single/multi tool calls, multi-turn with tool results, tool_choice, no-tools regression).
Remove tool use from the 'not wired up' list (OpenAI tools now work with the native DSML format), document the scope (streaming, multi-turn tool results, tool_choice, Anthropic translation) and fix a wording slip.
deepseek_v4.c + deepseek_v4_internal.h + new kv_persist_dsv4.h: the serve session's attention state (window kv + compressed slots + recurrent compressor/indexer state) is snapshotted to <model_dir>/.coli_kv after every turn (full rewrite via temp+rename, atomic/crash-safe) and restored at serve start, so the first request skips re-prefilling the history (prefix reuse, '[KV] resumed conversation from disk: N tokens'). Serialization reuses the existing ColiV4AttentionSnapshot create/restore machinery plus four new write/read hooks in the COMPRESSOR/INDEXER_SNAPSHOT units; restore validates shapes against the live state, so corrupt/foreign files degrade to a clean start. KVSAVE=0 disables saving and resume. c/coli: kv_resume_notice accepts the new magic (header layout matches GLM's, nrec at int32 6), shown in the DS4 chat/serve paths; :reset deletes the file. Verified: 15/15 T2 checks (resume prefix_reused>0, numerics identical to full prefill, corrupt-file fallback, KVSAVE=0, tool-conversation resume).
Remove .coli_kv from the 'not wired up' list; document the snapshot/resume behavior, KVSAVE=0 and the delete-to-start-clean workflow.
…s, measured A/B results
# Conflicts: # c/coli # c/deepseek_v4.c # c/openai_server.py
|
Reproducible CUDA build portability issue on Jetson AGX Orin (aarch64, The host compiler issue is resolved by using GCC 13 explicitly with nvcc, but the CUDA backend then fails to compile because Repro command: make -f Makefile.deepseek-v4 \
deepseek-v4 \
CUDA=1 \
CUDA_ARCH=sm_87 \
NVCCFLAGS="-O3 -std=c++17 -arch=sm_87 -ccbin /home/linuxbrew/.linuxbrew/bin/g++-13" \
-j$(nproc)Looking at the source, these symbols are used by the optional So the optional TC implementation is currently a compile-time dependency even when it cannot/will not be selected at runtime. This seems inconsistent with the PR's stated arch-agnostic A minimal fix would be to compile-gate the cuBLASLt TC helper path on availability of the required API/toolkit version (and make I can test a patch on physical AGX Orin if useful. |
…ntime PATH (verified 2026-08-15)
|
This is what i have in my implementation that i'm still testing, what about those numbers, System is Ryzen 9 3900x, 32GB ram, 5080 16GB, 2 nvme sdd in model mirror mode |
From my testings, the real nob for performance is the nvme. Having two fast nvme in mirror mode makes a HUGE difference in performance, greater than having more VRAM or RAM or a faster CPU/GPU. The compute is disk-bounded. As comparison, using llama.cpp that has no tiering optimization, no hot or warm experts but only disk streaming, I have DOUBLE the performances than colibri, but no kv persistance is a real pain for a "production" usage exceot than small chats. Also the prefills took ages, because have to read and execute ALL the experts, not the pinned one like colibri, so it takes A LOT, 10x than colibri. |
|
I cannot get to reproduce your findings, other than vram filling I see no GPU compute usage and also no tok/s gains vs CPU only. I checked out your branch feat/ds4-cuda-tier and built the engine with: make -f Makefile.deepseek-v4 deepseek-v4 CUDA=1 CUDA_ARCH=nativeAnd did the comparison using these commands: # CPU-only
OMP_NUM_THREADS=8 COLI_V4_PREWARM=1 ./coli web --model ~/ssd-m2/DeepSeek-V4-Flash --gpu none --ram 82
# GPU
OMP_NUM_THREADS=8 COLI_V4_PREWARM=1 ./coli web --model ~/ssd-m2/DeepSeek-V4-Flash --gpu 0 --ram 82 --vram 6Both instances gets me 0.6tok/s This is the nvidia-smi output mid-generating with GPU enabled: My system is: The model itself is in a dedicated m.2 ssd |
|
i will post my PR soon, so if you can take a test to it and report back would be good, dual SSD is not the only performance bound gap for the 4x series and onward i have used DeepGem for other the standard CUDA one. |
Hello @RobertKoval make -f Makefile.deepseek-v4 \
deepseek-v4 \
CUDA=1 \
CUDA_ARCH=sm_87 \
NVCCFLAGS="-O3 -std=c++17 -arch=sm_87 -ccbin /home/linuxbrew/.linuxbrew/bin/g++-13 -DCOLI_DSV4_NO_TC" \
-j$(nproc)With Fix commit: 4199e1b I would very much welcome a test on your physical AGX Orin, exactly the hardware I cannot reach from here. If the build passes and the FP4 tier runs ( I also added a Jetson-specific note to the build docs, but please confirm the Thanks again for offering to test. |
@dcutugno I dint follow the DeepGem route deliberately, because you cant use with Ampere / RTX 30XX (and I have only that). My goal was to provide a cuda arch-agnostic usage. Optimizations for other archs are welcome, this is obvious, but in my understanding of the Colibri project, having an older GPU (or no GPU at all) has to not stop you from compile and use a model. But this is just my opinion :) |
|
@rafpigna that's why it will compile two dll, if no deepgem hardware found it will fallback to CUDA one :) |
Move the five per-layer dense matmuls (wq_a/wq_b/wkv/wo_a/wo_b) to the GPU with numerics identical to the CPU path. Default OFF (env COLI_DSV4_DENSE_CUDA=1 enables it); silent CPU fallback on any error. Measured on the reference hardware (RTX 3080, --ram 52 --vram 4): +18% decode (0.955 -> 1.126 tok/s), -1.6 CPU cores, GPU util 5.6% -> 10%, at the cost of ~9.6 GB VRAM and ~+10 s TTFT (H2D preload of the 43 layers at startup). 42,785 dense-GPU calls with 0 CPU fallbacks over a 200-token run. Docs: tuning table gains COLI_DSV4_DENSE_CUDA / COLI_V4_DENSE_DEBUG; new Dense-on-GPU measurements section.
|
New commit on this branch: optional dense-on-GPU tier ( Following the placement discussion, this adds an opt-in tier that moves the five per-layer dense matmuls ( Measured on the reference hardware (RTX 3080 sm_86,
|
…U-util report on Ada)
Thank you @ANBAL534 for the detailed report, a 0% GPU-util with the VRAM tier filling is really strange and Ada / native Linux is a combination I cannot test from here, so this is very valuable. Quick sanity note: on my hardware (RTX 3080, sm_86) the tier does execute and I measure I have just pushed a diagnostic commit to the branch ( Please could you:
One note: the engine's shutdown counters ( If the new log shows the fallback reason, that should pinpoint the cause directly. Thanks again for taking the time to test. |
|
On my bracnh i get: |
|
We've been building the same thing from a different angle and just opened it against
On an RTX 5080 16 GB + 2× NVMe: 3.3k-token prefill 90 s, 8.3k opencode first turn ~4 min once and then 6–9 s per session/turn, decode 1.76 tok/s at 3k context. The dense-on-GPU tier and |
Thanks @dcutugno for the detailed status and congrats on the merge, the sequencing (kernels first, then wiring) was the right call and @JustVugg summary makes that easy to see. Since you offered to help reconciling, here is where I land, based on what is now in dev after #1054, #988 and #1055: What I will drop from #1031 (now covered by the merged tree):
What I would keep (not in
Questions
I'll start the rebase as soon as the direction is clear. |
|
Heads-up, and an apology: this went #1063 landed on A rebase on current Two things worth knowing while you're in there:
Sorry for the churn. Landing the registry before your branches was the right call for the project, but it does mean the cost of it fell on the people with open work. |
|
Before you spend an evening rebasing 4,019 lines, you deserve an honest map of what Superseded — already on Still unique to you, as far as I can see: So the ask is not "rebase" — it is rescope. Two smaller PRs against current
Both would go in clean and get merged on green CI; the tiering part I would simply drop rather than have you reconcile it against an implementation that already ships. If you think your tiering does something #1054/#1055 does not — different placement policy, different fallback shape — say what, and we will compare rather than assume. And to be explicit about whose problem this is: your PR is four days old and the collision happened inside those four days. That is the cost of a fast-moving |
|
Thanks again @JustVugg for the honest map of dev — and no apology needed: a structural change landing on open PRs is the natural cost of the sequencing decision, and the registry refactor (#1063) was clearly the right call for the project. I've gone through current dev (v1.7.0, 940ea50) against the branch. Here's what I find and what I intend to do, so we're explicit before I spend the effort: Dropping from #1031 — agreed, already on dev:
Two factual notes before deciding scope (I checked the tree, not just the title):
What I propose: close #1031 and open one clean PR against current dev, scoped to cross-session KV persistence for DeepSeek V4 ( A scope question so we align on ownership with #1053: its "prefix checkpoints (memory + disk)" overlap conceptually with an attention-state snapshot. Yours is prefix-agnostic and chunked for the prefill machinery; mine is a per-conversation on-disk snapshot of the full attention state. Do you want #1053 to own that domain (then I drop I'll start the new branch as soon as the direction is clear. Thanks for taking the time to write this up. |
|
Closing as you proposed, and here are the answers you were waiting on. Sorry these took a week. Your DSML pushback was right. I checked the tree rather than the titles: Ownership question, #1053 vs What is still a genuine gap, and what I would rather have from you. V4 emits Two notes if you pick it up: The user guide: Thank you for the whole exchange on this one. You checked dev against your own branch, dropped what was superseded without being asked, pushed back where I was wrong, and asked the scope question before writing code instead of after. That is more care than most contributors spend on a PR that ends up closed, and it is exactly the reason the parts that were still real are easy to name. |



feat(dsv4): DeepSeek V4 Flash support — CUDA/VRAM expert tiering, DSML tool use, cross-session KV persistence
Motivation
Until now, DeepSeek V4 Flash on colibri has been a CPU-only citizen: every
expert streams from disk (O_DIRECT), dense/attention run on the CPU, and the
OpenAI-compatible layer has no DSML tool calling and no cross-session KV
persistence. The engine works, but it is missing the three things that make a
model actually usable day-to-day on the hardware people own:
run CUDA-capable NVIDIA GPUs (10-24 GB class). This PR adds a VRAM expert
tier so the hottest routed experts per layer stay resident on the GPU
(usage-ranked via
.coli_usage) instead of being re-read from disk — witha silent CPU fallback when CUDA is absent or disabled, so the
dependency-free default path is untouched. The honest numbers: on a
10.7 GB VRAM card the measured gain of CPU+GPU over CPU-only is ~+4-5%
decode, because the bottleneck at that VRAM size is the disk read volume,
not the matmul. The gain is small but real, it grows with the VRAM budget,
and the tier is arch-agnostic (sm_86 → sm_120) and opt-in.
|DSML|format is now wiredend-to-end (render, stream, parse, Anthropic translation). Without it the
model cannot call functions, which rules it out for agent workflows.
.coli_kvevery restartre-prefills the entire history; with it a conversation resumes from disk
in seconds (
prefix_reused>0).In short: this PR turns DeepSeek V4 Flash from a CPU-only engine into a
complete colibri model — GPU tiering when you have the VRAM, tool calling,
and conversation state that survives restarts.
Summary
Full DeepSeek V4 Flash support for colibri, in one PR:
(usage-ranked,
.coli_usage) stay resident in VRAM on top of the existingRAM hot-store; the rest streams cold from disk (O_DIRECT). Arch-agnostic
kernels (sm_86 → sm_120), CUDA DLL split on Windows (
coli_dsv4_cuda.dll,silent CPU fallback via
backend_loader_dsv4.c), direct CUDA link onLinux. Dense/attention stay on CPU/RAM. Numerics identical to the CPU path
(verified A/B).
|DSML|tool format wiredend-to-end in
openai_server.py: streaming with multi-marker suppression(
tool_calls/invoke), multi-turn tool results merged into user turns,tool_choicenone/auto/required/forced, tolerant parser for truncatedblocks, Anthropic
/v1/messagestranslation (content_blocks). Builds onthe DSML primitives vendored by feat(v4): DSML tool calling for DeepSeek V4 (#916) #948.
.coli_kv) — attention state(window + compressed + recurrent indexer) snapshotted after every turn
(atomic temp+rename,
KVSAVE=0disables) and resumed at the next start:no re-prefill of the history. Verified by
prefix_reused>0in the serveDONE frame.
docs/deepseek-v4-cuda-tiering.md) — baselinelaunch commands for CPU-only and CPU+CUDA, tuning knobs, reference
measurements.
Build
make -f Makefile.deepseek-v4 deepseek-v4 CUDA=1 CUDA_ARCH=sm_86make -f Makefile.deepseek-v4 dsv4-cuda-dll CUDA=1 CUDA_ARCH=sm_86(nvcc/MSVC DLL) +
make -f Makefile.deepseek-v4 deepseek-v4 CUDA=1 CUDA_ARCH=sm_86 LTO=0make deepseek-v4forwardsCUDA/CUDA_ARCHto the DS4 sub-makefile.Testing
ordering pitfall fixed).
[DSV4 CUDA] device 0 ... sm_86, hit_rate climbs withautopin, clean VRAM teardown; silent CPU fallback with the DLL absent.
prefix_reused>0, corrupt-file ignored,KVSAVE=0disables).decode with
--ram 52 --vram 4+COLI_V4_PREWARM=1; details in the guide.Notes / limitations
V4_MTP=0)."inverted" placement vs GLM, documented in the guide).
measured tuning levers are documented in the guide (
--ram≈ RAM − 12 GB,--vram≈ 50% VRAM,COLI_V4_PREWARM=1).Acknowledgements
The CUDA kernels (
backend_cuda_dsv4.cu/.h,dsv4_mhc.h,dsv4_quant.h) areported from ZacharyZcR's colibri fork, branch
feat/deepseek-v4-long-context(PRs #772/#773), adapted from the all-residentexpert layout to the streaming/offload tier used by this engine. Everything on
top of those kernels — the tiering integration, DSML tool use, cross-session KV
persistence, and the Windows DLL loader — is original work on this branch.
Same Apache-2.0 license as colibri.
Files
14 files, +3555/−25. New:
backend_cuda_dsv4.cu/.h,backend_loader_dsv4.c,dsv4_mhc.h,dsv4_quant.h,kv_persist_dsv4.h,docs/deepseek-v4-cuda-tiering.md. Modified:deepseek_v4.c,deepseek_v4_internal.h,openai_server.py,coli,Makefile,Makefile.deepseek-v4,.gitignore. Synced withupstream/devby merge.