Pytorch多GPU并行计算

  • 当batch_size设置较大时,单个GPU的显存容易占满耗尽,导致Memeror。而较小的batch_size导致需要每个epoch需要迭代训练更多次,造成效率低下。因此可以考虑采用多个GPU并行计算的方式训练模型(但一般batch_size也不宜过大,训练的时候随机性很重要,极端的情况是batch_size=whole_dataset,训练效果可能不容易收敛且、模型不鲁棒)。一般有两种方法,一是多个GPU并行计算(DataParallel),比较简单,常规易用(但是因为loss等操作是将各副卡的推理结果汇总之后在主卡计算的,因此容易出现主GPU利用率比其他副GPU更高的情况,也就是负载不平衡现象),这种方式也稍微慢些(比分布式计算,多级多卡,或者单机多卡也可以用);二是多台机器分布式计算(DistributedDataParallel),速度相对前者更快,也不会出现负载不均衡现象,但是比前者配置起来要麻烦很多。

  • 处理机制
    多卡并行机制:首先是将模型加载到主GPU,然后将模型复制到其他指定的GPU,接着把输入数据按batch维度划分给各个GPU去计算(batch_size_per_gpu=total_batch_size / num_gpu),各个GPU上的模型和数据独立进行前向推理计算,得到结果(loss)后汇总到主gpu上反向传播更新模型权重,再将主GPU模型更新复制到其他GPU上,over。
    分布式计算有时间学到再补充。

  • 具体实现细节
    单机多卡-并行计算

    # torch.cuda.set_device(origin_device) # 设置.cuda()时默认使用的gpu_id
    os.environ["CUDA_VISIBLE_DEVICS"] = "0,1,2,..."
    # ...
    # set model parallel
    model = torch.nn.DataParallel(model).cuda()
    # dataset...
    dataloader = torch.utils.data.DataLoader(dataset, batch_size=bs_per_gpu * num_gpu, **kwargs)
    # 后面的基本不用任何改动
    

    多机多卡或者单机多卡-分布式计算
    DistributedDataParallel

  • 其他参考--Pytorch--
    1.什么情况下应该设置 cudnn.benchmark = True
    2.pytorch学习笔记:pytorch多gpu并行训练
    3.torch.backends.cudnn.benchmark ?!
    4.利用随机数种子来使pytorch中的结果可以复现
    5.DataParallel与DistributedDataParallel

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在机器学习和深度学习领域中,PyTorch已成为众多数据科学家、研究人员和开发人员的首选框架。PyTorch具有交互式和动态图形特性,因此易于使用和调试。一方面,PyTorch也支持多GPU并行运算,可以加速训练过程并提升深度学习模型的效率与精度。 下面将介绍一些pytorchGPU并行的案例: 1. 使用nn.DataParallel nn.DataParallel是pytorch提供的一种简单的方式,用于在多个GPU上进行模型训练。该方法适用于需要在单个GPU上加载并训练大型模型的情景。 这里提供一个范例:利用ResNet模型对CIFAR-10数据集进行分类。可以通过以下代码来实现多GPU并行训练。 ``` import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import torchvision from torchvision import datasets, models, transforms import time import os import copy device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") if not os.path.isdir('data'): os.mkdir('data') data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } data_dir = 'data/cifar10' image_datasets = {x: datasets.CIFAR10(data_dir, train=(x == 'train'), download=True, transform=data_transforms[x]) for x in ['train', 'val']} dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=32, shuffle=True, num_workers=4) for x in ['train', 'val']} dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes def train_model(model, criterion, optimizer, scheduler, num_epochs=25): since = time.time() best_model_wts = copy.deepcopy(model.state_dict()) best_acc = 0.0 for epoch in range(num_epochs): print('Epoch {}/{}'.format(epoch, num_epochs - 1)) print('-' * 10) for phase in ['train', 'val']: if phase == 'train': model.train() # Set model to training mode else: model.eval() # Set model to evaluate mode running_loss = 0.0 running_corrects = 0 for inputs, labels in dataloaders[phase]: inputs = inputs.to(device) labels = labels.to(device) optimizer.zero_grad() with torch.set_grad_enabled(phase == 'train'): outputs = model(inputs) _, preds = torch.max(outputs, 1) loss = criterion(outputs, labels) if phase == 'train': loss.backward() optimizer.step() running_loss += loss.item() * inputs.size(0) running_corrects += torch.sum(preds == labels.data) if phase == 'train': scheduler.step() epoch_loss = running_loss / dataset_sizes[phase] epoch_acc = running_corrects.double() / dataset_sizes[phase] print('{} Loss: {:.4f} Acc: {:.4f}'.format( phase, epoch_loss, epoch_acc)) if phase == 'val' and epoch_acc > best_acc: best_acc = epoch_acc best_model_wts = copy.deepcopy(model.state_dict()) print() time_elapsed = time.time() - since print('Training complete in {:.0f}m {:.0f}s'.format( time_elapsed // 60, time_elapsed % 60)) print('Best val Acc: {:4f}'.format(best_acc)) model.load_state_dict(best_model_wts) return model model_ft = models.resnet18(pretrained=True) num_ftrs = model_ft.fc.in_features model_ft.fc = nn.Linear(num_ftrs, 10) model_ft = model_ft.to(device) criterion = nn.CrossEntropyLoss() optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9) exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1) model_ft = nn.DataParallel(model_ft) model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=25) ``` 2. 使用nn.parallel.DistributedDataParallel 如果我们希望加快模型训练的速度,那么就可以考虑使用nn.parallel.DistributedDataParallel。这个工具允许我们在多个GPU上宏观地将模型分发,从而更高效地进行深度学习。 使用DistributedDataParallel进行多GPU并行的方法如下: (1)启动多个进程 首先,我们需要启动多个进程。代码如下所示: ``` python3 -m torch.distributed.launch --nproc_per_node=2 train.py --dist-url='tcp://127.0.0.1:8000' --world-size=2 ``` 这就会以两个进程启动主脚本。这两个进程实际上对应两个GPU,它们之间会进行通信。 (2)编写代码 在主脚本中,需要如下所示编写代码: ``` import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import os import copy import torch.distributed as dist import torch.multiprocessing as mp from torch.nn.parallel import DistributedDataParallel as DDP def setup(rank, world_size): os.environ['MASTER_ADDR'] = 'localhost' os.environ['MASTER_PORT'] = '8000' # initialize the process group dist.init_process_group("nccl", rank=rank, world_size=world_size) def cleanup(): dist.destroy_process_group() class MyModel(nn.Module): def __init__(self): super(MyModel, self).__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 5 * 5) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x def train(rank, world_size): setup(rank, world_size) model = MyModel() model = DDP(model.to(rank)) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9) exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1) train_loader = get_data_loader(num_replicas=world_size, rank=rank) for epoch in range(25): for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data.to(rank)) loss = criterion(output, target.to(rank)) loss.backward() optimizer.step() cleanup() if __name__ == '__main__': mp.spawn(train, args=(2, 2), nprocs=2, join=True) ``` 其中,setup()函数启动了进程组,并使所有进程可以互相通信。cleanup()函数在训练完之后关闭进程组。 ```MyModel```代表了一个简单的卷积神经网络,通过DistributedDataParallel方法进行多GPU负载均衡,可以将训练速度加快至少两倍。 总结起来,PyTorch的多GPU并行训练的方法较为灵活,可根据实际需求选择适用的方法。无论是使用nn.DataParallel还是nn.parallel.DistributedDataParallel,都能在多个GPU上加速模型训练。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值