[关闭]
@x-power 2023-03-31T23:20:40.000000Z 字数 3567 阅读 308

分布式训练

深度学习


分为计划、想法和测试三部分。

计划部分:用于进度共享

想法部分:我的一些自问自答,都是关于具体应用的时候一些需要注意的问题,没有回答的原因是因为没有来得及去调研。

测试部分:用来记录一些实现的时候需要注意的东西。

计划

1.公网情况下的多机多卡------------ 100%
2.ZeroTier局域网数据互通
3.局域网下的多机多卡
4.模型使用PointNet++进行多机多卡训练、并记录性能占用
5.性能瓶颈与优化

想法


需要注意的问题


多机多卡情况的梯度合并

Ring-Reduce: 这个方法对于带宽要求确实低、但是害怕算力提供端不稳定、 某个提供点突然下线怎么办? 目前有没有解决方案? 需要再找找。


不同显存与算力机器的Batch Size设置

这个应该根据当前机器的性能去动态的指定、 需要考虑一下, 不同的BS下 是否会对精度产生影响? 梯度聚合的时候需不需要额外操作?


动态增加算力提供端

现在的ddp是否支持动态增加机器?如何实现?
torchrun支持动态算力提供、可以设置worker范围。


测试环境:

Server Cuda pytorch
123.125.240.218 11.1 1.8.0
36.138.4.117 12.0 2.0.0

代码测试部分

  1. import argparse
  2. from tqdm import tqdm
  3. import torch
  4. import torchvision
  5. import torch.nn as nn
  6. import torch.nn.functional as F
  7. import torch.distributed as dist
  8. from torch.nn.parallel import DistributedDataParallel as DDP
  9. import random
  10. import numpy as np
  11. import os
  12. def init_seeds(seed=0, cuda_deterministic=True):
  13. random.seed(seed)
  14. np.random.seed(seed)
  15. torch.manual_seed(seed)
  16. # 模型无需修改
  17. class ToyModel(nn.Module):
  18. def __init__(self):
  19. super(ToyModel, self).__init__()
  20. self.conv1 = nn.Conv2d(3, 6, 5)
  21. self.pool = nn.MaxPool2d(2, 2)
  22. self.conv2 = nn.Conv2d(6, 16, 5)
  23. self.fc1 = nn.Linear(16 * 5 * 5, 120)
  24. self.fc2 = nn.Linear(120, 84)
  25. self.fc3 = nn.Linear(84, 10)
  26. def forward(self, x):
  27. x = self.pool(F.relu(self.conv1(x)))
  28. x = self.pool(F.relu(self.conv2(x)))
  29. x = x.view(-1, 16 * 5 * 5)
  30. x = F.relu(self.fc1(x))
  31. x = F.relu(self.fc2(x))
  32. x = self.fc3(x)
  33. return x
  34. def get_dataset():
  35. transform = torchvision.transforms.Compose([
  36. torchvision.transforms.ToTensor(),
  37. torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
  38. ])
  39. my_trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
  40. download=True, transform=transform)
  41. # dataLoader需要使用DistributedSampler去分发数据。
  42. train_sampler = torch.utils.data.distributed.DistributedSampler(my_trainset)
  43. trainloader = torch.utils.data.DataLoader(my_trainset,
  44. batch_size=16, num_workers=2, sampler=train_sampler)
  45. return trainloader
  46. # 在torchrun时已经指定参数、 此时无序传参
  47. dist.init_process_group()
  48. rank = torch.distributed.get_rank()
  49. init_seeds(1 + rank)
  50. #torchrun的新改动,替代原先的LOCAL_RANK获取方式
  51. local_rank = int(os.environ["LOCAL_RANK"])
  52. torch.cuda.set_device(local_rank)
  53. # 准备就绪、开发分割数据。
  54. trainloader = get_dataset()
  55. # 分发模型
  56. model = ToyModel().to(local_rank)
  57. # load模型数据要在构造DDP模型之前,且只需要在master上加载就行了。
  58. ckpt_path = None
  59. if dist.get_rank() == 0 and ckpt_path is not None:
  60. model.load_state_dict(torch.load(ckpt_path))
  61. # DDP: 构造DDP model
  62. model = DDP(model, device_ids=[local_rank], output_device=local_rank)
  63. # DDP: 要在构造DDP model之后,才能用model初始化optimizer。
  64. optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
  65. # loss分发
  66. loss_func = nn.CrossEntropyLoss().to(local_rank)
  67. model.train()
  68. iterator = tqdm(range(100))
  69. for epoch in iterator:
  70. # DDP:设置sampler的epoch,
  71. # DistributedSampler需要这个来指定shuffle方式,
  72. # 通过维持各个进程之间的相同随机数种子使不同进程能获得同样的shuffle效果。
  73. trainloader.sampler.set_epoch(epoch)
  74. # 后面这部分,则与原来完全一致了。
  75. for data, label in trainloader:
  76. data, label = data.to(local_rank), label.to(local_rank)
  77. optimizer.zero_grad()
  78. prediction = model(data)
  79. loss = loss_func(prediction, label)
  80. loss.backward()
  81. iterator.desc = "loss = %0.3f" % loss
  82. optimizer.step()
  83. # DDP:
  84. # 1. save模型的时候,和DP模式一样,有一个需要注意的点:保存的是model.module而不是model。
  85. # 因为model其实是DDP model,参数是被`model=DDP(model)`包起来的。
  86. # 2. 只需要在进程0上保存一次就行了,避免多次保存重复的东西。
  87. if dist.get_rank() == 0:
  88. torch.save(model.module.state_dict(), "%d.ckpt" % epoch)
  89. # 多机环境下 $PORT需要一致。 此处可以自行实现分发程序、指定端口号。
  90. CUDA_VISIBLE_DEVICES="2,3" torchrun --nnodes=2 --nproc-per-node=2 --max-restarts=3 --rdzv-id=777 --rdzv-backend=c10d --rdzv-endpoint=localhost:8777 main.py
  91. CUDA_VISIBLE_DEVICES="0,1" torchrun --nnodes=2 --nproc-per-node=2 --max-restarts=3 --rdzv-id=777 --rdzv-backend=c10d --rdzv-endpoint=36.138.4.117:8777 main.py

CUDA_VISIBLE_DEVICES="2,3" python -m torch.distributed.launch --nnodes 2 --node_rank 1 --nproc_per_node 2 --master_addr 36.138.4.117 --master_port 8777 main.py


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注