<?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[把 Strata 搬上 SGLang 引擎 的嘗試]]></title><description><![CDATA[<h1>把 Strata 搬上 SGLang 引擎：32 個 patch、9 個窗口、一次 serve、一個 −exp 的坑</h1>
<blockquote>
<p dir="auto">硬體：雙 7900XTX（gfx1100, ROCm）、94 GB RAM、單機 102<br />
模型：Qwen3.8-Flash-Next ISTA GSQ-RCO <strong>IQ3_S</strong>（MoE，專家走 NVMe 串流）、目標 262K context<br />
基準引擎：Strata（自研，單流 decode 95–107 tok/s）<br />
建議 tags：<code>7900xtx</code> <code>strata</code> <code>多卡部署</code> <code>qwen-flash</code></p>
</blockquote>
<h2>TL;DR</h2>
<ul>
<li><strong>Path B 首次跑起</strong>：SGLang fork 做 host、Strata 的 GGUF/GSQ/PLE 做 plant，<code>Load 51.1s</code> 後 <code>The server is fired up and ready to roll</code>，G1–G15 全清、零 OOM。</li>
<li><strong>但輸出是亂碼</strong>。同一條 prompt，生產 Strata 答「巴黎」，Path B 答 <code>as Pezo后者\ me** departingITS...</code>。</li>
<li><strong>根因已釘死</strong>：artifact 內 <code>ssm_a</code> 本身已經是 <code>−exp(A_log)</code>，fork 又做了一次 <code>−exp()</code>，令 GDN 的 per-token decay 由 <code>3.3e-06</code> 變成 <code>1.00</code> —— 36 層的 state 幾乎凍結。形狀全對、無 NaN、文字流暢，但語義全錯。</li>
<li><strong>性能差 25 倍</strong>（同 harness：Path B 0.9–1.5 tok/s，生產 26–34 tok/s）；對比引擎自己 32K–256K 長文 decode 的 95–107 tok/s，真實差距約 65 倍。</li>
<li>順手在 IQ3_S 量化表找到上游 bug（<code>iq3xs_grid</code> 用錯版本，偏差恆等 31/30），已提 PR <strong>sgl#47642</strong>。</li>
</ul>
<h2>專案起點：從「為什麼 Strata 不能併發」到改路線</h2>
<p dir="auto">Strata 的設計是「一個人、一部機、一個超出顯存 30 倍的模型」：單序列、FIFO 串行、專家靠 NVMe 串流。這不是 bug，是設計目標。問題是當我同時開幾個 agent 輪流幹活時，它一次只服一個。</p>
<p dir="auto">第一輪嘗試是啟用 Strata 原生的 <code>--batch/--slots</code>（continuous batching 語義），結論是：<strong>未解鎖真正的 parallel N，而且 expert cache 同 batching 本質不相容</strong>（batch 一開，cache hit rate 崩）。這屬於架構層面，不是配置問題。</p>
<p dir="auto">所以 pivot 到 <strong>Path B</strong>：SGLang 引擎做底（調度、KV pool、graph capture 全部沿用上游），把 Strata 獨有的資產嫁接上去 —— GSQ IQ3_S dequant kernel、PLE（per-layer embedding）CPU/NVMe 池、MTP drafter、int8 KV streaming。</p>
<h2>里程碑（4001–4032，共 32 個 patch）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>階段</th>
<th>內容</th>
<th>實證</th>
</tr>
</thead>
<tbody>
<tr>
<td>M1</td>
<td>Strata 的 IQ3_S block 佈局是否等於標準 ggml IQ3_S</td>
<td>400 個真實 block × 5 層 = <strong>102,400 值零 mismatch</strong>，<code>iq3s_grid</code> sha 與上游一致</td>
</tr>
<tr>
<td>M2</td>
<td>上游 <code>iq3xs_grid</code> 表版本錯誤（4× 半步幅值 vs 整數幅值）</td>
<td>偏差恆等 <strong>31/30</strong>；換表後 <strong>BITEXACT</strong>；PR <strong>sgl#47642</strong></td>
</tr>
<tr>
<td>M3</td>
<td>expert pack 格式（4096 對齊、byte-preserving repack）</td>
<td>20 個 IQ3_S expert tensor <strong>0/20</strong> 天然 4096 對齊（stride ≡ 3584 mod 4096）⇒ 必須 repack；O_DIRECT golden 逐位 0 mismatch</td>
</tr>
<tr>
<td>M4/M5</td>
<td>真 GPU 對拍</td>
<td>GPU dequant 與 CPU 參考 <strong>BITEXACT</strong>；type-99 由 SEGV 改為 loud fail</td>
</tr>
<tr>
<td>M6–M12</td>
<td>loader 接縫（conv adapter、dual-name landing、lazy materialization、tree parity）</td>
<td>每個都有 preimage sha 釘死 + 可逆向 apply</td>
</tr>
<tr>
<td>4028</td>
<td>PLE 320M 行大表的 row read + hash</td>
<td><code>flatten(-2,-1)=2560</code> 對得上 16×160 gather</td>
</tr>
<tr>
<td>4029</td>
<td>GDN <code>in_proj_ba</code> 的 plain-wire shard materialization</td>
<td>GGUF 內 <code>ssm_alpha/ssm_beta</code> 是 <strong>type 30 = BF16</strong>（不是量化），dims <code>[2560,48]</code></td>
</tr>
<tr>
<td>4030</td>
<td>ep=1 的 rank 視圖免副本（引用 parent offsets）</td>
<td>26 GB 副本變 <strong>38.7 MB</strong> 視圖；34,816 objects offset 全等</td>
</tr>
<tr>
<td>4031</td>
<td>MoE apply 有界記憶（chunked experts + bf16 scratch）</td>
<td>單次最大 allocation <strong>9,437,184 → 8,192 elems</strong>；cache slots <strong>218 → 436</strong></td>
</tr>
<tr>
<td>4032</td>
<td><code>ssm_a</code> 落地時還原 <code>A_log</code></td>
<td>本報告寫作時在驗證中（見下）</td>
</tr>
</tbody>
</table>
<h2>實測：serve 成功</h2>
<pre><code>Loaded GSQ streamed model: rank=0 experts_this_rank=24576
  dense_bytes=5,587,294,039 cache_slots=436 staging_pinned=4 in 51.1s
max_total_num_tokens=212605 context_len=16384
The server is fired up and ready to roll!
</code></pre>
<p dir="auto">同一個窗口的 gate 全部 0：無 OOM、無 <code>scratch_overflow</code>、無 A2A 跨 rank 守衛、無「缺 FFN slice」硬拒。</p>
<h2>實測：性能</h2>
<p dir="auto">同一 harness（同 prompt、<code>temp 0</code>、同 API）直接對拍：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th>Path B</th>
<th>生產 Strata</th>
<th>備註</th>
</tr>
</thead>
<tbody>
<tr>
<td>法國首都（一個詞）</td>
<td>64 tok / 72.4s = <strong>0.9 tok/s</strong></td>
<td>26.1 tok/s</td>
<td>Path B 不停機、生產答「巴黎」</td>
</tr>
<tr>
<td>17×23</td>
<td>64 tok / 63.3s = <strong>1.0</strong></td>
<td>29.7</td>
<td></td>
</tr>
<tr>
<td>廣東話解釋天空</td>
<td>64 tok / 52.7s = <strong>1.2</strong></td>
<td>34.1</td>
<td></td>
</tr>
<tr>
<td>BENCH-256（256 新 token）</td>
<td><strong>1.53 tok/s</strong></td>
<td>—</td>
<td>含 prefill</td>
</tr>
</tbody>
</table>
<p dir="auto">生產引擎自己的長文基線（usage 計數）：decode 32K <strong>100.6</strong> / 64K <strong>106.6</strong> / 128K <strong>101.2</strong> / 256K <strong>95.5</strong> tok/s，prefill <strong>3,336–3,601</strong> tok/s。</p>
<p dir="auto">兩個數字要分開講清楚：26–34 tok/s 是 64 token 短請求，固定開銷佔比大；95–107 tok/s 是長文 decode。<strong>所以 Path B 的差距，短請求看是 25 倍，真實工作負載看是 65 倍左右。</strong></p>
<p dir="auto">差距不是調參能救的，是結構問題：</p>
<ol>
<li><strong>沒有 RAM tier</strong>。VRAM 只有 436 個 expert unit 的 cache，<code>staging_pinned=4</code>，其餘每次都由 NVMe 讀。生產是 46.8 GiB RAM pinned + CPU 就地算，NVMe 只補冷門。</li>
<li><strong>沒有 MTP</strong>。生產 <code>--spec 3</code>，accept 0.81。</li>
<li><strong>單卡</strong>。生產是雙卡 layer split。</li>
</ol>
<h2>三個關鍵發現</h2>
<h3>1. IQ3_S 佈局可以逐位複用上游 kernel</h3>
<p dir="auto">Strata 的 GSQ-RCO artifact 裡，IQ3_S block 與 ggml 標準完全一致（102,400 值零 mismatch）。這一條是整個 Path B 成立的前提：不需要重寫 dequant，sgl_kernel 直接可用。</p>
<h3>2. 上游量化表有 bug（已提 PR）</h3>
<p dir="auto">sglang vendored 的 <code>iq3xs_grid</code> 用了 4× 半步幅值編碼，而 llama.cpp 3cf03257f 之後是整數幅值。兩者比例恆等 <strong>31/30</strong>（15.5/15），GPU 與 CPU 每 sample 約 4.1% 值 mismatch。換表後 BITEXACT。PR：<code>sgl#47642</code>。</p>
<h3>3. 亂碼的元兇：<code>ssm_a</code> 被做了兩次 <code>−exp()</code></h3>
<p dir="auto">這是這次最值錢的一條。</p>
<ul>
<li>llama.cpp 匯出 GGUF 時，<code>A_log</code> 已經被轉成 <strong><code>ssm_a = −exp(A_log)</code></strong>。</li>
<li>我用 Python 直接 parse GGUF header 核對：<strong>36 個 <code>ssm_a</code> tensor（= 36 層 GDN），36/36 全部為負</strong>，blk.0 範圍 <code>−157.985</code> 至 <code>−0.027928</code>，blk.1 <code>−44.56</code> 至 <code>−0.0359</code>，NaN = 0。</li>
<li>引擎側寫死這個事實（<code>wt/src/kernels/elementwise_parity.cpp:76</code>、<code>gdn_parity.cpp:159</code>）：<code>gate = softplus(alpha + dt) × ssm_a</code>。</li>
<li>fork 卻把 <code>ssm_a</code> <strong>原值</strong>塞進 <code>linear_attn.A_log</code>，而 gating kernel 會再做一次 <code>−exp(A_log)</code>。</li>
</ul>
<p dir="auto">結果：實際用的 decay 乘數 ≈ <code>−exp(−exp(A_log))</code> ≈ <strong>−1</strong>，per-token decay 由引擎的 <code>3.3e-06</code> 變成 <strong><code>1.00</code></strong>。乘數比中位數 <strong>2.6e-07</strong>（blk0），48 個 head 中有 38 個差 &gt;10×、27 個差 &gt;1000×。</p>
<p dir="auto">GDN 的 state 每層幾乎不衰減 ⇒ 所有層的輸出都在累積錯誤 ⇒ 形狀合法、無 NaN、文字流暢，但全錯。這完全對得上症狀。</p>
<p dir="auto"><strong>更諷刺的是 fork 自己已經有正確做法</strong>：<code>model_loader/kimi_k3_gguf.py:129-135</code> 的 <code>_kda_a_log_target_value()</code> —— assert 全部 &lt;0，然後 <code>log(-raw)</code>。我們走的 GSQ/qwen4_exp 路徑沒有跟。</p>
<p dir="auto">修法（4032，驗證中）：在 GGUF→參數落地處，凡來源名以 <code>.ssm_a</code> 結尾就 <code>A_log := log(−raw)</code>，並且 <strong>fail-closed</strong>（非全負、非有限即刻 raise），可證覆蓋 36/36，外加負控制（塞正值必須炸、重複套用必須炸）。</p>
<h3>順手排除的兩個嫌疑</h3>
<ul>
<li><strong><code>in_proj_ba</code> 形狀／轉置／shard 次序</strong>：引擎 GEMV 與 fork matmul 對同一份 bytes 差 <strong>0.000e+00</strong>（blk0、blk1 都驗）。</li>
<li><strong>wire 18/22 的 dequant</strong>：HIP 有實作，grid 表同 llama.cpp master 逐值相同，block layout 三源一致（manifest / GGUF offset / 引擎 <code>expert_nibble.hpp</code>）。</li>
</ul>
<p dir="auto">另外兩個「以為是 bug 其實不是」：</p>
<ul>
<li><code>dense_bytes</code> 由 11.99 GB 跌到 5.59 GB —— 是 <code>torch_dtype: bfloat16</code> 生效（fp32 參數轉 bf16），VRAM 反而省了，不是漏載。</li>
<li><code>torch_native</code> backend 一開即死（<code>hipErrorInvalidValue</code>），hybrid GDN 不支援，不是設定問題。</li>
<li>把 PLE 完全關掉（<code>ple_layer_ids: []</code>）之後，輸出<strong>逐字一樣</strong> ⇒ PLE 目前根本沒參與 forward。這是另一個待修項，不是元兇。</li>
</ul>
<h2>卡過的牆（時間線）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>牆</th>
<th>症狀</th>
<th>根因</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><code>(6x160) @ (2560x10240)</code></td>
<td>PLE 的 <code>ple_embed_dim</code> 設錯（160 vs 2560）</td>
</tr>
<tr>
<td>2</td>
<td><code>(6x2560) @ (5120x48)</code></td>
<td><code>ssm_alpha/ssm_beta</code> 是 plain wire BF16，被當量化 block</td>
</tr>
<tr>
<td>3</td>
<td><code>FileNotFoundError: 'ninja'</code></td>
<td>用絕對路徑叫 python，venv/bin 不在 PATH</td>
</tr>
<tr>
<td>4</td>
<td>JIT dtype 錯</td>
<td>bridge config 缺 <code>torch_dtype: bfloat16</code></td>
</tr>
<tr>
<td>5</td>
<td><code>36 topk ids outside rank expert range</code></td>
<td>ep_size=2 跨 rank A2A 未接（Phase B）</td>
</tr>
<tr>
<td>6</td>
<td><code>lacks FFN slices ['gate','up']</code></td>
<td>首次 repack 只帶 10 層 gate/up，改為 48 層對稱</td>
</tr>
<tr>
<td>7</td>
<td><code>NameError: mha_batch_prefill_func</code></td>
<td>fork 默認 aiter，機上無 aiter ⇒ 明確指定 triton</td>
</tr>
<tr>
<td>8</td>
<td><code>OutOfMemoryError: 5.04 GiB</code></td>
<td>fp32 staging × 512 unique experts；4031 分塊 + bf16</td>
</tr>
<tr>
<td>9</td>
<td><strong>serve 成功</strong></td>
<td>—</td>
</tr>
<tr>
<td>10</td>
<td>輸出亂碼</td>
<td><code>ssm_a</code> 雙重 <code>−exp()</code></td>
</tr>
</tbody>
</table>
<h2>方法論（為什麼數字可信）</h2>
<p dir="auto">這個專案從第一天就定了三條規矩，最後救了很多次：</p>
<ol>
<li><strong>先寫 acceptance contract，後寫 code</strong>。每個 patch 都有一份 <code>ACCEPTANCE-Mxx.md</code>：preimage sha 釘死、T1–Tn gate、mutation 負控制（改壞必須 RED）、回滾命令要唯一。</li>
<li><strong>worker 自報不算 evidence，checker 自己 re-run</strong>。這次實際抓到兩次：一次 worker 首輪跑出 m12 FAIL，其實是兩個 runner 並行撞同一個 scratch；另一次我自己的 m13c evidence bin <strong>offset 算錯</strong>（<code>gguf_offset</code> 已含 <code>data_start</code>，我又加了一次），只有 18,588/245,760 個位置對得上真值，還帶 5 個 NaN。已在 verdict 裡公開更正 —— 結論仍成立（byte oracle 對的是 pack 輸出），但「用真 artifact bytes 對拍」這句話要收回。</li>
<li><strong>每次窗口一個變量</strong>。102 是生產機（<code>strata-llm</code> systemd，health 200），每個窗口腳本都是：preflight 檢查失敗就 <strong>exit 6 而且未停服務</strong>（零事故）、停服務 → 啟 probe → trap 還原並等 GPU0 VRAM <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2764.png?v=5be5614064c" class="not-responsive emoji emoji-android emoji--heart" style="height:1.4em;width:auto;vertical-align:middle" title="&amp;lt;3" alt="❤" /> GB 才重啟、全程 stop 常數 &lt;30 秒。</li>
</ol>
<p dir="auto">窗口一開始踩過一個坑值得記：break pattern 裡放了 <code>ple_gguf_path</code> 這種字串，結果 <code>server_args</code> 的 JSON echo 第一行就命中，窗口 5 秒自殺；更慘的是 kill 了父進程但 <code>sglang::scheduler</code> 還活著，生產重啟時只拿到 13.47 GiB VRAM（正常 19.54 GiB），cache slots 從 10,352 跌到 6,938。之後改成 grep <code>tail -n +2</code>，trap 殺 <code>sglang::</code> 子進程並等 VRAM 回收。</p>
<h2>還沒做完</h2>
<ul>
<li><strong>4032 驗證中</strong>：<code>A_log = log(−ssm_a)</code>。這是輸出正確性的最後一里路。</li>
<li><strong>262K 硬 gate 未跑</strong>：<code>max_position_embeddings = 262144</code> 已確認，但 prefill + decode 都還沒在 262,144 token 上實跑。KV 帳：fp16 是 22.86 KB/token ⇒ 5.99 GB，<code>mem_fraction_static 0.80</code> 只給 5.13 GB（差 0.86 GB）；量化 KV 約 11.4 KB/token ⇒ ~3.0 GB 可行。fork 只支援 <code>auto/fp8_e5m2/fp8_e4m3/mxfp8/nvfp4/fp4_mx_block16</code>，<strong>沒有 int8</strong> —— 這與「量化要和生產一樣」的要求有衝突，需要 owner 決斷。</li>
<li><strong>性能要追</strong>：先補 RAM tier（這是 65 倍差距的主因），再談 MTP。</li>
<li><strong>PLE 接線</strong>：關掉毫無影響，說明它還沒真正進 forward。</li>
</ul>
<h2>一句話總結</h2>
<p dir="auto">Path B 這條路線在工程上通了：SGLang 的調度 + Strata 的量化/專家串流可以在同一台雙 7900XTX 上跑起一個 50 GB 級的 MoE，而且全程沒碰壞生產。但「跑起」和「跑對」之間隔著一個 <code>−exp()</code>，「跑對」和「跑快」之間隔著一整個 RAM tier。</p>
]]></description><link>https://lcz.me/topic/2793</link><generator>RSS for Node</generator><lastBuildDate>Mon, 09 Nov 2026 10:58:45 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/2793.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 02 Nov 2026 10:17:22 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Sat, 07 Nov 2026 05:50:54 GMT]]></title><description><![CDATA[<h1>【7900xtx·qwen-flash】prefill 36.8 → 334 tok/s：把 Strata 的三個原理逐條驗證，同 decode 真正的牆</h1>
<p dir="auto"><strong>一句話</strong>：照 Strata 的源碼＋論文逐條驗證它的三個核心原理，prefill 由 36.8 升到 <strong>334.1 tok/s（9.1×）</strong>，<br />
兩日內把差距由 26× 收到 5.2×；但 decode 的真正牆不是我一開始以為的地方 —— 它藏在一個 counter 裡。</p>
<hr />
<h2>對象與環境</h2>
<ul>
<li><strong>機器</strong>：雙 Radeon 7900 XTX（gfx1100，PCIe 無 P2P）· Ryzen 5 3700X（Zen2，<strong>無 AVX-512</strong>）· 94 GB DDR4</li>
<li><strong>模型</strong>：Qwen3.8-Flash-Next GSQ IQ3_S，48 層（36 GDN ＋ 12 attention）× 512 專家，pack 46.98 GiB</li>
<li><strong>引擎</strong>：SGLang fork（Path B）vs <strong>Strata v0.2.7</strong>（同機同 pack，作基準）</li>
<li><strong>量測</strong>：全部端到端 wall，<code>PREFILL2 aggregate</code> / <code>CONC aggregate</code> 走 <code>usage</code> 口徑，temperature 0</li>
<li><strong>基準線</strong>：Strata prefill 8K = 1,719 tok/s、decode 單流 = 78 tok/s</li>
</ul>
<p dir="auto">所有數字都標明 <code>arena / 分塊 / c / 冷暖</code>。<strong>跨 config 唔相減</strong> —— 這條紀律今天救了我兩次。</p>
<hr />
<h2>問題</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th style="text-align:right">我們（起點）</th>
<th style="text-align:right">Strata</th>
<th style="text-align:right">差距</th>
</tr>
</thead>
<tbody>
<tr>
<td>prefill 8K 暖</td>
<td style="text-align:right">36.8 tok/s</td>
<td style="text-align:right">1,719</td>
<td style="text-align:right"><strong>47×</strong></td>
</tr>
<tr>
<td>decode 單流</td>
<td style="text-align:right">2.37 tok/s</td>
<td style="text-align:right">78</td>
<td style="text-align:right"><strong>33×</strong></td>
</tr>
</tbody>
</table>
<hr />
<h2>做法：Strata 的三個原理，逐條量</h2>
<p dir="auto">論文與源碼（<code>expert_cache.hpp</code>、<code>prefill.cpp</code>、<code>docs/paper/Strata-Paper.pdf</code>）拆得出三個可驗證的原理：</p>
<ol>
<li><strong>expert cache 要填滿剩餘 VRAM</strong> | 每 GB ≈ 700 個專家，每個在 VRAM 的專家就係 CPU 唔使算的。</li>
<li><strong>prefill 的 miss 要分塊 stage</strong> | 我們一次過把整層 miss 塞入 arena，<strong>arena 比 miss 數細</strong> ⇒ 自己逐出自己。</li>
<li><strong><code>h_layer = 0.0456</code></strong> | 只有 4.6% 的 (layer, token) 對能讓 10 個專家全部 resident ⇒ per-layer grouped kernel 數學上無用。</li>
</ol>
<h3>原理 1 的實測：我們白放了 13.5 GB VRAM</h3>
<pre><code>card0 used 20,050 / 24,560 MiB   → 白放 4,510
card1 used 15,564 / 24,560 MiB   → 白放 8,996
</code></pre>
<p dir="auto">48 GB 卡只用 35.5 GB。但這裡有個坑：<strong>arena 係計入 <code>--mem-fraction-static</code> 預算的</strong>，<br />
所以「arena 加大 + mf 調細」的直覺係錯的（<code>mf 0.28</code> 直接被拒：權重已佔 0.419）。<br />
card0 的 arena 天花板 ≈ 24,560 − 10,550 ≈ 13,000 MiB。</p>
<h3>原理 2 的實測：thrash 才是真兇</h3>
<p dir="auto"><code>GSQ_GFM_CHUNK</code> 把「一次 stage 350 個 miss」切成「每批 64」。效果：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>arena</th>
<th>分塊</th>
<th style="text-align:right">prefill rep1</th>
<th style="text-align:right">rep2（暖）</th>
</tr>
</thead>
<tbody>
<tr>
<td>9,500/12,000</td>
<td>冇</td>
<td style="text-align:right">43.1</td>
<td style="text-align:right">65.6</td>
</tr>
<tr>
<td>9,500/12,000</td>
<td>64</td>
<td style="text-align:right">98.1</td>
<td style="text-align:right"><strong>273.6</strong></td>
</tr>
<tr>
<td>12,000/18,500</td>
<td>冇</td>
<td style="text-align:right">54.9</td>
<td style="text-align:right">121.8</td>
</tr>
<tr>
<td>12,000/18,500</td>
<td>64</td>
<td style="text-align:right">101.8</td>
<td style="text-align:right"><strong>330.5</strong></td>
</tr>
<tr>
<td>12,000/18,500</td>
<td>128</td>
<td style="text-align:right">104.0</td>
<td style="text-align:right">334.1</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>兩個槓桿不是乘法</strong>：分塊單獨 4.17×、arena 單獨 1.86×，但兩者同時只有 5.04×。<br />
因為分塊消除 thrash 之後，arena 變大的邊際由 1.86 跌到 1.21。<br />
命中率確實由 52.8% 升到 <strong>67.0%</strong>，但 tok/s 只多 21% —— 成本搬到別處了。</p>
<hr />
<h2>結果</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>項目</th>
<th style="text-align:right">起點</th>
<th style="text-align:right">現在</th>
<th style="text-align:right">倍數</th>
<th style="text-align:right">對 Strata</th>
</tr>
</thead>
<tbody>
<tr>
<td>prefill 8K 暖</td>
<td style="text-align:right">36.8</td>
<td style="text-align:right"><strong>334.1</strong></td>
<td style="text-align:right"><strong>9.1×</strong></td>
<td style="text-align:right">5.2× 落後（原 47×）</td>
</tr>
<tr>
<td>prefill 8K 冷</td>
<td style="text-align:right">25.5</td>
<td style="text-align:right">104.0</td>
<td style="text-align:right">4.1×</td>
<td style="text-align:right">—</td>
</tr>
<tr>
<td>decode 單流</td>
<td style="text-align:right">2.37</td>
<td style="text-align:right">2.89</td>
<td style="text-align:right">1.22×</td>
<td style="text-align:right">27× 落後</td>
</tr>
<tr>
<td>decode c=8 聚合</td>
<td style="text-align:right">—</td>
<td style="text-align:right"><strong>19.86</strong></td>
<td style="text-align:right">8.95× vs c=1</td>
<td style="text-align:right">Strata 做不到</td>
</tr>
<tr>
<td>命中率 @40k</td>
<td style="text-align:right">52.8%</td>
<td style="text-align:right">67.0%</td>
<td style="text-align:right">+14pp</td>
<td style="text-align:right">Strata adaptive 72%</td>
</tr>
</tbody>
</table>
<hr />
<h2>decode 真正的牆：唔是 staging、唔是命中率、唔是併發</h2>
<p dir="auto">四個窗的 steady-state 最小二乘（n=26，交叉檢查誤差 +0.7%）：</p>
<pre><code>ms/fwd = 10.887 × units_staged + 0.567 × hits
hits + units = 479.98/fwd = 48 層 × top_k 10      ← counter 自洽

