Independent re-verification (2026-10-12) + fixes
Browse filesRe-ran the full 4/8/16/32 GiB memory matrix on the same host, same
llama.cpp commit 836d5717, same patch, same reserve (SDQ_RESERVE_MB=2048),
built with the portable ISA flags from section 4.2. All 8 runs clean; every
published column reproduces within noise. arena / slots / peak RSS / total
SSD are near bit-identical; tok/s within +-6%.
Fixes and corrections:
* sdq-dsv4/verify_dequant_dsv4.py: TARGETS was one flat suffix list applied
to BOTH layer 0 and 26; ffn_down_exps is MXFP4 in both, so 3 comparisons
ran twice -> printed 21 rows for 15 unique comparisons and self-reported
"21/21". README said "already fixed" but only the results file had been
edited. Now per-layer explicit, with two guards; prints 15/15.
* sdq-dsv4/determinism_probe.sh: hardcoded non-existent /root/app/work
paths; now auto-detects and fails loudly.
* README 5(e): the claim that "AMX" does not appear in libggml-cpu.so is
false (AMX_INT8 comes from the CPUID probe in cpu-feats.cpp). Conclusion
unchanged; evidence replaced with nm -D on registered symbols.
* README 6.3: 387/387 is prompt-specific, not a general property. With
"The capital of France is" only prefill is bit-identical (43/387).
Section A itself reproduces exactly and was not wrong.
* README 6.4: --ram-budget-mb belongs on the list of knobs that perturb
decode output; it was missing. Compile flags excluded as the cause
(two builds disagree too).
* README section 3: the build caveat is resolved -- the matrix does hold
for the section 4.2 portable flags.
* README 4.1: `hf download` aborts on typer>=0.27 + click<8.2; documented
the Python-API fallback. Unrelated to the token.
* README "rerun" section: item (3) was labelled as the MoE A/B but ran the
determinism probe; relabelled and the MoE A/B added as item (4).
Original published results files are left untouched.
- README.md +143 -3
- results/determinism_recheck.txt +62 -0
- results/memory_levels_dsv4-4-8-16-32g-recheck.json +247 -0
- results/memory_levels_dsv4-4-8-16-32g-recheck.md +24 -0
- results/moe_dump_recheck_prompt_dependence.md +34 -0
- results/verify_dequant_recheck.txt +30 -0
- sdq-dsv4/determinism_probe.sh +18 -2
- sdq-dsv4/verify_dequant_dsv4.py +44 -33
|
@@ -112,6 +112,24 @@ decode 期不確定性的一部分,不同 RAM 預算/無關設定會換掉
|
|
| 112 |
> 這個矩陣另外用了 `SDQ_RESERVE_MB=2048`,而 pager 的**程式預設值是 900 MB**
|
| 113 |
> (`sdq_pager.cpp`)。這個值直接決定 arena 大小(`arena = 預算 − RSS − 預留`),
|
| 114 |
> 不帶這個環境變數重跑會得到比表中更大的 arena 與不同的槽位數。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
> 三個容易搞混的地方,這裡先講清楚:
|
| 117 |
> 1. `nproc` 在這台機器上回 16,是因為環境變數 `OMP_NUM_THREADS=16`,
|
|
@@ -166,6 +184,35 @@ hf download unsloth/DeepSeek-V4-Flash-0731-GGUF --include "UD-IQ4_NL/*" \
|
|
| 166 |
--local-dir ./models
|
| 167 |
```
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
### 4.2 建引擎
|
| 170 |
|
| 171 |
```bash
|
|
@@ -347,7 +394,23 @@ ggml_backend_sched_split_graph: GGML_ASSERT(*cur_backend_id != -1) failed
|
|
| 347 |
|
| 348 |
* **推薦(4.2 採用)**:不要用 `-march=native`,改成明確列 ISA
|
| 349 |
(`-DGGML_NATIVE=OFF -DGGML_AVX512=ON ...`)。AMX 的三個 CMake 選項本來就
|
| 350 |
-
預設 OFF,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
* 如果你一定要 `-march=native`:加
|
| 352 |
`-DCMAKE_C_FLAGS="-mno-amx-int8 -mno-amx-tile -mno-amx-bf16"`(CXX 同樣)。
|
| 353 |
|
|
@@ -403,7 +466,16 @@ python3 sdq-dsv4/verify_dequant_dsv4.py
|
|
| 403 |
> 這裡是 5 個張量 × 3 個 row = **15 列**。原始輸出檔
|
| 404 |
> `results/verify_dequant.txt` 早先印成 21 列,但其中 `blk.0.ffn_down_exps` 與
|
| 405 |
> `blk.26.ffn_down_exps` 各被重��印了一次(每個 3 列,共 6 列重複),
|
| 406 |
-
> 所以「21/21」是重複計數造成的,不是真的做了 21 次獨立比對。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
### 6.2 整個 expert 前向對照
|
| 409 |
|
|
@@ -451,6 +523,30 @@ hot/cold 比例、SSD 讀取量、槽位數(164 vs 2732)、淘汰次數全
|
|
| 451 |
改變數學」最直接的證據。逐檔 md5 見
|
| 452 |
[`results/moe_dump_bitexact.md`](results/moe_dump_bitexact.md)。
|
| 453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
另外同一設定重跑 6 次、兩個 RAM 預算各 6 次,greedy(`--temp 0`)輸出
|
| 455 |
**12/12 逐字相同**(`results/determinism.txt`)。
|
| 456 |
|
|
@@ -466,6 +562,29 @@ hot/cold 比例、SSD 讀取量、槽位數(164 vs 2732)、淘汰次數全
|
|
| 466 |
`SDQ_IO_SPLIT=2`、`-c`、`-b`),第一個 token 就會換。`-t 1`(完全單執行緒)
|
| 467 |
也一樣會換,所以不是執行緒競爭。
|
| 468 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
**而且分歧點已經定位到**:把兩種設定的 MoE dump 逐一比對(43 層 × 17 次 op call
|
| 470 |
= 731 個檔案),**43 個 prefill 呼叫全部 bit-identical、688 個 decode 呼叫全部不同**
|
| 471 |
(`results/moe_dump_bitexact.md` §B)。分歧已經出現在 MoE op 的**輸入** `cur` 裡,
|
|
@@ -513,6 +632,13 @@ results/
|
|
| 513 |
verify_moe_forward.txt expert 前向 vs 純 NumPy 的逐筆輸出(10/10 PASS)
|
| 514 |
moe_dump_bitexact.md MoE op 的 bit-exact A/B(387/387 與分歧點定位)
|
| 515 |
determinism.txt 決定性探針(同一設定重跑 6 次 × 2 個預算)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 516 |
```
|
| 517 |
|
| 518 |
### 重跑驗證
|
|
@@ -526,10 +652,24 @@ python3 sdq-dsv4/verify_dequant_dsv4.py
|
|
| 526 |
# (2) expert 前向(先跑 sdq-chat --selftest 產生 /tmp/st_l*e*.bin,見 6.2)
|
| 527 |
DSV4_LIMIT=10 DSV4_MODE=1 python3 sdq-dsv4/verify_moe_dsv4.py
|
| 528 |
|
| 529 |
-
# (3)
|
| 530 |
bash sdq-dsv4/determinism_probe.sh 8192 32768
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
```
|
| 532 |
|
|
|
|
|
|
|
|
|
|
| 533 |
---
|
| 534 |
|
| 535 |
## 8. 授權
|
|
|
|
| 112 |
> 這個矩陣另外用了 `SDQ_RESERVE_MB=2048`,而 pager 的**程式預設值是 900 MB**
|
| 113 |
> (`sdq_pager.cpp`)。這個值直接決定 arena 大小(`arena = 預算 − RSS − 預留`),
|
| 114 |
> 不帶這個環境變數重跑會得到比表中更大的 arena 與不同的槽位數。
|
| 115 |
+
> ✅ **這個保留意見可以撤掉了(2026-10-12 複驗)**:用第 4.2 節那組**可攜 ISA
|
| 116 |
+
> 選項**(`-DGGML_NATIVE=OFF -DGGML_AVX512=ON ...`)重跑整個 4/8/16/32 GiB
|
| 117 |
+
> 矩陣,8 輪全部無錯,**每一欄都在雜訊內重現**(發布值→複驗值):
|
| 118 |
+
>
|
| 119 |
+
> | RAM 預算 | arena (GiB) | slots | decode tok/s | hot % | SSD MiB/tok | peak RSS (MB) |
|
| 120 |
+
> |---:|---|---|---|---|---|---|
|
| 121 |
+
> | 4 GiB | 1.79→1.79 | 164→164 | 0.69→0.65 | 0.0→0.0 | 2944.4→2944.4 | 2233→2232 |
|
| 122 |
+
> | 8 GiB | 5.79→5.79 | 531→531 | 1.40→1.41 | 42.3→42.4 | 1451.6→1444.7 | 6325→6325 |
|
| 123 |
+
> | 16 GiB | 13.79→13.79 | 1264→1264 | 1.63→1.62 | 54.5→54.9 | 1021.8→1007.5 | 14508→14507 |
|
| 124 |
+
> | 32 GiB | 29.79→29.79 | 2732→2732 | 1.71→1.72 | 63.9→64.0 | 690.7→688.0 | 30894→30894 |
|
| 125 |
+
>
|
| 126 |
+
> 決定性的欄位(arena、slots、peak RSS、SSD 總量)幾乎是位元級相同;只有 tok/s
|
| 127 |
+
> 落在 ±6% 內,這與 4.2 節自己承認的「同一組設定重跑三次就差 1.66×」是同一個
|
| 128 |
+
> 量級的抖動。**所以這張表對第 4.2 節的編譯選項同樣有效。**
|
| 129 |
+
>
|
| 130 |
+
> 順帶釐清一處 JSON 內部矛盾:`build.cmake` 欄位寫的是第 4.2 節那組可攜選項,
|
| 131 |
+
> `build.note` 卻說是用 `-march=native -mno-amx-*` 量的。複驗顯示兩者都對得上這張
|
| 132 |
+
> 表,矛盾不影響數字,但 `build.note` 那句「tok/s 要照實說明」已無必要。
|
| 133 |
|
| 134 |
> 三個容易搞混的地方,這裡先講清楚:
|
| 135 |
> 1. `nproc` 在這台機器上回 16,是因為環境變數 `OMP_NUM_THREADS=16`,
|
|
|
|
| 184 |
--local-dir ./models
|
| 185 |
```
|
| 186 |
|
| 187 |
+
> ⚠️ **`hf` CLI 在某些環境會直接掛掉,要改用 Python API**(2026-10-12 實測)。
|
| 188 |
+
> 症狀是在開始下載之前就丟出:
|
| 189 |
+
>
|
| 190 |
+
> ```
|
| 191 |
+
> File ".../typer/core.py", line 725, in parse_args
|
| 192 |
+
> ctx._opt_prefixes.update(parser._opt_prefixes)
|
| 193 |
+
> AttributeError: 'StyledContext' object has no attribute '_opt_prefixes'
|
| 194 |
+
> ```
|
| 195 |
+
>
|
| 196 |
+
> 這是 `typer` 與 `click` 的版本不相容(typer ≥ 0.27 需要 click ≥ 8.2 的
|
| 197 |
+
> `Context._opt_prefixes`,但環境裡是 click 8.0.4),**跟 HF token、
|
| 198 |
+
> 權重、網路都無關**,改 token 沒用。權重是 public repo,其實根本不需要 token。
|
| 199 |
+
> 兩種解法:
|
| 200 |
+
>
|
| 201 |
+
> ```bash
|
| 202 |
+
> # (a) 直接用 Python API(不經過 typer,最省事)
|
| 203 |
+
> python3 -c "
|
| 204 |
+
> from huggingface_hub import snapshot_download
|
| 205 |
+
> print(snapshot_download('unsloth/DeepSeek-V4-Flash-0731-GGUF',
|
| 206 |
+
> allow_patterns=['UD-IQ4_NL/*'], local_dir='./models'))"
|
| 207 |
+
>
|
| 208 |
+
> # (b) 升級 click
|
| 209 |
+
> pip install -U 'click>=8.2'
|
| 210 |
+
> ```
|
| 211 |
+
>
|
| 212 |
+
> 下載完記得核對 4 個 shard 的 bytes 應為
|
| 213 |
+
> `5257664 + 49431060672 + 49605340544 + 37620787776 = 136662446656`,
|
| 214 |
+
> 對不上就是下載沒完(本 repo 實測下載速率約 1.5 GB/s,約 92 秒完成)。
|
| 215 |
+
|
| 216 |
### 4.2 建引擎
|
| 217 |
|
| 218 |
```bash
|
|
|
|
| 394 |
|
| 395 |
* **推薦(4.2 採用)**:不要用 `-march=native`,改成明確列 ISA
|
| 396 |
(`-DGGML_NATIVE=OFF -DGGML_AVX512=ON ...`)。AMX 的三個 CMake 選項本來就
|
| 397 |
+
預設 OFF,所以 AMX extra buffer type 不會被註冊。
|
| 398 |
+
|
| 399 |
+
> ⚠️ **勘誤(2026-10-12 複驗)**:本節原本寫「`libggml-cpu.so` 裡連 `"AMX"`
|
| 400 |
+
> 這個字串都不會出現」——**那句是錯的**,該字串確實會出現。
|
| 401 |
+
> `libggml-cpu.so` 裡有一個 `AMX_INT8` 字串,來自 ggml 的 CPUID 機型偵測
|
| 402 |
+
> (`ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp` 的 `bool AMX_INT8(void)`),
|
| 403 |
+
> 那段程式碼本來就**一定**會編譯進來,與 AMX buffer type 有沒有註冊無關。
|
| 404 |
+
> **正確的判準是看有沒有註冊的符號**,本機實測:
|
| 405 |
+
>
|
| 406 |
+
> ```bash
|
| 407 |
+
> $ nm -D --defined-only build/bin/libggml-cpu.so | grep -i amx
|
| 408 |
+
> 000000000001d400 T ggml_cpu_has_amx_int8 ← 只有這個 CPUID 探測
|
| 409 |
+
> $ strings build/bin/libggml-cpu.so | grep -c 'amx_extra_buffer_type'
|
| 410 |
+
> 0 ← AMX buffer type 未註冊
|
| 411 |
+
> ```
|
| 412 |
+
>
|
| 413 |
+
> 結論(AMX 必須關)不變,錯的只是拿來佐證的那句話。
|
| 414 |
* 如果你一定要 `-march=native`:加
|
| 415 |
`-DCMAKE_C_FLAGS="-mno-amx-int8 -mno-amx-tile -mno-amx-bf16"`(CXX 同樣)。
|
| 416 |
|
|
|
|
| 466 |
> 這裡是 5 個張量 × 3 個 row = **15 列**。原始輸出檔
|
| 467 |
> `results/verify_dequant.txt` 早先印成 21 列,但其中 `blk.0.ffn_down_exps` 與
|
| 468 |
> `blk.26.ffn_down_exps` 各被重��印了一次(每個 3 列,共 6 列重複),
|
| 469 |
+
> 所以「21/21」是重複計數造成的,不是真的做了 21 次獨立比對。
|
| 470 |
+
>
|
| 471 |
+
> ✅ **2026-10-12:根因已修掉(先前只改了結果檔,腳本沒動)**。
|
| 472 |
+
> 根因是 `verify_dequant_dsv4.py` 把 `TARGETS` 寫成一張「張量後綴」清單,
|
| 473 |
+
> 然後外層 `for il in (0, 26)` 把整張清單套用到**兩層**;而 layer 0 與 layer 26
|
| 474 |
+
> 的 `ffn_down_exps` 都是 MXFP4(39),所以那 3 列被比對了兩次 → 印 21 列、實際 15 列。
|
| 475 |
+
> 已改成 `(層, 後綴, 型別, 元素數)` 逐項寫死,並加上兩道防呆:
|
| 476 |
+
> 張量不存在或型別不符會直接 `SystemExit`(原本是 `continue` 靜靜跳過),
|
| 477 |
+
> 以及比對結束後檢查「列數 == 唯一張量數」,重複就直接報錯。
|
| 478 |
+
> 修完重跑輸出 **15/15 bit-exact**,與本節表格與 `results/verify_dequant.txt` 一致。
|
| 479 |
|
| 480 |
### 6.2 整個 expert 前向對照
|
| 481 |
|
|
|
|
| 523 |
改變數學」最直接的證據。逐檔 md5 見
|
| 524 |
[`results/moe_dump_bitexact.md`](results/moe_dump_bitexact.md)。
|
| 525 |
|
| 526 |
+
> ⚠️ **重要限定:387/387 是「這個 prompt」才有的結果,不是通則**(2026-10-12 複驗)。
|
| 527 |
+
> 把 §A 的設定整個照抄、只換 prompt 成 `The capital of France is`,
|
| 528 |
+
> 得到的**不是** 387/387,而是:
|
| 529 |
+
>
|
| 530 |
+
> | prompt | prefill bit-identical | decode bit-identical | 合計 |
|
| 531 |
+
> |---|---:|---:|---:|
|
| 532 |
+
> | `Explain mixture-of-experts routing in one sentence.`(§A 原文) | 43 / 43 | **344 / 344** | **387 / 387** |
|
| 533 |
+
> | `The capital of France is` | 43 / 43 | **0 / 344** | 43 / 387 |
|
| 534 |
+
>
|
| 535 |
+
> 兩邊都是 `--ram-budget-mb 4096` vs `32768`、其餘設定完全相同。
|
| 536 |
+
> 第一列**精確重現**了 §A 的 387/387,所以 §A 本身沒有問題。
|
| 537 |
+
> 第二列說明:換成 top-1/top-2 本來就幾乎並列的 prompt,decode 期就會分岔。
|
| 538 |
+
> 分岔點同樣在**第一個 decode call** 就出現(`d.0.43`,也就是 layer 0 的第 1 次
|
| 539 |
+
> decode),此時 `cur` 的 `max|Δ|` 相對值已經是 2.1(不是微小浮點雜訊),
|
| 540 |
+
> `ids` 也跟著換成別組 expert。
|
| 541 |
+
>
|
| 542 |
+
> 合理的解釋是:prefill 結束後的 logits 有極小差異 → `--temp 0` 的 argmax 換成
|
| 543 |
+
> 另一個同義 token → 後續 decode 的輸入 `cur` 整條岔開。這與 6.4 節的結論一致
|
| 544 |
+
> (分歧來自 llama.cpp 的 decode 期 dsv4 CSA/HCA 路徑,不是 SDQ 的分頁)。
|
| 545 |
+
>
|
| 546 |
+
> 所以這節標題「分頁結果與 arena 大小無關」要這樣讀:
|
| 547 |
+
> **對這個 prompt 成立;對 top-1/top-2 接近的 prompt 不成立。**
|
| 548 |
+
> 引用 387/387 這個數字時必須連 prompt 一起引用,否則會被誤讀成端到端通則。
|
| 549 |
+
|
| 550 |
另外同一設定重跑 6 次、兩個 RAM 預算各 6 次,greedy(`--temp 0`)輸出
|
| 551 |
**12/12 逐字相同**(`results/determinism.txt`)。
|
| 552 |
|
|
|
|
| 562 |
`SDQ_IO_SPLIT=2`、`-c`、`-b`),第一個 token 就會換。`-t 1`(完全單執行緒)
|
| 563 |
也一樣會換,所以不是執行緒競爭。
|
| 564 |
|
| 565 |
+
> ⚠️ **`--ram-budget-mb` 也要加進這份清單(2026-10-12 複驗新增)**。
|
| 566 |
+
> 本來這份清單裡沒有 RAM 預算,本 repo 的 `results/determinism.txt` 也顯示
|
| 567 |
+
> 8192 MB 與 32768 MB 兩個預算**輸出相同**(同為 `0e637837ac89`)。
|
| 568 |
+
> 但在本機用 4.2 的可攜編譯選項重跑,每個預算**各自**仍是 6/6 逐字相同,
|
| 569 |
+
> **兩個預算彼此卻不同**:
|
| 570 |
+
>
|
| 571 |
+
> | build | 8192 MB | 32768 MB | 是否相同 |
|
| 572 |
+
> |---|---|---|---|
|
| 573 |
+
> | 可攜 ISA(第 4.2 節) | `08c061788823` | `175b890dddeb` | **不同** |
|
| 574 |
+
> | `-march=native -mno-amx-*` | `d5cf2396b424` | `54a418d53304` | **不同** |
|
| 575 |
+
>
|
| 576 |
+
> 兩種 build 都一樣,所以**不是編譯選項造成的**(原本懷疑是,已排除)。
|
| 577 |
+
> 實際內容:8192 MB 給出 `capital of France is **Paris**.`,
|
| 578 |
+
> 32768 MB 給出 `'m sorry, I can't answer that question.`。
|
| 579 |
+
> 配合 6.3 節新加的限定表,這是同一件事的兩種表現:
|
| 580 |
+
> **arena 大小會改變 decode 期的 I/O 時序,而這個 prompt 的 top-1/top-2
|
| 581 |
+
> 幾乎並列,於是 argmax 換掉、輸出整段岔開。**
|
| 582 |
+
>
|
| 583 |
+
> 換句話說,`determinism.txt` 那份「兩個預算 md5 相同」的結果,
|
| 584 |
+
> 在本機**無法重現**;能重現的只有「同一預算內 6/6 相同」這個部分
|
| 585 |
+
> (本機兩個 build、兩個預算都成立,合計 24/24)。
|
| 586 |
+
> 要引用時請照這個範圍引用,不要說「RAM 預算不影響輸出」。
|
| 587 |
+
|
| 588 |
**而且分歧點已經定位到**:把兩種設定的 MoE dump 逐一比對(43 層 × 17 次 op call
|
| 589 |
= 731 個檔案),**43 個 prefill 呼叫全部 bit-identical、688 個 decode 呼叫全部不同**
|
| 590 |
(`results/moe_dump_bitexact.md` §B)。分歧已經出現在 MoE op 的**輸入** `cur` 裡,
|
|
|
|
| 632 |
verify_moe_forward.txt expert 前向 vs 純 NumPy 的逐筆輸出(10/10 PASS)
|
| 633 |
moe_dump_bitexact.md MoE op 的 bit-exact A/B(387/387 與分歧點定位)
|
| 634 |
determinism.txt 決定性探針(同一設定重跑 6 次 × 2 個預算)
|
| 635 |
+
--- 以下為 2026-10-12 獨立複驗新增(原始結果未被覆蓋) ---
|
| 636 |
+
memory_levels_dsv4-4-8-16-32g-recheck.json / .md
|
| 637 |
+
用 4.2 可攜 ISA 選項重跑整個 4/8/16/32 GiB 矩陣
|
| 638 |
+
determinism_recheck.txt 決定性探針 × 2 種 build(證明編譯選項非成因)
|
| 639 |
+
moe_dump_recheck_prompt_dependence.md
|
| 640 |
+
6.3 的 387/387 為何是 prompt 專屬(含對照表)
|
| 641 |
+
verify_dequant_recheck.txt 修正後 verify_dequant_dsv4.py 的 15/15 輸出
|
| 642 |
```
|
| 643 |
|
| 644 |
### 重跑驗證
|
|
|
|
| 652 |
# (2) expert 前向(先跑 sdq-chat --selftest 產生 /tmp/st_l*e*.bin,見 6.2)
|
| 653 |
DSV4_LIMIT=10 DSV4_MODE=1 python3 sdq-dsv4/verify_moe_dsv4.py
|
| 654 |
|
| 655 |
+
# (3) 決定性探針(同一設定重跑 N 次比對輸出)
|
| 656 |
bash sdq-dsv4/determinism_probe.sh 8192 32768
|
| 657 |
+
|
| 658 |
+
# (4) MoE op bit-exact A/B:同一設定、只改 --ram-budget-mb,各 dump 一次再逐檔 cmp
|
| 659 |
+
# 見 6.3 / results/moe_dump_bitexact.md
|
| 660 |
+
for mb in 4096 32768; do
|
| 661 |
+
rm -rf /tmp/moe_$mb && mkdir -p /tmp/moe_$mb
|
| 662 |
+
SDQ_MOE_DUMP=/tmp/moe_$mb/d SDQ_RESERVE_MB=2048 \
|
| 663 |
+
./build/bin/sdq-chat -m $MODEL \
|
| 664 |
+
-p "Explain mixture-of-experts routing in one sentence." -n 8 -c 2048 -t 16 -b 128 \
|
| 665 |
+
--temp 0 --ram-budget-mb $mb --no-interactive >/dev/null 2>&1
|
| 666 |
+
done
|
| 667 |
+
diff -r --brief /tmp/moe_4096 /tmp/moe_32768 && echo "387/387 bit-identical"
|
| 668 |
```
|
| 669 |
|
| 670 |
+
> ⚠️ **(4) 的結論強烈依賴 prompt**,請見 6.3 節的限定表:換成
|
| 671 |
+
> `The capital of France is` 只會得到 prefill 43/43、decode 0/344。
|
| 672 |
+
|
| 673 |
---
|
| 674 |
|
| 675 |
## 8. 授權
|
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### determinism — re-verification 2026-10-12
|
| 2 |
+
|
| 3 |
+
```
|
| 4 |
+
### build A: portable ISA flags (README section 4.2)
|
| 5 |
+
=== ram-budget 8192 MB × 6 ===
|
| 6 |
+
run 1: 08c061788823
|
| 7 |
+
run 2: 08c061788823
|
| 8 |
+
run 3: 08c061788823
|
| 9 |
+
run 4: 08c061788823
|
| 10 |
+
run 5: 08c061788823
|
| 11 |
+
run 6: 08c061788823
|
| 12 |
+
distinct outputs: 1 / 6
|
| 13 |
+
6 08c061788823b08e328fd862bf0af9af
|
| 14 |
+
=== ram-budget 32768 MB × 6 ===
|
| 15 |
+
run 1: 175b890dddeb
|
| 16 |
+
run 2: 175b890dddeb
|
| 17 |
+
run 3: 175b890dddeb
|
| 18 |
+
run 4: 175b890dddeb
|
| 19 |
+
run 5: 175b890dddeb
|
| 20 |
+
run 6: 175b890dddeb
|
| 21 |
+
distinct outputs: 1 / 6
|
| 22 |
+
6 175b890dddebb91cce0bd2cd9c28e193
|
| 23 |
+
|
| 24 |
+
### build B: -march=native -mno-amx-int8 -mno-amx-tile -mno-amx-bf16
|
| 25 |
+
=== ram-budget 8192 MB × 6 ===
|
| 26 |
+
run 1: d5cf2396b424
|
| 27 |
+
run 2: d5cf2396b424
|
| 28 |
+
run 3: d5cf2396b424
|
| 29 |
+
run 4: d5cf2396b424
|
| 30 |
+
run 5: d5cf2396b424
|
| 31 |
+
run 6: d5cf2396b424
|
| 32 |
+
distinct outputs: 1 / 6
|
| 33 |
+
6 d5cf2396b4240a393092d3a2b2456900
|
| 34 |
+
=== ram-budget 32768 MB × 6 ===
|
| 35 |
+
run 1: 54a418d53304
|
| 36 |
+
run 2: 54a418d53304
|
| 37 |
+
run 3: 54a418d53304
|
| 38 |
+
run 4: 54a418d53304
|
| 39 |
+
run 5: 54a418d53304
|
| 40 |
+
run 6: 54a418d53304
|
| 41 |
+
distinct outputs: 1 / 6
|
| 42 |
+
6 54a418d533041aa9af313eff8b01bc33
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
#### What this shows
|
| 46 |
+
|
| 47 |
+
1. Within a single fixed configuration the greedy (--temp 0) output is
|
| 48 |
+
reproducible: 6/6 identical runs at 8192 MB and 6/6 at 32768 MB, in BOTH
|
| 49 |
+
builds (24/24). This reproduces results/determinism.txt.
|
| 50 |
+
|
| 51 |
+
2. NEW, NOT reproducible: the published determinism.txt reports the SAME
|
| 52 |
+
md5 for 8192 MB and 32768 MB (0e637837ac89). Here the two budgets differ
|
| 53 |
+
in both builds. So --ram-budget-mb belongs on the list of knobs that
|
| 54 |
+
perturb decode output (README section 6.4), which previously omitted it.
|
| 55 |
+
|
| 56 |
+
3. The compile flags were the obvious suspect and are EXCLUDED: builds A and B
|
| 57 |
+
disagree with each other too, and neither reproduces 0e637837ac89.
|
| 58 |
+
|
| 59 |
+
4. Content at 8192 MB: 'capital of France is **Paris**.'
|
| 60 |
+
Content at 32768 MB: "'m sorry, I can't answer that question."
|
| 61 |
+
Consistent with the README 6.4 analysis: this prompt's top-1/top-2 are
|
| 62 |
+
nearly tied, so the argmax flips. Same config -> same answer, always.
|
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_id": "DeepSeek-V4-Flash-0731-UD-IQ4_NL",
|
| 3 |
+
"model_repo": "unsloth/DeepSeek-V4-Flash-0731-GGUF",
|
| 4 |
+
"model_subdir": "UD-IQ4_NL",
|
| 5 |
+
"architecture": "deepseek4",
|
| 6 |
+
"shards": 4,
|
| 7 |
+
"model_bytes": 136662446656,
|
| 8 |
+
"host": {
|
| 9 |
+
"cpu_model": "Intel(R) Xeon(R) Platinum 8559C",
|
| 10 |
+
"cpu_threads": 192,
|
| 11 |
+
"mem_total_bytes": 2147448107008
|
| 12 |
+
},
|
| 13 |
+
"method": "RAM budget passed to the SDQ expert pager arena sizing; no hard cgroup limit (host /sys/fs/cgroup is read-only). Page cache dropped before each run where permitted.",
|
| 14 |
+
"settings": {
|
| 15 |
+
"levels_gib": [
|
| 16 |
+
4,
|
| 17 |
+
8,
|
| 18 |
+
16,
|
| 19 |
+
32
|
| 20 |
+
],
|
| 21 |
+
"repeat": 2,
|
| 22 |
+
"ctx": 2048,
|
| 23 |
+
"ubatch": 128,
|
| 24 |
+
"threads": 16,
|
| 25 |
+
"n_predict": 48,
|
| 26 |
+
"reserve_mb": 2048,
|
| 27 |
+
"temp": 0
|
| 28 |
+
},
|
| 29 |
+
"results": [
|
| 30 |
+
{
|
| 31 |
+
"level_mb": 4096,
|
| 32 |
+
"level_gib": 4,
|
| 33 |
+
"repeat": 1,
|
| 34 |
+
"prompt": "The capital of France is",
|
| 35 |
+
"wall_s": 91.45,
|
| 36 |
+
"decode_tok_s": 0.6,
|
| 37 |
+
"decode_tok": 47,
|
| 38 |
+
"prefill_tok_s": 1.6,
|
| 39 |
+
"prefill_tok": 22,
|
| 40 |
+
"peak_rss_mb": 2232,
|
| 41 |
+
"final_rss_mb": 2232,
|
| 42 |
+
"vmswap_mb": 0,
|
| 43 |
+
"arena_gib": 1.79,
|
| 44 |
+
"n_slots": 164,
|
| 45 |
+
"total_ssd_gb": 158.76,
|
| 46 |
+
"decode_ssd_mb": 138385.1,
|
| 47 |
+
"ssd_mb_per_token": 2944.4,
|
| 48 |
+
"expert_requests": 14551,
|
| 49 |
+
"expert_hits": 0,
|
| 50 |
+
"hot_rate_pct": 0,
|
| 51 |
+
"cold_rate_pct": 100.0,
|
| 52 |
+
"evictions": 14387,
|
| 53 |
+
"per_layer_hit_min": 0,
|
| 54 |
+
"per_layer_hit_max": 0,
|
| 55 |
+
"assistant": "capital of France is **Paris**.<|end▁of▁sentence|> of * {@link ListenerRule#getCondition()}. If omitted, the default action is * {@code forward}. For use with custom listener. For more information, in"
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"level_mb": 4096,
|
| 59 |
+
"level_gib": 4,
|
| 60 |
+
"repeat": 2,
|
| 61 |
+
"prompt": "請用一句話說明什麼是 SSD 快取。",
|
| 62 |
+
"wall_s": 84.45,
|
| 63 |
+
"decode_tok_s": 0.69,
|
| 64 |
+
"decode_tok": 47,
|
| 65 |
+
"prefill_tok_s": 1.7,
|
| 66 |
+
"prefill_tok": 29,
|
| 67 |
+
"peak_rss_mb": 2233,
|
| 68 |
+
"final_rss_mb": 2233,
|
| 69 |
+
"vmswap_mb": 0,
|
| 70 |
+
"arena_gib": 1.79,
|
| 71 |
+
"n_slots": 164,
|
| 72 |
+
"total_ssd_gb": 165.11,
|
| 73 |
+
"decode_ssd_mb": 138388.2,
|
| 74 |
+
"ssd_mb_per_token": 2944.4,
|
| 75 |
+
"expert_requests": 15133,
|
| 76 |
+
"expert_hits": 0,
|
| 77 |
+
"hot_rate_pct": 0,
|
| 78 |
+
"cold_rate_pct": 100.0,
|
| 79 |
+
"evictions": 14969,
|
| 80 |
+
"per_layer_hit_min": 0,
|
| 81 |
+
"per_layer_hit_max": 0,
|
| 82 |
+
"assistant": "SSD 快取是使用固態硬碟作為高速暫存區,將頻繁存取的資料預先儲存以加速系統回應的技術。<|end▁of▁sentence|> of * {@link ListenerRule#getCondition"
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"level_mb": 8192,
|
| 86 |
+
"level_gib": 8,
|
| 87 |
+
"repeat": 1,
|
| 88 |
+
"prompt": "The capital of France is",
|
| 89 |
+
"wall_s": 52.17,
|
| 90 |
+
"decode_tok_s": 1.31,
|
| 91 |
+
"decode_tok": 47,
|
| 92 |
+
"prefill_tok_s": 1.6,
|
| 93 |
+
"prefill_tok": 22,
|
| 94 |
+
"peak_rss_mb": 6325,
|
| 95 |
+
"final_rss_mb": 6325,
|
| 96 |
+
"vmswap_mb": 0,
|
| 97 |
+
"arena_gib": 5.79,
|
| 98 |
+
"n_slots": 531,
|
| 99 |
+
"total_ssd_gb": 93.86,
|
| 100 |
+
"decode_ssd_mb": 71924.1,
|
| 101 |
+
"ssd_mb_per_token": 1530.3,
|
| 102 |
+
"expert_requests": 14551,
|
| 103 |
+
"expert_hits": 5946,
|
| 104 |
+
"hot_rate_pct": 40.8632,
|
| 105 |
+
"cold_rate_pct": 59.1368,
|
| 106 |
+
"evictions": 8074,
|
| 107 |
+
"per_layer_hit_min": 3.14136,
|
| 108 |
+
"per_layer_hit_max": 55.0898,
|
| 109 |
+
"assistant": "capital of France is **Paris**.<|end▁of▁sentence|> of * {@link ListenerRule#getCondition()}. If omitted, the default action is * {@code forward}. For use with custom listener. For more information, in"
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"level_mb": 8192,
|
| 113 |
+
"level_gib": 8,
|
| 114 |
+
"repeat": 2,
|
| 115 |
+
"prompt": "請用一句話說明什麼是 SSD 快取。",
|
| 116 |
+
"wall_s": 50.58,
|
| 117 |
+
"decode_tok_s": 1.5,
|
| 118 |
+
"decode_tok": 47,
|
| 119 |
+
"prefill_tok_s": 1.8,
|
| 120 |
+
"prefill_tok": 29,
|
| 121 |
+
"peak_rss_mb": 6325,
|
| 122 |
+
"final_rss_mb": 6325,
|
| 123 |
+
"vmswap_mb": 0,
|
| 124 |
+
"arena_gib": 5.79,
|
| 125 |
+
"n_slots": 531,
|
| 126 |
+
"total_ssd_gb": 92.34,
|
| 127 |
+
"decode_ssd_mb": 63877.3,
|
| 128 |
+
"ssd_mb_per_token": 1359.1,
|
| 129 |
+
"expert_requests": 15133,
|
| 130 |
+
"expert_hits": 6663,
|
| 131 |
+
"hot_rate_pct": 44.0296,
|
| 132 |
+
"cold_rate_pct": 55.9704,
|
| 133 |
+
"evictions": 7939,
|
| 134 |
+
"per_layer_hit_min": 3.64964,
|
| 135 |
+
"per_layer_hit_max": 62.4277,
|
| 136 |
+
"assistant": "SSD 快取是使用固態硬碟作為高速暫存區,將頻繁存取的資料預先儲存以加速系統回應的技術。<|end▁of▁sentence|> of * {@link ListenerRule#getCondition"
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"level_mb": 16384,
|
| 140 |
+
"level_gib": 16,
|
| 141 |
+
"repeat": 1,
|
| 142 |
+
"prompt": "The capital of France is",
|
| 143 |
+
"wall_s": 53.04,
|
| 144 |
+
"decode_tok_s": 1.49,
|
| 145 |
+
"decode_tok": 47,
|
| 146 |
+
"prefill_tok_s": 1.7,
|
| 147 |
+
"prefill_tok": 22,
|
| 148 |
+
"peak_rss_mb": 14507,
|
| 149 |
+
"final_rss_mb": 14507,
|
| 150 |
+
"vmswap_mb": 0,
|
| 151 |
+
"arena_gib": 13.79,
|
| 152 |
+
"n_slots": 1264,
|
| 153 |
+
"total_ssd_gb": 71.54,
|
| 154 |
+
"decode_ssd_mb": 49075.9,
|
| 155 |
+
"ssd_mb_per_token": 1044.2,
|
| 156 |
+
"expert_requests": 14551,
|
| 157 |
+
"expert_hits": 7987,
|
| 158 |
+
"hot_rate_pct": 54.8897,
|
| 159 |
+
"cold_rate_pct": 45.1103,
|
| 160 |
+
"evictions": 5300,
|
| 161 |
+
"per_layer_hit_min": 15.1832,
|
| 162 |
+
"per_layer_hit_max": 69.906,
|
| 163 |
+
"assistant": "'m sorry, I can't answer that question. I'm an AI assistant designed to provide helpful and harmless responses.<|end▁of▁sentence|> of * {@link ListenerRule#getCondition()}. If omitted, the default act"
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"level_mb": 16384,
|
| 167 |
+
"level_gib": 16,
|
| 168 |
+
"repeat": 2,
|
| 169 |
+
"prompt": "請用一句話說明什麼是 SSD 快取。",
|
| 170 |
+
"wall_s": 51.11,
|
| 171 |
+
"decode_tok_s": 1.75,
|
| 172 |
+
"decode_tok": 47,
|
| 173 |
+
"prefill_tok_s": 1.8,
|
| 174 |
+
"prefill_tok": 29,
|
| 175 |
+
"peak_rss_mb": 14507,
|
| 176 |
+
"final_rss_mb": 14507,
|
| 177 |
+
"vmswap_mb": 0,
|
| 178 |
+
"arena_gib": 13.79,
|
| 179 |
+
"n_slots": 1264,
|
| 180 |
+
"total_ssd_gb": 74.52,
|
| 181 |
+
"decode_ssd_mb": 45626.5,
|
| 182 |
+
"ssd_mb_per_token": 970.8,
|
| 183 |
+
"expert_requests": 15133,
|
| 184 |
+
"expert_hits": 8298,
|
| 185 |
+
"hot_rate_pct": 54.8338,
|
| 186 |
+
"cold_rate_pct": 45.1662,
|
| 187 |
+
"evictions": 5571,
|
| 188 |
+
"per_layer_hit_min": 16.3415,
|
| 189 |
+
"per_layer_hit_max": 66.474,
|
| 190 |
+
"assistant": "SSD 快取是使用固態硬碟作為高速暫存區,將頻繁存取的資料預先儲存以加速系統回應的技術。<|end▁of▁sentence|> of * {@link ListenerRule#getCondition"
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"level_mb": 32768,
|
| 194 |
+
"level_gib": 32,
|
| 195 |
+
"repeat": 1,
|
| 196 |
+
"prompt": "The capital of France is",
|
| 197 |
+
"wall_s": 56.59,
|
| 198 |
+
"decode_tok_s": 1.88,
|
| 199 |
+
"decode_tok": 47,
|
| 200 |
+
"prefill_tok_s": 1.8,
|
| 201 |
+
"prefill_tok": 22,
|
| 202 |
+
"peak_rss_mb": 30894,
|
| 203 |
+
"final_rss_mb": 30894,
|
| 204 |
+
"vmswap_mb": 0,
|
| 205 |
+
"arena_gib": 29.79,
|
| 206 |
+
"n_slots": 2732,
|
| 207 |
+
"total_ssd_gb": 55.6,
|
| 208 |
+
"decode_ssd_mb": 32746.2,
|
| 209 |
+
"ssd_mb_per_token": 696.7,
|
| 210 |
+
"expert_requests": 14551,
|
| 211 |
+
"expert_hits": 9453,
|
| 212 |
+
"hot_rate_pct": 64.9646,
|
| 213 |
+
"cold_rate_pct": 35.035399999999996,
|
| 214 |
+
"evictions": 2366,
|
| 215 |
+
"per_layer_hit_min": 41.3613,
|
| 216 |
+
"per_layer_hit_max": 71.5569,
|
| 217 |
+
"assistant": "<|end▁of▁sentence|> of * {@link ListenerRule#getCondition()}. If omitted, the default action is * {@code forward}. For use with custom listener. For more information, including * the valid values of"
|
| 218 |
+
},
|
| 219 |
+
{
|
| 220 |
+
"level_mb": 32768,
|
| 221 |
+
"level_gib": 32,
|
| 222 |
+
"repeat": 2,
|
| 223 |
+
"prompt": "請用一句話說明什麼是 SSD 快取。",
|
| 224 |
+
"wall_s": 66.17,
|
| 225 |
+
"decode_tok_s": 1.56,
|
| 226 |
+
"decode_tok": 47,
|
| 227 |
+
"prefill_tok_s": 1.9,
|
| 228 |
+
"prefill_tok": 29,
|
| 229 |
+
"peak_rss_mb": 30894,
|
| 230 |
+
"final_rss_mb": 30894,
|
| 231 |
+
"vmswap_mb": 0,
|
| 232 |
+
"arena_gib": 29.79,
|
| 233 |
+
"n_slots": 2732,
|
| 234 |
+
"total_ssd_gb": 61.14,
|
| 235 |
+
"decode_ssd_mb": 31923.0,
|
| 236 |
+
"ssd_mb_per_token": 679.2,
|
| 237 |
+
"expert_requests": 15133,
|
| 238 |
+
"expert_hits": 9526,
|
| 239 |
+
"hot_rate_pct": 62.9485,
|
| 240 |
+
"cold_rate_pct": 37.0515,
|
| 241 |
+
"evictions": 2875,
|
| 242 |
+
"per_layer_hit_min": 28.5366,
|
| 243 |
+
"per_layer_hit_max": 70.5202,
|
| 244 |
+
"assistant": "SSD 快取是使用固態硬碟作為高速暫存區,將頻繁存取的資料預先儲存以加速系統回應的技術。<|end▁of▁sentence|> of * {@link ListenerRule#getCondition"
|
| 245 |
+
}
|
| 246 |
+
]
|
| 247 |
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!--
|
| 2 |
+
獨立複驗(2026-10-12),非原始發布結果。
|
| 3 |
+
與 results/memory_levels_dsv4-4-8-16-32g.md 同一支 runner、同一台機器,
|
| 4 |
+
差別只有編譯選項:這一組是用 README 4.2 的可攜 ISA 選項
|
| 5 |
+
(-DGGML_NATIVE=OFF -DGGML_AVX512=ON ...)建的。
|
| 6 |
+
逐欄對照見 README 第 3 節。原始發布結果未被覆蓋,仍在原檔名。
|
| 7 |
+
-->
|
| 8 |
+
|
| 9 |
+
# RAM 預算矩陣:dsv4-4-8-16-32g
|
| 10 |
+
|
| 11 |
+
RAM budget passed to the SDQ expert pager arena sizing; no hard cgroup limit (host /sys/fs/cgroup is read-only). Page cache dropped before each run where permitted.
|
| 12 |
+
|
| 13 |
+
- Host: Intel(R) Xeon(R) Platinum 8559C, 192 threads
|
| 14 |
+
- ctx=2048, ubatch=128, threads=16, output tokens=48, temp=0, repeats=2
|
| 15 |
+
- KV/SSM state + compute reserve: 2048 MB
|
| 16 |
+
|
| 17 |
+
| RAM budget | arena (GiB) | slots | decode tok/s | prefill tok/s | hot % | cold % | SSD MiB/tok | total SSD read | peak RSS (MB) | swap | per-layer hit min..max |
|
| 18 |
+
|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
| 19 |
+
| 4 GiB | 1.79 | 164 | 0.65 | 1.65 | 0.0 | 100.0 | 2944.4 | 161.9 GB | 2232 | 0 MB | 0.0..0.0 |
|
| 20 |
+
| 8 GiB | 5.79 | 531 | 1.41 | 1.70 | 42.4 | 57.6 | 1444.7 | 93.1 GB | 6325 | 0 MB | 3.4..58.8 |
|
| 21 |
+
| 16 GiB | 13.79 | 1264 | 1.62 | 1.75 | 54.9 | 45.1 | 1007.5 | 73.0 GB | 14507 | 0 MB | 15.8..68.2 |
|
| 22 |
+
| 32 GiB | 29.79 | 2732 | 1.72 | 1.85 | 64.0 | 36.0 | 688.0 | 58.4 GB | 30894 | 0 MB | 34.9..71.0 |
|
| 23 |
+
|
| 24 |
+
JSON: `memory_levels_dsv4-4-8-16-32g.json`
|
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### MoE op bit-exact A/B — re-verification 2026-10-12
|
| 2 |
+
|
| 3 |
+
Identical command in both rows; the ONLY difference is `--ram-budget-mb 4096`
|
| 4 |
+
vs `32768`. Build = portable ISA flags (README 4.2), `-n 8`, `ctx=2048`,
|
| 5 |
+
`ubatch=128`, `-t 16`, `--temp 0`. 43 layers x 9 op calls = 387 files per side.
|
| 6 |
+
|
| 7 |
+
| prompt | prefill bit-identical | decode bit-identical | total |
|
| 8 |
+
|---|---:|---:|---:|
|
| 9 |
+
| `Explain mixture-of-experts routing in one sentence.` (published section A) | **43 / 43** | **344 / 344** | **387 / 387** |
|
| 10 |
+
| `The capital of France is` | **43 / 43** | **0 / 344** | **43 / 387** |
|
| 11 |
+
|
| 12 |
+
## Reading
|
| 13 |
+
|
| 14 |
+
* Row 1 **exactly reproduces** the published `results/moe_dump_bitexact.md`
|
| 15 |
+
section A (387/387). Section A itself is sound and was not wrong.
|
| 16 |
+
* Row 2 is the correction: 387/387 is **prompt-specific**, not a general
|
| 17 |
+
property of the pager. With a prompt whose top-1/top-2 are nearly tied,
|
| 18 |
+
only prefill stays bit-exact and every decode call diverges.
|
| 19 |
+
|
| 20 |
+
* Row 1 first diverging decode call: none (all 344 identical)
|
| 21 |
+
* Row 2 first diverging decode call: layer 0, decode #1 (`d.0.43`)
|
| 22 |
+
* expert `ids` identical at that point: **False**
|
| 23 |
+
* `cur` max|delta| / max|cur| = **2.12**
|
| 24 |
+
|
| 25 |
+
Row 2's divergence is not floating-point noise: at the very FIRST decode step
|
| 26 |
+
`cur` already differs by a relative max of ~2.1 and the routed expert `ids`
|
| 27 |
+
have switched. Prefill was bit-identical, so the chain is: prefill logits
|
| 28 |
+
differ infinitesimally -> `--temp 0` argmax picks a different near-tied token
|
| 29 |
+
-> every later decode input is a different sequence. This matches the
|
| 30 |
+
README 6.4 conclusion that the instability lives in llama.cpp's decode-phase
|
| 31 |
+
dsv4 CSA/HCA path, not in SDQ's paging.
|
| 32 |
+
|
| 33 |
+
Consequence for citation: always quote 387/387 **together with the prompt**.
|
| 34 |
+
It is not an end-to-end guarantee.
|
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### dequant bit-exactness — re-verification 2026-10-12
|
| 2 |
+
|
| 3 |
+
Same host/build as the published results. Output of the FIXED
|
| 4 |
+
verify_dequant_dsv4.py: 5 tensors x 3 rows = 15 unique comparisons.
|
| 5 |
+
|
| 6 |
+
The pre-fix script printed 21 rows (6 redundant, because TARGETS was one flat
|
| 7 |
+
suffix list applied to BOTH layer 0 and layer 26, and ffn_down_exps is MXFP4 in
|
| 8 |
+
both) and self-reported "21/21". After the fix the script and the published
|
| 9 |
+
results/verify_dequant.txt agree at 15/15.
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
blk.0.ffn_gate_exps.weight type=21 row=0 max|NumPy - ggml| = 0 EXACT
|
| 13 |
+
blk.0.ffn_gate_exps.weight type=21 row=1 max|NumPy - ggml| = 0 EXACT
|
| 14 |
+
blk.0.ffn_gate_exps.weight type=21 row=137 max|NumPy - ggml| = 0 EXACT
|
| 15 |
+
blk.0.ffn_up_exps.weight type=21 row=0 max|NumPy - ggml| = 0 EXACT
|
| 16 |
+
blk.0.ffn_up_exps.weight type=21 row=1 max|NumPy - ggml| = 0 EXACT
|
| 17 |
+
blk.0.ffn_up_exps.weight type=21 row=137 max|NumPy - ggml| = 0 EXACT
|
| 18 |
+
blk.0.ffn_down_exps.weight type=39 row=0 max|NumPy - ggml| = 0 EXACT
|
| 19 |
+
blk.0.ffn_down_exps.weight type=39 row=1 max|NumPy - ggml| = 0 EXACT
|
| 20 |
+
blk.0.ffn_down_exps.weight type=39 row=137 max|NumPy - ggml| = 0 EXACT
|
| 21 |
+
blk.26.ffn_gate_exps.weight type=39 row=0 max|NumPy - ggml| = 0 EXACT
|
| 22 |
+
blk.26.ffn_gate_exps.weight type=39 row=1 max|NumPy - ggml| = 0 EXACT
|
| 23 |
+
blk.26.ffn_gate_exps.weight type=39 row=137 max|NumPy - ggml| = 0 EXACT
|
| 24 |
+
blk.26.ffn_down_exps.weight type=39 row=0 max|NumPy - ggml| = 0 EXACT
|
| 25 |
+
blk.26.ffn_down_exps.weight type=39 row=1 max|NumPy - ggml| = 0 EXACT
|
| 26 |
+
blk.26.ffn_down_exps.weight type=39 row=137 max|NumPy - ggml| = 0 EXACT
|
| 27 |
+
|
| 28 |
+
15/15 bit-exact
|
| 29 |
+
ALL BIT-EXACT
|
| 30 |
+
```
|
|
@@ -8,8 +8,24 @@
|
|
| 8 |
# 本來就不決定
|
| 9 |
# 兩者必須分開,否則 README 上寫什麼都沒有意義。
|
| 10 |
set -u
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
PROMPT=${PROMPT:-"The capital of France is"}
|
| 14 |
NTOK=${NTOK:-16}
|
| 15 |
N=${N:-6}
|
|
|
|
| 8 |
# 本來就不決定
|
| 9 |
# 兩者必須分開,否則 README 上寫什麼都沒有意義。
|
| 10 |
set -u
|
| 11 |
+
# 預設值不要綁死某台機器的路徑:先用環境變數,否則在 repo 根目錄往上下找。
|
| 12 |
+
# BIN = sdq-chat 執行檔(build/bin/sdq-chat)
|
| 13 |
+
# MODEL = shard 1(metadata-only 的那個 shard,pager 會自己串另外三個)
|
| 14 |
+
# 三者都可以用環境變數覆寫。
|
| 15 |
+
BIN=${BIN:-}
|
| 16 |
+
MODEL=${MODEL:-}
|
| 17 |
+
if [ -z "$BIN" ]; then
|
| 18 |
+
BIN=$(ls -1 ./llama.cpp/build/bin/sdq-chat ./build/bin/sdq-chat 2>/dev/null | head -1)
|
| 19 |
+
fi
|
| 20 |
+
if [ -z "$MODEL" ]; then
|
| 21 |
+
MODEL=$(ls -1 ./models/UD-IQ4_NL/*00001-of-00004.gguf 2>/dev/null | head -1)
|
| 22 |
+
fi
|
| 23 |
+
if [ -z "$BIN" ] || [ ! -x "$BIN" ]; then
|
| 24 |
+
echo "ERROR: 找不到 sdq-chat,請用 BIN=/path/to/sdq-chat 指定" >&2; exit 2
|
| 25 |
+
fi
|
| 26 |
+
if [ -z "$MODEL" ] || [ ! -f "$MODEL" ]; then
|
| 27 |
+
echo "ERROR: 找不到 GGUF shard 1,請用 MODEL=/path/to/*00001-of-00004.gguf 指定" >&2; exit 2
|
| 28 |
+
fi
|
| 29 |
PROMPT=${PROMPT:-"The capital of France is"}
|
| 30 |
NTOK=${NTOK:-16}
|
| 31 |
N=${N:-6}
|
|
@@ -24,12 +24,18 @@ import verify_moe_dsv4 as V # noqa: E402
|
|
| 24 |
GGML_DEQ = os.environ.get('GGML_DEQ', '/tmp/opencode/ggml_deq')
|
| 25 |
|
| 26 |
# (tensor suffix, ggml type id, 每列的元素數)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
TARGETS = [
|
| 28 |
-
('ffn_gate_exps.weight', 21, 4096),
|
| 29 |
-
('ffn_up_exps.weight', 21, 4096),
|
| 30 |
-
('ffn_down_exps.weight', 39, 2048),
|
| 31 |
-
('ffn_gate_exps.weight', 39, 4096), # MXFP4(layer 26 的 gate
|
| 32 |
-
('ffn_down_exps.weight', 39, 2048), # MXFP4(layer 26 的 down)
|
| 33 |
]
|
| 34 |
|
| 35 |
|
|
@@ -38,34 +44,39 @@ def main() -> int:
|
|
| 38 |
|
| 39 |
rows = []
|
| 40 |
all_ok = True
|
| 41 |
-
for il
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
print()
|
| 71 |
print('%d/%d bit-exact' % (sum(1 for r in rows if r[5]), len(rows)))
|
|
|
|
| 24 |
GGML_DEQ = os.environ.get('GGML_DEQ', '/tmp/opencode/ggml_deq')
|
| 25 |
|
| 26 |
# (tensor suffix, ggml type id, 每列的元素數)
|
| 27 |
+
# 每個項目都是「(層, 張量後綴, 預期 ggml 型別 id, 該列元素數)」。
|
| 28 |
+
#
|
| 29 |
+
# 這裡必須逐層寫死,不能寫成「一張 suffix 清單 + 外層 for il in (0, 26)」:
|
| 30 |
+
# 那樣子 ('ffn_down_exps.weight', 39, ...) 會同時被套用到 layer 0 與 layer 26,
|
| 31 |
+
# 而 layer 0 / layer 26 的 down_exps 都是 MXFP4(39) → 同一組位元組被比對兩次,
|
| 32 |
+
# 於是印出 21 列但只有 15 列是獨立比對(README 6.1 記錄的 6 列重複)。
|
| 33 |
TARGETS = [
|
| 34 |
+
(0, 'ffn_gate_exps.weight', 21, 4096), # IQ3_S(layer 0)
|
| 35 |
+
(0, 'ffn_up_exps.weight', 21, 4096), # IQ3_S(layer 0)
|
| 36 |
+
(0, 'ffn_down_exps.weight', 39, 2048), # MXFP4(layer 0)
|
| 37 |
+
(26, 'ffn_gate_exps.weight', 39, 4096), # MXFP4(layer 26 的 gate)
|
| 38 |
+
(26, 'ffn_down_exps.weight', 39, 2048), # MXFP4(layer 26 的 down)
|
| 39 |
]
|
| 40 |
|
| 41 |
|
|
|
|
| 44 |
|
| 45 |
rows = []
|
| 46 |
all_ok = True
|
| 47 |
+
for il, suffix, tt, n in TARGETS:
|
| 48 |
+
name = 'blk.%d.%s' % (il, suffix)
|
| 49 |
+
if name not in tensors:
|
| 50 |
+
raise SystemExit('tensor missing from GGUF: %s' % name)
|
| 51 |
+
si, off, dims, ttt = tensors[name]
|
| 52 |
+
if ttt != tt:
|
| 53 |
+
raise SystemExit('%s: expected ggml type %d, header says %d'
|
| 54 |
+
% (name, tt, ttt))
|
| 55 |
+
nrow = V.row_bytes(n, tt)
|
| 56 |
+
# 取該 (layer, tensor) 的第 0 個 expert 的前幾列
|
| 57 |
+
for row in (0, 1, 137):
|
| 58 |
+
byte_off = off + row * nrow
|
| 59 |
+
raw = V.SHARDS[si]
|
| 60 |
+
got = subprocess.run([GGML_DEQ, str(tt), raw, str(byte_off), str(n)],
|
| 61 |
+
capture_output=True, check=True).stdout
|
| 62 |
+
ref = np.frombuffer(got, dtype=np.float32)
|
| 63 |
+
# ggml_deq 讀的是整列(一個 weight 向量),NumPy 這邊用同一段
|
| 64 |
+
# 位元組還原 —— 兩邊必須對齊同一個 offset。
|
| 65 |
+
with open(raw, 'rb') as f:
|
| 66 |
+
f.seek(byte_off)
|
| 67 |
+
mine = V.dequant(f.read(nrow), n, tt)
|
| 68 |
+
assert ref.shape == mine.shape == (n,)
|
| 69 |
+
d = np.abs(ref - mine)
|
| 70 |
+
exact = bool(np.array_equal(ref, mine))
|
| 71 |
+
all_ok &= exact
|
| 72 |
+
rows.append((il, suffix, tt, row, float(d.max()), exact))
|
| 73 |
+
print('%-34s type=%-2d row=%-4d max|NumPy - ggml| = %g %s'
|
| 74 |
+
% (name, tt, row, d.max(), 'EXACT' if exact else 'MISMATCH'))
|
| 75 |
+
|
| 76 |
+
seen = {(r[0], r[1], r[2]) for r in rows}
|
| 77 |
+
if len(seen) != len(TARGETS):
|
| 78 |
+
raise SystemExit('duplicate comparisons: %d rows over %d unique tensors'
|
| 79 |
+
% (len(rows), len(seen)))
|
| 80 |
|
| 81 |
print()
|
| 82 |
print('%d/%d bit-exact' % (sum(1 for r in rows if r[5]), len(rows)))
|