跳至主要內容
推論基礎設施

將模型分配到多張 GPU

從記憶體、通訊與失效邊界,比較資料、張量、管線與上下文平行化。

作者
Huang Tzu LinFounder
發布日期
閱讀時間
約 19 分鐘
更新於
目錄
  1. 01本篇在學習路線中的位置
  2. 02開始之前:先備知識與學習成果
  3. 03你將建置的成品
  4. 04凍結架構與工作負載
  5. 05四種平行化,四種不同任務
  6. 資料平行化
  7. 張量平行化
  8. 管線平行化
  9. 上下文平行化
  10. 06集體通訊詞彙表
  11. 07兩個可重現的規劃公式
  12. 公式一:每個 rank 的權重記憶體
  13. 公式二:Ring All-Reduce 規劃估算
  14. 08完整範例:部署 70B 級模型
  15. 步驟一:計算權重記憶體
  16. 步驟二:計算 decode 的 activation 訊息
  17. 步驟三:比較節點內 TP2 與跨節點 TP8
  18. 09建立成品
  19. 10刻意破壞的組態
  20. 第二個錯誤的 All-to-All 方案
  21. 11動手實作
  22. 12可量測的完成標準
  23. 13提取練習
  24. 14解答
  25. 15本文不涵蓋的內容
  26. 16來源與延伸閱讀

分散式推論常見的動機有兩種:讓模型放得進記憶體,以及達成延遲或吞吐量目標,兩者會導向不同的設計。把一筆請求拆到更多 GPU 上,可能讓模型放得下,但每次前向傳播都會多出通訊。複製模型可以提高請求吞吐量,卻不會減少任何一個副本所需的記憶體。

請先讀這篇,再讀介紹混合專家(MoE)部署的 I-05。本篇範圍刻意收窄:把密集的僅解碼器(decoder-only)模型放上多 GPU、多節點叢集,估算記憶體需求與集體通訊成本,並淘汰放得進記憶體、卻不適合實際營運的組態。

互動實驗

將模型配置到八張 GPU

權重分片縮小,通訊量可能增加。

4完整模型副本
77.2 / 80 GiB每張 GPU 記憶體
2.44 ms每步通訊估算

副本是一整份模型,分片是其中一部分。

每個框起來的副本都包含一整份模型權重。副本內的 GPU 各持有不同分片並協同運作;其他副本則是獨立的模型複本。

4 個完整模型副本 × 每個副本 2 張 GPU
節點 1 · 4 張 GPU
副本 1一整份模型
GPU 0分片 1 / 265.2 GiB模型權重
GPU 1分片 2 / 265.2 GiB模型權重
副本 2一整份模型
GPU 2分片 1 / 265.2 GiB模型權重
GPU 3分片 2 / 265.2 GiB模型權重
節點 2 · 4 張 GPU
副本 3一整份模型
GPU 4分片 1 / 265.2 GiB模型權重
GPU 5分片 2 / 265.2 GiB模型權重
副本 4一整份模型
GPU 6分片 1 / 265.2 GiB模型權重
GPU 7分片 2 / 265.2 GiB模型權重
此配置放得下。

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 經驗。

完成後,你將能夠:

  1. 區分資料、張量、管線與上下文平行化;

  2. 解釋 all-reduce、all-gather、reduce-scatter 與 all-to-all,而不把它們視為同一件事;

  3. 在明確的每 GPU 記憶體預留量下,計算模型是否放得下;

  4. 計算考量拓撲的通訊成本估計;

  5. 選擇留在最快通訊域內的張量平行群組;以及

  6. 產出附有可量測驗收條件的部署配置成品。

你將建置的成品

你會建立 parallelism-plan.json,內容包括:

  • 模型、引擎與執行環境版本、精度、層數、隱藏維度與工作負載假設;

  • 叢集拓撲與有效連結假設;

  • 候選 TP × PP × DP 配置;

  • 每個 rank 的權重記憶體;

  • decode 集體通訊成本估算;以及

  • 選定的部署配置及其失效域理由。

這份成品是篩選用的規劃,不是基準測試。估算負責挑出值得做基準測試的配置;正式環境的容量仍要由量測決定。

凍結架構與工作負載

