將模型分配到多張 GPU
從記憶體、通訊與失效邊界,比較資料、張量、管線與上下文平行化。
- 作者
- Huang Tzu LinFounder
- 發布日期
- 閱讀時間
- 約 19 分鐘
- 更新於
目錄
- 01本篇在學習路線中的位置
- 02開始之前:先備知識與學習成果
- 03你將建置的成品
- 04凍結架構與工作負載
- 05四種平行化,四種不同任務
- 資料平行化
- 張量平行化
- 管線平行化
- 上下文平行化
- 06集體通訊詞彙表
- 07兩個可重現的規劃公式
- 公式一:每個 rank 的權重記憶體
- 公式二:Ring All-Reduce 規劃估算
- 08完整範例:部署 70B 級模型
- 步驟一:計算權重記憶體
- 步驟二:計算 decode 的 activation 訊息
- 步驟三:比較節點內 TP2 與跨節點 TP8
- 09建立成品
- 10刻意破壞的組態
- 第二個錯誤的 All-to-All 方案
- 11動手實作
- 12可量測的完成標準
- 13提取練習
- 14解答
- 15本文不涵蓋的內容
- 16來源與延伸閱讀
分散式推論常見的動機有兩種:讓模型放得進記憶體,以及達成延遲或吞吐量目標,兩者會導向不同的設計。把一筆請求拆到更多 GPU 上,可能讓模型放得下,但每次前向傳播都會多出通訊。複製模型可以提高請求吞吐量,卻不會減少任何一個副本所需的記憶體。
請先讀這篇,再讀介紹混合專家(MoE)部署的 I-05。本篇範圍刻意收窄:把密集的僅解碼器(decoder-only)模型放上多 GPU、多節點叢集,估算記憶體需求與集體通訊成本,並淘汰放得進記憶體、卻不適合實際營運的組態。
將模型配置到八張 GPU
權重分片縮小,通訊量可能增加。
副本是一整份模型,分片是其中一部分。
每個框起來的副本都包含一整份模型權重。副本內的 GPU 各持有不同分片並協同運作;其他副本則是獨立的模型複本。
節點 1 · 4 張 GPU
↔ 此副本內的分片協同運作
↔ 此副本內的分片協同運作
節點 2 · 4 張 GPU
↔ 此副本內的分片協同運作
↔ 此副本內的分片協同運作
每個副本都留在同一節點內,其分片使用 100 GB/s 的節點內鏈路。
65.2 GiB 權重 + 12 GiB 預留 = 每張 GPU 77.2 GiB。每張 GPU 的容量是 80 GiB。
增加每個副本的 GPU 數量會縮小權重分片,也會減少獨立副本的數量。
測例:70B BF16 權重,每張 GPU 預留 12 GiB。鏈路頻寬與通訊時間是規劃假設,不是實測結果。
TP2:4 份完整模型,每張 GPU 77.2 GiB,每步通訊估算 2.44 ms。只有同一副本內的 GPU 參與這項張量平行交換。
70B BF16 權重、每 GPU 80 GiB、預留 12 GiB;通訊為 ring 模型估算,不是實測延遲。
本篇如何銜接前後內容
本篇在學習路線中的位置
帶入前作:I-00:請求時間軸與指標計算器、I-02:KV 區塊容量計算表
本篇新增:平行化計畫與集體通訊成本估算。請將假設、來源 ID 與失敗案例連同成果一併留存。
後續用途:I-03、I-05 與 I-07 將沿用這些成果。跨主題系列的先備順序請見完整閱讀路線。文章 ID 是固定標籤,編號不代表閱讀順序。
學習目標與實作準備
開始之前:先備知識與學習成果
請先完成 I-00 與 I-02;I-01 能提供實用的排程背景。你不需要先有分散式系統或 CUDA 經驗。
完成後,你將能夠:
區分資料、張量、管線與上下文平行化;
解釋 all-reduce、all-gather、reduce-scatter 與 all-to-all,而不把它們視為同一件事;
在明確的每 GPU 記憶體預留量下,計算模型是否放得下;
計算考量拓撲的通訊成本估計;
選擇留在最快通訊域內的張量平行群組;以及
產出附有可量測驗收條件的部署配置成品。
你將建置的成品
你會建立 parallelism-plan.json,內容包括:
模型、引擎與執行環境版本、精度、層數、隱藏維度與工作負載假設;
叢集拓撲與有效連結假設;
候選
TP × PP × DP配置;每個 rank 的權重記憶體;
decode 集體通訊成本估算;以及
選定的部署配置及其失效域理由。
這份成品是篩選用的規劃,不是基準測試。估算負責挑出值得做基準測試的配置;正式環境的容量仍要由量測決定。
凍結架構與工作負載
本篇所有計算都採用下列假設條件。套用到其他模型或叢集之前,請先換掉這些輸入。
輸入 | 假設 |
|---|---|
模型 | 密集型 decoder-only Transformer,700 億參數 |
模型版本 |
|
服務引擎版本 |
|
加速器/集體通訊執行環境 |
|
權重精度 | BF16,每個參數 2 bytes |
Transformer 區塊 | 80 |
隱藏維度 | 8,192 |
輸入上下文分布 | 100% 的請求都有 2,048 個輸入 token |
每個副本的 decode 批次 | 32 條活躍序列,每條一個 token |
叢集 | 2 個節點 × 4 張 GPU = 8 張 GPU |
GPU 記憶體 | 每張 80 GiB |
執行期 + KV 預留 | 每張 12 GiB |
有效節點內頻寬 | 100 GB/s |
有效節點間頻寬 | 25 GB/s |
節點內步驟延遲 | 5 微秒 |
節點間步驟延遲 | 20 微秒 |
服務目標 | 篩選記憶體放得下、且模型估算的 decode 通訊成本低於 5 ms 的配置;請求容量之後再實測 |
三個 fixture 識別碼是教學標籤,不是產品版本;真正的規劃會記錄計算時鎖定的模型、引擎與執行環境版本。重複使用這份規劃之前,請連同工作負載與拓撲一起替換。連結的頻寬與延遲數字是規劃假設,不是產品規格;請用實際部署的通訊函式庫與硬體,量測真實的訊息大小與拓撲。目前 vLLM 指南的方向一致:模型放不進單張 GPU、但放得進單一節點時,建議在節點內使用張量平行;模型大到單一節點放不下時,則在每個節點內使用張量平行,並以管線平行跨節點。互連條件會改變哪種策略最好(vLLM Parallelism and Scaling)。
四種平行化,四種不同任務
資料平行化
資料平行化建立彼此獨立的模型副本,並把不同請求送到不同副本。一般推論中的資料平行副本不需要同步梯度,因為沒有訓練步驟。資料平行化能提高整體請求容量並隔離故障,但每個副本仍必須容納完整模型;副本內部可以再使用張量或管線平行化。
如果每個副本使用 TP=2,叢集共有 8 張 GPU,那麼 DP=4 代表四個雙 GPU 副本。任一 TP rank 故障都會讓所屬的雙 GPU 副本失效,但其餘三個副本只要處理程序與相依服務仍正常,就能繼續服務。整個節點故障則會移除該節點上的兩個副本;四個副本群組並不是四個彼此獨立的節點層級失效域。
張量平行化
張量平行化切分單一層內的矩陣。各 rank 協同處理同一批 token,並在每個 transformer 區塊中的多個固定位置交換 activation 的部分結果。Megatron-LM 建立了具影響力的層內張量平行設計;目前 vLLM 也明確指出其張量平行實作包含 Megatron-LM 演算法(Shoeybi et al., 2019;vLLM Parallelism and Scaling)。
張量平行化會降低每個 rank 的權重記憶體,卻也會把集體通訊放進延遲關鍵路徑。不能只因為還有 GPU 可用,就持續增加 TP。
管線平行化
管線平行化把連續的層段分配給不同階段(stage)。請求的 activation 從階段 0 傳到階段 1,不需要每個 rank 都在每一層內協作。多個微批次(microbatch)可以在不同階段上重疊執行,但管線啟動或排空時閒置的階段,就是管線氣泡(pipeline bubble)。在各階段耗時相等、p 個階段處理 m 個微批次的簡化假設下,理想化的管線利用率為:
pipeline_utilization = m / (m + p - 1)
bubble_fraction = (p - 1) / (m + p - 1)若 p=2、m=8,利用率為 8/9 = 88.9%,氣泡比例為 1/9 = 11.1%。真實推論還有各層負載不均、排隊、activation 傳輸與 decode 相依性。GPipe 奠定了微批次管線的基礎;現代推論引擎則各自實作排程(Huang et al., 2019)。
上下文平行化
上下文平行化把長序列切分到多個 rank,使注意力狀態與運算不必全部放在單一裝置。以 Ring Attention 為例,它會分散序列區塊並循環傳遞 key-value 區塊,同時把通訊與分塊注意力運算重疊(Liu, Zaharia, and Abbeel, 2023)。
上下文平行化解決的是長序列的記憶體或注意力運算問題,不是提高一般短上下文請求吞吐量的預設手段。本例所有輸入上下文都固定為 2,048 個 token,這樣的分布用不到它,因此選定方案使用 CP=1。
集體通訊詞彙表
下表描述的是操作完成後資料位於何處,不代表只能採用 ring、tree 或某一種融合式實作。NCCL 的現行文件直接定義了這些操作的語意(NVIDIA NCCL collective API)。
集體操作 | 操作完成後的結果 | 常見推論用途 |
|---|---|---|
All-reduce | 對對應值做歸約,並在每個 rank 留下完整歸約結果 | 合併張量平行的部分總和 |
Reduce-scatter | 對對應值做歸約,並在每個 rank 只留下其中一個結果分片 | 保持歸約後的 activation 為分片狀態 |
All-gather | 串接各分片,並在每個 rank 留下完整結果 | 重建每個 rank 都需要的 activation |
All-to-all | 每個 rank 都向其他每個 rank 發送不同的分片 | 許多專家平行配置中的 token 分派與回傳 |
概念上,all-reduce 可以拆成 reduce-scatter 再接 all-gather,但最佳化過的函式庫可能採用其他演算法。同樣地,專家平行系統也不會一律使用同一種集體通訊;I-05 會說明引擎、DP/TP 配置、訊息大小與硬體如何共同決定實作。
兩個可重現的規劃公式
公式一:每個 rank 的權重記憶體
對於權重以張量平行平均分片的密集模型:
weight_bytes_total = parameters × bytes_per_parameter
weight_gib_total = weight_bytes_total / 2^30
weight_gib_per_rank = weight_gib_total / TP / PP
usable_gib_per_gpu = gpu_gib - runtime_and_kv_reserve_gib
fits = weight_gib_per_rank <= usable_gib_per_gpu這只是第一層篩選。各層切分不均、embedding、輸出頭(output head)、記憶體配置器行為、CUDA graph、activation 與量化中繼資料,都可能讓看似剛好放得下的估算破功。所以 12 GiB 預留量要明確寫出來,不能默默假設。
公式二:Ring All-Reduce 規劃估算
對 p 個 rank、每個 rank 的邏輯訊息大小為 M bytes 的 ring all-reduce,實用的規劃近似式如下:
wire_bytes_per_rank ≈ 2 × (p - 1) / p × M
time_per_collective ≈ wire_bytes_per_rank / effective_bandwidth
+ 2 × (p - 1) × link_step_latency請把結果當成 ring 專用的篩選估算。它既不是效能預測,也不是所有有效演算法的下限,因為它忽略了協定選擇、分塊傳輸(chunking)、資源爭用、拓撲感知的 tree 演算法、重疊、運算核心啟動成本與網路壅塞。把每個 ring 步驟都算成跨節點延遲,可能高估同時包含節點內與節點間連結的 ring;重疊或改用其他集體通訊演算法,也會改變關鍵路徑。沒通過這道篩選的組態值得進一步調查,但這不證明最佳化過的實作一定無法通過。
完整範例:部署 70B 級模型
步驟一:計算權重記憶體
total weight bytes = 70,000,000,000 × 2
= 140,000,000,000 bytes
total weight GiB = 140,000,000,000 / 1,073,741,824
= 130.39 GiB
usable per GPU = 80 - 12
= 68 GiB候選記憶體結果:
配置 | 每 GPU 權重 GiB | 符合 68 GiB 預算? | 獨立副本數 |
|---|---|---|---|
TP1 × PP1 × DP8 | 130.39 | 否 | 8 |
TP2 × PP1 × DP4 | 65.19 | 是 | 4 |
TP4 × PP1 × DP2 | 32.60 | 是 | 2 |
TP8 × PP1 × DP1 | 16.30 | 是 | 1 |
TP4 × PP2 × DP1 | 16.30 | 是 | 1 |
在 PP1 候選中,符合明確記憶體預留條件的最小張量平行群組是 TP=2。選擇 TP4 或 TP8,會讓每筆請求使用超過「放得下」所需的 GPU,並減少獨立副本數。
至於 TP4 × PP2 候選配置,下方的計算器只計入 TP 集體通訊流量,沒有計入 PP 階段之間的 activation 傳輸與管線氣泡成本。在量測這些額外成本之前,不能選用這一列。
步驟二:計算 decode 的 activation 訊息
以每條活躍 decode 序列一個 BF16 隱藏層 activation 計算:
M = decode_batch × hidden_size × bytes_per_element
= 32 × 8,192 × 2
= 524,288 bytes
= 0.5 MiB本練習假設每個 transformer 區塊有兩次 all-reduce,因此一次 decode 前向傳播共有 2 × 80 = 160 次集體通訊。實際的集體通訊位置取決於模型與引擎,所以把結果用於營運決策之前,必須用追蹤紀錄(trace)驗證。
步驟三:比較節點內 TP2 與跨節點 TP8
在節點內連結上使用 TP=2 時:
wire bytes/rank = 2 × 1/2 × 524,288 = 524,288 bytes
transfer time = 524,288 / 100,000,000,000 = 5.24 microseconds
latency term = 2 × 1 × 5 = 10 microseconds
one collective ≈ 15.24 microseconds
160 collectives ≈ 2.44 millisecondsTP=8 跨越兩個節點時:
wire bytes/rank = 2 × 7/8 × 524,288 = 917,504 bytes
transfer time = 917,504 / 25,000,000,000 = 36.70 microseconds
latency term = 2 × 7 × 20 = 280 microseconds
one collective ≈ 316.70 microseconds
160 collectives ≈ 50.67 milliseconds兩種配置都放得下模型,但只有 TP2 符合練習的 <5 ms 集體通訊估算條件,而且 TP2 還能建立四個獨立副本。因此依這套篩選規則,應該優先做基準測試的配置是:
Node A: [GPU0, GPU1] replica 0, TP2 [GPU2, GPU3] replica 1, TP2
Node B: [GPU4, GPU5] replica 2, TP2 [GPU6, GPU7] replica 3, TP2
PP=1, DP=4, CP=1這個選擇取決於這座叢集的拓撲與記憶體預算;TP2 並非永遠勝出。更大的 KV 需求、不同的精度,或放不進單一節點的模型,都可能改變答案。
建立成品
將以下內容存為 plan_parallelism.py,執行後重新導向輸出:
import json
PARAMETERS = 70_000_000_000
MODEL_REVISION = "dense-70b-fixture-r1"
ENGINE_VERSION = "tutorial-engine-fixture-1.0"
RUNTIME_VERSION = "tutorial-runtime-fixture-1.0"
BYTES_PER_PARAMETER = 2
GPU_GIB = 80
RESERVE_GIB = 12
LAYERS = 80
HIDDEN = 8192
INPUT_CONTEXT_DISTRIBUTION = {"2048": 1.0}
DECODE_BATCH = 32
COLLECTIVES_PER_LAYER = 2
COLLECTIVE_LIMIT_MS = 5.0
ACTIVATION_BYTES = 2
NODES = 2
GPUS_PER_NODE = 4
TOTAL_GPUS = NODES * GPUS_PER_NODE
CANDIDATES = [
{"tp": 1, "pp": 1, "dp": 8, "domain": "single_gpu"},
{"tp": 2, "pp": 1, "dp": 4, "domain": "intra_node"},
{"tp": 4, "pp": 1, "dp": 2, "domain": "intra_node"},
{"tp": 8, "pp": 1, "dp": 1, "domain": "inter_node"},
{"tp": 4, "pp": 2, "dp": 1, "domain": "pipeline_across_nodes"},
]
LINKS = {
"single_gpu": {"bandwidth_gb_s": None, "step_us": 0},
"intra_node": {"bandwidth_gb_s": 100, "step_us": 5},
"inter_node": {"bandwidth_gb_s": 25, "step_us": 20},
"pipeline_across_nodes": {"bandwidth_gb_s": 100, "step_us": 5},
}
total_weight_gib = PARAMETERS * BYTES_PER_PARAMETER / 2**30
message_bytes = DECODE_BATCH * HIDDEN * ACTIVATION_BYTES
usable_gib = GPU_GIB - RESERVE_GIB
rows = []
for candidate in CANDIDATES:
tp = candidate["tp"]
pp = candidate["pp"]
weight_gib = total_weight_gib / tp / pp
link = LINKS[candidate["domain"]]
if tp == 1:
estimate_ms = 0.0
else:
wire_bytes = 2 * (tp - 1) / tp * message_bytes
transfer_s = wire_bytes / (link["bandwidth_gb_s"] * 1e9)
latency_s = 2 * (tp - 1) * link["step_us"] * 1e-6
estimate_ms = (transfer_s + latency_s) * LAYERS * COLLECTIVES_PER_LAYER * 1e3
assert candidate["tp"] * candidate["pp"] * candidate["dp"] == TOTAL_GPUS
fully_modeled = pp == 1
rows.append({
**candidate,
"weight_gib_per_gpu": round(weight_gib, 2),
"fits": weight_gib <= usable_gib,
"decode_collective_estimate_ms": round(estimate_ms, 2),
"fully_modeled": fully_modeled,
"passes": (weight_gib <= usable_gib and estimate_ms < COLLECTIVE_LIMIT_MS) if fully_modeled else None,
})
eligible = [r for r in rows if r["passes"] is True]
choice = min(eligible, key=lambda r: r["tp"]) if eligible else None
selected = {k: choice[k] for k in ("tp", "pp", "dp")} | {"cp": 1} if choice else None
artifact = {
"assumptions": {
"parameters": PARAMETERS,
"model_revision": MODEL_REVISION,
"engine_version": ENGINE_VERSION,
"runtime_version": RUNTIME_VERSION,
"bytes_per_parameter": BYTES_PER_PARAMETER,
"gpu_gib": GPU_GIB,
"runtime_and_kv_reserve_gib": RESERVE_GIB,
"layers": LAYERS,
"hidden_size": HIDDEN,
"input_context_distribution": INPUT_CONTEXT_DISTRIBUTION,
"decode_batch": DECODE_BATCH,
"activation_bytes": ACTIVATION_BYTES,
"collectives_per_layer": COLLECTIVES_PER_LAYER,
"collective_limit_ms": COLLECTIVE_LIMIT_MS,
"topology": {"nodes": NODES, "gpus_per_node": GPUS_PER_NODE, "total_gpus": TOTAL_GPUS},
"effective_links": LINKS,
"bandwidth_unit": "decimal GB/s; null means no TP communication",
"link_model_scope": "TP ring collectives only; PP transfers and bubbles are not modeled",
},
"candidates": rows,
"selected": selected,
"selection_rationale": (
"Choose the smallest TP among listed fully modeled PP1 candidates passing both criteria; "
"this is a screening choice, not a measured optimum."
) if choice else "No listed fully modeled candidate passes both criteria.",
"failure_domain_rationale": {
"selected_domain": choice["domain"] if choice else None,
"assumption": "Treat loss of any required rank as failure of its replica.",
"placement": "Keep each TP group within one node when TP fits the node.",
"node_failure": "A node outage removes every replica with a rank on that node; shared services may create wider failures.",
},
"selection_scope": "listed fully-modeled PP1 candidates only",
}
print(json.dumps(artifact, indent=2, allow_nan=False))執行:
python plan_parallelism.py > parallelism-plan.json預期檢查結果:
TP1: fits=false
TP2: weight_gib_per_gpu=65.19, decode_collective_estimate_ms=2.44, passes=true
TP8: weight_gib_per_gpu=16.30, decode_collective_estimate_ms=50.67, passes=false
selected: TP2 × PP1 × DP4 × CP1刻意破壞的組態
下列組態在某些分散式執行環境中足以啟動,但套用在這個工作負載上是錯的:
world_size: 8
tensor_parallel_size: 8
pipeline_parallel_size: 1
data_parallel_size: 1
placement: spread_across_two_nodes
reason: "use every GPU for the lowest per-rank weight memory"它失敗的原因有三個,而且都可以量測:
TP2 已符合 68 GiB 的容量預算,已經沒有放不下的問題需要 TP8 解決。
規劃估算約為每次 decode 前向傳播 50.67 ms,高於 5 ms 條件。
任一 rank 故障都會移除唯一副本;選定的 TP2/DP4 方案有四個副本失效域。
第二種失敗可能要到系統承受負載時才會浮現:分配 rank 時若沒有檢查 GPU 與 NIC、GPU 與 GPU 之間的親和性(affinity),流量可能走較慢的路徑。目前的 NCCL 會自動偵測拓撲,但部署時仍須讓它看得到正確的裝置與網路介面(NVIDIA NCCL overview)。
第二個錯誤的 All-to-All 方案
假設某個長上下文後端在 CP=8 上,每個區塊使用兩次轉置序列的 all-to-all(sequence-transpose all-to-all),而且每個 rank 持有 4,096 個 BF16 token 的 activation,隱藏維度為 8,192。統一序列平行(Unified Sequence Parallelism,USP)說明了 all-to-all 與 ring 式序列平行為何有不同的拓撲取捨(Fang and Zhao, 2024)。本練習把成本簡化如下:rank 送往其他 rank 的每個位元組,都以 25 GB/s 的節點間連結計算,而且 160 次操作依序執行:
local activation M = 4,096 × 8,192 × 2
= 67,108,864 bytes = 64 MiB
bytes sent to other ranks = 7/8 × M
= 58,720,256 bytes
one bandwidth-only floor = 58,720,256 / 25,000,000,000 seconds
= 2.34881024 ms ≈ 2.35 ms
160 all-to-alls = 2.34881024 × 160 ms
= 375.8096384 ms ≈ 375.81 ms在這些依序傳輸的假設下,這個估算沒有通過教學用的通訊條件。把送往七個對端 rank 的流量全部算在節點間連結上是保守的做法,因為其中三個與發送端位於同一節點;只計算離開節點的那一半 M(33,554,432 bytes,每次操作約 1.34 ms,160 次約 214.75 ms),結果依然不通過。這兩個數字都無法代表重疊或拓撲感知實作實際暴露的延遲。實作可能把大部分流量重疊掉,或改用其他演算法,但這種可能性必須實際量測,不能當成把資料搬移從規劃中刪掉的理由。
動手實作
針對以下新需求修改成品產生器:
以輸出為主的工作負載;
每張 GPU 為 KV 快取與執行期預留 24 GiB;
仍使用相同的 8 張 GPU 與連結假設;
集體通訊估算的上限仍為 5 ms。
在 placement-decision.md 中回答:
TP2 是否仍放得下?
放得下的最小 TP 大小是多少?
還能保有幾個獨立副本?
放得下的最小配置是否跨越節點邊界?
若答案改變,是哪個限制條件造成的:模型能否放得下、集體通訊估算,還是故障隔離?
預期記憶體計算:
usable per GPU = 80 - 24 = 56 GiB
TP2 weight = 65.19 GiB -> does not fit
TP4 weight = 32.60 GiB -> fitsTP4 × PP1 × DP2 是列出的候選中,放得下的最小純 TP 配置,而且每個 TP 群組都留在同一個四 GPU 節點內。用同一公式算出的集體通訊估算約為 6.06 ms,因此不符合原本 5 ms 的目標。這是刻意設計的結果:完整建模的 PP1 候選全部沒有通過這道篩選。但這不代表全域都不可行,因為清單外的 TP2 × PP2 × DP2 等配置,仍值得分析其管線傳輸、排程與記憶體。請擴充候選集合,或調整硬體、精度、預留量或 SLO 後再做基準測試,不要隱藏未通過的條件。
可量測的完成標準
你的教學成品只有在以下條件全部成立時才算通過:
每個候選配置都滿足
TP × PP × DP = 8,或明確標記未使用的 GPU;權重記憶體與預留量使用相同 GiB 單位;
選定配置中的 rank 都不超過 80 GiB;
除非模型無法以其他方式放下,選定 TP 群組不得跨節點;
選定方案的集體通訊估算低於 5 ms,或明確回報沒有候選方案通過;
部署配置圖標出各個獨立副本的失效域;
在正式核准前,假設必須包含模型版本、精度、引擎與執行環境版本、輸入上下文分布、GPU 拓撲,以及實測的有效頻寬;以及
在承諾容量之前,必須用實際負載測試取代規劃估算。
提取練習
哪種平行化策略會建立獨立的請求服務副本?
為什麼張量平行化可能讓模型放得下,卻惡化 decode 延遲?
All-gather 和 reduce-scatter 在語意上有何差異?
什麼情況適合使用上下文平行化?
在完整範例中,為什麼 TP2 優於 TP8?
如果沒有候選配置同時符合記憶體與通訊條件,該怎麼辦?
解答
資料平行化。
它會切分權重,但也會在前向傳播的關鍵路徑上加入反覆執行的集體通訊。
All-gather 在每個 rank 上從分片重建完整張量;reduce-scatter 則歸約數值,並在每個 rank 上只留下其中一個結果分片。
當序列狀態記憶體或長上下文注意力運算無法在單一 rank 放下或達成目標時;它不是短上下文吞吐量的預設工具。
TP2 是放得下的最小群組,留在單一節點內,能建立四個副本,且規劃估算為 2.44 ms;跨節點的 TP8 則約為 50.67 ms。
回報已評估候選都未通過,未建模配置仍待釐清。擴大搜尋或修改精度、硬體、預留量、拓撲或目標,再重新量測。不要悄悄刪除條件。
本文不涵蓋的內容
本篇涵蓋密集模型的部署配置,不處理專家路由、專家負載平衡或專家平行的集體通訊;這些內容由 I-05 接續。本篇也不主張簡化的 ring 公式能預測正式環境的延遲。運算核心追蹤、集體通訊基準測試、排隊、KV 容量與端對端負載測試,仍然缺一不可。
I-07 會把已部署的配置轉成可重現的基準測試,推導符合 SLO 的容量,並定義能及時發現規劃錯誤的遙測資料。
來源與延伸閱讀
Shoeybi, M., Patwary, M., Puri, R., et al. "Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism." 2019。具影響力的層內張量平行設計的第一手來源。arxiv.org/abs/1909.08053
Narayanan, D., Shoeybi, M., Casper, J., et al. "Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM." 2021。組合張量、管線與資料平行化的第一手來源。arxiv.org/abs/2104.04473
Huang, Y., Cheng, Y., Bapna, A., et al. "GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism." 2019。微批次管線平行與管線氣泡攤提的第一手來源。arxiv.org/abs/1811.06965
Liu, H., Zaharia, M., and Abbeel, P. "Ring Attention with Blockwise Transformers for Near-Infinite Context." 2023。將長序列注意力分散到多個裝置的第一手來源。arxiv.org/abs/2310.01889
Fang, J., and Zhao, S. "USP: A Unified Sequence Parallelism Approach for Long Context Generative AI." 2024。比較 all-to-all 與 ring 式序列平行方法的第一手來源。arxiv.org/abs/2405.07719
NVIDIA. "Collective Communication Functions." NCCL 現行文件,查閱日期 2026-11-02。All-reduce、all-gather、reduce-scatter 與 all-to-all 語意的第一方定義。github.com/NVIDIA/nccl
vLLM Project. "Parallelism and Scaling." 現行文件,查閱日期 2026-11-02。單節點與多節點系統中張量及管線平行的第一方部署指南。docs.vllm.ai
閱讀順序
完整閱讀路線
章節 21 / 25
Huang Tzu Lin
富宇資訊科技創辦人。撰寫 AI 系統設計、證據與工程取捨的文章。
