Views
No views yet
Mirrors: canonical repo is on GitHub at fattchris/qwen-dflash2-spark (identical content).
1git clone https://github.com/fattchris/qwen-dflash2-spark.git
2cd qwen-dflash2-spark
3# on BOTH nodes: ~30 min (bandwidth-bound)
4bash scripts/00-download-models.sh
5# on node 1 only: ~1–2 h (compiles vLLM fork)
6bash scripts/01-build-image.sh
7# on node 1 only: ~10 min
8bash scripts/02-make-bf16head.sh
9# from node 1: ~5 min (rsync ~23 GB)
10bash scripts/03-replicate.sh
11# from anywhere with SSH to both: ~4–5 min to health 200
12bash scripts/04-launch-pair.sh
13# verify generation + throughput:
14bash scripts/06-verify.sh && bash scripts/07-quality-gate.shhttp://NODE1:8004/v1, model name
qwen3.8-27b-dflash2, 131–135 tok/s typical on the
edit-heavy C1 benchmark.unsloth/Qwen3.8-27B-NVFP4 (FP4 weights, FP8 attention) —
the bandwidth-floor baseline on GB10.z-lab/Qwen3.8-27B-DFlash2 (1.92B params, block_size 8,
local convolution + candidate selector head).subsir/upstream-dflash2), compiled aarch64 in the official
vllm/vllm-openai:0.27.1-aarch64 image, TP=2 across two Sparks via RoCE v2.lm_head to
BF16 in a copy of the NVFP4 checkpoint. Every public NVFP4 Qwen3.8
checkpoint quantizes lm_head, but DFlash2's candidate selector performs
TopK over the target model's lm_head logits and hard-rejects
quantized heads — so nothing out of the box works. 02-make-bf16head.sh
does the surgery + config fix atomically and hardlink-safely.| Config | tok/s (C1 edit-heavy) | accept | mean tok/pass |
|---|---|---|---|
| DSpark (MTP) K=14 | 91–95 | 68.6% | ~9.7 |
| DFlash2 K=7 | 73–74 | 99.6% | 7.0 |
| DFlash2 K=16 | 124–135 | 93.1% | 15.9 |
| DFlash2 K=24 | 121–129 | 66.4% | 16.9 |
scripts/00-download-models.sh # hf download target + draft
scripts/01-build-image.sh # compile z-lab vllm-fork inside official image
scripts/Dockerfile.df2 # overlay built vllm/ onto clean official image
scripts/02-make-bf16head.sh + make_bf16head.py # the lm_head surgery
scripts/03-replicate.sh # rsync checkpoints node1 → node2
scripts/04-launch-pair.sh # TP2 launch, health-wait
scripts/06-verify.sh # health + generation + bench
scripts/07-quality-gate.sh # greedy math gate (17*23+45 == 436)
scripts/qwen-dflash2-rank.sh # the actual docker run (single rank)
bench/edit_bench.py # C1 edit-heavy/fresh benchmark (from engine counters)
bench/quality_capture.py # 6-prompt greedy capture
bench/prod_tps.py # simple client-side tps probe
docs/architecture.md # how the pieces fit, RoCE env details
docs/README-agent.md # runbook for AI agents operating this stack
docs/results.md # full benchmark tables + methodologyadmin@192.168.1.205 (node1/rank0) and
admin@192.168.1.206 (node2/rank1); override with NODE1= NODE2= env vars.
Note the image only exists for aarch64 — this stack is GB10-specific.bash scripts/00-download-models.shunsloth/Qwen3.8-27B-NVFP4 (~21 GB) and z-lab/Qwen3.8-27B-DFlash2
(~4 GB). Idempotent — safe to re-run.bash scripts/01-build-image.shvllm/ tree, and overlays it onto a fresh official image via
Dockerfile.df2. Tag: local/vllm-dflash2-pr52816:v2. Then docker save it
to node2 — see below.01 builds on node1 only. Move it to node2:1docker save local/vllm-dflash2-pr52816:v2 | gzip > /tmp/df2.tgz
2scp /tmp/df2.tgz node2:/tmp/ && ssh node2 'gunzip -c /tmp/df2.tgz | docker load'bash scripts/02-make-bf16head.shunsloth-nvfp4-bf16head/ — a hardlink copy of the NVFP4 checkpoint
with lm_head.weight dequantized (w * scale → bf16, vocab 151k × 4.1k
hidden) and the config fixed (see Pitfalls #2). The original checkpoint is
left pristine (verify with fix_configs.py's proof mode).bash scripts/03-replicate.shbash scripts/04-launch-pair.sh1bash scripts/06-verify.sh
2bash scripts/07-quality-gate.sh17*23+45 must answer 436.UnquantizedEmbeddingMethod. Dequant via 02. (This is the
headline fix; every public NVFP4 Qwen3.8 checkpoint ships a quantized
lm_head.)config_groups.group_0.targets overrides
the ignore list. Your ignore: ["lm_head"] does nothing while
re:.*lm_head sits in targets. 02 strips it from targets AND adds it to
ignore. (Cost me three failed boots to find.)shutil.copytree(copy_function=os.link) keeps the
original and the copy sharing inodes — a later json.dump into
config.json rewrites the shared inode and corrupts the original
checkpoint. Always write-temp-then-os.replace() configs (02 does).02 runs copytree into an existing dir → symlink
loops. It removes .safetensors in DST first; if DST is partial, delete it
and re-run.
4b. Served model name is exactly qwen3.8-27b-dflash2 (dot-separated,
set by --served-model-name in the rank script). Clients must match it.qwen-dflash2-rank.sh
(NCCL_IB_HCA=rocep1s0f1, RoCE v2, NCCL_CUMEM_ENABLE=0,
VLLM_MARLIN_USE_ATOMIC_ADD==1 etc.). Don't hand-tune without capturing a
baseline first.--headless). 04 launches r1 first for this reason. If
you restart rank0 only, expect a stuck handshake → restart both, r1 first.docker rm -f'd
a healthy pair and relaunched the wrong checkpoint.launchctl kickstart -k
recycles only the worker; the master keeps the old config. Kill the master
PID and let launchd respawn for config changes to take.