codecamp

PyTorch 分布式数据并行入门

在深度学习模型的训练过程中,数据并行是一种常见的加速训练的方法。PyTorch 提供了 DistributedDataParallel(DDP)模块,用于实现高效的多 GPU 分布式训练。DDP 通过使用 torch.distributed 包中的通信集合来同步梯度、参数和缓冲区,支持在单机或跨多机的多进程环境中进行训练。本文将带您深入了解 PyTorch 分布式数据并行的基本概念、实现方法和优化技巧,帮助您高效地利用多 GPU 资源加速模型训练。

一、DDP 与 DataParallel 的比较

DDP 与 DataParallel 相比具有显著的优势:

  1. 模型并行支持 :DDP 可与模型并行结合使用,而 DataParallel 不支持。当模型规模过大无法放入单个 GPU 时,DDP 能更好地处理这种情况。
  2. 多进程支持DataParallel 是单进程多线程,仅限单机;DDP 是多进程,支持单机多 GPU 和多机多 GPU 训练,训练速度更快。
  3. 性能优化 :DDP 预先复制模型,避免了每次迭代的模型复制和全局解释器锁定,性能更优。

二、DDP 基本用法

(一)环境设置

在使用 DDP 之前,需要正确设置分布式环境。以下代码展示了如何初始化和清理进程组:

import os
import torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optim
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'] = '12355'
    dist.init_process_group("gloo", rank=rank, world_size=world_size)
    torch.manual_seed(42)


def cleanup():
    dist.destroy_process_group()

(二)定义模型并封装 DDP

将定义好的模型封装到 DDP 中,以实现分布式训练:

class ToyModel(nn.Module):
    def __init__(self):
        super(ToyModel, self).__init__()
        self.net1 = nn.Linear(10, 10)
        self.relu = nn.ReLU()
        self.net2 = nn.Linear(10, 5)


    def forward(self, x):
        return self.net2(self.relu(self.net1(x)))


def demo_basic(rank, world_size):
    setup(rank, world_size)
    n = torch.cuda.device_count() // world_size
    device_ids = list(range(rank * n, (rank + 1) * n))
    model = ToyModel().to(device_ids[0])
    ddp_model = DDP(model, device_ids=device_ids)
    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
    optimizer.zero_grad()
    outputs = ddp_model(torch.randn(20, 10))
    labels = torch.randn(20, 5).to(device_ids[0])
    loss_fn(outputs, labels).backward()
    optimizer.step()
    cleanup()


def run_demo(demo_fn, world_size):
    mp.spawn(demo_fn, args=(world_size,), nprocs=world_size, join=True)

三、保存和加载检查点

在分布式训练中,检查点的保存和加载可以提高训练的可靠性和恢复能力。DDP 提供了优化的方法来保存和加载模型:

import tempfile


def demo_checkpoint(rank, world_size):
    setup(rank, world_size)
    n = torch.cuda.device_count() // world_size
    device_ids = list(range(rank * n, (rank + 1) * n))
    model = ToyModel().to(device_ids[0])
    ddp_model = DDP(model, device_ids=device_ids)
    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
    CHECKPOINT_PATH = tempfile.gettempdir() + "/model.checkpoint"
    if rank == 0:
        torch.save(ddp_model.state_dict(), CHECKPOINT_PATH)
    dist.barrier()
    rank0_devices = [x - rank * len(device_ids) for x in device_ids]
    device_pairs = zip(rank0_devices, device_ids)
    map_location = {'cuda:%d' % x: 'cuda:%d' % y for x, y in device_pairs}
    ddp_model.load_state_dict(torch.load(CHECKPOINT_PATH, map_location=map_location))
    optimizer.zero_grad()
    outputs = ddp_model(torch.randn(20, 10))
    labels = torch.randn(20, 5).to(device_ids[0])
    loss_fn(outputs, labels).backward()
    optimizer.step()
    dist.barrier()
    if rank == 0:
        os.remove(CHECKPOINT_PATH)
    cleanup()

四、DDP 与模型并行结合

DDP 还可以与多 GPU 模型结合使用,以支持更大的模型和更多的数据:

class ToyMpModel(nn.Module):
    def __init__(self, dev0, dev1):
        super(ToyMpModel, self).__init__()
        self.dev0 = dev0
        self.dev1 = dev1
        self.net1 = torch.nn.Linear(10, 10).to(dev0)
        self.relu = torch.nn.ReLU()
        self.net2 = torch.nn.Linear(10, 5).to(dev1)


    def forward(self, x):
        x = x.to(self.dev0)
        x = self.relu(self.net1(x))
        x = x.to(self.dev1)
        return self.net2(x)


def demo_model_parallel(rank, world_size):
    setup(rank, world_size)
    dev0 = rank * 2
    dev1 = rank * 2 + 1
    mp_model = ToyMpModel(dev0, dev1)
    ddp_mp_model = DDP(mp_model)
    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_mp_model.parameters(), lr=0.001)
    optimizer.zero_grad()
    outputs = ddp_mp_model(torch.randn(20, 10))
    labels = torch.randn(20, 5).to(dev1)
    loss_fn(outputs, labels).backward()
    optimizer.step()
    cleanup()

五、总结与展望

本文详细介绍了 PyTorch 中分布式数据并行的基本概念、实现方法和优化技巧,包括 DDP 与 DataParallel 的比较、DDP 的基本用法、保存和加载检查点的方法,以及 DDP 与模型并行的结合使用。通过这些内容,您可以利用多 GPU 资源高效地加速深度学习模型的训练过程。未来,您可以进一步探索更复杂的分布式训练场景和优化策略,以满足更大规模模型和数据集的训练需求。编程狮将持续为您提供更多深度学习分布式训练的优质教程,助力您的技术成长之路。

PyTorch 单机模型并行最佳实践
PyTorch 用 PyTorch 编写分布式应用程序
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

Pytorch 音频

PyTorch 命名为 Tensor(实验性)

PyTorch 强化学习

PyTorch 用其他语言

PyTorch 语言绑定

PyTorch torchvision参考

PyTorch 音频参考

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }