|
|
1 week geleden | |
|---|---|---|
| .. | ||
| README.md | 1 week geleden | |
| make_padded.py | 1 week geleden | |
| tp3pad.py | 1 week geleden | |
| vocab_parallel_embedding.py | 1 week geleden | |
GLM-5.3-Flash at tensor parallel 3. Four dimensions do not divide by 3, so they are zero-padded; the padding is exact (zero heads and zero expert columns add nothing) and the checkpoint on disk is not rewritten.
| stock | padded | per rank | |
|---|---|---|---|
| MLA heads | 64 | 66 | 22 |
| KDA heads | 64 | 66 | 22 |
| MoE intermediate | 2048 | 2304 | 768 |
| vocab | 154880 | 154944 | 51648 |
| DFlash2 drafter q / kv heads | 32 / 8 | 36 / 9 | 12 / 3 |
make_padded.py SRC_MODEL DST_MODEL SRC_DRAFT DST_DRAFT: the target dir is
hardlinks of every checkpoint file plus a config.json with the padded sizes
and tp_pad_orig; the drafter (small) is padded offline. Run it inside the image.tp3pad.py: pads the target's tensors as load_weights reads them (hooked
from experimental/fixes/model.py; a no-op when the config has no tp_pad_orig).vocab_parallel_embedding.py: pads the vocab on to a multiple of 64 x TP.experimental/fixes/gb10_sparse_mla.py: the Triton sparse-MLA kernel took
tl.arange(0, H) over heads, which needs a power of two; 22 heads per rank
now run in the next power-of-two tile with a head mask.experimental/snapshot/dense_fp8.py: the KDA in_proj at TP=3 has N=8726
rows, not a multiple of 16, and stayed bf16; rows are now zero-padded to 16
and the output trimmed.image/entrypoint.sh: a TP=3 case. KV pin 12 GiB (26 GiB had the
host OOM-killer take rank 0 during graph capture), block size 3456 (vLLM
lifts it to 3584, 14% mamba page padding against 46% at the 4608 it picks
from 2304).Everything else is the four-box setup from the main README (image, mentatd, fabric), on three boxes.
Padded model dirs, on every box. The target dir is hardlinks, so it must sit on the same filesystem as the checkpoint; the drafter is copied and padded. Run inside the image this repo builds:
docker run --rm -v /srv/models:/srv/models --entrypoint python3
-v "$PWD/experimental/tp3":/tp3:ro spark-glm53:v9 /tp3/make_padded.py \
/srv/models/glm-5.3-flash-nvfp4 /srv/models/glm-5.3-flash-nvfp4-tp3 \
/srv/models/glm-5.3-flash-dflash2 /srv/models/glm-5.3-flash-dflash2-tp3
compose/.env on every box (tp3.yaml sets TP=3):
MODEL_HOST_DIR=/srv/models/glm-5.3-flash-nvfp4-tp3 DFLASH_HOST_DIR=/srv/models/glm-5.3-flash-dflash2-tp3
Start with every override, recoverssm.yaml included, and tp3.yaml last (it
restates adaptive-k.yaml's EXTRA_ARGS and adds a data-parallel vision
tower, whose 16 heads do not split by 3):
./glm53 -f experimental/compose/tp3.yaml up -d
The first boot pads while it
loads and writes a weight snapshot under its own tag (tp3pad-..., set in
tp3.yaml; a TP=4 snapshot must never restore here); later boots restore it.
The entrypoint's TP=3 case sets the KV pin (12 GiB), block size (3456),
MAX_NUM_SEQS 64 with RecoverSSM (32 without) and the adaptive-k starting cost. With RecoverSSM on, the head keeps ~6.6 GB of
host memory free while serving; a 16 GiB pin would leave ~2.6 GB, so do not raise it.
At TP=3, on this stack, one change at a time against the defaults above:
sequence parallel off (-16% prefill), VLLM_ARXBIG_AG=1 (-26 to -30%
prefill), max_num_batched_tokens 8192 (-4% at 22k), megamoe
VLLM_MEGAMOE_MAX_TOKENS=16 and its tile variants (within noise), 72 MLA
heads instead of 66 (-10% prose decode, measured on the PR #4 base). A MoE intermediate of 2112 (704 per
rank) would pad less, but megamoe needs a multiple of 128 per rank.
dev/patch-tests/_glm53_tp3pad_test.py (CPU) and
dev/patch-tests/_glm53_tp3_sparse_mla_test.py (one GB10); each file says how
to run it.
Two sets of three boxes (one 200G switch, both ConnectX ports), each booted
clean with the defaults above (RecoverSSM on, MAX_NUM_SEQS 64), on this
branch over main 6db84d4 plus the capture-size fix from its own PR
(tp-cudagraph-tiers: an explicit capture cap dropped adaptive-k's decode
sizes 3, 5, 6, 10, 12 and 15). KV held 1.48M tokens then; with #16 the head log reports 1,905,585. On main 2288993 plus #20 and the zeroer fix, set 1 re-measured within noise: RigMark 43.9 / 76.2 / 113.7, cold prefill 8k / 32k / 64k 3312 / 3637 / 3587.
| set 1 | set 2 | |
|---|---|---|
| RigMark prose / code / structured, tok/s | 43.8 / 75.7 / 113.8 | 44.0 / 76.2 / 114.0 |
| RigMark cold prefill 8k / 32k / 64k, tok/s | 3295 / 3602 / 3565 | 3325 / 3610 / 3583 |
gate/prefill.py cold 32k / 128k, tok/s (2 seeds) |
3574, 3533 / 3440, 3449 | 3561, 3554 / 3422, 3437 |
gate/conc_workload.py code 1 / 2 / 4 / 8 streams, tok/s |
86.5 / 101.8 / 137.4 / 163.7 | 87.4 / 100.5 / 153.7 / 170.2 |
conc_workload.py mixed 8 / 16 / 32 / 48 streams, tok/s |
134.1 / 195.5 / 262.7 / 335.9 | 141.0 / 200.3 / 260.0 / 333.9 |
dev/repro/needle.py 32k to 480k |
12/12 | 12/12 |
At 48 streams, MAX_NUM_SEQS 64 gave +24% over 32 (269 tok/s); single-stream
decode is the same at both. A 30-minute soak of the same TP=3 changes on main
14cc721 (MAX_NUM_SEQS 32, 16 mixed streams back to back, 824 requests) had
no errors or restarts.
The same padded checkpoint splits by 6: 11 MLA heads, 11 KDA heads and 384 MoE columns per rank. The pieces above cover it: the KDA in_proj has N=4491 per rank and takes the same row padding to 16, and the sparse-MLA kernel runs 11 heads in a 16-row tile. Only the drafter needs a different pad: its 8 kv heads need 12 (48 q heads) to split by 6.
Padded model dirs, on every box, as step 1 above but with the drafter padded for 6:
... /tp3/make_padded.py SRC_MODEL DST_MODEL SRC_DRAFT DST_DRAFT
--draft-heads 48 --draft-kv-heads 12 --tp 6
compose/.env on every box: MODEL_HOST_DIR / DFLASH_HOST_DIR at the
padded dirs, as for TP=3.
Start with the TP=3 command, tp6.yaml in place of tp3.yaml. It sets
TP=6 and its own snapshot tag (tp6pad-...).
The entrypoint's TP=6 case sets the TP=4 KV pin (26 GiB; weights are ~1/6
per rank), block size 1792, MAX_NUM_SEQS 64 with RecoverSSM and the
adaptive-k starting cost. With 11 KDA heads per rank the mamba page is ~1573
tokens of attention page: the default 2304 pads it 46%, 1792 (the smallest
multiple of 256 above it) 14%, for a 1.7% bigger pool (4.47M tokens) and a
faster cached TTFT (0.677 against 0.903 s).
Tried and not kept at TP=6 (screened on an earlier build): sequence parallel off (-25% prefill),
max_num_batched_tokens 32768 (no prefill gain, and it needs a bigger arxbig
slot), VLLM_MEGAMOE_MAX_TOKENS=16 (within noise).
dev/patch-tests/_glm53_tp3_sparse_mla_test.py includes H=11.
Measured on six boxes (one 200G switch, both ConnectX ports, GPU clocks locked
at 1989 MHz), booted clean with the entrypoint defaults on this branch's TP=6
changes over main 3df22b8 plus the padded-config import guard (#24):
| RigMark prose / code / structured, tok/s | 66.5 / 120.3 / 176.4 |
| RigMark cold prefill 8k / 32k / 64k, tok/s | 4776 / 4902 / 4903 |
gate/prefill.py cold 32k / 128k, tok/s (2 seeds) |
4900, 4914 / 4737, 4724 |
gate/conc_workload.py code 1 / 2 / 4 / 8 streams, tok/s |
145.0 / 153.8 / 218.6 / 281.7 |
conc_workload.py mixed 8 / 16 / 32 / 48 / 64 streams, tok/s |
196.6 / 298.7 / 415.3 / 506.7 / 596.5 |
dev/repro/needle.py 32k to 480k |
12/12 |
A 30-minute soak at 64 mixed streams (2700 requests) had no errors, preemptions or restarts.
Three boxes with one cable per pair also form a ring. The entrypoint has no
mode for it (only TP=RING4), so the NCCL ring and each rank's
ARX_RING_PREV_HCAS / ARX_RING_NEXT_HCAS are set by hand, with
VLLM_ARX_RING=1 and VLLM_ARXBIG=0: arx's ring takes three ranks, arxbig's
does not (experimental/README.md).
Through a switch, with both neighbours on one port, ring and mesh at three ranks gave the same bits and the same all-reduce latency: 14.5 / 21.5 / 45.7 / 72.9 us in ring mode against 13.6 / 24.2 / 44.9 / 72.6 in mesh mode, at 8 / 64 / 256 / 512 KB.
@calvarado2004 measured a cabled triangle on 45b438b, with every overlay and
RecoverSSM off, from their own launcher with the TP=3 case's arguments and on
their own harness, so these aren't comparable with the main README's table
(#52):
--max-model-len 1048576 at the 12 GiB pin the KV pool held 1,849,306
tokens, and needles at 291,517, 600,405 and 955,301 tokens were found in
104, 236 and 422 s.smoketest/run.sh
passed 8/8.