**这是本文档旧的修订版!**
目录
TP(Tensor Parallelism,张量并行)和 DP(Data Parallelism,数据并行)
在 vLLM 里,TP(Tensor Parallelism,张量并行)和 DP(Data Parallelism,数据并行)都是为了让多个 GPU 一起跑模型,但分工完全不同。
可以先记一句:
**TP:一个模型拆到多个 GPU 上。****DP:一个模型复制多份,每份放到不同 GPU 上。**
—
1. TP:Tensor Parallelism
假设你有一个 70B 模型,单张 GPU 放不下。
比如有 4 张 24GB GPU:
- snippet.text
70B 模型 │ ┌────────┼─────────────────┐ ↓ ↓ ↓ ↓ GPU0 GPU1 GPU2 GPU3 1/4 1/4 1/4 1/4
模型的权重、计算矩阵等被切分到多个 GPU。
vLLM:
- snippet.bash
vllm serve model \ --tensor-parallel-size 4
也就是:
- snippet.text
TP=4
意味着一个模型实例使用 4 张 GPU。
TP 的主要目的
让“大模型能够装进去”。
例如:
- snippet.text
模型需要 80GB 显存 GPU0 24GB GPU1 24GB GPU2 24GB GPU3 24GB TP=4 ↓ 每张 GPU 大约承担 20GB
因此 4 张 GPU 可以共同加载模型。
2. DP:Data Parallelism
DP 完全不同。
假设一个模型只需要 1 张 GPU 就能装下:
- snippet.text
模型 │ ┌─────┼─────┐ ↓ ↓ ↓ GPU0 GPU1 GPU2 模型 模型 模型 ① ② ③
每张 GPU 都有完整的一份模型。
然后不同请求分发给不同 GPU:
- snippet.text
请求1 ──→ GPU0 请求2 ──→ GPU1 请求3 ──→ GPU2 请求4 ──→ GPU0 请求5 ──→ GPU2
所以 DP 的主要目的不是让模型变大,而是:
**提高吞吐量。**
—
3. TP 和 DP 的核心区别
| TP | DP | |
| ———– | —————— | —————- |
| 全称 | Tensor Parallelism | Data Parallelism |
| 模型 | 拆开 | 复制 |
| 每 GPU | 模型的一部分 | 完整模型 |
| 主要目的 | 让大模型跑起来 | 提高吞吐量 |
| GPU 间通信 | 很频繁 | 相对少 |
| 对 GPU 间网络要求 | 较高 | 较低 |
| 显存利用 | 模型被分摊 | 每份模型都占一份 |
| 典型场景 | 70B/100B 等大模型 | 多请求、高并发 |
4. vLLM 里 TP + DP 可以一起用
这个比较重要。
假设你有:
- snippet.text
8 × 24GB GPU
模型需要 2 张 GPU 才能放下。
那么可以:
- snippet.text
TP = 2 DP = 4
整体结构:
- snippet.text
8 GPUs │ ┌──────────┴──────────┐ │ │ DP副本1 DP副本2 TP=2 TP=2 ┌─────┐ ┌─────┐ │GPU0 │ │GPU2 │ │GPU1 │ │GPU3 │ └─────┘ └─────┘ DP副本3 DP副本4 TP=2 TP=2 ┌─────┐ ┌─────┐ │GPU4 │ │GPU6 │ │GPU5 │ │GPU7 │ └─────┘ └─────┘
也就是:
- snippet.text
每个模型副本 = 2 GPU 模型副本数量 = 4 总 GPU = 2 × 4 = 8
这样既解决了模型太大的问题,又可以增加吞吐。
5. 一个非常实用的理解
假设:
- snippet.text
模型 = 40GB GPU = 24GB GPU数量 = 4
TP=1
- snippet.text
40GB ↓ GPU0:放不下 ❌
TP=2
- snippet.text
40GB ↓ 20GB + 20GB GPU0:20GB GPU1:20GB 可以 ✅
但是只有一个模型副本。
如果:
- snippet.text
TP=2 DP=2
那么:
- snippet.text
模型40GB │ ┌─────┴─────┐ ↓ ↓ 副本1 副本2 TP=2 TP=2 GPU0 GPU1 GPU2 GPU3
现在有两个完整的模型实例。
因此:
- snippet.text
4 GPU = TP2 × DP2
6. 为什么不全部用 TP?
例如你有:
- snippet.text
8 × H100
模型只需要 2 张 H100 就能跑。
你可以选择:
- snippet.text
TP=8
但通常不一定划算。
因为 TP 会产生大量 GPU 间通信:
- snippet.text
GPU0 ←→ GPU1 ↕ ↕ GPU2 ←→ GPU3 ↕ ↕ ...
特别是模型推理过程中,会频繁进行 All-Reduce、All-Gather 等通信。
如果你的目标是高并发推理,更合理的方案可能是:
- snippet.text
TP=2 DP=4
而不是:
- snippet.text
TP=8 DP=1
前者相当于:
- snippet.text
2 GPU × 4 个模型副本
后者:
- snippet.text
8 GPU × 1 个模型副本
通常前者更适合提高整体吞吐。
7. 和你之前问的 vLLM“准确率”也有关系吗?
这里有一个容易混淆的地方:
TP/DP 本身一般不会改变模型的理论能力或准确率。
正常情况下:
- snippet.text
TP=1 TP=2 TP=4
计算结果应该基本一致,允许存在一些由于 GPU 浮点计算顺序、量化、kernel 等产生的微小数值差异。
但是如果你发现:
- snippet.text
TP=1 → 回答很好 TP=4 → 回答明显变差
那就值得排查:
dtype- quantization
- attention backend
- FlashAttention
- KV Cache
max_model_len- sampling 参数
- CUDA / PyTorch / vLLM 版本
- TP 通信
- MoE 模型的并行配置
- 是否发生 OOM 后的异常行为
而 DP 更多影响的是吞吐和请求分配,不是单个模型的能力。
