ai部署1
可以。下面给你一份从裸机 CentOS 9 到单机训练、8 GPU DDP、4×8=32 GPU 分布式语言模型训练的完整文档,并且每个关键操作都增加:
-
做什么
-
为什么做
-
作用
-
验证方法
-
异常时看什么
-
4 台机器哪些操作完全一样
-
哪些参数必须每台不同
另外,我会把之前容易混淆的 Driver / CUDA / NCCL / PyTorch / DDP / FSDP / 数据 / 模型 / checkpoint / 网络 / NUMA 全部串起来。
**重要修正:**不要把“安装 CUDA Toolkit 的版本”和“NVIDIA Driver 的版本”简单理解成必须一一对应;Driver 负责 GPU 内核接口,CUDA Toolkit 提供编译器和用户态库,实际兼容关系应以 NVIDIA/PyTorch 当前支持矩阵为准。部署时四台机器必须统一版本。
CentOS 9 + 4×8 NVIDIA A100 80GB
裸机 AI 语言模型单机与 32 GPU 分布式训练完整实施文档
1. 文档目标
本文部署:
4 台 CentOS 9
│
├── gpu01
│ └── 8 × NVIDIA A100 80GB
│
├── gpu02
│ └── 8 × NVIDIA A100 80GB
│
├── gpu03
│ └── 8 × NVIDIA A100 80GB
│
└── gpu04
└── 8 × NVIDIA A100 80GB
总 GPU:
4 × 8 = 32 GPU
总显存:
32 × 80GB = 2560GB
部署方式:
裸机
├── NVIDIA Driver
├── CUDA
├── NCCL
├── Python
├── PyTorch
├── Transformers
├── Datasets
└── Distributed Training
明确:
不使用 Docker
不使用 Kubernetes
不依赖容器运行训练
训练阶段:
单 GPU
↓
单机 8 GPU
↓
4机 32 GPU
↓
大模型 FSDP / ZeRO
2. 整体架构
整个软件栈必须理解清楚。
语言模型
│
▼
Transformers
│
▼
PyTorch
│
┌──────────┴──────────┐
│ │
CUDA NCCL
│ │
▼ ▼
NVIDIA Driver GPU Collective
│ │
└──────────┬──────────┘
│
▼
A100
跨机器时:
gpu01 gpu02
8 GPU 8 GPU
│ │
└────── NCCL ─────────────┘
│
Network
│
Ethernet / IB / RoCE
四台:
gpu01 ─┐
gpu02 ─┤
gpu03 ─┼── NCCL ── Network
gpu04 ─┘
3. 为什么不能直接运行训练?
因为语言模型训练实际上依赖很多层:
训练代码
↓
Python
↓
PyTorch
↓
CUDA
↓
NVIDIA Driver
↓
GPU
多机以后增加:
PyTorch Distributed
↓
NCCL
↓
NIC
↓
交换机
↓
其他节点
所以必须逐层验证。
4. 节点规划
以下 IP 为示例。
| Node | Hostname | IP | GPU | Node Rank |
|---|---|---|---|---|
| 1 | gpu01 | 10.10.10.11 | 8 | 0 |
| 2 | gpu02 | 10.10.10.12 | 8 | 1 |
| 3 | gpu03 | 10.10.10.13 | 8 | 2 |
| 4 | gpu04 | 10.10.10.14 | 8 | 3 |
最终:
NNODES = 4
GPUS_PER_NODE = 8
WORLD_SIZE = 32
5. 哪些操作四台完全一样?
以后文档中:
【4台全部执行】
代表:
gpu01
gpu02
gpu03
gpu04
全部执行相同命令。
只有下面这些必须不同:
hostname
IP
node-rank
例如:
gpu01 → rank 0
gpu02 → rank 1
gpu03 → rank 2
gpu04 → rank 3
6. 第一阶段:操作系统检查
6.1 查看 OS
【4台全部执行】
cat /etc/redhat-release
检查:
uname -a
检查:
uname -r
作用
确认:
CentOS / RHEL 9
Kernel
Architecture
为什么?
NVIDIA Driver、CUDA、RDMA 等软件都依赖 Kernel。
7. 设置 hostname
gpu01
hostnamectl set-hostname gpu01
gpu02
hostnamectl set-hostname gpu02
gpu03
hostnamectl set-hostname gpu03
gpu04
hostnamectl set-hostname gpu04
检查:
hostname
作用
给每台服务器一个唯一名字。
8. 配置 hosts
【4台全部执行】
cat >> /etc/hosts <<'EOF'
10.10.10.11 gpu01
10.10.10.12 gpu02
10.10.10.13 gpu03
10.10.10.14 gpu04
EOF
检查:
getent hosts gpu01
getent hosts gpu02
getent hosts gpu03
getent hosts gpu04
作用
实现:
gpu01 → 10.10.10.11
为什么?
方便:
ssh gpu02
ping gpu03
以及后续分布式运维。
9. 安装基础工具
【4台全部执行】
dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
git \
wget \
curl \
vim \
tmux \
pciutils \
ethtool \
numactl \
numactl-libs \
hwloc \
lsof \
net-tools \
sysstat \
procps-ng \
python3 \
python3-devel \
python3-pip \
openssh-server \
openssh-clients \
chrony
作用
这些不是 AI 框架本身,而是:
系统管理
编译
网络
NUMA
监控
SSH
Python
10. 时间同步
【4台全部执行】
systemctl enable --now chronyd
检查:
chronyc tracking
检查:
timedatectl
作用
让四台服务器保持时间同步。
为什么?
分布式训练时日志可能来自:
gpu01
gpu02
gpu03
gpu04
如果时间不一致,故障分析非常困难。
11. CPU / NUMA 检查
【4台全部执行】
lscpu
numactl -H
重点记录:
CPU(s)
Socket(s)
Core(s)
NUMA node(s)
作用
确定 CPU 和 NUMA 拓扑。
这会影响:
GPU
PCIe
NIC
CPU
内存
之间的数据路径。
12. GPU PCIe 检查
【4台全部执行】
lspci | grep -i nvidia
必须看到 8 张 GPU。
作用
这是最底层的 GPU 检查。
如果:
lspci | grep -i nvidia
没有结果:
不要检查 PyTorch。
因为 Linux PCIe 层都没有识别 GPU。
13. 查看网卡
【4台全部执行】
ip -br link
ip -br addr
查看 PCI:
lspci | grep -i -E 'ethernet|mellanox|infiniband'
作用
确定:
管理网卡
训练网卡
高速网卡
IB / RoCE
后面 NCCL 需要使用正确的高速网络。
14. Nouveau
检查:
lsmod | grep nouveau
如果有:
cat > /etc/modprobe.d/blacklist-nouveau.conf <<'EOF'
blacklist nouveau
options nouveau modeset=0
EOF
然后:
dracut --force
重启:
reboot
重新检查:
lsmod | grep nouveau
作用
避免 Nouveau 和 NVIDIA 官方 Driver 冲突。
15. NVIDIA Driver
添加 NVIDIA Repository。
【4台全部执行】
dnf config-manager --add-repo \
https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo
然后:
dnf clean all
dnf makecache
查看:
dnf module list nvidia-driver
安装适合当前系统和 CUDA 组合的稳定 Driver。
例如环境统一采用 580 系列:
dnf module reset -y nvidia-driver
dnf module enable -y nvidia-driver:580-dkms
dnf module install -y nvidia-driver:580-dkms
重启:
reboot
Driver 的作用
建立:
Linux
↓
NVIDIA Driver
↓
A100
没有 Driver:
CUDA
PyTorch
都不能正常使用 GPU。
16. NVIDIA Driver 验证
【4台全部执行】
nvidia-smi
检查 GPU:
nvidia-smi -L
检查版本:
nvidia-smi --query-gpu=index,name,driver_version,memory.total \
--format=csv
必须:
8 GPU
A100
80GB
Driver版本一致
17. NVIDIA Persistence
【4台全部执行】
dnf install -y nvidia-persistenced
systemctl enable --now nvidia-persistenced
检查:
systemctl status nvidia-persistenced
作用
让 GPU 保持稳定的持久化状态。
18. CUDA Toolkit
统一安装一个经过验证的 CUDA 版本。
例如:
dnf install -y cuda-toolkit-13-0
配置:
cat > /etc/profile.d/cuda.sh <<'EOF'
export CUDA_HOME=/usr/local/cuda
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}
EOF
然后:
ln -sfn /usr/local/cuda-13.0 /usr/local/cuda
加载:
source /etc/profile.d/cuda.sh
检查:
nvcc --version
CUDA 的作用
CUDA 是 GPU 计算平台。
提供:
CUDA Runtime
CUDA libraries
nvcc
GPU kernel execution
19. Driver 和 CUDA 的关系
一定要区分:
NVIDIA Driver
和:
CUDA Toolkit
架构:
PyTorch
↓
CUDA Runtime
↓
NVIDIA Driver
↓
A100
而:
nvcc
来自:
CUDA Toolkit
所以:
nvidia-smi
和:
nvcc --version
检查的是不同东西。
20. 创建 AI 用户
【4台全部执行】
useradd -m -s /bin/bash ai 2>/dev/null || true
创建目录:
mkdir -p /data/ai/{venv,models,datasets,checkpoints,logs,scripts}
授权:
chown -R ai:ai /data/ai
作用
不要使用 root 直接训练。
AI 用户负责:
模型
数据
训练
checkpoint
日志
21. Python 虚拟环境
【4台全部执行】
su - ai
python3 -m venv /data/ai/venv
激活:
source /data/ai/venv/bin/activate
升级:
pip install -U pip setuptools wheel
作用
隔离 Python 依赖。
22. PyTorch
【4台全部执行】
根据实际 CUDA/Driver 组合选择经过验证的 PyTorch wheel。
例如 CUDA 13.0:
pip install \
torch==2.12.1 \
torchvision==0.27.1 \
--index-url https://download.pytorch.org/whl/cu130
PyTorch 的作用
提供:
Tensor
Autograd
Neural Network
Optimizer
DataLoader
Distributed
CUDA backend
23. PyTorch CUDA 验证
【4台全部执行】
python - <<'PY'
import torch
print("PyTorch =", torch.__version__)
print("CUDA runtime =", torch.version.cuda)
print("CUDA available =", torch.cuda.is_available())
print("GPU count =", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
print(
i,
torch.cuda.get_device_name(i),
torch.cuda.get_device_properties(i).total_memory / 1024**3
)
PY
必须:
CUDA available = True
GPU count = 8
24. 为什么需要 PyTorch 验证?
因为:
nvidia-smi
正常只说明:
Driver → GPU
而:
torch.cuda.is_available()
验证:
PyTorch
↓
CUDA
↓
Driver
↓
GPU
25. 安装 Transformers
【4台全部执行】
pip install transformers
作用
提供:
Transformer
Tokenizer
Model
Trainer
Config
例如:
Qwen
Llama
BERT
GPT
等模型可以通过 Transformers 加载。
26. 安装 Datasets
pip install datasets
作用
处理训练数据:
JSON
JSONL
Parquet
Arrow
例如:
train.jsonl
validation.jsonl
转换成:
Dataset
27. 安装 Accelerate
pip install accelerate
作用
统一管理:
CPU
GPU
Multi-GPU
Mixed Precision
Distributed
后续使用:
FSDP
DeepSpeed
也经常通过 Accelerate 配置。
28. 安装 TensorBoard
pip install tensorboard
作用
观察训练:
loss
learning rate
step
epoch
throughput
29. 安装 DeepSpeed
如果以后需要:
pip install deepspeed
作用
大模型显存优化。
例如:
ZeRO-1
ZeRO-2
ZeRO-3
30. SSH 免密
在 gpu01:
su - ai
ssh-keygen -t ed25519
复制:
ssh-copy-id ai@gpu01
ssh-copy-id ai@gpu02
ssh-copy-id ai@gpu03
ssh-copy-id ai@gpu04
测试:
ssh ai@gpu01 hostname
ssh ai@gpu02 hostname
ssh ai@gpu03 hostname
ssh ai@gpu04 hostname
作用
方便:
集群管理
同步代码
同步数据
启动训练
故障排查
注意:
torchrun 的 rendezvous 本身并不依赖 SSH 免密;免密 SSH 是为了运维便利,以及后续脚本化启动/同步。
31. GPU Topology
【4台全部执行】
nvidia-smi topo -m
作用
查看:
GPU ↔ GPU
GPU ↔ CPU
GPU ↔ NIC
之间的拓扑关系。
例如:
GPU0
│
PCIe Switch
│
GPU1
可能比:
GPU0
│
CPU
│
GPU1
通信更快。
32. GPU P2P
【4台全部执行】
nvidia-smi topo -p2p p
作用
确认 GPU 间 Peer-to-Peer。
DDP/NCCL 单机 8 GPU 会大量使用 GPU collective communication。
如果 P2P 有问题:
NCCL
↓
GPU communication
↓
性能下降 / 初始化失败
33. NUMA
numactl -H
作用
确认:
CPU socket
NUMA node
Memory
例如:
NUMA 0
├── CPU
├── GPU
└── NIC
NUMA 1
├── CPU
├── GPU
└── NIC
如果 GPU 和 NIC 位于不同 NUMA:
GPU
↓
PCIe
↓
NUMA 0
↓
CPU interconnect
↓
NUMA 1
↓
NIC
通信可能产生额外开销。
34. NCCL
NCCL 是:
NVIDIA Collective Communications Library
主要负责:
AllReduce
Broadcast
Reduce
AllGather
ReduceScatter
最重要的就是:
梯度同步
35. 为什么 DDP 需要 NCCL?
假设:
GPU0
GPU1
GPU2
GPU3
每个 GPU 都计算了一部分:
gradient
最后必须:
GPU0 gradient
GPU1 gradient
GPU2 gradient
GPU3 gradient
进行同步。
例如:
Gradient
│
┌─────────┼─────────┐
│ │ │
GPU0 GPU1 GPU2 ...
│ │ │
└────── AllReduce ──┘
│
同样的 gradient
这个工作就是 NCCL 非常擅长做的。
36. NCCL 基础环境
【4台全部执行】
cat > /etc/profile.d/nccl.sh <<'EOF'
export NCCL_DEBUG=WARN
export NCCL_ASYNC_ERROR_HANDLING=1
EOF
加载:
source /etc/profile.d/nccl.sh
为什么不一开始配置一堆 NCCL 参数?
因为 NCCL 会根据:
PCIe
NUMA
GPU topology
NIC
自动选择通信路径。
在不知道实际硬件拓扑之前强制设置:
NCCL_P2P_DISABLE
NCCL_IB_DISABLE
NCCL_SOCKET_IFNAME
NCCL_NET_GDR_LEVEL
可能反而降低性能或造成问题。
37. 网络
查看:
ip -br addr
查看网卡:
ip -br link
查看速率:
ethtool <网卡>
例如:
ethtool ens1f0
作用
确定:
10GbE
25GbE
50GbE
100GbE
200GbE
400GbE
等实际链路。
38. 为什么网络对 32 GPU 很重要?
单机:
GPU0 ↔ GPU1
主要走:
PCIe
跨机:
GPU0
↓
PCIe
↓
NIC
↓
Switch
↓
NIC
↓
PCIe
↓
GPU8
所以:
GPU计算速度
和:
GPU之间通信速度
都会影响最终训练速度。
39. IB / RoCE
如果有 Mellanox/NVIDIA 高速网卡:
lspci | grep -i mellanox
安装:
dnf install -y \
rdma-core \
libibverbs \
libibverbs-utils \
infiniband-diags
检查:
ibstat
ibdev2netdev
ibv_devinfo
rdma link
作用
确认 RDMA 是否正常。
40. 单 GPU CUDA 测试
创建:
cat > /data/ai/scripts/gpu_test.py <<'PY'
import torch
import time
print("GPU count:", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
print(i, torch.cuda.get_device_name(i))
x = torch.randn(8192, 8192, device="cuda")
y = torch.randn(8192, 8192, device="cuda")
torch.cuda.synchronize()
start = time.time()
for _ in range(20):
z = torch.matmul(x, y)
torch.cuda.synchronize()
print("elapsed:", time.time() - start)
print("mean:", z.mean().item())
PY
运行:
CUDA_VISIBLE_DEVICES=0 \
python /data/ai/scripts/gpu_test.py
作用
验证真正 GPU 计算。
不是只验证:
nvidia-smi
而是:
Python
↓
PyTorch
↓
CUDA
↓
GPU kernel
↓
A100
41. 单机 8 GPU DDP
创建:
cat > /data/ai/scripts/ddp_test.py <<'PY'
import os
import torch
import torch.distributed as dist
def main():
dist.init_process_group("nccl")
rank = dist.get_rank()
world_size = dist.get_world_size()
local_rank = int(os.environ["LOCAL_RANK"])
torch.cuda.set_device(local_rank)
x = torch.tensor(
[float(rank + 1)],
device="cuda"
)
dist.all_reduce(x)
print(
f"rank={rank}, "
f"local_rank={local_rank}, "
f"world_size={world_size}, "
f"gpu={torch.cuda.get_device_name(local_rank)}, "
f"allreduce={x.item()}"
)
dist.barrier()
dist.destroy_process_group()
if __name__ == "__main__":
main()
PY
运行:
torchrun \
--standalone \
--nproc-per-node=8 \
/data/ai/scripts/ddp_test.py
作用
测试:
8 GPU
8 process
8 rank
NCCL
AllReduce
理论结果:
1+2+3+4+5+6+7+8 = 36
所以每个 rank 应该看到:
allreduce=36
42. torchrun 是什么?
torchrun ...
负责启动多个 PyTorch 进程。
单机:
torchrun
├── rank0 → GPU0
├── rank1 → GPU1
├── rank2 → GPU2
...
└── rank7 → GPU7
多机:
gpu01
├── rank0
├── ...
└── rank7
gpu02
├── rank8
├── ...
└── rank15
gpu03
├── rank16
├── ...
└── rank23
gpu04
├── rank24
├── ...
└── rank31
43. --nnodes=4
--nnodes=4
作用
告诉 PyTorch:
总共有 4 台机器
44. --nproc-per-node=8
--nproc-per-node=8
作用
每台机器启动 8 个训练进程。
因为:
8 GPU
所以:
1 process ↔ 1 GPU
45. --node-rank
例如 gpu01:
--node-rank=0
gpu02:
--node-rank=1
gpu03:
--node-rank=2
gpu04:
--node-rank=3
作用
告诉系统:
我是第几台训练节点。
46. --master-addr
--master-addr=10.10.10.11
作用
指定 rendezvous/master 地址。
例如:
gpu01 = master
其他机器需要能够访问:
10.10.10.11:29500
47. --master-port
--master-port=29500
作用
提供分布式初始化通信端口。
检查:
ss -lntp | grep 29500
48. 32 GPU 启动
gpu01
torchrun \
--nnodes=4 \
--nproc-per-node=8 \
--node-rank=0 \
--master-addr=10.10.10.11 \
--master-port=29500 \
/data/ai/scripts/ddp_test.py
gpu02
torchrun \
--nnodes=4 \
--nproc-per-node=8 \
--node-rank=1 \
--master-addr=10.10.10.11 \
--master-port=29500 \
/data/ai/scripts/ddp_test.py
gpu03
torchrun \
--nnodes=4 \
--nproc-per-node=8 \
--node-rank=2 \
--master-addr=10.10.10.11 \
--master-port=29500 \
/data/ai/scripts/ddp_test.py
gpu04
torchrun \
--nnodes=4 \
--nproc-per-node=8 \
--node-rank=3 \
--master-addr=10.10.10.11 \
--master-port=29500 \
/data/ai/scripts/ddp_test.py
49. 32 GPU 成功标准
必须看到:
rank 0
rank 1
...
rank 31
并且:
world_size=32
每个 rank 都有:
local_rank=0~7
并且:
allreduce=528
因为:
1+2+...+32 = 528
50. 为什么 world_size=32?
公式:
world_size
=
node_count
×
GPU_per_node
所以:
4 × 8 = 32
51. 准备语言模型数据
目录:
/data/ai/datasets/
├── train.jsonl
├── validation.jsonl
└── test.jsonl
JSONL:
{"text":"Linux 是一种开源操作系统。"}
{"text":"NVIDIA A100 是数据中心 GPU。"}
{"text":"PyTorch 可以用于深度学习训练。"}
作用
模型训练的原始数据。
52. 为什么需要 train / validation / test?
train
↓
更新模型参数
validation
↓
判断模型是否过拟合
选择参数
test
↓
最终评价
不能把所有数据都拿来训练。
53. Tokenizer
例如:
tokenizer = AutoTokenizer.from_pretrained(...)
作用
把:
文本
变成:
token ID
例如:
Linux 是操作系统
变成:
[1234, 567, 8910, ...]
GPU 不能直接训练字符串。
54. Causal Language Model
训练目标:
输入:
我 喜欢
预测:
学习
即:
x1 → x2
x1 x2 → x3
x1 x2 x3 → x4
核心:
next token prediction
55. Forward
模型:
token IDs
↓
Embedding
↓
Transformer layers
↓
Logits
得到:
logits
表示每一个 token 的预测概率。
56. Loss
使用:
Cross Entropy
比较:
预测 token
和:
真实 token
差异。
训练目标:
loss ↓
57. Backward
执行:
loss.backward()
计算:
∂Loss / ∂Parameter
也就是:
gradient
58. Optimizer
例如:
AdamW
负责:
Parameter
+
Gradient
→
新的 Parameter
也就是:
模型更新
59. DDP 中的 AllReduce
这是多 GPU 训练的核心。
每个 GPU:
Forward
↓
Loss
↓
Backward
↓
Gradient
然后:
GPU0 ─┐
GPU1 ─┤
GPU2 ─┼── AllReduce
... ┤
GPU7 ─┘
最后:
所有 GPU
拥有一致的 gradient
然后各自更新模型。
60. 单机训练
先:
CUDA_VISIBLE_DEVICES=0 \
python train_lm.py
作用
验证:
模型
数据
Tokenizer
Loss
Optimizer
61. 单机 8 GPU 训练
torchrun \
--standalone \
--nproc-per-node=8 \
train_lm.py
作用
验证:
单机 8 GPU
DDP
NCCL
梯度同步
62. Global Batch Size
公式:
Global Batch Size
=
per_device_batch_size
×
gradient_accumulation_steps
×
world_size
例如:
per_device = 1
gradient_accumulation = 16
world_size = 32
得到:
1 × 16 × 32
=
512
63. Gradient Accumulation
如果:
GPU显存不够
不能继续增加:
batch size
可以:
batch = 1
gradient accumulation = 16
等效增加训练 batch。
64. BF16
A100 支持 BF16。
训练大模型通常优先考虑:
bf16=True
作用:
降低显存
提高吞吐
保持比 FP16 更大的指数范围
65. Gradient Checkpointing
gradient_checkpointing=True
作用:
保存更少 activation
训练时重新计算一部分 activation。
结果:
显存 ↓
计算量 ↑
66. Sequence Length
例如:
2048
4096
8192
长度越大:
显存需求 ↑
计算量 ↑
因此第一次训练建议:
2048
确认正常后再增加。
67. DataLoader
dataloader_num_workers=8
作用
多个 CPU worker 并行准备数据。
流程:
磁盘
↓
CPU workers
↓
DataLoader
↓
GPU
如果 worker 太少:
GPU 等数据
如果太多:
CPU / 内存 / IO 压力
68. TensorBoard
tensorboard \
--logdir /data/ai/logs \
--bind_all \
--port 6006
作用
观察:
loss
learning rate
step
epoch
69. GPU 监控
watch -n 1 nvidia-smi
或者:
nvidia-smi dmon -s pucm
作用
观察:
GPU utilization
memory
power
clock
70. CPU 监控
mpstat -P ALL 1
作用
检查 CPU 是否成为瓶颈。
71. 内存监控
free -h
72. NUMA 监控
numastat
作用
检查是否存在:
NUMA remote memory
73. IO 监控
iostat -xz 1
作用
判断训练是不是卡在:
NVMe
磁盘
文件系统
74. 网络监控
sar -n DEV 1
作用
观察:
RX
TX
bandwidth
packet
75. checkpoint
训练过程中:
checkpoint-500
checkpoint-1000
checkpoint-1500
作用
防止:
服务器宕机
GPU故障
进程异常
网络异常
导致全部重训。
76. checkpoint 应保存什么?
至少:
model
optimizer
scheduler
trainer state
global step
random state
不能只保存:
model.safetensors
否则只能恢复模型,不能完整恢复训练过程。
77. 单纯 DDP 的局限
DDP 的基本模型:
GPU0 → 一份模型
GPU1 → 一份模型
GPU2 → 一份模型
...
GPU31 → 一份模型
也就是说:
32 GPU
=
32 model replicas
如果模型很大:
70B
可能根本放不下。
78. FSDP
FSDP:
Fully Sharded Data Parallel
核心思想:
模型参数
梯度
Optimizer State
进行分片。
例如:
GPU0 → shard0
GPU1 → shard1
GPU2 → shard2
...
因此:
单 GPU 显存压力 ↓
79. DeepSpeed ZeRO
ZeRO:
ZeRO-1
ZeRO-2
ZeRO-3
逐步切分:
Optimizer states
↓
Gradients
↓
Parameters
ZeRO-3 可以进一步切分模型参数。
80. 什么时候 DDP?
适合:
小模型
中等模型
显存充足
追求简单
例如:
0.6B
1B
3B
7B
具体还取决于:
sequence length
batch size
optimizer
activation
81. 什么时候 FSDP / ZeRO?
例如:
14B
32B
70B
如果 DDP:
每张 GPU 都保存完整模型
显存压力会非常大。
这时:
FSDP
或者:
ZeRO-3
更加合理。
82. 训练故障排查顺序
GPU 不识别
lspci
↓
nvidia-smi
↓
Driver
CUDA 不可用
nvidia-smi
↓
nvcc
↓
PyTorch
↓
torch.cuda.is_available()
单机 DDP 卡住
torchrun
↓
NCCL
↓
GPU topology
↓
P2P
多机 DDP 卡住
优先:
IP
↓
port
↓
firewall
↓
NCCL interface
↓
NIC
↓
IB/RoCE
↓
NCCL
83. 多机 NCCL Debug
临时:
export NCCL_DEBUG=INFO
如果重点看网络:
export NCCL_DEBUG_SUBSYS=NET
然后运行:
torchrun ...
重点看:
Socket
IB
NET
P2P
84. NCCL 网卡指定
只有确认高速网卡以后再设置。
例如:
ens1f0
可以:
export NCCL_SOCKET_IFNAME==ens1f0
如果是 IB/RoCE,还要进一步确认:
RDMA
verbs
NIC
GDR
NCCL
不能只看到 Mellanox 就认为 NCCL 一定使用 RDMA。
85. 防火墙
查看:
firewall-cmd --list-all
测试端口:
nc -zv 10.10.10.11 29500
作用
确认:
其他节点
↓
gpu01
↓
29500
能够访问。
生产环境不要长期:
systemctl stop firewalld
而应该只开放必要端口。
86. 训练时 GPU 低利用率
例如:
GPU = 20%
CPU = 100%
优先检查:
DataLoader
Tokenizer
CPU
IO
NUMA
87. 单机高,多机低
例如:
8 GPU:
95%
32 GPU:
40%
优先检查:
NCCL
网络
NIC
RDMA
PCIe
NUMA
GPU-NIC topology
而不是首先修改:
learning rate
batch size
88. GPU OOM
出现:
CUDA out of memory
推荐顺序:
1. batch size ↓
2. sequence length ↓
3. gradient checkpointing
4. gradient accumulation
5. BF16
6. FSDP / ZeRO
89. 训练数据和代码一致性
四台必须保持:
train_lm.py
transformers版本
PyTorch版本
CUDA环境
模型配置
Tokenizer
一致。
例如不要:
gpu01 transformers 5.x
gpu02 transformers 4.x
90. 四台环境检查脚本
建议创建:
cat > /data/ai/scripts/check_env.sh <<'EOF'
#!/bin/bash
set -e
echo "========== HOST =========="
hostname
echo "========== OS =========="
cat /etc/redhat-release
echo "========== KERNEL =========="
uname -r
echo "========== NVIDIA =========="
nvidia-smi --query-gpu=index,name,driver_version,memory.total \
--format=csv
echo "========== CUDA =========="
nvcc --version | tail -n 4
echo "========== PYTORCH =========="
python - <<'PY'
import torch
print("torch:", torch.__version__)
print("cuda:", torch.version.cuda)
print("available:", torch.cuda.is_available())
print("count:", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
print(i, torch.cuda.get_device_name(i))
PY
echo "========== TOPOLOGY =========="
nvidia-smi topo -m
echo "========== NUMA =========="
numactl -H
echo "========== NETWORK =========="
ip -br addr
EOF
授权:
chmod +x /data/ai/scripts/check_env.sh
执行:
/data/ai/scripts/check_env.sh
作用
统一检查四台机器环境。
91. 四台机器最终应该完全一致的内容
OS
Kernel
NVIDIA Driver
CUDA
NCCL
Python
PyTorch
Transformers
Datasets
Accelerate
DeepSpeed
训练代码
92. 四台机器必须不同的内容
只有:
hostname
IP
node-rank
例如:
gpu01:
node-rank=0
gpu02:
node-rank=1
gpu03:
node-rank=2
gpu04:
node-rank=3
93. 第一轮实验顺序
严格按照:
阶段 1
裸机检查
↓
阶段 2
Driver
↓
阶段 3
CUDA
↓
阶段 4
PyTorch
↓
阶段 5
单 GPU CUDA
↓
阶段 6
单机 8 GPU NCCL
↓
阶段 7
单机 8 GPU DDP
↓
阶段 8
4机网络
↓
阶段 9
4机 32 GPU NCCL
↓
阶段 10
4机 32 GPU DDP
↓
阶段 11
小语言模型训练
↓
阶段 12
正式数据
↓
阶段 13
7B+
↓
阶段 14
FSDP / ZeRO
94. 不要直接做的事情
不要第一步就:
32 GPU
70B
8192 sequence
因为出了问题不知道是哪一层。
正确方法:
GPU
↓
CUDA
↓
PyTorch
↓
NCCL
↓
DDP
↓
Model
↓
Data
↓
Large Model
逐层验证。
95. 最终完整架构
最终生产环境:
AI Training
│
Transformer LM
│
PyTorch Trainer
│
┌──────────┴──────────┐
│ │
DDP FSDP
│ │
└──────────┬──────────┘
│
NCCL
│
┌─────────────────┼─────────────────┐
│ │ │
gpu01 gpu02 gpu03 gpu04
│ │ │ │
8 × A100 8 × A100 8 × A100 8 × A100
│ │ │ │
└─────────────────┴─────────────────┴───────────┘
│
Network
│
IB / RoCE / Ethernet
96. 资源关系
最终可以把整个系统理解为:
A100
│
│ 负责计算
▼
CUDA
│
│ 提供GPU计算接口
▼
PyTorch
│
│ 负责Tensor/Autograd/Training
▼
NCCL
│
│ 负责GPU之间通信
▼
Network
│
│ 负责机器之间通信
▼
Distributed Training
│
▼
Transformer
│
▼
Language Model
97. 最终验收表
| 层级 | 检查命令 | 正常结果 |
|---|---|---|
| OS | cat /etc/redhat-release |
CentOS/RHEL 9 |
| Kernel | uname -r |
统一 |
| PCIe | lspci | grep -i nvidia |
8 GPU |
| Driver | nvidia-smi |
正常 |
| GPU | nvidia-smi -L |
8 GPU |
| CUDA | nvcc --version |
统一 |
| PyTorch | python -c 'import torch' |
正常 |
| CUDA/PyTorch | torch.cuda.is_available() |
True |
| GPU count | torch.cuda.device_count() |
8 |
| Topology | nvidia-smi topo -m |
正常 |
| NUMA | numactl -H |
正常 |
| Network | ping |
正常 |
| TCP | nc |
正常 |
| RDMA | ibstat |
如使用 IB |
| NCCL | DDP test | 正常 |
| 单机 DDP | torchrun |
8 ranks |
| 多机 DDP | torchrun |
32 ranks |
| 模型 | train_lm.py |
loss 正常 |
| Checkpoint | checkpoint-* |
正常 |
| TensorBoard | tensorboard |
正常 |
98. 最终目标
最终形成:
4台裸机
│
┌─────────┴─────────┐
│ │
每台8 GPU 每台统一环境
│ │
└─────────┬─────────┘
│
32 GPU
│
PyTorch
│
NCCL
│
Distributed DDP
│
Language Model
│
┌──────────┴──────────┐
│ │
单机训练 分布式训练
│ │
8 GPU 32 GPU
│ │
└──────────┬──────────┘
│
大模型训练
│
FSDP / ZeRO
核心原则:
先把硬件层打通
↓
再把 Driver 打通
↓
再把 CUDA 打通
↓
再把 PyTorch 打通
↓
再把单机 NCCL 打通
↓
再把单机 DDP 打通
↓
再把跨机网络打通
↓
再把 32 GPU NCCL 打通
↓
再做 32 GPU DDP
↓
最后才进入正式语言模型训练
这套顺序可以把问题明确定位到具体层,而不是出现“32 GPU 训练卡住”以后同时怀疑 Driver、CUDA、NCCL、网络、模型、数据和代码。
浙公网安备 33010602011771号