欢迎访问宙启技术站
智能推送

PyTorch分布式数据并行:从torch.nn.parallel到torch.nn.DataParallel

发布时间:2023-12-23 05:32:47

在深度学习中,神经网络的训练往往需要大量的数据和计算资源。为了加速训练过程,提高模型的性能,可以使用分布式数据并行技术。PyTorch提供了两种主要的分布式数据并行方案:torch.nn.parallel和torch.nn.DataParallel。

torch.nn.parallel是一个底层的API,可以灵活地实现自定义的分布式数据并行策略。它允许用户对不同的模型、算法进行更加细粒度的控制。然而,使用torch.nn.parallel需要用户自行管理模型的复制、数据的划分和通信等细节,相对较为复杂。

torch.nn.DataParallel是一个高级封装的API,它能够自动将模型和数据划分到多个GPU上进行并行计算,用户只需要简单地将模型放到DataParallel中即可。DataParallel会自动管理模型的复制、数据的划分和通信等细节,大大简化了分布式数据并行的使用。

下面我们以一个简单的卷积神经网络为例,演示如何使用torch.nn.parallel和torch.nn.DataParallel实现分布式数据并行。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler
from torchvision import datasets, transforms

# 定义模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv = nn.Conv2d(1, 10, kernel_size=5)
        self.fc = nn.Linear(1440, 10)

    def forward(self, x):
        x = self.conv(x)
        x = x.view(-1, 1440)
        x = self.fc(x)
        return x

# 初始化分布式数据并行
def init_ddp(rank, world_size):
    # 初始化进程组
    torch.distributed.init_process_group(backend='nccl', init_method='env://')
    # 初始化GPU设备
    torch.cuda.set_device(rank)
    # 设置随机种子
    torch.manual_seed(0)

# 训练函数
def train(model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = nn.functional.cross_entropy(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 10 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))

# 主函数
def main():
    # 初始化分布式数据并行
    init_ddp(rank=0, world_size=1)
    # 设置设备
    device = torch.device("cuda")
    # 加载数据
    train_dataset = datasets.MNIST('../data', train=True, download=True,
                                   transform=transforms.Compose([
                                       transforms.ToTensor(),
                                       transforms.Normalize((0.1307,), (0.3081,))
                                   ]))
    # 分布式采样
    train_sampler = DistributedSampler(train_dataset)
    # 构建数据加载器
    train_loader = torch.utils.data.DataLoader(
        train_dataset, batch_size=64, sampler=train_sampler)
    # 初始化模型
    model = Net().to(device)
    # 初始化优化器
    optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
    # 将模型放入分布式数据并行
    model = DDP(model)
    # 训练模型
    for epoch in range(1, 3):
        train(model, device, train_loader, optimizer, epoch)

if __name__ == '__main__':
    main()

上述代码中,首先定义了一个简单的卷积神经网络模型Net,并实现了一个训练函数train。然后,在主函数中,首先调用init_ddp函数初始化分布式数据并行,然后设置设备,加载数据,并分布式采样。接着初始化模型和优化器,将模型放入DataParallel中,最后调用train函数训练模型。

在使用torch.nn.parallel时,需要手动管理模型的复制、数据的划分和通信等细节,相对较为复杂。而torch.nn.DataParallel则更加简洁,只需要将模型放入DataParallel中即可自动实现分布式数据并行。在代码中,我们将Net模型放入了DataParallel,这样模型就可以自动在多个GPU上进行并行计算。

总之,PyTorch提供了丰富的分布式数据并行工具,使用起来非常方便。对于大规模的深度学习任务,合理地利用分布式数据并行可以大大提升训练速度和模型的性能。