Repository navigation
Conversation
|
One thing the description does not mention: setup writes |
|
Using this version as my daily driver with 2 and 3 GPUs. |
|
A same-setup A/B for this patch, on a 2x RTX 5060 Ti layer split. Identical 91,712-token prompt,
The freed 192 tensors are exactly the 4x48 |
|
A KL check for the one value change this patch makes, on the layer split. The yardstick is single-GPU by design, so the split is spelled out: Prompt path (where the patch changes the read: the bf16 copy -> the Q8_0 through
Decode path (the same
The decode figure is larger than the prompt path's (0.0013) because the decode is teacher-forced and the difference accumulates over the sequence. It is not the read alone: the patch also frees ~1.1 GiB per card, so the expert cache grows (1539 -> 1932 slots), and the cache's GPU/CPU rounding moves the yardstick KL by about as much on its own (#704: "Changing only the cache size (no HC_Q8) moves it as much: top-1 94.1%, KL 3.4e-2"). The draft acceptance is unchanged (same prompt, T=0, 3 runs each: 53.7% vs 54.0%). The direction is the Q8_0 read the single-GPU path has used since b60aab1 ( |
|
The A/B is in the table above: same config (2x RTX 5060 Ti, And you are right about |
|
Thanks for the pull request. We're resetting the tracker for 0.2.0-beta. There are more than 1,300 open issues and pull requests, too many for us to review properly, so we're closing everything that isn't being worked on right now. Closed here does not mean rejected. To reopen it takes about two minutes:
The rules are in CONTRIBUTING.md. |
… too STRATA_HC_Q8=1 leaves the layers' bf16 hyper-connection down/up projections out of the arena on a single GPU. On a layer split the loader kept them and the Q8_0 copies were added on top, because add_hc_skip was gated on !multi_gpu. The prompt path and the token read already take these rows through hc_bf16_view, which dequantizes the Q8_0 into a per-device scratch, so the split can drop the bf16 copies exactly as the single-GPU path does. Measured (UD-Q4_K_XL, two RTX 5060 Ti, layer split auto, STRATA_HC_Q8=1): - 495 canonical tensors skipped instead of 303 (the 192 hc_*_down/up bf16 rows) - 216 MiB of dense weights loaded instead of 1416 MiB - CUDA1's expert cache 2538 slots instead of 2143; the split search then picks K=7 (6083 profiled pairs) instead of K=5 (4799) - a short request answers correctly; the read only moves from the bf16 copy to the Q8_0 copy (the single-GPU KL is in docs/QUANTS.md)
The comment still called add_hc_skip 'the single-GPU default' and read as if a layer split always keeps the arena's bf16 rows; the gate is not single-GPU any more.
|
/reopen |
|
Reopened, thank you. A maintainer will pick it up from here. If it conflicts with main, rebase it first; that speeds up review. |
b7ea7b7 to
3908d71
Compare
|
Rebased on 0.2.1 and re-validated. The description now follows the template. On the two points @qiuzan2001 raised: the description now states that setup enables `STRATA_HC_Q8=1` for CUDA UD-* installs. |
…pies on a layer split too) — integ batch 19
Problem and result
STRATA_HC_Q8=1reads the hyper-connection down/up projections from Q8_0 copies. On a single GPU it also leaves their bf16 copies out of the arena (add_hc_skip). On a layer split that skip was gated off (!multi_gpuingenerate.cpp), so each card kept the bf16 copies and got the 0.63 GiB of Q8_0 copies on top. HC_Q8 cost VRAM on a split instead of saving it.With this change a split skips the bf16 copies the same way, and each card gives the freed VRAM to its expert cache. Measured on 0.2.1 (
c093ac26), UD-Q4_K_XL, 2x RTX 5060 Ti,--layer-split auto:hc_*_down/uprows)Related discussion
This is #2427, closed by the 2026-10-19 tracker reset, rebased on 0.2.1 and re-validated. It answers the review there: the default reach via setup (below), a same-config A/B on the split (Validation), and the
native_dense.cppcomment (fixed). It extends the single-GPU HC_Q8 path (b60aab1) to a layer split. #704 was a requantization approach and was closed as "not with a layer split".Default reach, needs the owner's call:
setup.py:3190writesSTRATA_HC_Q8=1for CUDA UD-* installs. So this change is active by default on every CUDA UD-* layer split, not only for users who set the variable. There the prompt path and the per-token read switch from the bf16 copy to the Q8_0 dequantized into scratch (the read one GPU has used since b60aab1). The freed VRAM also moves the auto placement (split point, prompt chunk, cache slots). Greedy output on such a split is therefore no longer bit-identical to 0.2.1 (KL below).STRATA_HC_Q8=0keeps the full bf16 read as before.Approach
One gate in
src/program/generate.cpp: drop!multi_gpufrom theadd_hc_skipcondition. Plus a comment fix innative_dense.cpp.The prompt path and the token read already take these rows through
hc_bf16_view, which dequantizes the Q8_0 into per-device scratch. So a split can drop the bf16 copies exactly as one GPU does.add_hc_skipnames allhc_*_down/uprows. Each stage's loader still limits itself to its own layers throughin_range, and a skipped row is quantized on the host from the pack file. Kernels are untouched.What changes on a split: the verify windows already read the Q8_0 copies with and without the patch (
STRATA_HC_Q8=1: 0.63 GiB of Q8_0 hyper-connection projectionsin both logs). The prompt path and the per-token read move from the bf16 copy to the Q8_0 throughhc_bf16_view, as on one GPU.Validation
Environment: AMD Ryzen 7 5700X3D (8C/16T), 94 GB RAM, 2x RTX 5060 Ti 16 GB (sm_120, driver 610.57.04; CUDA0 on a x4 link, probed 3.1 GB/s, CUDA1 x8, 14.3 GB/s), Debian kernel 6.12.107, CUDA build
-DCMAKE_CUDA_ARCHITECTURES="86;120". Patched3908d716(= this branch) against stockc093ac26, both built with identical options. The server config is my production config (UD-Q4_K_XL,--spec 4 --mtp,--kv int8,--prefill auto,--layer-split auto,STRATA_HC_Q8=1).Passed:
ctest -j 4on3908d716: 66/68 passed.ple_parityandplatform_memory_test(mlock,ulimit -l) fail identically on stock.finish: stop, no errors.e88ee39d, 5 rounds) gave prompt 32k +2.9%, 120k +3.1%, 5/5 pairs each.--batch 2on the split, two concurrent requests (45k + 49k and 4k + 4k tokens), patched, stock and stock again. Run in the 0.2.1 default (one serial group) and with--batch-groups 2(pipelined, 2 groups of 1). All answers complete, correct and coherent, no errors in the engine logs.layer_split "7",--prefill 4096) the divergence moves later. Changing only the placement on stock (auto vs pinned) diverges about as early as the patch does, so placement is a large part of the difference, beside the bf16 → Q8_0 read.tools/quant_quality.py,--layer-split auto,CUDA_VISIBLE_DEVICES=0,2, reserve raised so the MTP head fits, the same on both arms. Prompt path (prompt/pcompare, 20 prompts of 256-1000 tokens, full vocabulary): top-1 100% (20/20), KL mean / median / max 0.00134 / 0.00042 / 0.00781. Decode (run/compare, teacher-forced, 4,995 positions): top-1 95.10%, KL mean / p99 0.02858 / 0.4818, perplexity 4.062 vs 4.020. The decode figure includes the cache-size effect (1539 → 1932 slots): changing only the cache size moves it about as much (STRATA_HC_Q8: hyper-connection projections as int8 + fp32 scale per 32 #704: top-1 94.1%, KL 3.4e-2). Draft acceptance unchanged (53.7% vs 54.0%, 3 runs each).Per-run results
Run 2, decode tok/s (rounds 0-9):
Run 2, prompt 32k tok/s:
Run 1, prompt tok/s (rounds 0-4):
Run 1, decode tok/s:
Failed:
None observed. One observation in the decode numbers: 3 of 20 patched servers across the 0.2.0 and 0.2.1 five-round runs decoded 10-35% slower for their whole lifetime (0 of 20 stock). They showed the same cache layout, cache hit rate, draft acceptance and graph captures as the fast ones. The 10-round decode run (10 patched servers) had none, and the cause is not found.
Not run:
--keep-canonical(the gate sits inside!keep_canonical, unchanged).--batch-mtp.Limits
layer_splitsees only the cache part.🤖 Generated with Claude Code