438 lines
9.5 KiB
Markdown
438 lines
9.5 KiB
Markdown
# DeepSpeed
|
||
|
||
## 概述
|
||
|
||
DeepSpeed是微软开发的深度学习训练优化库,专注于大规模模型的分布式训练加速和显存优化。核心特性包括ZeRO(Zero Redundancy Optimizer)优化器、3D并行支持、混合精度训练等。
|
||
|
||
## ZeRO实现
|
||
|
||
### 核心架构
|
||
|
||
DeepSpeed的ZeRO实现分为三个阶段(详见"数据并行与ZeRO"文档),这里重点介绍实现细节。
|
||
|
||
### ZeRO-1: 优化器状态分片
|
||
|
||
```python
|
||
# DeepSpeed ZeRO-1配置
|
||
{
|
||
"zero_optimization": {
|
||
"stage": 1,
|
||
"contiguous_gradients": true,
|
||
"reduce_scatter": true,
|
||
"allgather_partitions": true
|
||
}
|
||
}
|
||
```
|
||
|
||
**实现机制**:
|
||
- 每个GPU持有优化器状态的1/N分片
|
||
- 梯度计算后执行Reduce-Scatter,每个GPU只保留对应分片的梯度
|
||
- 参数更新只涉及本地分片
|
||
- 需要时通过AllGather重建完整梯度
|
||
|
||
### ZeRO-2: 梯度分片
|
||
|
||
```json
|
||
{
|
||
"zero_optimization": {
|
||
"stage": 2,
|
||
"stage1_param": false,
|
||
"stage2_param": false,
|
||
"stage2_cpu_offload": false,
|
||
"contiguous_gradients": true,
|
||
"overlap_comm": true
|
||
}
|
||
}
|
||
```
|
||
|
||
**额外特性**:
|
||
- 梯度分片存储,避免完整梯度复制
|
||
- Overlap通信与计算:利用CUDA Stream技术在反向传播时同步梯度
|
||
- Gradient accumulation支持
|
||
|
||
### ZeRO-3: 参数分片
|
||
|
||
```json
|
||
{
|
||
"zero_optimization": {
|
||
"stage": 3,
|
||
"stage3_param_persistence_threshold": 1e5,
|
||
"stage3_max_live_parameters": 1e9,
|
||
"stage3_max_reuse_distance": 1e5
|
||
}
|
||
}
|
||
```
|
||
|
||
**关键参数**:
|
||
- `stage3_max_live_parameters`:GPU上同时保持的最大参数分片数
|
||
- `stage3_param_persistence_threshold`:超过此阈值的参数保持在GPU
|
||
|
||
### ZeRO-Inference
|
||
|
||
```python
|
||
# ZeRO-Inference配置
|
||
{
|
||
"zero_optimization": {
|
||
"stage": 3,
|
||
"stage3_offload_param": {
|
||
"device": "cpu"
|
||
}
|
||
},
|
||
"inference": {
|
||
"enabled": true
|
||
}
|
||
}
|
||
```
|
||
|
||
推理时将参数卸载到CPU,通过动态加载满足计算需求。
|
||
|
||
## 3D并行配置
|
||
|
||
### 并行策略组合
|
||
|
||
DeepSpeed支持数据并行、流水线并行、张量并行的组合配置:
|
||
|
||
```json
|
||
{
|
||
"parallelism": {
|
||
"tensor_parallel": {
|
||
"enabled": true,
|
||
"size": 8,
|
||
"mpu": "MegatronMPU"
|
||
},
|
||
"pipeline": {
|
||
"enabled": true,
|
||
"stages": 4,
|
||
"pipe_schedule": "GPipe"
|
||
},
|
||
"data_parallel": {
|
||
"degree": 32
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 设备映射
|
||
|
||
```python
|
||
# 假设有 256 个 GPU
|
||
# 配置: TP=8, PP=4, DP=8
|
||
# 总GPU需求: 8 × 4 × 8 = 256
|
||
|
||
# 数据并行度 = 总GPU数 / (TP × PP) = 256 / 32 = 8
|
||
data_parallel_size = 8
|
||
tensor_parallel_size = 8
|
||
pipeline_parallel_size = 4
|
||
|
||
# 模型切分
|
||
model = transformer_layer / pipeline_parallel_size # 每Stage 1/4层
|
||
layer = weight / tensor_parallel_size # 每GPU 1/8权重
|
||
```
|
||
|
||
### 通信域配置
|
||
|
||
```python
|
||
# 通信域层级
|
||
# 1. TP通信域(张量并行):all-reduce within 8 GPUs
|
||
# 2. PP通信域(流水线并行):send/recv between stages
|
||
# 3. DP通信域(数据并行):all-reduce across DP replicas
|
||
|
||
# DeepSpeed自动构建通信域
|
||
ds_config = DeepSpeedConfig(config)
|
||
```
|
||
|
||
## Gradient Checkpointing
|
||
|
||
### 原理
|
||
|
||
Gradient Checkpointing(也称Activation Checkpointing)通过在前向传播时不保存中间激活值,而在反向传播时重新计算来节省显存。
|
||
|
||
```python
|
||
# DeepSpeed Gradient Checkpointing配置
|
||
{
|
||
"gradient_checkpointing": {
|
||
"enabled": true,
|
||
"checkpoint_every_n_steps": 1,
|
||
"contiguous": true,
|
||
"checkpoint_in_cpu": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### 内存-计算权衡
|
||
|
||
```
|
||
标准前向:
|
||
- 前向计算: O(1)
|
||
- 激活存储: O(N) # N=层数
|
||
|
||
Checkpointing:
|
||
- 前向计算: O(N) # 每层重新计算
|
||
- 激活存储: O(1) # 只保存输入输出
|
||
- 反向计算: O(N) # 重新计算中间激活
|
||
|
||
节省显存: ~70%(取决于模型结构)
|
||
额外计算开销: ~30%
|
||
```
|
||
|
||
### 与ZeRO结合
|
||
|
||
```python
|
||
{
|
||
"gradient_checkpointing": true,
|
||
"zero_optimization": {
|
||
"stage": 3
|
||
}
|
||
}
|
||
# ZeRO-3 + Checkpointing: 显存 ≈ 模型大小 / N + 激活 / N
|
||
```
|
||
|
||
## 混合精度训练支持
|
||
|
||
### BF16训练
|
||
|
||
```json
|
||
{
|
||
"bf16": {
|
||
"enabled": true,
|
||
"loss_scaling": "dynamic"
|
||
},
|
||
"fp16": {
|
||
"enabled": false
|
||
}
|
||
}
|
||
```
|
||
|
||
**关键特性**:
|
||
- 前向/反向传播使用BF16
|
||
- 优化器状态保持FP32精度
|
||
- Loss scaling动态调整
|
||
- 支持ZeRO-3与BF16结合
|
||
|
||
### 混合精度流程
|
||
|
||
```
|
||
1. 前向传播: BF16
|
||
↓
|
||
2. Loss计算: BF16
|
||
↓
|
||
3. 反向传播: BF16梯度
|
||
↓
|
||
4. 梯度转FP32: 用于优化器更新
|
||
↓
|
||
5. 参数更新: FP32优化器 → FP16/BF16参数
|
||
```
|
||
|
||
### Loss Scaling
|
||
|
||
```python
|
||
# DeepSpeed自动loss scaling
|
||
class BF16Scaler:
|
||
def __init__(self):
|
||
self.loss_scale = None
|
||
self.scale_factor = 1.0
|
||
|
||
def set_scale(self, loss_scale):
|
||
self.loss_scale = loss_scale
|
||
|
||
def update_scale(self, found_inf):
|
||
# 发现inf时缩小scale
|
||
if found_inf:
|
||
self.loss_scale /= 2
|
||
else:
|
||
self.loss_scale = self.loss_scale # 保持或增长
|
||
```
|
||
|
||
## 训练配置示例
|
||
|
||
### 7B模型单节点多卡
|
||
|
||
```json
|
||
{
|
||
"train_batch_size": 32,
|
||
"train_micro_batch_size_per_gpu": 4,
|
||
"gradient_accumulation_steps": 8,
|
||
"steps_per_print": 10,
|
||
|
||
"zero_optimization": {
|
||
"stage": 3,
|
||
"offload_optimizer": {
|
||
"device": "cpu",
|
||
"pin_memory": true
|
||
}
|
||
},
|
||
|
||
"bf16": {
|
||
"enabled": true
|
||
},
|
||
|
||
"gradient_clipping": 1.0,
|
||
|
||
"WallClockBreakdown": true,
|
||
"memory_breakdown": false
|
||
}
|
||
```
|
||
|
||
### 65B模型多节点
|
||
|
||
```json
|
||
{
|
||
"train_batch_size": 1536,
|
||
"train_micro_batch_size_per_gpu": 1,
|
||
"gradient_accumulation_steps": 1536,
|
||
|
||
"parallelism": {
|
||
"tensor_parallel": 8,
|
||
"pipeline": 4,
|
||
"data_parallel": 64
|
||
},
|
||
|
||
"zero_optimization": {
|
||
"stage": 3,
|
||
"stage3_param_persistence_threshold": 1e5,
|
||
"stage3_max_live_parameters": 1e9
|
||
},
|
||
|
||
"bf16": {
|
||
"enabled": true
|
||
},
|
||
|
||
"通信优化": {
|
||
"overlap_comm": true,
|
||
"contiguous_gradients": true
|
||
}
|
||
}
|
||
```
|
||
|
||
## ZeRO-Stage 3关键技术细节
|
||
|
||
### 参数分片管理
|
||
|
||
```python
|
||
class ParameterShardingManager:
|
||
"""管理参数分片的加载和卸载"""
|
||
|
||
def __init__(self, model, device):
|
||
self.param_shapes = {} # 参数形状信息
|
||
self.param_offsets = {} # 分片偏移信息
|
||
self.param缓存 = {} # 已加载的分片
|
||
|
||
def get_param_shard(self, param, shard_id):
|
||
"""获取参数分片"""
|
||
shape = param.shape
|
||
num_shards = self.get_num_shards(shape)
|
||
|
||
# 计算分片范围
|
||
start = shard_id * (shape[0] // num_shards)
|
||
end = (shard_id + 1) * (shape[0] // num_shards)
|
||
|
||
return param[start:end].clone()
|
||
|
||
def load_param_async(self, param, shard_id):
|
||
"""异步加载参数分片到GPU"""
|
||
shard = self.get_param_shard(param, shard_id)
|
||
self.param_cache[param] = shard.to(device)
|
||
|
||
def scatter_param(self, param):
|
||
"""将参数分片分发到各GPU"""
|
||
# 使用集合通信
|
||
return self.all_gather(param)
|
||
```
|
||
|
||
### 通信重叠
|
||
|
||
```python
|
||
# Overlap策略:反向传播与梯度同步重叠
|
||
backward_pass():
|
||
for layer in reversed(layers):
|
||
# 1. 计算本地梯度
|
||
grad = layer.compute_gradient()
|
||
|
||
# 2. 触发异步梯度同步
|
||
if should_sync(layer):
|
||
dist.all_reduce_async(grad, op=dist.ReduceOp.SUM)
|
||
|
||
# 3. 继续计算后续层梯度
|
||
next_layer.compute_gradient(grad)
|
||
|
||
# 等待所有同步完成
|
||
dist.synchronize()
|
||
```
|
||
|
||
### 混合分片策略
|
||
|
||
```python
|
||
# 部分参数使用不同分片策略
|
||
{
|
||
"zero_optimization": {
|
||
"stage": 3,
|
||
"param_sharding_strategy": "order_based",
|
||
"stage3_order": [
|
||
"embeddings",
|
||
"attention",
|
||
"mlp"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
## DeepSpeed训练流程
|
||
|
||
```python
|
||
import deepspeed
|
||
|
||
# 1. 初始化DeepSpeed
|
||
deepspeed.init_distributed()
|
||
|
||
# 2. 创建模型
|
||
model = MyModel()
|
||
|
||
# 3. 创建优化器(可选,DeepSpeed内部创建)
|
||
optimizer = torch.optim.Adam(model.parameters())
|
||
|
||
# 4. 初始化DeepSpeed
|
||
model_engine, optimizer, _, _ = deepspeed.initialize(
|
||
model=model,
|
||
optimizer=optimizer,
|
||
config=ds_config
|
||
)
|
||
|
||
# 5. 训练循环
|
||
while training:
|
||
# 前向
|
||
loss = model_engine.forward(batch)
|
||
|
||
# 反向
|
||
model_engine.backward(loss)
|
||
|
||
# 更新
|
||
model_engine.step()
|
||
```
|
||
|
||
## 与PyTorch FSDP对比
|
||
|
||
| 特性 | DeepSpeed ZeRO-3 | PyTorch FSDP |
|
||
|------|-----------------|--------------|
|
||
| 参数分片 | ZeRO-3分片 | Full Sharded |
|
||
| 通信模式 | AllGather + ReduceScatter | AllGather |
|
||
| CPU Offload | 原生支持 | 需要额外配置 |
|
||
| 优化器卸载 | 原生支持 | 部分支持 |
|
||
| 易用性 | 配置驱动 | 代码驱动 |
|
||
| 生态 | 成熟度高 | 官方维护 |
|
||
|
||
## 性能调优建议
|
||
|
||
1. **通信优化**:启用`overlap_comm`和`contiguous_gradients`
|
||
2. **内存优化**:适当使用CPU卸载缓解GPU压力
|
||
3. **Batch Size**:配合gradient accumulation调整
|
||
4. **通信带宽**:确保使用高速互联(NVLink)
|
||
5. **混合精度**:使用BF16而非FP16
|
||
|
||
## 常见问题
|
||
|
||
| 问题 | 解决方案 |
|
||
|------|---------|
|
||
| OOM错误 | 降低batch size或启用ZeRO-3 |
|
||
| 通信瓶颈 | 检查网络拓扑,启用overlap |
|
||
| 精度问题 | 使用BF16,检查loss scaling |
|
||
| 速度慢 | 调整num_workers,增加warmup | |