服務
fable-9b · V100:8600
健康 · HTTP 200
Qwopus-27B regen · V100:8900
無回應 (000)
V100 機櫃
背景產線
DSpark drafter 訓練 · DGX GB103773 / 13440 · 28.1%
1400 樣本子集 × 10 epoch,梯度累積 64。記憶體已打平,約 2.53 s / micro-step
DSpark target cache 建置 · DGX4948 / 5093 · 97.2%
已完成,4948 樣本 / 103GB
Qwopus-27B regen 資料生成 · V100 TP28931 / 8931 · 100.0%
可斷點續傳,供訓練資料擴量
吞吐量實測
9B-Q4_K_M · 64K · TP4×1人 · TQ-2bit s96
現行生產
107.5 tok/s
9B-Q4_K_M · 64K · TP2×1人 · TQ-2bit s96
90.5 tok/s
9B-Q4_K_M · 64K · 單卡×1人 · TQ-2bit s96
切換前
66.6 tok/s
9B-Q4_K_M · 64K · TP4×8人 · TQ-2bit s96
每人
60.3 tok/s
27B-Q4_0 · 8K · TP2×1人 · KV auto
37.2 tok/s
27B-Q4_0 · 8K · TP2×4人 · KV auto
每人
22.5 tok/s
0每使用者 tok/s108
併發曲線
| 配置 | 1 人 | 2 人 | 4 人 | 8 人 | 8 人合計 |
| 9B · TP4 · 生產 | 107.5 | 83.9 | 67.4 | 60.3 | 391.4 |
| 9B · TP2 | 90.5 | 74.7 | 56.0 | 45.3 | 277.0 |
| 27B · TP2 | 37.2 | 30.6 | 22.5 | 17.0 | 104.5 |
27B TP4 為何沒有數字
那一臂在切換前執行,GPU0 還被生產佔著:Free memory on device cuda:0 (0.3/31.73 GiB) —— 排程順序問題,不是 27B TP4 的退化。先前量到的 38.4 tok/s 仍然成立。
串流陷阱
max_tokens 太小時,推理模型會把整個額度花在思考段,串流下呼叫端會收到完全空白且無錯誤的回應(實測 200 tokens 時 4/6 空白)。請給 1024 以上。
已撤回的數字
52.5 tok/s / 每人 — 當時以隨機 token 當提示,掩蓋了輸出退化,而退化的輸出解碼更快,反而灌高數字。基準測試現已內建真實文本的詞彙重複度斷言。
推測解碼 sweep · GPU3
假設
MTP 在自由文本上是淨損,但工具呼叫的輸出高度重複(JSON 骨架、欄位名、<tool_call> 標籤幾乎每次相同)—— 那是 n-gram 命中率最高的地形。因此每個臂同時測工具呼叫與中文散文兩種負載:前者驗證假設,後者當對照組,確認它不會拖累一般對話。三種方法都不需要額外的 draft 模型。
| 方法 | 工具 c1 | 工具 c4 合計 | 散文 c1 | uniq | 備註 |
| baseline(無推測) | 50.9 | 92.6 | 71.3 | 0.58 | 對照組 |
| ngram · 3 tokens | 15.7 | 23.6 | 16.5 | 0.68 | 工具 c1 -69.2% · 工具呼叫失敗 |
| ngram · 5 tokens | 15.6 | 45.5 | 19.2 | 0.53 | 工具 c1 -69.4% · 工具呼叫失敗 |
| ngram_gpu · 5 tokens | 16.2 | 44.5 | 25.6 | 0.20 | 工具 c1 -68.2% · 工具呼叫失敗 · 輸出退化 |
| suffix · 5 tokens | — | — | — | — | 缺 arctic-inference 套件,未測 |
閘門(單向有效)
散文臂帶詞彙重複度斷言。ngram_gpu 正是它攔下的:散文 25.6 tok/s 是所有推測臂最高,但 uniq 只有 0.20,輸出已是垃圾 —— 沒有閘門會被記成「最快」。但這道閘門只有單向效力:它用空白切詞,而中文不用空白,純中文輸出可能只切出一個 token 而得到 uniq=1.00。低 uniq 是退化的證據,高 uniq 不能當成輸出健康的證據。
假設已被推翻
vLLM 的 ngram proposer 比對的是精確 token ID 序列,不是「這看起來像 JSON」—— 結構相似不等於 token 序列相同,所以工具呼叫的重複性並不會轉成命中率。而且失敗是正確性問題而非速度問題:三個推測臂都產不出合法的 tool_calls。同樣的量化 KV + ngram 失敗在 RTX 3090 上也有回報(vLLM issue #40831),因此不能歸因於 SM70 世代。
2×2 隔離 · 是 TurboQuant 還是推測本身
為什麼要隔離
推測臂同時出現「慢三倍」與「工具呼叫失敗」,兩者很可能同源於 TQ2 的 verify / rollback 路徑而非 proposer。五個臂統一用 8192 context —— FP16 KV 在 32K 下裝不進 32GB,不統一就沒有可比性;因此絕對值低於 32K 的 baseline,只有內部比較有意義。
這批數據不可採信
三個量測缺陷,都在我自己的測試工具裡,結論待重測:
① draft / accepted 全為 0,連開了推測的臂也是 —— 代表我抓的 metric 名稱在這個 fork 不存在,整欄沒有訊號,不能讀成「推測沒運作」。
② uniq=1.00 是假的健康,見上方閘門說明。
③ FP16 · 推測關 工具呼叫 0/3 講不通 —— 它沒開推測,理應與 TQ2 · 推測關 的 3/3 一致。這推翻了「責任完全在 TQ2 verify」的乾淨假設,但同樣可能是測試本身的問題。下一步要看實際回應內容,不能再看聚合數字。
| KV / 推測 | 工具 c1 | 工具呼叫 | 散文 | uniq | draft → accepted |
| TQ2 · 推測關 | 60.6 | 3/3 | 70.9 | 0.74 | — |
| TQ2 · ngram 3 | 17.1 | 0/3 | 23.1 | 0.75 | — |
| FP16 · 推測關 | 54.5 | 0/3 | 68.3 | 1.00 | — |
| FP16 · ngram 3 | 19.3 | 0/3 | 16.4 | 0.78 | — |
| TQ2 · ngram 3 · eager | 11.6 | 0/3 | 11.2 | 1.00 | — |
DSpark 記憶體診斷 · DGX
為什麼四層才到底
前三個假設都被實測推翻,而且它們都很有說服力 —— 留在這裡是為了不再重走。真正的轉折是不再靠推論、改看哪一套帳本對不上:當 cuda_reserved 與程序 RSS 同時持平、系統可用記憶體卻持續下降,這個組合只指向一個地方。
推翻
27B 目標模型全載吃掉 54GB
lowmem 路徑早已只從 safetensors 取出 embed_tokens 與 lm_head。它只在失敗時列印訊息,所以「log 裡沒有訊息」正好代表它有生效。
推翻
103GB 的 target cache 被 mmap 讀爆
輾轉當下 buff/cache 只有 1GB。mmap 的頁面計入 page cache 且可回收,不會逼出 swap。為此建的 1400 樣本子集沒有解決問題,但保留 —— 它讓每輪實驗快很多。
推翻
凍結的 embed / lm_head 仍被配了 Adam 狀態
optim.py 已濾掉 requires_grad=False 的參數,而且用的是 bitsandbytes AdamW8bit。
成立
① 孤兒 CUDA 子程序扣住 59GB
kill 父程序不會殺掉 multiprocessing.spawn 的子程序;它孤兒化後仍持有 CUDA context。GB10 的 GPU 記憶體從系統 RAM 切出,驅動那份不計入 /proc/meminfo 任何類別(所有具名項目加總只有 23GB / 121GB),nvidia-smi 回報 [N/A],該程序 RSS 僅 2.4GB —— ps 和 nvidia-smi 都看不見它。基準線因此從 121GB 悄悄掉到 61GB。
成立
② 注意力 scores 矩陣被實體化
drafter 的注意力是 Q=3584 × KV=7680。sm_121a 拿不到融合核心:flex_attention 不能編譯,換 SDPA 又因自訂遮罩退回 math 後端。兩條路都會實體化整個 fp32 scores 矩陣。
成立
③ 釘選主機記憶體快取無限成長
最後一層,也最隱蔽:cuda_allocated、cuda_reserved 與程序 RSS 三者同時持平,系統可用記憶體卻在 365 步內掉了 9.2GB。釘選區塊不在任何一套帳本裡,而 torch 依尺寸快取且從不釋放 —— 這份資料每個樣本長度都不同,每個新形狀就留下一塊永久快取。
修法與實測
| 修法 | 修法前 | 修法後 | 說明 |
| num_anchors 512 → 128 | 跑不到第一個 micro-step | 穩定推進 | Q_LEN 3584 → 896,scores 面積少 6.2 倍。硬體逼出的偏離,τ 需註明在 128 anchors 下測得。 |
| expandable_segments | 49→99 步流失 12.3GB | 流失 1.7GB | 治裝置端碎片。有效但不足以收斂。 |
| pin_memory=False | 步 464 剩 12.3GB 後陣亡 | 步 900 仍有 37.4GB | 治主機端釘選快取。GB10 主機與裝置共用實體 RAM,釘選換不到 DMA 好處 —— 每步耗時反而從 5.0s 降到 2.53s,全程預估從 19 小時縮到 9.4 小時。 |
本期紀事
修復
TPFIX2 — 多卡輸出從此正確
此 vLLM fork 的張量並行輸出從來沒對過(9B / 27B 都是亂碼)。逐層 dump 定位到 out_proj 的 rank 切片與各卡持有的 head 集合對不上,修好後 TP2 / TP4 首次產出正確文字。
修復
SPECFIX — CUDA graph capture 缺陷根治
capture 時把 CPU 純量烘進圖裡,導致「快但輸出壞」與「正確但很慢」二選一。改成 verify-as-decode 後兩難消失。
翻案
27B 從判死到可用
單卡 14.5 tok/s(判定不可用)→ TP4 單人 38.4,首次越過 30 的互動門檻。
交付
fable-9b 工具呼叫上線
hermes parser + qwen3 reasoning + 支援 tools 的對話模板。非串流 8/8、串流 7/7 通過;含 tool_calls JSON、結果回灌、think 不外洩。
研究
DSpark 訓練方向修正
比對論文後找出三個方向性錯誤:drafter 容量過大、資料規模不足、confidence 排程未部署。已用輕量 drafter 重啟訓練。
交付
生產切換 TP4 — 每人 66.6 → 107.5 tok/s
量測鏈在 regen 釋放 GPU 後自動完成 27B TP2 / 9B TP2 量測並切換生產,帶健康檢查與工具呼叫閘門、失敗自動回滾。切換後 8/8 驗收全過(純文字對話、tool_calls JSON、結果回灌、think 不外洩),8 人併發每人仍有 60.3、合計 391.4。
診斷
DSpark 訓練記憶體 — 四層才到底
訓練一啟動就把 121GB 吃光並開始輾轉。前三個歸因(27B 全載 / mmap cache / Adam 狀態)都被實測推翻。真正的原因有三層:孤兒 CUDA 子程序扣住 59GB、注意力 scores 矩陣被實體化、釘選主機快取無限成長。修好後記憶體打平,每步耗時反而從 5.0s 降到 2.53s。
研究
推測解碼 sweep 啟動
單卡旋鈕已測到盡頭(全在 ±3% 雜訊內),TP4 又被 regen 擋著,而 GPU3 整晚閒置。改測三種免 draft 模型的推測方法,針對工具呼叫這種高重複輸出。
事故
PSU 陣亡並更換
多模型同時載入的主板軌尖峰疑似壓垮電供,停機 15 小時。已改為序列載入紀律;四卡與載板無損。
下一步
- WayneHermes gateway 端對端測試,確認後啟用工具呼叫
- agentDSpark 訓練完成 → 以 accepted length 對比舊 checkpoint,裁決容量修正是否正確
- agent推測解碼:先修測試工具(metric 名稱、中文可用的退化偵測),再看實際回應內容重測
- agent27B TP4 補量(需先讓出 GPU0),確認 38.4 tok/s 是否仍成立
- agentregen 8931 筆已收齊 → 資料擴量重訓