Views
No views yet
deepseek-ai/DeepSeek-V4-Flash
intended for Apple-Silicon inference via vMLX (or any
MLX-aware runtime that loads mlx_lm.utils.load).head_dim=512 and grouped output projection, mHC
(Manifold-Constrained Hyper-Connections, hc_mult=4),
sqrtsoftplus + hash routing for the first 3 layers.affine mode (output of mx.quantize,
not TurboQuant). Tensor naming <module>.{weight, scales, biases}.
Group size 32. Layout in safetensors:
layers.N.ffn.experts.E.{w1,w2,w3}): 4-bitlayers.N.attn.{wq_a, wkv, wo_a, wo_b, ...}): 8-bitjang_tools.load_jangtq)jang_tools.load_jangtq._patch_quant_config_inplace
(/Applications/vMLX.app/.../jang_tools/load_jangtq.py) infers
quantization overrides from raw safetensors keys
(model.layers.N.ffn.experts.E.w1) — these never match the
post-sanitize() module paths the MLX Model exposes
(model.layers.N.mlp.switch_mlp.gate_proj), so it overwrites this
bundle's correct config with unmatchable disk-keyed entries. After
overwrite, mlx_lm's class_predicate falls through to top-level
bits=8 and the routed experts get wrapped as 8-bit modules. The
4-bit-packed weights then silently fail to load (with strict=False)
and the model produces BOS-token loops at inference._patch_quant_config_inplace
that returns early when the user's config already has post-sanitize
overrides:1if existing_overrides and any(k.startswith("model.") for k in existing_overrides):
2 return {"action": "user_provided", "existing_overrides": len(existing_overrides)}build_mlx_q4q8.sh script's
patch_loader step applies this idempotently. See
requantization-plan.md for the full diagnosis.--continuous-batching for DSV4 because the
batched generator is incompatible with the model's 4-D mHC residual
stream. All requests go through SimpleEngine. Throughput on
Mac Studio M3 Ultra (256 GB unified memory): ~22 tok/s decode,
~75 tok/s prefill.1/Applications/vMLX.app/Contents/Resources/bundled-python/python/bin/python3 \
2 -m vmlx_engine.cli serve \
3 /path/to/DeepSeek-V4-Flash-MLX-Q4Q8 \
4 --served-model-name deepseek-v4-flash-mlx-q4q8 \
5 --host 127.0.0.1 --port 8010 \
6 --max-tokens 4096 \
7 --tool-call-parser deepseek \
8 --enable-auto-tool-choice1curl -s http://127.0.0.1:8010/v1/chat/completions \
2 -H 'Content-Type: application/json' \
3 -d '{
4 "model": "deepseek-v4-flash-mlx-q4q8",
5 "messages": [{"role": "user", "content": "What is 17+28?"}],
6 "max_tokens": 120
7 }'<think>...</think> blocks land in
reasoning_content; the final answer in content).jang_tools.load_jangtq._apply_wired_limit_safe_default)
needs comfortable spillover. Will technically load on 128 GB with
reduced max-tokens, but expect SSD pressure.|DSML| / <|tool_calls|> / <|invoke|>); pair it with vMLX's
--tool-call-parser deepseek --enable-auto-tool-choice. Reasoning
modes:<think> block.<think>...</think> wrapped reasoning, parsed
out into reasoning_content by DeepSeekR1ReasoningParser.<|latest_reminder|> anchor automatically — vMLX
adds a default system prompt (DSV4: injected default system prompt
in the load log) to keep multi-turn chat from running away on
reasoning loops.jang_tools.dsv4.convert_dsv4_jangtq --profile 4 --format jang.mx.quantize(..., group_size=32, bits=4, mode="affine").
The upstream converter direct-copies FP4 onto disk in MXFP4 form
(uint8 E8M0 scales, no biases) regardless of --format; vMLX's
MXFP4 dispatch is broken at 4-bit and produces gibberish. The
re-quantization step rewrites .weight + .scales + .biases for
each of the 33,024 routed expert tensors using MLX's actual affine
formula:
scale = max((w_max - w_min) / 15, eps)
side = abs(w_min) > abs(w_max)
scale = side ? scale : -scale
edge = side ? w_min : w_max
q0 = round(edge / scale)
scale = (q0 != 0) ? edge / q0 : scale
bias = (q0 != 0) ? edge : 0mlx/include/mlx/backend/metal/kernels/quantized.h:2387).model.safetensors.index.json to include the
newly-introduced .biases keys.bias tensors that MXFP4 doesn't carry.| Knob | Size saved | Quality cost |
|---|---|---|
| group_size 32 → 64 | ~6–8 GB | +0.1–0.3 % PPL |
| group_size 32 → 128 | ~10–12 GB | +0.3–0.8 % PPL |
| Non-experts Q8 → Q6 | ~3–5 GB | +0.1–0.3 % PPL |
| Non-experts Q8 → Q4 | ~8–10 GB | +0.5–2 % PPL, noticeable on long-context / reasoning |
| Experts Q4 → Q3 | ~30–40 GB | +2–6 % PPL, real degradation |
group_size=64 — saves ~6–8 GB,
quality loss is in the noise. Going below Q4 on the experts is where
MoE models fall off a cliff (each token only sees 6 of 256 experts,
so quantization noise does not average out across the population),
and gs=128 starts to bite on 1M-token contexts where small per-token
errors compound.mxfp4_to_affine.py script that ships in some upstream
DSV4 conversion guides uses scale = (max-min)/15, bias = min, which
does not match MLX's affine convention. Bundles produced that way
load but compound quantization error across the 43 transformer layers
(activations explode by layer ~20, NaN by layer ~29) and emit BOS-loop
gibberish. Do not use that script..
├── config.json # 132 quantization entries (129 routed-expert per-module + globals)
├── jang_config.json # vMLX chat / reasoning / tool-call schema
├── generation_config.json # eos_token_id = [1, 128803, 128804]
├── tokenizer.json
├── tokenizer_config.json # embedded chat_template + special tokens
├── encoding/ # DSV4 encoding adapter
├── model-00001-of-00159.safetensors # 159 shards, total ~173 GB
│ ...
├── model.safetensors.index.json
├── LICENSE
├── README.md # this file
├── README.upstream.md # upstream DeepSeek-V4 model card
└── DeepSeek_V4.pdf # upstream tech reportbuild_mlx_q4q8.sh (companion script in the
project repo). Quick reference of the steps:./build_mlx_q4q8.sh check # sanity-check disks + tools
./build_mlx_q4q8.sh patch_loader # apply the load_jangtq.py guard
./build_mlx_q4q8.sh download # hf download deepseek-ai/DeepSeek-V4-Flash
./build_mlx_q4q8.sh convert # ~40 min: jang_tools convert_dsv4_jangtq
./build_mlx_q4q8.sh requantize # ~30 min: mx.quantize routed experts
./build_mlx_q4q8.sh finalize # tokenizer / encoding asset copy
./build_mlx_q4q8.sh patch # EOS / chat_template fixes
./build_mlx_q4q8.sh verify # check the bundle
./build_mlx_q4q8.sh serve # launch vMLX./build_mlx_q4q8.sh all runs everything in order. Total runtime on
M3 Ultra: ~75 minutes plus the initial download (~160 GB at ~150 MB/s =
~18 minutes on a fast link).requantization-plan.md for the
diagnostic write-up of why the requantize step is needed.@misc{deepseekv4,
title = {DeepSeek-V4: Towards Highly Efficient Million-Token Context Intelligence},
author = {DeepSeek-AI},
year = {2025},
url = {https://github.com/deepseek-ai/DeepSeek-V4}
}mlx.core.quantize reference implementation.jang_tools tooling and the load_jangtq
loader (modulo the patch noted above).