SmallThinker4b / AGENTS.md
Auto Upload Agent
v10: model card 加上完整實測數據(記憶體/速度/SSD/權重組成);修 pager expert 總量高估 7% 的 bug
f279c31
|
Raw History Blame Contribute Delete
4.59 kB

AGENTS.md — 續作指引

這個檔案的存在理由:本機很不穩,agent 可能隨時崩潰。 無論你(人或 agent)從哪裡開始,只要 clone 這個 repo 並讀完本檔,就能接著做。

git clone https://huggingface.co/HelloSun/SmallThinker4b
cd SmallThinker4b
cat STATUS.md      # 進度真相來源,先讀這個
cat AGENTS.md      # 本檔

專案一句話

SmallThinker-4B-A0.6B-Instruct(Q4_K_M,2508 MiB,MoE 32 層 × 32 experts) 在 llama.cpp 上跑,熱的 expert 權重留在 RAM,冷的丟回 SSD。

最重要原則(聽到沒)

只要到能跑、能驗證的階段,就立刻上傳。後面每改到程式並編譯過,也要上傳。 本機十分不穩,你必須保存工作成果,並且假設 agent 崩潰後要能指定 repo 繼續工作。

./sync.sh "改了什麼"

git clone https://huggingface.co/HelloSun/SmallThinker4b 就能接著做。

硬約束

  1. 行程總 RSS(含 file-backed mmap 的權重頁)要受 RAM 預算約束。 只驗證匿名記憶體是不成立的 —— 權重頁會算進 RSS 且真的佔用系統 RAM。
  2. VmSwap = 0。
  3. 輸出必須與上游逐字相同。分頁只該影響「權重住哪裡」, 不該影響任何一個 token 的數值。

實測成果(validate/ab-test.json,all_passed: true): peak RSS 從上游的 2.565 GiB 降到 0.596 GiB(預算 256 MiB,−76.8%), swap 全程 0,冷權重真的從 SSD 重讀 2.3 GiB,輸出四種設定逐字相同。

已知的坑(不要重蹈)

完整清單在 STATUS.md 的「踩過的坑」表格,每一條都有實測證據。 最容易再犯的三個:

  1. -DGGML_CPU_REPACK=OFF 是硬性要求。開著時 ggml 把權重放進匿名緩衝區, madvise 會把它歸零,輸出變亂碼但行程看起來正常。
  2. init_mappings(!st::will_page(arch)) 這個 ! 不能拿掉。 它是整個機制裡最容易寫反的一行 —— 寫反的話 peak RSS 會變成 2.6 GiB, 但分頁統計看起來完全正常(sweep 有跑、帳面 resident 也對), 所以光看分頁統計抓不到。
  3. fscanf 讀 /proc/self/io 開頭要空格,否則 read_bytes 永遠是 0。
  4. will_page() 只能看 arch,不能看 enabled() —— init_mappings() 在權重載入之前跑,那時 register_model() 還沒被呼叫。

環境

本機(開發/驗證用):16 vCPU、MemTotal 約 2 TB、cgroup memory.max = 104 GB、 無 GPU。SSD 是 overlayfs。 換機器一定要用 tools/io_probe.py 重測讀取能力,tok/s 會跟著全變。

常用指令

# 完整流程
ST_HOME=~/.cache/smallthinker4b ./llama_server.sh --verify

# 只看參數
./llama_server.sh --plan

# A/B 驗證
python3 tools/ab_test.py --bin <llama-cli> --model <gguf> \
    --budget 1024 --budget 512 --out validate/ab-test.json

# 對照組(關分頁)
ST_PAGER=0 ./llama_server.sh

# 上傳
./sync.sh "改了什麼"

下一步(可選,非必要)

  1. I/O 預取:目前是 demand paging(第一次碰到缺頁才讀 SSD)。 可以在 sweep 裡對「下一個 token 極可能用到、但現在是冷的」expert 發 MADV_WILLNEED,讓 SSD 讀取與計算重疊。參考 sddqwen35a3b_v01 的結論: 它實測預取命中率 0%(相鄰 token 的 top-k 重疊率已達 70%,LRU 本來就留著), 所以不確定這邊有沒有價值 —— 要先量路由重疊率。
  2. KV cache 也放 SSD:ctx 拉到 32768 時 KV 是 128 MiB(f16), 目前是留在 RAM 的。要更省可以加 KV 檔案 mmap(llama.cpp 有 --kv-unified 與部分 lazy load 的機制可利用)。
  3. prefill 的工作集:prefill 會一次摸遍幾乎所有 expert,所以 prefill 階段 的峰值必然接近整個模型。要壓低只能限制 prefill 批次大小(-ub), 分批送 prompt。

常數(改模型就要改)

llama_server.sh 頂部。這些是模型事實,不是可調參數:

N_LAYER=32  N_EMBD=1536  N_EXPERT=32  N_EXPERT_USED=4  EXPERT_FFN=768
N_HEAD=12  N_HEAD_KV=2  KEY_LEN=128  VAL_LEN=128  MODEL_MAX_CTX=32768
MODEL_REPO=Tiiny/SmallThinker-4BA0.6B-Instruct-GGUF
MODEL_FILE=SmallThinker-4B-A0.6B-Instruct.Q4_K.gguf
MODEL_SIZE=2630212704
LLAMA_COMMIT=b9acf138a1e28ce1fc23b5a4fc4b12444b50f7ea

⚠️ EXPERT_BYTES 只是粗估(0.6 B/elem),因為 down_exps 逐層量化型別不同。 真正精確的數字由 st_pager.cpp 在載入時從 GGUF metadata 算出來並印出。