本篇所有計算都採用下列假設條件。套用到其他模型或叢集之前,請先換掉這些輸入。

輸入

假設

模型

密集型 decoder-only Transformer,700 億參數

模型版本

dense-70b-fixture-r1

服務引擎版本

tutorial-engine-fixture-1.0

加速器/集體通訊執行環境

tutorial-runtime-fixture-1.0

權重精度

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 個微批次的簡化假設下,理想化的管線利用率為:

plaintext
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 的權重記憶體

對於權重以張量平行平均分片的密集模型:

plaintext
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,實用的規劃近似式如下:

plaintext
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 級模型

步驟一:計算權重記憶體

plaintext
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 計算:

plaintext
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 時:

plaintext
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 milliseconds

TP=8 跨越兩個節點時:

plaintext
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 還能建立四個獨立副本。因此依這套篩選規則,應該優先做基準測試的配置是:

plaintext
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,執行後重新導向輸出:

python
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))

執行:

bash
python plan_parallelism.py > parallelism-plan.json

預期檢查結果:

plaintext
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

刻意破壞的組態

下列組態在某些分散式執行環境中足以啟動,但套用在這個工作負載上是錯的:

yaml
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"

它失敗的原因有三個,而且都可以量測:

  1. TP2 已符合 68 GiB 的容量預算,已經沒有放不下的問題需要 TP8 解決。

  2. 規劃估算約為每次 decode 前向傳播 50.67 ms,高於 5 ms 條件。

  3. 任一 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 次操作依序執行:

plaintext
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 中回答:

  1. TP2 是否仍放得下?

  2. 放得下的最小 TP 大小是多少?

  3. 還能保有幾個獨立副本?

  4. 放得下的最小配置是否跨越節點邊界?

  5. 若答案改變,是哪個限制條件造成的:模型能否放得下、集體通訊估算,還是故障隔離?

預期記憶體計算:

plaintext
usable per GPU = 80 - 24 = 56 GiB
TP2 weight     = 65.19 GiB -> does not fit
TP4 weight     = 32.60 GiB -> fits

TP4 × 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 拓撲,以及實測的有效頻寬;以及

  • 在承諾容量之前,必須用實際負載測試取代規劃估算。

提取練習

  1. 哪種平行化策略會建立獨立的請求服務副本?

  2. 為什麼張量平行化可能讓模型放得下,卻惡化 decode 延遲?

  3. All-gather 和 reduce-scatter 在語意上有何差異?

  4. 什麼情況適合使用上下文平行化?

  5. 在完整範例中,為什麼 TP2 優於 TP8?

  6. 如果沒有候選配置同時符合記憶體與通訊條件,該怎麼辦?

解答

  1. 資料平行化。

  2. 它會切分權重,但也會在前向傳播的關鍵路徑上加入反覆執行的集體通訊。

  3. All-gather 在每個 rank 上從分片重建完整張量;reduce-scatter 則歸約數值,並在每個 rank 上只留下其中一個結果分片。

  4. 當序列狀態記憶體或長上下文注意力運算無法在單一 rank 放下或達成目標時;它不是短上下文吞吐量的預設工具。

  5. TP2 是放得下的最小群組,留在單一節點內,能建立四個副本,且規劃估算為 2.44 ms;跨節點的 TP8 則約為 50.67 ms。

  6. 回報已評估候選都未通過,未建模配置仍待釐清。擴大搜尋或修改精度、硬體、預留量、拓撲或目標,再重新量測。不要悄悄刪除條件。

本文不涵蓋的內容

本篇涵蓋密集模型的部署配置,不處理專家路由、專家負載平衡或專家平行的集體通訊;這些內容由 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

你在這裡84%
  1. 01
  2. 02
  3. 03
  4. 04
  5. 05
  6. 06
  7. 07
  8. 08
  9. 09
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25

查看先備知識、分支路線與共用實作 →

分享這篇文章
XLinkedIn

Huang Tzu Lin

富宇資訊科技創辦人。撰寫 AI 系統設計、證據與工程取捨的文章。

透過 RSS 訂閱

使用慣用的 RSS 閱讀器追蹤最新的 AI 系統實作教學。

開啟 RSS Feed

支援任何 RSS 閱讀器,新文章將自動送達。

回到頂端