openPangu-2.0-Flash-base Q3_K_M — EPQ 專家分頁
一套實驗性的 CPU 推論路徑:把未使用的 Mixture-of-Experts(MoE)權重留在 GGUF 檔案,推論時只把用到的 expert 讀進有界的 RAM arena,讓 40 GiB 的模型能在較小的 記憶體下推論。本 repo 不含模型權重。
一鍵啟動
只需要一條指令,腳本會自動 clone llama.cpp、套用 patch、編譯、下載模型、啟動
llama-server:
git clone https://huggingface.co/HelloSun/openPangu-2.0-Flash-base-Q3_K_M_EPQ
cd openPangu-2.0-Flash-base-Q3_K_M_EPQ
./serve.sh
完成後伺服器在 http://localhost:22222。第一次會下載約 41 GiB 的模型並編譯,
之後再跑同一個指令即可直接啟動。
常用調整(環境變數):
RAM_BUDGET_MB=8192 PORT=8080 ./serve.sh # 更小的記憶體預算、換埠
EPQ_MODEL=/path/to/model.gguf ./serve.sh # 使用已下載的模型
只想做單一步驟時:
./serve.sh download # 只下載模型
./serve.sh build # 只編譯
./serve.sh run # 只啟動伺服器
模型資訊
- GGUF:
openPangu-2.0-Flash-base-Q3_K_M.gguf(43,729,887,872 bytes = 40.727 GiB) - 共 46 層,前 2 層 dense;44 層 MoE
- 每個 MoE 層 256 個 expert;每 token 使用 8 個;另有 1 個 shared expert
- Expert 投影:gate/up 為 Q3_K;down 為 Q4_K
- Expert 權重合計 39.10 GiB;單一 expert triplet = 3.55 MiB(3,727,360 bytes)
- Router:sigmoid gating、
expert_weights_norm=true、expert_weights_scale=2.5 - EPQ 以 expert triplet 為單位分頁;routing 與權重計算仍由 llama.cpp 負責
實驗環境
本 repo 的數據在下列 Docker 容器內實測(非模擬):
| 項目 | 實際可用值 |
|---|---|
| 平台 | Docker 容器(AWS;kernel 6.18.48-107.148.amzn2023.x86_64,Debian 13 trixie) |
| CPU | Intel Xeon Platinum 8559C;主機可見 192 個 logical CPU,cgroup 配額 16 CPUs(cpu.max 1600000/100000) |
| 記憶體 | 主機 MemTotal 約 2000 GiB;本容器 cgroup 上限 96.9 GiB(memory.max 104000000000 bytes) |
| Swap | 1.6 TiB(SwapTotal);所有量測 swap 增量為 0 |
| 磁碟 | overlay 7.9 TiB,可用約 2.2 TiB |
| GPU | 容器可見 8 個 /dev/nvidia0-7,但 NVML 初始化失敗 → 無法使用 GPU,全程 CPU |
程式以 prlimit --data 進一步施加 8/16/32 GiB 的匿名記憶體硬上限;下表即為在
這些上限下的實測結果。
記憶體與 decode 效能
以 Linux prlimit --data 施加硬性匿名記憶體上限。每級跑兩次,條件相同:ctx 2048、
ubatch 128、16 threads、greedy、生成 47 個 decode token。每輪 swap 均為 0。
| 匿名硬上限 | EPQ arena | 槽位 | 匿名 HWM | RSS HWM | decode tok/s(中位數) | prefill tok/s(中位數) | hot hit | SSD MiB / decode token |
|---|---|---|---|---|---|---|---|---|
| 8 GiB | 0.69 GiB | 199 | 2.13 GiB | 3.29 GiB | 1.59 | 5.0 | 0.00% | 1,282.2 |
| 16 GiB | 9.08 GiB | 2,616 | 10.52 GiB | 11.68 GiB | 4.88 | 3.9 | 66.79% | 255.6 |
| 32 GiB | 25.08 GiB | 7,225 | 26.52 GiB | 27.68 GiB | 4.89 | 2.1 | 74.84% | 131.9 |
openPangu 有約 7.1 GiB 的固定常駐量,因此 4 GiB 匿名上限不可行;本版最小可用
設定為 8 GiB。對照組未改的 upstream llama.cpp 需要單一 15.47 GiB 的匿名
CPU_REPACK 緩衝,在 8/16 GiB 上限下無法載入模型(EPQ 仍可推論);32 GiB 下
upstream 約 8.6 tok/s 但 RSS 約 55 GiB。完整量測、upstream 對照與 I/O 稽核見
results/report.md。
本機重現與最佳記憶體(2026-10-16)
上表為作者容器的量測。以下為另一台主機重跑的結果:Intel Xeon Platinum 8559C、16 threads、
主機記憶體約 2 TiB(與其他使用者共享)、無 cgroup 記憶體上限。模型為同一個
openPangu-2.0-Flash-base-Q3_K_M.gguf(43,729,887,872 bytes)。參數與上表一致:ctx 2048、
ubatch 128、16 threads、greedy、生成 47 個 decode token;每級 2 次。原始數據見
results/strict_memory_levels_rerun.json。
| 匿名硬上限 | EPQ arena (GiB) | 槽位 | 匿名 HWM (GiB) | RSS HWM (GiB) | decode tok/s(兩次) | decode 中位數 | prefill 中位數 | hot hit | evictions(第 1 次) | SSD MiB / decode token |
|---|---|---|---|---|---|---|---|---|---|---|
| 8 GiB | 0.69 | 199 | 2.13 | 3.29 | 1.59, 1.59 | 1.59 | 4.60 | 0.00% | 20,055 | 1,282.2 |
| 12 GiB | 5.08 | 1,464 | 6.52 | 7.69 | 3.80, 4.02 | 3.91 | 4.05 | 56.35% | 7,377 | 416.1 |
| 16 GiB | 9.08 | 2,616 | 10.52 | 11.68 | 4.46, 4.16 | 4.31 | 3.05 | 66.79% | 4,110 | 255.6 |
| 20 GiB | 13.08 | 3,768 | 14.52 | 15.68 | 4.89, 4.70 | 4.79 | 2.50 | 72.26% | 1,850 | 171.6 |
| 24 GiB | 17.08 | 4,920 | 18.51 | 19.68 | 4.61, 4.66 | 4.63 | 2.05 | 74.79% | 187 | 132.8 |
| 32 GiB | 25.08 | 7,225 | 26.52 | 27.68 | 3.70, 3.48 | 3.59 | 1.35 | 74.84% | 0 | 131.9 |
SDQ_RESERVE_MB 為 8 GiB 採 7400、其餘各級採 7000(6.84 GiB)。12、20、24 GiB 的值沿用 16、32 GiB 的換算:arena ≈ 上限 − 6.84 GiB − 0.08 GiB,與實測吻合。
六級皆 swap 為 0,且匿名峰值均低於上限。
結論
- 建議:20 GiB(
RAM_BUDGET_MB=20480)。 本機 decode 中位數 4.79 tok/s 為本次最高,RSS 峰值 15.68 GiB。 - 省記憶體:16 GiB(
RAM_BUDGET_MB=16384)。 decode 約為 20 GiB 的 90%(4.31 tok/s),RSS 峰值 11.68 GiB。 - 8 GiB 可執行但明顯變慢。 arena 只有 0.69 GiB,hot hit 為 0%,每 token 從 SSD 讀取約 1,282 MiB,decode 1.59 tok/s。
- 24 GiB 以上沒有收益。 24 GiB 時 evictions 已降到 187;32 GiB 時為 0,hit rate 與 24 GiB 相同(約 75%),decode 反而降到 3.59 tok/s。
- 32 GiB 下 evictions = 0,因此每次 miss 都是該 expert 第一次被載入。本次生成的 miss 次數為 5,095,即約 5,095 個不同 expert 被載入(全部 11,264 個中的一部分)。這部分的 miss 無法靠增加記憶體消除。
- prefill tok/s 隨 arena 增大而單調下降(4.60 → 1.35)。原因未查明,decode 數據不受此項直接影響。
注意
- 主機與其他使用者共享,同一設定單次結果的差異可達 20% 以上(16 GiB 冒煙測試另一次為 3.37 tok/s,與表中中位數 4.31 相差約 22%)。判讀以趨勢為主。
- 作者容器與本機的 32 GiB decode 差距(4.89 vs 3.59)可能來自主機負載,未進一步排查。
重現指令(需先依 serve.sh build 的步驟建置 llama.cpp/build/bin/sdq-chat;--evict-helper 預設為 /tmp/pagecache_resident,不存在時略過清快取步驟):
python3 strict_bench.py --model "$EPQ_MODEL" --shards "$EPQ_MODEL" \
--bin llama.cpp/build/bin/sdq-chat \
--levels-mb 8192 12288 16384 20480 24576 32768 --repeat 2 --threads 16 --ctx 2048 \
--ubatch 128 --n-predict 48 \
--reserve-map 8192:7400,12288:7000,16384:7000,20480:7000,24576:7000,32768:7000
正確性驗證
| 檢查 | 結果 |
|---|---|
| NumPy 反量化 vs ggml Q3_K/Q4_K | 36/36 完全相等(layer 2、5、20、45;expert 0、17、255) |
| 單 expert L2/L5/L20/L45 E17 | 全部 PASS;最大相對誤差 0.0135–0.0204;correlation ~0.9998 |
| 全層(真實 router)L2/L20/L45 | 全部 PASS;最大相對誤差 0.0048–0.0269;correlation ~0.9997–0.9998 |
驗證腳本:verify_dequant.py、verify_epq.py、verify_moe_layer.py。
檔案內容
serve.sh— 一鍵建置與啟動llama.cpp-openpangu-v0.7.0.diff、0001-epq-openpangu.patch— llama.cpp 整合src/sdq_*.{cpp,h}— EPQ 原始碼(沿用先前 EPQ 移植的內部命名)strict_bench.py、verify_*.py、watch_io.py、ggml_deq.cpp、pagecache_resident.cpp— 量測與驗證工具results/— 原始數據與報告
模型授權與使用條款依上游 openPangu 模型規定。
Model tree for HelloSun/openPangu-2.0-Flash-base-Q3_K_M_EPQ
Base model
openpangu/openPangu-2.0-Flash