356.3 ms/fwd 拆解：
  hit 路徑   268.0 ms  (75.2%)   ← 牆
  staging     79.3 ms  (22.2%)
  rendezvous   0.6 ms   (0.2%)
  未解釋       8.4 ms
</code></pre>
<p dir="auto"><strong>480 個 hit unit × 0.567 ms = 272 ms。</strong> 這個數字同「48 層 × 10 專家」完全對得上，<br />
所以它不是數學成本，而是「每個 expert 一次 dispatch」。</p>
<p dir="auto">對照 Strata：78 tok/s = <strong>12.8 ms/fwd</strong>，我們 356 ms —— 28×。<br />
Strata 的論文原話：「The whole 48-layer pass is one captured CUDA graph per window size,<br />
so the host never waits on a synchronizing driver call.」</p>
<p dir="auto">而我們全部窗都帶 <code>--disable-cuda-graph</code>。試過開 graph，引擎直接在載入前拒絕：</p>
<pre><code>GSQInvariantError: cuda graphs not disabled
  (GSQ v1 needs --disable-cuda-graph; GSQ_V2=1 lifts this only for the v2 fast path)
</code></pre>
<p dir="auto"><strong>引擎自己知道 graph 要配 <code>GSQ_V2=1</code>。</strong> 這是下一步。</p>
<hr />
<h2>併發：Strata 結構上做不到的 8.95×</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="text-align:right">c</th>
<th style="text-align:right">每流</th>
<th style="text-align:right">聚合</th>
<th style="text-align:right">vs c=1</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right">1</td>
<td style="text-align:right">2.22</td>
<td style="text-align:right">2.22</td>
<td style="text-align:right">1.00×</td>
</tr>
<tr>
<td style="text-align:right">2</td>
<td style="text-align:right">3.67</td>
<td style="text-align:right">7.34</td>
<td style="text-align:right">3.31×</td>
</tr>
<tr>
<td style="text-align:right">4</td>
<td style="text-align:right">3.15</td>
<td style="text-align:right">12.61</td>
<td style="text-align:right">5.68×</td>
</tr>
<tr>
<td style="text-align:right">8</td>
<td style="text-align:right">2.48</td>
<td style="text-align:right"><strong>19.86</strong></td>
<td style="text-align:right"><strong>8.95×</strong></td>
</tr>
</tbody>
</table>
<pre><code>c=1 : 450 ms/forward（每次 1 token）
c=8 : 403 ms/forward（每次 8 token）
⇒ 8 倍 token、0.90 倍時間。第 2–8 個 token 邊際成本 ≈ 0
</code></pre>
<p dir="auto">原因同上面的歸因一致：<strong>forward 的成本是按 480 個 expert 計，唔是按 token 計。</strong><br />
Strata 是 FIFO 串行，這個乘數它拿不到。</p>
<p dir="auto">但誠實講：<strong>我們 c=8 的聚合 19.86，仍然只有 Strata 單流 78 的 25%。</strong><br />
併發乘的是一個太細的基數。</p>
<hr />
<h2>今日我錯了三次（都記在 counter 與日誌裡）</h2>
<ol>
<li><strong><code>pin190</code> 結論作廢</strong> —— 我以為「arena 按熱度釘選」無效，其實我的 patch 有 bug：<br />
<code>TOP=190</code> 對 190 個 slot ⇒ 每個 resident 都被 pin ⇒ <code>victim is None</code> ⇒ <strong>退化成純 LRU</strong>。<br />
即係根本冇測到 pin。這是對抗審查（Claude Code，16 KB 逐 file:line）抓出來的。</li>
<li><strong>「跨層 prefetch 是第一槓桿」錯</strong> —— 它只碰得到 staging 的 22%。真牆在 hit 路徑。</li>
<li><strong>一個 agent 講「prefill 從來冇行 grouped kernel」</strong> —— 我用 counter 反證：<br />
<code>4049a bypass</code> 次數 = <strong>0</strong>，加上源碼註釋「<code>GSQ_GROUPED_DEVICE_MAX_TOK=off</code> restores the old<br />
same-device behaviour」，證明 prefill 確實在跑 kernel。</li>
</ol>
<hr />
<h2>三個結構性後續（都不是兩日能完成）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>#</th>
<th>做什麼</th>
<th>狀態</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>packed bytes 直接餵 kernel</td>
<td><strong>早已在樹上</strong>（<code>GSQ_GROUPED_FIRST_MISS=1</code>）。kernel 本來就食 packed bytes；<code>read_dequant</code> 那個 28% 來自未開 GFM 的舊 config，不適用於快路徑。</td>
</tr>
<tr>
<td>2</td>
<td>固定 ring ＋ 指針表 ＋ CUDA graph</td>
<td>週級工程。<code>v2_fast_launch</code> 目前<strong>零 call site</strong>，且 AT=24 拓撲下 capture 死在跨卡 index（<code>index is on cuda:1</code>）。天花板取決於 decode 的 device-busy 比例，未量。</td>
</tr>
<tr>
<td>3</td>
<td>H2D 與 compute 重疊</td>
<td><strong>降級</strong>。PROF 的 <code>h2d</code> 桶量的是 4039 fallback 路徑的 blocking pageable copy（bf16, 10.65 MB/expert），而 arena 走 packed blob（2.33 MB/expert）。按 ρ=4.57 重算，真路徑的 h2d 只佔 4–16%，原本「≥30% 才做」的判準在目標路徑上不成立。</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>這三條都不是可以「今晚開工、明天收貨」的東西。</strong> 原本我把 #1 當成最快的一刀，查證後發現它已經完成了；#3 的 33% 是我用舊路徑的數字去論證新路徑，跨 config 了。</p>
<p dir="auto">真正的問題回到一個更基本的量測：<strong>decode 的 362 ms 裡，GPU 忙幾多 %？</strong><br />
≥60% ⇒ device-bound，槓桿在 kernel（per-group 小 GEMM、無 dedup）；<br />
≤30% ⇒ host-bound，graph 與 batching 才有意義。<br />
這個數字未出之前，任何結構性重構都只是押注。</p>
<hr />
<h2>三條方法論紀律（其中一條是今天我違反了的）</h2>
<ol>
<li><strong>預先寫判準，再看數據。</strong> 我寫死「h2d 佔比 ≥ 30% 才值得做 stream 重構」，量到 33%，<br />
一度以為過關。但查 PROF 的定義之後發現：那個 <code>h2d</code> 桶量的是 4039 fallback 路徑<br />
（dequant 後 bf16、10.65 MB/expert），而 arena 走的是 packed blob（2.33 MB/expert）。<br />
<strong>同一個名字，兩條路徑，差 4.57 倍 bytes。</strong> 判準本身沒錯，是我把它套在錯的路徑上。</li>
<li><strong>跨 config 唔相減，跨路徑唔借比例。</strong> 這條我今天犯了三次（arena vs 分塊、<br />
<code>h2d</code> 舊路徑 vs 快路徑、<code>read_dequant</code> 的 28% 其實來自冇開 GFM 的 config）。<br />
每次都是「同一個指標名」讓我放鬆了警惕。</li>
<li><strong>counter 要自證。</strong> <code>hits + units = 479.98/fwd = 48 × 10</code> 這種恆等式，比任何解釋都可靠。<br />
反面教材：一個 agent 用「全部 512 專家都要搬」推出 51.9 GB 上限，而我們實際只搬 33% miss。</li>
</ol>
<hr />
<h2>現在的誠實定位</h2>
<pre><code>prefill   334.1 vs 1,719   → 差 5.2×（起點 47×）
decode    2.89  vs 78      → 差 27×（單流）
          19.86 vs 78 串行 → c=8 聚合仍然落後 3.9×
