靜態批次浪費了 GPU
請求批次處理 最簡單的形式是靜態的:收集 N 個請求,一起跑到全部完成,再開始下一批。這對生成而言糟糕透頂,因為請求結束的長度天差地別。一個 N 大小的批次,只能跟它最長的序列一樣快;短的一旦結束,它們的槽位就閒置地產生填充(padding),而 GPU 等著那個落後者。利用率正好在你想要效率時崩潰。
静态批处理浪费 GPU:整批必须等到最长序列结束,生成长度差异越大,利用率 U 越远低于 1。
連續(飛行中)批次
連續批次(continuous batching),又稱飛行中批次(in-flight batching),讓批次成員在單一 decode 步的粒度上動態變化。每次迭代後,排程器淘汰剛吐出序列結束 token 的序列、釋放它們的 KV 區塊,並把等待中的請求立刻納入空出的槽位——無須等整個批次排空。
- 對批次中當前每個序列跑一次前向步驟。
- 為每個序列取樣下一個 token;把它附加到該請求的輸出串流。
- 淘汰任何達到停止條件的序列並釋放其 KV 區塊。
- 把佇列中的請求(其 prefill,可能分塊)納入空出的槽位。
- 重複。批次永遠不會被它最長的成員人為地拖住。
結合 分塊預填,這給排程器一個統一的工作佇列,prefill 分塊與 decode 步在同一次迭代中共存。這單一的設計選擇,造就了研究級生成迴圈與生產引擎之間大部分的吞吐量差距。
把 prefill 與 decode 解耦
即使有分塊,prefill 與 decode 的硬體輪廓相反——prefill 受算力限制,decode 受記憶體限制——硬把它們塞在同一批 GPU 上,意味著兩者都無法跑到最好,而一陣 prefill 爆發仍可能讓 decode 延遲抖動。prefill/decode 解耦(disaggregated prefill/decode) 讓它們在分開的 GPU 池上運行:prefill 工作節點算出提示的 KV 快取,透過互連網路把它送給 decode 工作節點,後者再串流輸出。
为何要分离:解码步是访存受限(每生成一个词元都要读全部权重),而预填充是计算受限——两种相反的硬件画像,需要不同的 GPU。
分片模型:張量平行服務
當模型對單張 GPU 太大,或你需要比單張 GPU 更低的延遲時,就把它分片。張量平行推論(tensor-parallel inference) 把每個權重矩陣切分到多張 GPU,使每個裝置持有每一層的一片,並在每個 token 上協作,透過 all-reduce 交換部分結果。這是你在訓練軌道見過的 張量平行 在推論期的用法,但取捨不同:服務時 all-reduce 位於每一個 decode 步的關鍵路徑上,因此互連頻寬直接限制了你的 TPOT。
多头注意力示意图:并行的注意力头被拼接并融合。
實務指引是:張量平行降低延遲並解鎖大模型,但超過某個點後,通訊開銷會吃掉收益。在單一具備高速互連的節點內,它是預設的槓桿;跨節點時,你會改用其他形式的平行化或解耦。
张量并行把计算量按 p 等分,但每层都要做一次 all-reduce;超过某一点后通信项占主导,时延不再下降。
把 token 串流回去
最後是使用者體驗。既然 decode 反正一次產生一個 token,token 串流 就在每個 token 取樣的當下把它送給客戶端,而非等待完整回應。這把感知延遲與總延遲解耦:邊讀的使用者會覺得系統很快,即使完整答案要花上好幾秒,因為相關指標變成了 TTFT 加上一個舒適的 TPOT,正是第一篇那組 指標。