Instructions to use LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E
- SGLang
How to use LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E with Docker Model Runner:
docker model run hf.co/LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E
DeepSeek-V4.1-Flash-REAP-256E
deepseek-ai/DeepSeek-V4.1-Flash with its routed-expert pool pruned 384 β 256 per
layer (β33.3%) by REAP β router-weighted expert activation pruning β using a
modality-balanced ranking calibrated on text and images.
475.2 GiB β 385.5 GiB. Nothing is re-quantized: experts stay MXFP4 (E2M1 + E8M0,
block 32), dense layers stay FP8 block 32Γ32, the Engram tables are untouched. 128 of
384 experts per layer are gone, along with their rows of gate.weight, gate.bias and
gate.bias_vl.
This is the checkpoint to use under vLLM. Its sibling
-REAP-272E scores
better but does not load β see below.
Recipe, calibration scripts and every measurement behind this card: github.com/Libertai/deepseek-v41-flash-reap
Why 256 and not 272
vLLM's fused MoE router kernel dispatches on a fixed table of expert counts β
{1, 2, 4, 8, 16, 32, 64, 128, 192, 256, 320, 384, 448, 512, 576}. Anything else fails
at startup with Unsupported expert number: 272. 256 is the largest legal value below
384, so it is the only prune ratio in this range that an engine will actually run.
That constraint has a cost, and it is not the one text perplexity shows.
Why the ranking is different from 272E β and what it costs
The default REAP score is the mean router-weighted activation norm over the calibration set. Our corpus is 64.4M text tokens against 13.0M image tokens, so the mean inherits that 5:1 ratio and the ranking is quietly text-heavy. At 272 kept it survives anyway. Below 272 the vision path falls off a cliff that text perplexity gives no warning of:
| experts kept, mean-saliency ranking | text ppl | caption ppl |
|---|---|---|
| 384 (unpruned) | 3.6552 | 24.307 |
| 272 | 3.8060 | 24.769 |
| 264 | β | 30.070 |
| 256 | 3.8557 | 30.959 |
Text walks smoothly from +4.1% to +5.5% across that range. Captions jump +27%.
The fix is to normalise the text and image saliency vectors to equal mean per layer before averaging them, so the ranking does not depend on how many of each kind of token you happened to calibrate on:
st = sal_text.double() / cnt_text.double().clamp(min=1)
si = sal_image.double() / cnt_image.double().clamp(min=1)
st = st / st.mean(dim=1, keepdim=True).clamp(min=1e-30)
si = si / si.mean(dim=1, keepdim=True).clamp(min=1e-30)
score = 0.5 * st + 0.5 * si
This is a trade, not a free repair. Both rankings were measured on both modalities at 256 kept:
| 256 kept, ranked by | text ppl | vs unpruned | caption ppl | vs unpruned |
|---|---|---|---|---|
| mean saliency | 3.8557 | +5.5% | 30.959 | +27.4% |
| balanced (this repo) | 4.1723 | +14.1% | 26.479 | +8.9% |
Balanced ranking buys back 14.5% of caption perplexity by giving up 8.2% of text perplexity β it keeps experts that earn their place on images and little else. Neither column dominates, so pick by workload:
- Multimodal, or vision matters at all β this repo. A +27% caption regression is not something you want shipped silently.
- Text-only at 256 experts β prune with
--mode meaninstead (the recipe repo does this in one flag); you will get 3.8557 and a vision path you should not use. - Anything that can load 272 experts β use 272E, which needs no such choice: +4.1% text and no measurable caption regression. It is strictly the better checkpoint, and vLLM simply will not load it.
21.4% of total saliency mass is dropped by this keep-set.
The underlying reason: this model routes vision separately
The model carries two router biases β gate.bias and gate.bias_vl β and their
correlation is β0.05 (min β0.45 across layers). Expert specialisation here is
modality-dependent.
Rank by text saliency alone and you discard 267 experts that a combined ranking keeps, including layer 0 expert 235: 376th of 384 on text, 21st on images. At 272 kept, the resulting checkpoint is worse than randomly pruning the same number of experts on vision:
| 272 kept, ranked by | caption ppl | vs unpruned |
|---|---|---|
| text + image saliency | 24.769 | +1.9% |
| random | 26.066 | +7.2% |
| text-only saliency | 28.173 | +15.9% |
β¦and its text perplexity looks fine β marginally better than the combined ranking (3.7300 vs 3.7359 at 304 kept). Only an image-conditioned evaluation catches it.
If you prune this model yourself, calibrate on both modalities, and normalise between them.
Measurements
Held-out text perplexity, 65,504 tokens, verified zero overlap with the calibration corpus:
| experts kept | perplexity | vs unpruned |
|---|---|---|
| 384 (unpruned) | 3.6552 | β |
| 272 | 3.8060 | +4.13% |
| 256, mean-saliency ranking | 3.8557 | +5.49% |
| 256, balanced ranking (this repo) | 4.1723 | +14.14% |
| 240 | 3.9156 | +7.12% |
| 192 | 4.1910 | +14.66% |
Backbone parameters fall from ~552B to ~371B. Active parameters are unchanged (6 routed + 1 shared per token) β pruning buys memory, not decode speed.
No downstream task benchmarks were run. Perplexity is not a benchmark.
Serving
Verified on 2Γ GB10 (sm_121, 120 GB unified each) under vLLM TP=2 over RoCE, with the Engram tables read from NVMe rather than resident.
π Full recipe, launcher and troubleshooting: github.com/Libertai/dsv41-flash-vllm-2x-spark
Throughput is workload-dependent, by a factor of three
Single stream, 600 tokens per case, DSpark k=5, greedy drafting, eager, 32K context:
| workload | decode c=1 | mean acceptance length (max 6) |
|---|---|---|
| counting ("1 to 220") | 49.4 tok/s | 5.90β6.00 |
| code generation | 30.4 tok/s | 3.26β4.51 |
| reasoning | 28.3 tok/s | 3.13β3.81 |
| chat / explanation | 27.0 tok/s | 3.23β3.59 |
| prose (essay) | 19.2 tok/s | 2.24β2.49 |
β οΈ Do not quote a single number for this model, and never benchmark it on counting prompts β a degenerate sequence lets the drafter accept every token and reads ~2.6Γ the honest rate. An earlier version of this card listed 13.7 tok/s; that figure was measured without speculative decoding on a prose-like prompt, i.e. close to the worst case.
| KV cache | 423,479 tokens @ 32K ctx β 12.9Γ concurrency |
| prefill | 700β2,200 tok/s depending on length |
| weights | ~94 GiB/rank; Engram 47.2 GiB/rank left on disk |
--gpu-memory-utilization |
0.90 (0.86 leaves no room for KV; above ~0.91 the free-memory check trips) |
Context: the checkpoint says 1M, two GB10s serve 32K
vLLM will start at --max-model-len 204800 and report a 1.27M-token KV pool. It cannot
serve it. Weights are 77% of the unified pool, so long-prefill working memory has nowhere
to go: a ~62K prompt at 64K ctx drops the host to 68 MB free and the engine is killed; a
~150K prompt made both boxes unreachable. Smaller prefill chunks do not help β the growth is
in the sparse-MLA indexer structures, not the chunk activations. 32K leaves a comfortable
~913 MB floor under load. Four GPUs, or a smaller footprint, are what buy more.
Five things this needs that are not obvious
--enforce-eageris mandatory. CUDA graphs fail here in bothPIECEWISEandFULL_AND_PIECEWISEmodes withCUDA error: an illegal memory access was encountered, consistent with the sm_120 sparse-MLA kernel receiving an uninstantiated batch shape. Reducing the capture set does not help. (A NaN-output failure mode was also seen on an earlier build β probe a new lane withlogprobsbefore trusting its throughput.) Consequentlyenable_adaptive_verificationis unavailable: it requires full graphs.num_speculative_tokensmust be a MULTIPLE ofdspark_block_size(5) β k=7 is rejected at startup. And k=5 is the fastest: k=10 is 24β38% slower on every workload, because verifying k+1 tokens scales expert-weight traffic on a sparse MoE while per-draft acceptance falls.- Turn on BOTH JIT warmups (
enable_jit_warmupandenable_cutedsl_warmup) and setVLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=1800. Otherwise Triton and CuTeDSL kernels compile during inference and the engine dies mid-workload withTimeoutError: RPC call to sample_tokens timed out. Some CuTeDSL kernels are reached only on the long-prefill path, so short smoke tests will not expose this. - FlashInfer has no sparse-MLA kernel for this model's index widths. DSV4.1 mixes
compress ratios, giving topk 1152 and 640, and the instantiation list is keyed
on
(num_heads, topk)β so the entries you need depend on your TP degree (TP=2 β 32 heads, TP=4 β 16). Without them the engine dies at profiling with "SM120 sparse-MLA has no decode kernel for this shape". Patching the.cualone does nothing β the wheel ships a prebuilt AOTsparse_mla_sm120.soandis_aotshort-circuits the JIT path. Mask the AOT directory, prebuild into a persistent cache, and mount that cache at serve time. - Wire the reasoning parser, or the chain-of-thought lands in
content. Thinking is on by default and the chat template supplies the opening<think>, so with no parser you get raw reasoning followed by a bare</think>insidecontent, and areasoningfield sittingnull. The parser ships and is registered asdeepseek_v41β the same name serves both kinds:--reasoning-parser deepseek_v41 --enable-auto-tool-choice --tool-call-parser deepseek_v41. The field isreasoning, notreasoning_content. β οΈ With thinking on, budgetmax_tokensβ₯ ~3000 β a simple prompt spends ~2,800 tokens (8.5k chars) reasoning, and a tighter cap returns emptycontent.
Contents β read this before downloading
This repo carries shards 1β46 only (196.4 GiB): the pruned weights, the config, the tokenizer, and the checkpoint's bundled reference implementation.
Shards 47β48 are the two Engram tables and are NOT in this repo. Pruning does not touch them β they are byte-identical to the base model, 189.1 GiB, and re-uploading them would cost every user a second copy of data they may already have. Fetch them from the base model and drop them in:
hf download LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E --local-dir dsv41-reap256
hf download deepseek-ai/DeepSeek-V4.1-Flash --local-dir dsv41-reap256 \
--include "model-00047-of-00048.safetensors" "model-00048-of-00048.safetensors"
model.safetensors.index.json already references them, so the model loads once both
files are present.
The Engram lookup is a hashed n-gram gather β 48 rows per token, ~12.4 KB β not a matmul. It never needs to be resident, which is why it can be served from disk or host RAM rather than accelerator memory, and why leaving it out of this repo costs nothing architecturally.
The FP4 Engram tables from
LibertAIDAI/DeepSeek-V4.1-Flash-NVFP4
(97.6 GiB instead of 189.1, cosine 0.9934) are a size-for-accuracy alternative β
lossy and untested under any serving engine, offered as-is.
config.json records the provenance:
"pruned_from": {"n_routed_experts": 384, "method": "REAP",
"calibration": "262,144 text tokens + 256 images, saliency combined",
"ranking": "balanced"}
Limitations
- Calibration is 262,144 text tokens and 256 images. Larger would be better.
- Perplexity only; no task evaluations.
- The caption evaluation is 2,048 tokens. It resolves the cliff (+27%) and the random/text-only gaps comfortably; it does not resolve differences of a few percent.
- MTP layers are retained and were not pruned (they carry their own 128-expert pool, which the 384-expert keep-set does not index).
License
Model: inherits the base model's license. Tooling: MIT.
Model tree for LibertAIDAI/DeepSeek-V4.1-Flash-REAP-256E
Base model
deepseek-ai/DeepSeek-V4.1-Flash