<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[雙 5090 跑 Qwen3.8-27B BF16 140K 實測數據與優化心得]]></title><description><![CDATA[<p dir="auto">看到板上幾篇 5070 Ti / 3070 Ti 異構雙卡跑 Qwen3.8 的分享，數據都很紮實。我這邊條件好一點（雙 RTX 5090 32GB），把生產環境<strong>實際在跑</strong>的 Qwen3.8-27B 數據整理出來分享，重點是「哪些優化方向實測有效、哪些是白做工」，希望對其他雙卡玩家有參考價值。</p>
<h2>1. 硬體與軟體</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>項目</th>
<th>配置</th>
</tr>
</thead>
<tbody>
<tr>
<td>GPU</td>
<td>2× RTX 5090 32GB（SM120 Blackwell）</td>
</tr>
<tr>
<td>CPU</td>
<td>Ryzen 9 9950X3D（16C/32T）</td>
</tr>
<tr>
<td>記憶體</td>
<td>60GB DDR5</td>
</tr>
<tr>
<td>系統</td>
<td>Ubuntu 24.04.4 LTS</td>
</tr>
<tr>
<td>引擎</td>
<td>llama.cpp（LM Studio 2.29.0 CUDA12 binary）</td>
</tr>
<tr>
<td>模型</td>
<td>Qwen3.8-27B-BF16（兩片 GGUF 共 54.6GB）＋ mmproj-F16（928MB，啟用 Vision）</td>
</tr>
<tr>
<td>Context</td>
<td>140,000（對齊 Hermes context_length；原 200000 多出的 70K 純佔 VRAM，已縮小）</td>
</tr>
<tr>
<td>KV</td>
<td>q8_0 / q8_0</td>
</tr>
<tr>
<td>Split</td>
<td>tensor 0.5,0.5</td>
</tr>
<tr>
<td>MTP</td>
<td><strong>關閉</strong>（實測更慢，見 §4.1）</td>
</tr>
<tr>
<td>用途</td>
<td>Hermes Agent 主腦，長期單 slot 真實對話流量，非固定短 prompt benchmark</td>
</tr>
</tbody>
</table>
<h2>2. 生產啟動參數</h2>
<pre><code class="language-bash">llama-server -m Qwen3.8-27B-BF16-00001-of-00002.gguf \
  --mmproj mmproj-F16.gguf \
  --n-gpu-layers 99 \
  --split-mode tensor --tensor-split 0.5,0.5 \
  --ctx-size 140000 -fa on \
  --batch-size 4096 --ubatch-size 4096 \
  --cache-type-k q8_0 --cache-type-v q8_0 \
  -np 1 --kv-unified \
  --jinja --metrics --no-webui
</code></pre>
<p dir="auto">重點說明：</p>
<ul>
<li><code>-np 1</code>：單 slot 長 context，避免 KV 爆炸。<code>--kv-unified</code> 保留著，之後開多 slot 時兩 slot 共享總 KV pool（按需分配，不靜態平分），目前單 slot 下無副作用。</li>
<li><code>-fa on</code>：長 context 下顯存與速度都受益，必開。</li>
<li><code>--metrics</code>：Prometheus endpoint，MTP 接受率、prefill/decode 總量都從這裡看，比翻 log 方便。</li>
<li><code>--jinja</code>：走模型官方 chat template，thinking 輸出行為才正確。</li>
</ul>
<h2>3. 實測數據（生產 log 為準）</h2>
<p dir="auto">以下全部取自 llama-server 自己的 <code>print_timing</code> 與 <code>/metrics</code>，<strong>不是</strong> client 端量測（client 端 burst 量測會偏高 ~30%，這坑我踩过）。統計區間為本次啟動後 53 筆已完成任務，真實 Agent 工作流（含工具操作與上下文逐步累積）：</p>
<pre><code class="language-text">llamacpp:prompt_tokens_total        395739
llamacpp:prompt_seconds_total       341.57   → prefill 平均 1158.6 tok/s
llamacpp:tokens_predicted_total      86194
llamacpp:tokens_predicted_seconds   1793.85  → decode 平均 48.05 tok/s
llamacpp:n_tokens_max               99372    → 單 task 最大 context
llamacpp:requests_deferred               0
</code></pre>
<p dir="auto">逐 task 抽樣（每 task 一個 session turn，* = 累計 context 已達 99.4K 的長任務）：</p>
<pre><code class="language-text">task    prompt       prefill     gen tok    decode
68781   ~1.7K        1017 t/s    119        47.72 t/s
68902   ~0.2K 增量    393 t/s     455        47.44 t/s
69995   ~2.8K        1168 t/s    433        50.01 t/s
70430   ~0.5K        678 t/s     117        50.37 t/s
74156   ~0.9K        848 t/s     1312       49.18 t/s
75470   ~4.5K        1121 t/s    1038       49.13 t/s
70549   ~4.7K        1104 t/s    3604       49.35 t/s
76862   ~1.6K *      989 t/s     9517       48.29 t/s
86382   ~1.1K        924 t/s     2728       48.43 t/s
</code></pre>
<p dir="auto">觀察：</p>
<ul>
<li><strong>decode 非常平穩：47.4–52.4 t/s，約 20.5 ms/token</strong>，從 1K 短 context 到 99.4K 長 context 幾乎不衰减——BF16 權重下 5090 的 1792GB/s 頻寬在 decode 端壓力還不大。</li>
<li>最長 task 一次生成 9517 tok（近 3.4 分鐘持續輸出），全程 0 OOM、0 pipeline fallback、0 deferred。</li>
<li>prefill 在 0.5K–4.7K 增量下穩定 840–1170 tok/s（前綴快取命中時更高）。</li>
<li>峰值 99,372 tokens &lt; 140K 上限，餘量健康。</li>
<li>VRAM：GPU0 ~31.3GB / GPU1 ~30.2GB（各 32.6GB），BF16 雙卡各分 ~27GB 權重 + KV，headroom 約 1–2.3GB/卡。想再拉 ctx 就得降量化。</li>
<li>載入：54.6GB BF16 兩片 mmap，NVMe 上約 30–40 秒。</li>
</ul>
<h2>4. 實測過的優化方向：哪些有效、哪些放棄</h2>
<h3>4.1 MTP（投機解碼）——實測放棄</h3>
<p dir="auto">Qwen3.8-27B GGUF 內建 MTP draft 層（blk.64），理論上 decode 可以白賺一截。實際開 <code>--spec-type draft-mtp</code> 實測後<strong>關閉</strong>：</p>
<ul>
<li>接受率約 40%（這模型的 draft head 偏弱，比 Qwen3.6 系的 62–71% 低一截），<code>--spec-draft-n-min</code> 調低變負優化；</li>
<li>draft 佔 VRAM + 配置複雜度上升；</li>
<li><strong>雙卡 tensor split + MTP 實測比純 decode 還慢</strong>——跨卡同步開銷吃掉了投機解碼的收益。</li>
</ul>
<p dir="auto">驗證 MTP 確已關閉的方法：啟動 log 會有 15 行 <code>model has unused tensor blk.64.* -- ignoring</code>，合計約 810MB——這 15 行代表內建 MTP 層被丟棄，是「MTP 已關」的正面證據，不是異常。</p>
<h3>4.2 雙卡 split：同型號卡 tensor，異構卡 layer</h3>
<ul>
<li>同型號雙卡（我這台）：<code>--split-mode tensor 0.5,0.5</code> 沒問題，每層雙卡各算一半。</li>
<li>異構卡（如 5070 Ti + 3070 Ti）：layer split 更合理，tensor split 每層跨卡 all-reduce 會被最慢那張卡釘死。</li>
<li>雙 5090 走 PCIe 的 internal AllReduce（用 LM Studio binary 時 log 裡有 NCCL 行），沒另編 NCCL build——<strong>實測 NCCL 自編版沒有更快</strong>，維持現狀。</li>
</ul>
<h3>4.3 換引擎——SGLang / NInfer 都測過</h3>
<ul>
<li><strong>SGLang 0.5.17：載不動</strong>。對 unsloth Qwen3.8 GGUF 直接報 <code>unknown architecture: qwen35</code>（2026-08 新架構還沒進 transformers GGUF arch map）；改載 HF 原生權重會反量化成 BF16 → 每卡 27GB OOM；<code>--quantization gguf</code> loader 仍找 safetensors。SM120 上 FP8/NVFP4 kernel 也不完整。結論：llama.cpp 是目前唯一完整支援 Qwen3.8 GGUF 的生產選項。</li>
<li><strong>NInfer（自 build）：更快，但生態封閉</strong>。同一顆空 5090、同 ctx、同 prompt 對決：NInfer prefill ~8575 tok/s（llama.cpp ~2975，約 2.9×）、decode 180.6 vs 141.25 t/s（約 1.28×）、warm ttft 19ms vs 66ms；MTP 接受率兩邊都 ~62% 打平——差距來自引擎本體 kernel 效率，不是 MTP。NInfer 現在是我的備用腦/實驗場，生產主腦維持 llama.cpp（OpenAI 相容 API + 生態成熟 + 換模型零成本）。</li>
</ul>
<h3>4.4 有效的長期配置決策</h3>
<ul>
<li><strong>ctx 對齊实际需求</strong>：llama.cpp 啟動時<strong>預分配整塊 <code>n_ctx</code> 的 KV buffer</strong>（不是按需長），200000 → 131072 一步直接省下 3–4GB/卡。</li>
<li><strong>KV 量化 q8_0</strong>：Qwen3.8-27B 是 GQA-4（head_count_kv=4，<strong>不是</strong> 30——早期用 30 heads 估 KV 會高估 7.5 倍），17 層 KV，q8_0 約 37KB/token：200K ctx ≈ 7.3GB、256K ≈ 9.7GB。KV 才是長 context 的大頭，不是權重。</li>
<li><strong>thinking 模型讀兩個欄位</strong>：長推理輸出落在 <code>reasoning_content</code>，<code>content</code> 會是空的——用 API 驗證時別把空 content 當成失敗。</li>
<li><strong>雙卡 VRAM 統計</strong>：<code>nvidia-smi --query-compute-apps</code> 裡 tensor split 的 PID 每張卡各出現一次，要加總，別只看一行。</li>
</ul>
<h2>5. 給雙卡玩家的參數建議（單 slot 長 context）</h2>
<pre><code class="language-text">-tp 2 / --split-mode tensor --tensor-split 0.5,0.5   # 同型號卡
--split-mode layer --tensor-split 16,8               # 異構卡（按 VRAM 比例）
-fa on                                               # 必開
-ctk q8_0 -ctv q8_0                                  # KV 量化
-np 1                                                # 單 slot
--ctx-size &lt;對齊前端 context_length&gt;                 # 別多開，KV 啟動即預分配
-b 4096 -ub 4096                                     # prefill 批大小（prefill 慢可降 ub）
--jinja --metrics                                    # 官方模板 + 可觀測性
</code></pre>
<h2>6. 結語</h2>
<p dir="auto">雙 5090 + BF16 140K 對我這種 7×24 單 slot agent 場景是「夠用且平穩」的配置：decode ~48 t/s 穩定、99K context 無衰减、零 fallback。最大的心得是：<strong>先測再優化</strong>——MTP、NCCL、SGLang 三個「理論上應該更快」的方向全數實測過，兩個更慢、一個載不動，最後贏的是最樸素的 tensor split + q8_0 KV + 合身的 ctx。</p>
<p dir="auto">數據全部可重現：引擎端 log（<code>print_timing</code>）+ <code>/metrics</code>，啟動參數如上。有問題歡迎直接問，踩過的坑都寫在上面了。</p>
<hr />
<p dir="auto"><em>附：所有數據以引擎端 log 為準；client 端量測（TTFT/burst）與引擎端 print_timing 計時窗不同，會偏高，引用時請註明口徑。</em></p>
]]></description><link>https://lcz.me/topic/1350</link><generator>RSS for Node</generator><lastBuildDate>Sun, 13 Sep 2026 20:08:11 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/1350.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 27 Aug 2026 03:22:50 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 雙 5090 跑 Qwen3.8-27B BF16 140K 實測數據與優化心得 on Fri, 28 Aug 2026 09:14:41 GMT]]></title><description><![CDATA[<p dir="auto">非常好的分享，双5090太奢侈。</p>
]]></description><link>https://lcz.me/post/14593</link><guid isPermaLink="true">https://lcz.me/post/14593</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Fri, 28 Aug 2026 09:14:41 GMT</pubDate></item></channel></rss>