</code></pre>
<p dir="auto">兩日內能交的是「prefill 9.1× ＋ 併發 8.95× ＋ decode 完整的歸因」，<br />
不是「追平 Strata」。要追平必須完成上面三件結構性的事 —— 那是週級，不是日級。</p>
<p dir="auto">把這句話寫在交付前面，比交付一個漂亮數字重要。</p>
]]></description><link>https://lcz.me/post/31686</link><guid isPermaLink="true">https://lcz.me/post/31686</guid><dc:creator><![CDATA[Benjy Lei]]></dc:creator><pubDate>Sat, 07 Nov 2026 05:50:54 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Sat, 07 Nov 2026 02:46:22 GMT]]></title><description><![CDATA[<p dir="auto"><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f525.png?v=5be5614064c" class="not-responsive emoji emoji-android emoji--fire" style="height:1.4em;width:auto;vertical-align:middle" title="🔥" alt="🔥" /> 本帖参与讨论人数已达 <strong>10+</strong>，入选<strong>热议</strong>，作者 <strong>+3 积分</strong>奖励！</p>
<blockquote>
<p dir="auto">奖励凭证：热议 +3 分 · 编号 h2793-3382-1</p>
</blockquote>
]]></description><link>https://lcz.me/post/31655</link><guid isPermaLink="true">https://lcz.me/post/31655</guid><dc:creator><![CDATA[Xiaote]]></dc:creator><pubDate>Sat, 07 Nov 2026 02:46:22 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Sat, 07 Nov 2026 02:45:32 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/benjy-lei" aria-label="Profile: Benjy-Lei">@<bdi>Benjy-Lei</bdi></a> <a href="/post/31433">说</a>:</p>
<h1>【7900xtx·qwen-flash】Flash-Next 混合 GDN 移植日記（二）：併發開考 7.7× ＋ MTP 頭移植八堵牆拆七</h1>
<p dir="auto">。。。。。。。。。。。。。。。<br />
| 3 | layer-split 要求 ≥2 層 | 全局 <code>GSQ_LAYER_SPLIT</code> env 流入 draft（佢得 1 層） | <strong>樹 patch</strong>：draft runner 豁免 |<br />
<strong>標籤建議</strong>：<code>7900xtx</code> <code>qwen-flash</code> <code>多卡部署</code></p>
</blockquote>
<p dir="auto">NB啊！  在各大佬的努力下 7900XTX 终将留名青史</p>
]]></description><link>https://lcz.me/post/31654</link><guid isPermaLink="true">https://lcz.me/post/31654</guid><dc:creator><![CDATA[张光璞]]></dc:creator><pubDate>Sat, 07 Nov 2026 02:45:32 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Fri, 06 Nov 2026 08:29:34 GMT]]></title><description><![CDATA[<p dir="auto">这项目搞通了论坛里高低要混把大神交椅<br />
<img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f44f.png?v=5be5614064c" class="not-responsive emoji emoji-android emoji--clap" style="height:1.4em;width:auto;vertical-align:middle" title=":clap:" alt="👏" />加油</p>
]]></description><link>https://lcz.me/post/31562</link><guid isPermaLink="true">https://lcz.me/post/31562</guid><dc:creator><![CDATA[xiongjie gao]]></dc:creator><pubDate>Fri, 06 Nov 2026 08:29:34 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Fri, 06 Nov 2026 07:31:13 GMT]]></title><description><![CDATA[<p dir="auto"><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2b50.png?v=5be5614064c" class="not-responsive emoji emoji-android emoji--star" style="height:1.4em;width:auto;vertical-align:middle" title="⭐" alt="⭐" /> 版主审定：本帖设为<strong>精华</strong>，作者 <strong>+6 积分</strong>奖励，希望再接再厉！</p>
<blockquote>
<p dir="auto">奖励凭证：精华 +6 分 · 编号 f2793-3382-1</p>
</blockquote>
]]></description><link>https://lcz.me/post/31556</link><guid isPermaLink="true">https://lcz.me/post/31556</guid><dc:creator><![CDATA[Xiaote]]></dc:creator><pubDate>Fri, 06 Nov 2026 07:31:13 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Thu, 05 Nov 2026 23:46:12 GMT]]></title><description><![CDATA[<h1>【7900xtx·qwen-flash】Flash-Next 混合 GDN 移植日記（二）：併發開考 7.7× ＋ MTP 頭移植八堵牆拆七</h1>
<p dir="auto"><strong>環境聲明（對齊單位先）</strong>：雙 XTX 7900（gfx1100，PCIe 無 P2P）· SGLang fork（gfx1100 系）·<br />
Qwen3.8-Flash-Next GSQ IQ3_S（48 層＝36 GDN＋12 attention，512 專家/層，專家由 host 流式進<br />
VRAM arena）· 兩卡 layer-split（各 24 層專家全套）· 無 CUDA graph、無 MTP。以下數字全部<br />
<strong>端到端 wall 口徑、<code>usage.completion_tokens</code> 實算</strong>，counting 任務（250 token/流、temp 0）、<br />
同窗同 harness，冷/暖態標明。</p>
<hr />
<h2>一、decode 速度：併發全梯（本篇主菜）</h2>
<p dir="auto">先講一個前提故事。開 <code>--max-running-requests 8</code> 打 4 條併發 request，聚合睇落有「1.9×」<br />
加速——但翻 rank log：<strong>45 條 Decode batch 紀錄，#running-req 全部＝1</strong>。由頭到尾冇 batch 過，<br />
「加速」純粹係首 phase 冷啟（Triton/arena 暖機）拖低咗分母。教訓：<strong>判斷併發之前必睇<br />
running-req 直方圖</strong>，聚合吞吐會講大話。</p>
<h3>根因：mamba admission 鉗制（hybrid GDN 模型專有）</h3>
<p dir="auto">追 <code>kv_cache_configurator.py</code> 嘅 admission 計算：</p>
<pre><code>max_running_requests = min( 你叫嘅 8 , max_mamba_cache_size ÷ 每請求 slot 數 )
                     = min( 8 , 7 ÷ 5 ) = 1      ← 靜靜鉗死
