PyTorch在CentOS上的分布式训练实践指南
系统与依赖配置
sudo yum install -y epel-release(启用EPEL仓库),sudo yum install -y libnccl-devel(NCCL后端依赖,用于多GPU通信)。wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh下载并安装。conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia。网络与SSH配置
MASTER_PORT=10086),命令:sudo firewall-cmd --add-port=10086/tcp --permanent → sudo firewall-cmd --reload。ssh-keygen -t rsa),将公钥复制到所有工作节点(ssh-copy-id user@worker_ip),测试登录(ssh user@worker_ip)是否无需密码。以下是一个基于DistributedDataParallel(DDP)的模板脚本(train_ddp.py):
import os import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, DistributedSampler from torchvision import datasets, transforms import torch.distributed as dist def setup(rank, world_size): """初始化分布式环境""" os.environ['MASTER_ADDR'] = '主节点IP' # 如'192.168.1.100' os.environ['MASTER_PORT'] = '10086' dist.init_process_group("nccl", rank=rank, world_size=world_size) torch.cuda.set_device(rank) # 将当前进程绑定到指定GPU def cleanup(): """清理分布式环境""" dist.destroy_process_group() class SimpleModel(nn.Module): """示例模型(替换为实际模型)""" def __init__(self): super().__init__() self.fc = nn.Linear(784, 10) def forward(self, x): return self.fc(x.view(-1, 784)) def train(rank, world_size, epochs=5): setup(rank, world_size) # 数据加载(使用DistributedSampler确保数据分片) transform = transforms.Compose([transforms.ToTensor()]) dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank, shuffle=True) dataloader = DataLoader(dataset, batch_size=64, sampler=sampler, num_workers=2) # 模型与优化器(DDP包装模型) model = SimpleModel().to(rank) ddp_model = nn.parallel.DistributedDataParallel(model, device_ids=[rank]) criterion = nn.CrossEntropyLoss().to(rank) optimizer = optim.SGD(ddp_model.parameters(), lr=0.01) # 训练循环 for epoch in range(epochs): sampler.set_epoch(epoch) # 每个epoch打乱数据分片 running_loss = 0.0 for inputs, labels in dataloader: inputs, labels = inputs.to(rank), labels.to(rank) optimizer.zero_grad() outputs = ddp_model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if rank == 0: # 仅主节点打印日志 print(f"Epoch {epoch+1}, Loss: {running_loss/len(dataloader)}") cleanup() if __name__ == "__main__": import argparse parser = argparse.ArgumentParser() parser.add_argument("--world_size", type=int, default=2, help="总进程数(节点数×每节点GPU数)") parser.add_argument("--rank", type=int, default=0, help="当前进程的全局排名") args = parser.parse_args() train(args.rank, args.world_size) 关键点说明:
setup()与cleanup():封装分布式环境初始化与清理,避免代码重复。DistributedSampler:确保每个GPU处理不同的数据分片,避免数据重复。DistributedDataParallel(DDP):自动处理梯度同步与模型更新,是PyTorch推荐的分布式训练方式。使用torch.distributed.launch工具(PyTorch内置),命令格式:
python -m torch.distributed.launch \ --nproc_per_node=NUM_GPUS_PER_NODE \ # 每个节点的GPU数量(如2) --nnodes=1 \ # 节点数量(单机为1) --node_rank=0 \ # 当前节点排名(单机主节点为0) --master_addr="主节点IP" \ # 主节点IP(单机为自己) --master_port=MASTER_PORT \ # 主节点端口(如10086) train_ddp.py 示例(单机2张GPU):
python -m torch.distributed.launch --nproc_per_node=2 --nnodes=1 --node_rank=0 --master_addr="192.168.1.100" --master_port=10086 train_ddp.py 在每台节点上运行相同的命令,通过--node_rank区分节点身份(主节点为0,工作节点依次递增)。
主节点(node0):
python -m torch.distributed.launch \ --nproc_per_node=4 \ # 主节点有4张GPU --nnodes=2 \ # 总节点数(主节点+1个工作节点) --node_rank=0 \ # 主节点排名 --master_addr="192.168.1.100" \ # 主节点IP --master_port=10086 \ # 主节点端口 train_ddp.py 工作节点(node1):
python -m torch.distributed.launch \ --nproc_per_node=2 \ # 工作节点有2张GPU --nnodes=2 \ # 总节点数 --node_rank=1 \ # 工作节点排名 --master_addr="192.168.1.100" \ # 主节点IP(与主节点一致) --master_port=10086 \ # 主节点端口(与主节点一致) train_ddp.py 注意:--nproc_per_node必须与节点实际的GPU数量一致,否则会报错。
nvidia-smi实时查看GPU利用率(如watch -n 1 nvidia-smi),确保GPU资源被充分利用。rank=0)保存模型(if rank == 0: torch.save(model.state_dict(), "model.pth")),避免重复保存。通过以上步骤,即可在CentOS系统上实现PyTorch的分布式训练,充分利用多机多卡的算力加速模型训练过程。