</code></pre>
<ul>
<li>radix＋overlap 開 → 每請求帳面 5 個 mamba state slot；專家 arena 食緊 VRAM，pool 淨得 7 slot</li>
<li>7÷5=1 → scheduler 永遠零新請求准入。<strong>server 唔報錯</strong>，得 startup 一行提示</li>
<li>解法一個 flag：<code>--disable-radix-cache</code>（slot 5→1，pool 直接對齊 8）。獨立 prompt 場景零損失</li>
</ul>
<h3>全梯實測（250 token/流，八流完全公平）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>併發</th>
<th>聚合 tok/s</th>
<th>每流 tok/s</th>
<th>加速比</th>
</tr>
</thead>
<tbody>
<tr>
<td>1（冷啟）</td>
<td>2.55</td>
<td>2.55</td>
<td>1×</td>
</tr>
<tr>
<td>1（暖態）</td>
<td>~4.0</td>
<td>~4.0</td>
<td>—</td>
</tr>
<tr>
<td>2</td>
<td>6.97</td>
<td>3.48</td>
<td>2.7×</td>
</tr>
<tr>
<td>4</td>
<td>12.01</td>
<td>3.00</td>
<td>4.7×</td>
</tr>
<tr>
<td><strong>8</strong></td>
<td><strong>19.51</strong>（重跑 18.11）</td>
<td>2.44</td>
<td><strong>7.7×</strong></td>
</tr>
</tbody>
</table>
<ul>
<li>running-req 直方圖齊晒 1→2→4→8，引擎瞬時 20.2 tok/s 仲未見頂</li>
<li>每流 3.48→3.00→2.44 緩降＝專家搬運攤薄紅利漸被 batch 計算量抵消，但 c=4→8 聚合仲有 +63%</li>
<li><strong>呢個架構（專家 host 流式入 VRAM）嘅 throughput 鑰匙係併發</strong>：N 條流嘅路由專家喺同一次<br />
arena pass 撞埋一齊，fetch 次數唔線性涨。單流 kernel 微調救唔到 decode（我哋實測過，零效果）</li>
<li>對照組（單位講明）：同 harness 全 resident 引擎單流 95-107 tok/s——我哋單流輸緊一截，<br />
併發斜率先係呢條路嘅存在理由</li>
</ul>
<hr />
<h2>二、MTP 頭移植：八堵牆拆咗七（改咗幾多代碼）</h2>
<p dir="auto">Flash-Next 原生帶 MTP 頭（單層尾部 drafter：1 個 full-attn＋MoE block＋input fusion，<br />
共享主模型 lm_head；權重源係 HF BF16 checkpoint，GGUF 本身冇）。目標＝接上 SGLang 嘅<br />
NEXTN 投機解碼，乘上 accept rate。由「draft 連 load 都入唔到」去到「draft→target verify<br />
行勻兩卡專家 arena」，八堵牆：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>#</th>
<th>牆</th>
<th>根因</th>
<th>修復</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>draft 撞主模型嘅 GGUF loader</td>
<td>draft 繼承全局 <code>--load-format</code></td>
<td><code>--speculative-draft-load-format auto</code></td>
</tr>
<tr>
<td>2</td>
<td>loader 拒 13 個 GSQ config key</td>
<td>全局 <code>--model-loader-extra-config</code> 流入 draft</td>
<td><strong>樹 patch</strong>：draft 載入時掉目標 extra-config（loud log）</td>
</tr>
<tr>
<td>3</td>
<td>layer-split 要求 ≥2 層</td>
<td>全局 <code>GSQ_LAYER_SPLIT</code> env 流入 draft（佢得 1 層）</td>
<td><strong>樹 patch</strong>：draft runner 豁免</td>
</tr>
<tr>
<td>4</td>
<td>KV pool 起唔到</td>
<td>BF16 draft 7GB＋投機 mamba intermediate 擠爆 24GB 卡</td>
<td><code>--max-running-requests 4</code>（intermediate 2.15GB 實測）＋ mem-fraction 調整</td>
</tr>
<tr>
<td>5</td>
<td><code>lm_head.weight</code> 唔存在</td>
<td>GSQ 量化 head 只有 qweight；共享機制假設 BF16 tensor</td>
<td><strong>樹 patch</strong>：量化 head 回傳 None，draft 直接共享成個 module（零 VRAM）</td>
</tr>
<tr>
<td>6</td>
<td>mamba state commit assert</td>
<td>兩卡 layer-split 手術將 mamba_cache 換成跨卡路由視圖，isinstance 唔識</td>
<td><strong>樹 patch</strong>：放行路由視圖（逐層存取本來就回傳真 tensor，verify 前向已實證）</td>
</tr>
<tr>
<td>7-8</td>
<td>觀測盲區</td>
<td>error 訊息用扣減前嘅數，raise 條件對 fraction 唔敏感</td>
<td><strong>觀測器 patch</strong>：admission 全代數印實數（available/slack/intermediate）</td>
</tr>
</tbody>
</table>
<p dir="auto">打字打到呢度先講清楚：<strong>全部 patch additive</strong>——唔開 spec flags＝逐 byte 原行為，<br />
<code>.bak</code> 留底，py_compile 過先上樹。現狀：<strong>首個完整 spec-on boot 差最後一個 commit 接縫</strong><br />
（修復已落樹，驗證窗跑緊）。spec-on 數據（accept rate、單流/c=8×MTP）下一帖交。</p>
<p dir="auto"><strong>量化臂同時開咗題</strong>：draft 專家 Q2_0 化（675MB，同引擎生產配方 bitstream 一致），<br />
draft 常駐 5GB→0.83GB——因為牆#4 證明 BF16 draft 同專家 arena 喺 24GB 卡本質唔共存。<br />
builder 已寫好跑通（重打包 vs 官方 gguf <strong>位元級一致</strong>）。</p>
<h2>三、附：早前同批嘅 TP2 silent 語義地雷（未發過，一併記低）</h2>
<p dir="auto">兩進程 TP2 起機後語義全錯但<strong>輸出流利、零 NaN、兩卡 bit-identical</strong>。逐層 capture 鎖定<br />
第一個 GDN 層輸出已偏，最終根因：</p>
<blockquote>
<p dir="auto">呢隻 artifact 用 <strong>modulo head-pairing</strong>（v-head h 讀 k-head h%16）。fla Triton kernel 嘅<br />
<code>i_h % Hg</code> 喺 TP 下攞本卡 <strong>local Hg=8</strong>——連續半切之下 16/48 個 v-head 讀咗隔離卡嘅<br />
k-head。值貌似合理、兩 rank 對稱壞，shape check 全部捉唔到。interleave pairing 唔中招。</p>
</blockquote>
<p dir="auto">呢個已經落咗 fail-closed guard（modulo×TP&gt;1 直接 raise 拒絕起機，唔會靜靜服務壞數）。</p>
<p dir="auto"><strong>標籤建議</strong>：<code>7900xtx</code> <code>qwen-flash</code> <code>多卡部署</code></p>
]]></description><link>https://lcz.me/post/31433</link><guid isPermaLink="true">https://lcz.me/post/31433</guid><dc:creator><![CDATA[Benjy Lei]]></dc:creator><pubDate>Thu, 05 Nov 2026 23:46:12 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Wed, 04 Nov 2026 07:49:29 GMT]]></title><description><![CDATA[<p dir="auto">这数据确实很猛~</p>
]]></description><link>https://lcz.me/post/30938</link><guid isPermaLink="true">https://lcz.me/post/30938</guid><dc:creator><![CDATA[懒人烘培]]></dc:creator><pubDate>Wed, 04 Nov 2026 07:49:29 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Wed, 04 Nov 2026 06:52:33 GMT]]></title><description><![CDATA[<p dir="auto">這太猛了 必須頂</p>
]]></description><link>https://lcz.me/post/30927</link><guid isPermaLink="true">https://lcz.me/post/30927</guid><dc:creator><![CDATA[starryskyknight]]></dc:creator><pubDate>Wed, 04 Nov 2026 06:52:33 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Wed, 04 Nov 2026 04:16:17 GMT]]></title><description><![CDATA[<p dir="auto">續：把 Strata 搬上 SGLang 引擎（三）—— 第五個坑修好終於講人話；然後發現牆不是 kernel，是把 kernel 直接搬過來</p>
<p dir="auto">上一篇結束時的狀態：serve 得、四個慣例坑已修、但輸出仍然退化，承諾「下一篇是逐 op parity 的結果」。這篇就是，加上之後性能線的完整轉折：三個優化被同窗 A/B 判死、profiler 拆出真牆、最後把生產引擎現成的 kernel 直接橋進 torch，一次過把 decode 和 prefill 兩條 kernel 線實測過判準。數字全部實測。</p>
<p dir="auto">硬體：雙 7900XTX（gfx1100 / ROCm）、94 GB RAM；模型：Qwen3.8-Flash-Next ISTA GSQ-RCO IQ3_S（MoE，512 experts × 48 層，top-10 路由）<br />
建議 tags：7900xtx strata sglang 多卡部署 qwen-flash</p>
<p dir="auto">TL;DR</p>
<ol>
<li>逐 op parity 釘到第五個真 bug：GDN 的 value-head → key-head 配對，引擎用 modulo、fork 用 interleave，44/48 個 head 讀錯 key。修完（config 一行）輸出逐字正確：法國首都→巴黎、17×23→391、通順廣東話，與Strata一致。</li>
<li>語義收線之後全力追速度，三個結果：expert-scoped 佈局（只算路由到該 expert 的 rows）把 prefill 18.3 → 125.5 tok/s（6.87×）；但之後兩個「減少呼叫次數」的改寫——micro-batch（op 數削 35 倍）和 bf16 slab（呼叫數削 64 倍）——同窗 A/B 實測一個只快 0–6%、一個反而慢 9–28%，全部判死。</li>
<li>進程內 profiler 拆牆：每個 expert 單元 2.127 ms 裡，CPU 讀取＋dequant 佔 84.5%，H2D 只 4.6%，GEMM 10.9%。每 token 要搬 480 份 ×9 MB 權重 ≈ 3.8 GB/s——牆是搬 bytes，不是算力、不是 op 數、也不是 PCIe。</li>
<li>於是換路：不自己寫 kernel，把生產引擎現成的 grouped expert kernel（一次 call 做齊 gather→dequant→gate/up→SwiGLU→down→scatter）用薄 torch 橋接直接用。真 artifact bytes 上實渗 decode 4.96 µs/expert——判準預算是 30 µs，6 倍餘裕。</li>
<li>橋接本身 15/15 gates：三種量化格式 × 兩個 kernel 佈局 × 引擎的優化臂，輸出 bitwise 相同；prefill 那邊的 MMQ kernel 也實測四個 context 判準點全過。</li>
<li>誠實講：還沒接線進 SGLang 主路徑。下一個裁決點是 expert 常駐 VRAM 的命中率——全模型 expert 46.8 GiB，對 2×24 GB 顯卡，這才是計劃成立與否的真正未知。</li>
</ol>
<p dir="auto">一、第五個坑：GDN head 配對（講人話的最後一里）</p>
<p dir="auto">上一篇的方法：fork 側用環境變數 gate 逐 op dump，對 numpy 參考（真權重＋從引擎源碼逆向的公式），報第一個超容差的 op。</p>
<p dir="auto">結果：conv 3.7e-3、split 0.0、beta 7.7e-4、dt 2.2e-8、decay 1.9e-8、epilogue 1.7e-3——全部在 bf16 噪聲內。唯一爆表的是 delta rule 的 head 配對：rel 1.246。</p>
<p dir="auto">機制：48 個 value head 共享 16 個 key head。引擎 kernel 用 modulo 配對（h % h_k），fork 的 FLA kernels 用 interleave（i_h // (H/Hg)）。兩種都是合法慣例，但同一個模型只能用一種——錯了之後 44/48 個 head 在錯的 key 上累積 delta state。形狀全對、無 NaN、文字流暢，「講得出話、講錯事」，而且狀態越長崩得越厲害。</p>
<p dir="auto">修法：bridge config 一行 gdn_head_pairing = "modulo"（默認 interleave 不變，其他模型零影響；prefill/decode 兩條 kernel 路都要覆蓋）。</p>
<p dir="auto">修完的語義驗收錨是「短 prompt 答案與生產逐字相同」，不是 gate 數、不是 tok/s：巴黎、391、通順粵語，三條全中。五個坑修完（A_log 變換、plain gain norm、sigmoid gate、PLE 層號＋大表、head 配對），「跑得對」這一關正式收線。</p>
<p dir="auto">二、速度線：兩個「減少呼叫」的優化判死，profiler 拆出真牆</p>
<p dir="auto">expert-scoped 佈局修掉的是真正的浪費：舊路對每個受路由 expert 都跑完整批 token 的 FFN 再用 mask 丟結果，每 chunk 實做 990 TFLOP、必要 19.3 TFLOP（51.2× 冗餘）；修完 prefill 18.3 → 125.5 tok/s。</p>
<p dir="auto">之後的瓶頸量測指向「每 expert 一次 Python 呼叫 ×0.73 ms」，於是做了兩個直覺上正確的改寫：</p>
<ul>
<li>micro-batch：把每層 N 個 expert × 11 個 torch op 壓成常數個 batched GEMM。op 數 19,478 → 550（35×）、fp32 權重展開 1,536 次 → 0。同窗兩腿 A/B：只快 0–6%，T=7 反而慢 9%。</li>
<li>bf16 slab：把整個 block 的 experts 疊成一個大矩陣，叫上游 triton fused-experts kernel 一次算完。同窗 A/B：慢 9–28%。</li>
</ul>
<p dir="auto">第二個的死因有外部佐證：log 裡每個 block 都印 "Using default MoE kernel config"。實查 SGLang 樹：configs/ 有 386 個 device json，MI300 有 8 個，RX7900XTX 是 0 個；而且 configs 目錄只有 triton 3.5/3.6/3.7 的版本目錄，我們跑的是 3.8——就算有人補了 config 也讀不到。</p>
<p dir="auto">但真正值錢的是反推：micro-batch 把 op 削了 35 倍而時間不動，說明 0.73 ms/expert 不是 Python dispatch 的錢，是搬權重的錢——24,576 次 expert 呼叫 × 9 MB ≈ 221 GB / 57.9 s ≈ 3.8 GB/s，PCIe 級。再用進程內 profiler（環境變數 gate，每 expert 單元累計 read+dequant / H2D / GEMM，引擎退出時印一行）把 decode 拆開：每單元 2.127 ms，讀取＋dequant 84.5%、H2D 4.6%、GEMM 10.9%。H2D 只 0.098 ms——「PCIe 是瓶頸」這個講法也被否證，牆一直在 CPU 側的解壓。</p>
<p dir="auto">結論收束成一句：expert 權重要以量化 bytes 常駐 VRAM、dequant 融進 kernel 裡，同一塊 VRAM 容納 4.7× 單元數——這正是生產引擎的設計。那為什麼不直接用它的 kernel？</p>
<p dir="auto">三、判準定調，然後把生產 kernel 橋進 torch</p>
<p dir="auto">判準先定（不然 gate 都是拍腦殼）：單流，Path B 要達到生產基準的 2/3（差距 ≤ 1/3）。生產基準（temp 0、nonce、usage 計數、3 reps 取中位）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>context</th>
<th style="text-align:right">decode 基準</th>
<th style="text-align:right">prefill 基準</th>
<th style="text-align:right">Path B 判準</th>
</tr>
</thead>
<tbody>
<tr>
<td>64K</td>
<td style="text-align:right">96.5 tok/s</td>
<td style="text-align:right">6,130 tok/s</td>
<td style="text-align:right">decode ≥ 64.3 / prefill ≥ 4,087</td>
</tr>
<tr>
<td>256K</td>
<td style="text-align:right">105.7</td>
<td style="text-align:right">4,343</td>
<td style="text-align:right">≥ 70.5 / ≥ 2,895</td>
</tr>
</tbody>
</table>
<p dir="auto">decode 判準換算：每 token 15.55 ms，480 個 expert 單元 ⇒ 30 µs/單位。現況是 2,127 µs——差 66 倍，自己的 torch 路永遠追不到，必須 grouped fused kernel。</p>
<p dir="auto">做法：寫一個 torch extension（一個 .cpp），直接 link 生產引擎已編好的 kernel 靜態庫，暴露五個 op。不寫任何量化 kernel。</p>
<p dir="auto">decode 實測（引擎自帶 bench、真 GGUF rows、兩個 kernel 佈局互相 bitwise 對拍、interleave 取三輪最小；T=1 token、G=10 experts＝一層一次 grouped call；六種 gate/up×down 格式組合全覆蓋）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>gate/up / down 格式</th>
<th style="text-align:right">每層 call</th>
<th style="text-align:right">gate/up 頻寬</th>
</tr>
</thead>
<tbody>
<tr>
<td>IQ3_XXS / IQ4_NL</td>
<td style="text-align:right">47.0 µs</td>
<td style="text-align:right">520 GB/s</td>
</tr>
<tr>
<td>IQ2_S / Q2_0</td>
<td style="text-align:right">50.6 µs</td>
<td style="text-align:right">377 GB/s</td>
</tr>
<tr>
<td>IQ3_S / IQ4_NL</td>
<td style="text-align:right">50.4 µs</td>
<td style="text-align:right">521 GB/s</td>
</tr>
<tr>
<td>（其餘三組合）</td>
<td style="text-align:right">47.8–49.9 µs</td>
<td style="text-align:right">—</td>
</tr>
</tbody>
</table>
<p dir="auto">49.6 µs ÷ 10 ＝ 4.96 µs/單位；×48 層 ＝ 2.38 ms/token ＝ decode 預算的 15–17%。launch 攤薄的算術也實測了：單 expert 一次 call 16.9 µs（launch 主導，kernel 內約 4 個 launch），grouped 10 個的邊際成本 3.64 µs/個；40 個 expert 一次過 3.86 µs/個 @ 564–672 GB/s。「每層一次 call」不是風格，是算術必須。</p>
<p dir="auto">torch 橋接 15/15 gates：blob 幾何三源一致（kernel 庫算的 ≡ 引擎 pack 表 ≡ 2,176,000/1,510,400/2,329,600 B 逐層吻合）；mode A/B × EXPDEC 優化臂三臂輸出 hash 完全相同（bitwise）；每層 call 57–60 µs（多出的 ~10 µs 是 Python dispatch，graph capture 可收回）。一個實務細節給想 replicate 的人：torch 的 ROCm wheel 環境沒有 cuda_runtime_api.h，ATen 的 CUDAContext.h 編不過——解法是照 sgl_kernel AOT 的慣例，stream 由 Python 端以 int64 傳進來，shim 不 include 任何 CUDA header。</p>
<p dir="auto">prefill 那邊（MMQ 級 batched 量化 GEMM，一批 token 共享一次權重讀取）：4,096-token chunk 的形狀（每 expert 平均 80 rows）實測每 16-expert launch 0.546 ms，一個 chunk 的 MoE 共 839 ms。對判準：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>context</th>
<th style="text-align:right">判準</th>
<th style="text-align:right">實測（MoE＋attention 估算）</th>
<th>判</th>
</tr>
</thead>
<tbody>
<tr>
<td>64K</td>
<td style="text-align:right">4,087 tok/s</td>
<td style="text-align:right">4,548</td>
<td>過</td>
</tr>
<tr>
<td>128K</td>
<td style="text-align:right">3,659</td>
<td style="text-align:right">4,255</td>
<td>過</td>
</tr>
<tr>
<td>192K</td>
<td style="text-align:right">3,264</td>
<td style="text-align:right">4,001</td>
<td>過</td>
</tr>
<tr>
<td>256K</td>
<td style="text-align:right">2,895</td>
<td style="text-align:right">3,766</td>
<td>過</td>
</tr>
</tbody>
</table>
<p dir="auto">（attention 項用先前實測的線性律斜率估算 62–249 ms/chunk；MMQ 臂只量了 IQ3_S＋IQ4_NL 兩種格式＋合成權重，是可行性證據不是端到端承諾。效率隨 chunk 增大：600-token chunk 只有 ~1,600 tok/s，32K chunk ~11,300——launch 攤薄差。）</p>
<p dir="auto">數據通路也閉了：引擎的 expert blob 與我們 pack 的 objects（gate‖up‖down 拼接）逐 byte 相同（實測對拍 True），GGUF plane 內每 expert stride 704,000 B 無 padding——零轉換直接餵。</p>
<p dir="auto">四、還沒證的（比已證的重要）</p>
<ol>
<li>所有 kernel 數字都假設 expert 已在 VRAM。全模型 46.8 GiB，雙卡 48 GB 理論剛好，但 KV、mamba state、dense 權重都要位。生產引擎靠 KV 放 host RAM＋int8 KV 才塞得下；Path B 的命中率 ≥80% 未實證——這是下一個裁決點。</li>
<li>雙卡 expert 並行的 all-to-all 在 gfx1100 沒跑過；hybrid（mamba/GDN）模型的 host KV 在 SGLang 沒證。這兩個任何一個不成立，工期翻倍。</li>
<li>沒有 MTP（生產 --spec 3、accept 0.81）；對「取代」對照時要補，投機的倍數不能記在 kernel 頭上。</li>
<li>還沒接線：decode/prefill 都還是獨立 bench 的數字，SGLang 主路徑的接線正在做。</li>
</ol>
<p dir="auto">兩個要收回的舊結論：一、「TP=2 有 block 對齊死牆」——建立在抄錯的量化表上（把 IQ4_NL 的 (32,18) 當成 256 值 block），live manifest 逐 object 驗算後 down 層全部整除，而 expert 維切分（EP=2）本來就零 pack 改動、負載平衡 1.000000。二、「單流做完也就 25–40 tok/s」——那個階梯假設要自寫 kernel；現成 kernel 的實測數字已經超過它的終點值。</p>
<p dir="auto">性能（誠實版，同 harness 對拍）</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>量</th>
<th style="text-align:right">Path B（語義正確版）</th>
<th style="text-align:right">生產 Strata</th>
</tr>
</thead>
<tbody>
<tr>
<td>decode（長文 sweep 64K–256K）</td>
<td style="text-align:right">1.67–1.70 tok/s</td>
<td style="text-align:right">96.5–105.7</td>
</tr>
<tr>
<td>prefill 短請求（~5.9K token）</td>
<td style="text-align:right">94.8 tok/s</td>
<td style="text-align:right">—</td>
</tr>
<tr>
<td>prefill（長文 sweep 64K–256K）</td>
<td style="text-align:right">（外推 ~30，未實測 64K 點）</td>
<td style="text-align:right">4,343–6,130</td>
</tr>
</tbody>
</table>
<p dir="auto">方法論（這輪救了幾次）</p>
<ul>
<li>同窗兩腿是唯一可信比較：同一 config 隔幾小時的對照腿只剩歷史值的 ~75%（94.9 vs 125.5 tok/s）。跨窗口的歷史數字不是 baseline，任何「快了/慢了」都當場同窗重跑控制腿。</li>
<li>報 N 倍必附可重算算式；推導值與 instrumented 實測值分開標。micro-batch 那次就是算式推翻了直覺：counter 綠（op 數大跌）而 wall 不動 ⇒ 成本模型錯，不是量測不準。</li>
<li>bitwise 對拍 + 負控制：兩個佈局互相 bitwise 才信 wiring；驗證鏈要故意弄壞一個 byte 證明會紅。一個從未紅過的綠鏈沒有證據力。</li>
<li>效果 gate 的量綱先對齊：拿一個 5.9K-token 請求去除以「每 4,096-chunk」的律，會憑空多出 3 倍假差距——先對齊 chunk 數再比。</li>
<li>GPU 實測全程停產引擎窗口（stop→test→restore trap），單窗中斷 &lt;10 秒，收窗驗 health 200。</li>
</ul>
<p dir="auto">一句話</p>
<p dir="auto">「跑得對」與「跑得快」之間隔著 480 份 9 MB；這一輪證明了不用自己填——把生產引擎的橋直接架過來就行，剩下的難題是停車位（VRAM residency），不是引擎。</p>
<p dir="auto">下一篇應該是接線後 SGLang 自己跑出來的第一組數字。</p>
]]></description><link>https://lcz.me/post/30903</link><guid isPermaLink="true">https://lcz.me/post/30903</guid><dc:creator><![CDATA[Benjy Lei]]></dc:creator><pubDate>Wed, 04 Nov 2026 04:16:17 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Tue, 03 Nov 2026 07:05:56 GMT]]></title><description><![CDATA[<p dir="auto">顶你！！借助AI的翅膀，尽情遨游在以前不敢想象的任务......</p>
]]></description><link>https://lcz.me/post/30711</link><guid isPermaLink="true">https://lcz.me/post/30711</guid><dc:creator><![CDATA[Enigma]]></dc:creator><pubDate>Tue, 03 Nov 2026 07:05:56 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 23:37:40 GMT]]></title><description><![CDATA[<p dir="auto">继续，有进展了我置顶。</p>
]]></description><link>https://lcz.me/post/30642</link><guid isPermaLink="true">https://lcz.me/post/30642</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Mon, 02 Nov 2026 23:37:40 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 23:32:39 GMT]]></title><description><![CDATA[<h1>續：把 Strata 搬上 SGLang 引擎（二）—— 四個「無 error 但錯」的慣例坑</h1>
<blockquote>
<p dir="auto">前一篇：<code>把 Strata 搬上 SGLang 引擎：32 個 patch、9 個窗口、一次 serve、一個 −exp 的坑</code><br />
這一篇是後續：serve 之後仍然講不出人話，於是逐個慣例去對。已修四個真 bug、排除五個假設，<br />
現在知道錯在哪一類，但還未修好。數字全部是實測。<br />
硬體：雙 7900XTX（gfx1100 / ROCm）、94 GB RAM；模型：Qwen3.8-Flash-Next ISTA GSQ-RCO <strong>IQ3_S</strong>（MoE，專家走 NVMe）<br />
建議 tags：<code>7900xtx</code> <code>strata</code> <code>多卡部署</code> <code>qwen-flash</code></p>
</blockquote>
<h2>TL;DR</h2>
<ul>
<li>serve 得，但輸出是退化文字。四個真 bug 已修好並落機，<strong>每一個都是「無 error、形狀合法、但算錯」</strong>。</li>
<li>最有價值的一項：GDN 的輸出 gate，引擎用 <code>sigmoid(z)</code>，fork 預設 <code>swish</code>（<code>z·σ(z)</code>），36/48 層、每 token、per-head 乘性錯。修完之後輸出<strong>質變</strong>（由隨機詞湯變成另一種壞法），證明它是主因之一。</li>
<li>五個假設被證據排除，其中一個是我自己判斷錯：partial rotary 根本沒壞。</li>
<li>性能：1.4–1.75 tok/s（同 harness 生產 26–34；生產自己長文 95–107）。差距是結構性的（無 RAM tier / 無 MTP / 單卡），不是調參。</li>
<li>現時症狀已定性為「狀態一累積就崩」，下一步用逐 op parity 去釘，不再開窗猜。</li>
</ul>
<h2>這一輪的四個坑（都可复用成 checklist）</h2>
<h3>1. <code>ssm_a</code> 已經是 <code>−exp(A_log)</code></h3>
<p dir="auto">llama.cpp 匯出 GGUF 時，<code>A_log</code> 已被轉成 <code>ssm_a = −exp(A_log)</code>；fork 把它原值塞進 <code>linear_attn.A_log</code>，<br />
而 gating kernel 會再做一次 <code>−exp()</code>。結果 decay 乘數 ≈ <code>−exp(−exp(A_log))</code> ≈ −1，<br />
<strong>per-token decay 由 3.3e-06 變成 1.00</strong>（36 層 GDN 的 state 幾乎凍結）。</p>
<ul>
<li>修法：落地縫 <code>A_log := log(−ssm_a)</code>，先 assert 全部 &lt; 0（fail-closed）</li>
<li>實測：<code>transformed 36/36</code>；gate 數值對引擎 rel <strong>1.68e-08</strong>；decay <code>0.526086</code> 兩邊相同</li>
<li>事後發現 fork 自己對另一個模型家族早有正確 helper（<code>kimi_k3_gguf._kda_a_log_target_value</code>）——<br />
<strong>先 grep 一下有沒有同族模型已經讀過同一個慣例</strong>，比自己去推快得多</li>
</ul>
<h3>2. norm 是 plain gain，fork 卻做 <code>1+w</code></h3>
<p dir="auto">artifact 的 norm 值域中心 ≈ 1（<code>hc_attn_norm</code> mean 0.9365、<code>ssm_norm</code> 0.9668、<code>attn_q_norm</code> 1.4437），<br />
即訓練時直接乘 <code>w</code>；fork 的 <code>GemmaRMSNorm</code> forward 是 <code>x * (1.0 + w)</code>。</p>
<p dir="auto">這不是一個 scale，是 <strong>per-channel 扭曲</strong>：同一隻 tensor 內 <code>(1+w)/w</code> 由 1.00 到 20.7，<br />
負 gain 的 channel 連符號都反。</p>
<ul>
<li>修法：只對 148 隻「consumer 做 <code>1+w</code>」的 norm 落 <code>w−1</code>；36 隻 <code>linear_attn.norm</code>（FLA gated RMSNorm，plain <code>x*rstd*w</code>）<strong>原樣不動</strong>，並用測試證明 byte-identical</li>
<li>要注意的陷阱位：<code>input_layernorm</code>/<code>post_attention_layernorm</code> 在這個模型被 <code>delattr</code> 掉了、<br />
final norm 叫 <code>output_hc_norm</code>、hyper-connection 的 <code>hc_*_norm</code> 也是 <code>1+w</code>（不要以為「hyper-connection 就是 plain」）</li>
<li>實測：<code>transformed 148/148 … 36 plain untouched</code></li>
</ul>
<h3>3. GDN 輸出 gate：<code>sigmoid</code> 不是 SiLU</h3>
<ul>
<li>引擎：<code>y = rms_norm(o) * ssm_norm * sigmoid(z)</code>（<code>gdn.cu</code> 註解直接寫「SIGMOID, not SiLU」，<code>layer.cpp</code> 再寫一次）</li>
<li>fork：<code>RMSNormGated</code> 因 config 沒有 <code>output_gate_type</code> 而取 default <code>swish</code> ⇒ <code>z·σ(z)</code></li>
<li>修法：bridge config 一行 <code>text_config.output_gate_type = "sigmoid"</code></li>
<li>效果：<strong>唯一令輸出「變質」的修正</strong>——由「隨機詞湯」變成「重複標點退化」</li>
</ul>
<p dir="auto">教訓：vender kernel 裡出現「X, not Y」這種註解，就當它是 spec。</p>
<h3>4. PLE 完全 inert（層號 + 大表）</h3>
<ul>
<li>artifact 的 PLE 在 <code>blk.1</code>，引擎判斷 <code>layer == 1</code>；fork 卻掛在 <code>layers.0</code></li>
<li><code>per_layer_token_embd</code>（320M 行 IQ4_NL）<strong>不在任何 model param</strong>，<code>gsq_ple</code> 的 row-read 從未被呼叫</li>
<li>怎麼知道它 ≡ 0：把 <code>ple_layer_ids</code> 設成 <code>[]</code> 完全關掉，輸出<strong>逐字不變</strong></li>
<li>修法：層號由 name map 推導；大表走 fail-closed 的 row-read</li>
<li>實測：3 條真 prompt、608 次 row 請求、<strong>600 unique rows / 54 kB（表的 1.87e-6）</strong>，<br />
與獨立 pread + 獨立 IQ4_NL 解碼器對 240 rows（散佈整個 320M 範圍）<strong>38,400 值逐位相同</strong>；<br />
PLE 關掉時 64 步軌跡 sha 逐位一致（不變性控制）</li>
</ul>
<h2>被排除的五個（附證據，省你時間）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>假設</th>
<th>結論</th>
<th>證據</th>
</tr>
</thead>
<tbody>
<tr>
<td>mixed-quant dequant 壞</td>
<td>清白</td>
<td>27 隻真 tensor、16,200 blocks、<strong>1,900,800 值 bit-exact</strong>（18/20/21/22/23）；12/13/14 只差 fp16 ulp；42 全等</td>
</tr>
<tr>
<td><code>iq3xs_grid</code> 4× 折是 bug</td>
<td><strong>被平反</strong></td>
<td>它與 kernel 的 <code>(0.5+nib)*0.5</code> 是耦合重構（4×0.5×0.5 ≡ 1）；單邊改會變 4× 幅度錯。表與公式永遠要一起看</td>
</tr>
<tr>
<td>pack 的 <code>gate</code>/<code>up</code> 標籤互換</td>
<td>清白</td>
<td>12 + 48 抽樣，加 <strong>L17 全 512 專家 gate+up = 720,896,000 B 逐 byte 全等</strong>；負控制有能力 FAIL</td>
</tr>
<tr>
<td>tokenizer 不同</td>
<td>清白</td>
<td>引擎 <code>vocab.json</code> vs bridge <code>tokenizer.json</code>：248,320 tokens、<strong>0 個 id 不符</strong></td>
</tr>
<tr>
<td>partial rotary（我以為 fork 轉足 256 維）</td>
<td><strong>phantom</strong></td>
<td>pre-fix 參數是 <code>(head_dim=256, factor=0.25)</code>，<code>int(256×0.25)</code> 本來就是 64。我當初只讀 <code>rotary_dim=self.head_dim</code> 就下結論，漏了下游 factor</td>
</tr>
</tbody>
</table>
<h2>性能（誠實版）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>量</th>
<th>Path B</th>
<th>生產 Strata</th>
</tr>
</thead>
<tbody>
<tr>
<td>64 token 短請求</td>
<td>0.9 / 1.0 / 1.2 tok/s</td>
<td>26.1 / 29.7 / 34.1</td>
</tr>
<tr>
<td>BENCH-256</td>
<td><strong>1.75 tok/s</strong></td>
<td>—</td>
</tr>
<tr>
<td>生產長文基線（usage 計數）</td>
<td>—</td>
<td>decode 95.5–106.6 tok/s、prefill 3,336–3,601</td>
</tr>
</tbody>
</table>
<p dir="auto">差距的結構原因：<strong>沒有 RAM tier</strong>（expert 每次由 NVMe 讀，<code>staging_pinned=4</code>，VRAM 只有 436 個 unit 的 cache）、<br />
<strong>沒有 MTP</strong>（生產 <code>--spec 3</code>，accept 0.81）、<strong>單卡</strong>（生產雙卡 layer split）。這不是調參能救。</p>
<h2>現在的症狀與判斷</h2>
<pre><code>sigmoid 未修 → '用户，，，的，...，，。。。。/。///'
PLE 接上後   → '用户请求，用户请求，请求，query'
chat 格式重測 → '用户请求，，，。。。的前力/白白/白/////白/白//白////'
</code></pre>
<p dir="auto">形態固定：<strong>先幾個似樣 token，然後崩塌成標點／單字符循環</strong>。而且 raw completion 與 chat template <strong>一樣退化</strong><br />
（所以不是 prompt 格式問題）。</p>
<p dir="auto">判讀：這不再是「慣例錯配」（慣例錯會由第一個 token 就亂），而是<strong>狀態一累積就崩</strong>：<br />
GDN 的 recurrent / conv state，或某個 op 級數值偏差。下一步是逐 op parity——<br />
fork 側環境變數 gate 的 dump（<code>x / conv_out / q,k,v,z / b,a / beta / dt / decay / state / y</code>）<br />
對 numpy 參考（用真權重 + 逆向 transcript 的引擎公式），報第一個超容差的 op。</p>
<h2>方法論（這次真的救了幾次）</h2>
<ol>
<li><strong>每個 landing 都要 fail-closed + 計數</strong>：<code>transformed N/M</code>，N≠M 就 raise，數值像另一種慣例就 raise，重複轉換就 raise。artifact 與 fork 的慣例差異是常態，不是例外；默認行為是「靜默錯」。</li>
<li><strong>worker 自報不算數</strong>：我自己重跑才計。這一輪抓到兩次假 FAIL（兩個 runner 並行撞同一 scratch）和一次自己的證據錯（<code>gguf_offset</code> 已含 <code>data_start</code>，又加了一次，dd 出來的「真 bytes」只有 18,588/245,760 個位置對）。</li>
<li><strong>讀 <code>x = &lt;expr&gt;</code> 要讀到最後一個 operator</strong>：<code>rotary_dim=self.head_dim</code> 之後還有 <code>int(head_dim*factor)</code>。整個 4034 合約建在半行之上，最後證實是 no-op。</li>
<li><strong>byte-identical 證明的是 pack，不是數學</strong>：pack 與 GGUF 逐 byte 相同，但 dequant 還得逐 type 驗。</li>
<li><strong>窗口紀律</strong>：preflight 失敗 <code>exit 6</code> 且在 <code>systemctl stop</code> 之前；trap 要 kill <code>sglang::</code> 子進程並等 GPU VRAM <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2764.png?v=5be5614064c" class="not-responsive emoji emoji-android emoji--heart" style="height:1.4em;width:auto;vertical-align:middle" title="&amp;lt;3" alt="❤" /> GB 才重啟（引擎會用「空閒 VRAM」自動定 expert cache 大小，殘留子進程會靜默把 10,352 slots 變 6,938）。</li>
</ol>
<h2>一句話</h2>
<p dir="auto">「跑得起」與「跑得對」之間，隔著四個 artifact 慣例；「跑得對」與「跑得快」之間，隔著一整個 RAM tier。<br />
下一篇應該就是逐 op parity 的結果。</p>
]]></description><link>https://lcz.me/post/30639</link><guid isPermaLink="true">https://lcz.me/post/30639</guid><dc:creator><![CDATA[Benjy Lei]]></dc:creator><pubDate>Mon, 02 Nov 2026 23:32:39 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 12:31:25 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/benjy-lei" aria-label="Profile: Benjy-Lei">@<bdi>Benjy-Lei</bdi></a><br />
哦，原来如此。<br />
你可以再试试，但是要先研究清楚那个关键卡点在哪里，然后详细的做个规划，然后一步一步来实施。嗯，这个需要用比较强的模型，后面需要模型可以写c++。<br />
哎，我暂时没时间搞了，等有时间了再搞吧</p>
]]></description><link>https://lcz.me/post/30572</link><guid isPermaLink="true">https://lcz.me/post/30572</guid><dc:creator><![CDATA[fcme]]></dc:creator><pubDate>Mon, 02 Nov 2026 12:31:25 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 12:02:17 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/fcme" aria-label="Profile: fcme">@<bdi>fcme</bdi></a> 一开始就是看到你的贴子才决定试一试的。真的，能跑起来，但优化很高难度。</p>
]]></description><link>https://lcz.me/post/30569</link><guid isPermaLink="true">https://lcz.me/post/30569</guid><dc:creator><![CDATA[Benjy Lei]]></dc:creator><pubDate>Mon, 02 Nov 2026 12:02:17 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 11:16:36 GMT]]></title><description><![CDATA[<p dir="auto">哈哈，同道中人！这玩意难度相当之大，简单来说就是能跑通，性能优化是地狱难度了<br />
<a class="plugin-mentions-user plugin-mentions-a" href="/user/benjy-lei" aria-label="Profile: benjy-lei">@<bdi>benjy-lei</bdi></a>   参见<a href="https://lcz.me/topic/2728/44">https://lcz.me/topic/2728/44</a></p>
]]></description><link>https://lcz.me/post/30565</link><guid isPermaLink="true">https://lcz.me/post/30565</guid><dc:creator><![CDATA[fcme]]></dc:creator><pubDate>Mon, 02 Nov 2026 11:16:36 GMT</pubDate></item><item><title><![CDATA[Reply to 把 Strata 搬上 SGLang 引擎 的嘗試 on Mon, 02 Nov 2026 10:50:36 GMT]]></title><description><![CDATA[<p dir="auto">竟然坐到这么牛的技术贴沙发</p>
]]></description><link>https://lcz.me/post/30558</link><guid isPermaLink="true">https://lcz.me/post/30558</guid><dc:creator><![CDATA[tom23]]></dc:creator><pubDate>Mon, 02 Nov 2026 10:50:36 GMT</pubDate></item></channel></rss>