在一台机器上的多个GPU上训练一个神经网络的最佳实践是什么?
nn.DataParallel
与.to('cuda:0') and .to('cuda:1')
在不同GPU上放置不同层的不同选项让我有点困惑。我在Pytorch文档中看到后一种方法的日期是2017年。有标准吗?还是取决于偏好或模型类型?
方法1
class ToyModel(nn.Module):
def __init__(self):
super(ToyModel, self).__init__()
self.net1 = torch.nn.Linear(10, 10)
self.relu = torch.nn.ReLU()
self.net2 = torch.nn.Linear(10, 5)
def forward(self, x):
x = self.relu(self.net1(x))
return self.net2(x)
model = ToyModel().to('cuda')
model = nn.DataParallel(model)
方法2
class ToyModel(nn.Module):
def __init__(self):
super(ToyModel, self).__init__()
self.net1 = torch.nn.Linear(10, 10).to('cuda:0')
self.relu = torch.nn.ReLU()
self.net2 = torch.nn.Linear(10, 5).to('cuda:1')
def forward(self, x):
x = self.relu(self.net1(x.to('cuda:0')))
return self.net2(x.to('cuda:1'))
我不确定Pytorch是否有更多的方法可以在多个GPU上进行训练。这两种方法似乎都会导致我的系统冻结,这取决于我使用的模型。在Jupyter中,单元保持在[*],如果我不重新启动内核,屏幕就会冻结,我必须进行硬重置。一些关于multi-gpu的教程导致我的系统像这样挂起并冻结。
既然你说了2020和最优,答案肯定是分布式数据并行。DataParallel
的效率要低得多,只适合在2020年进行快速轻松的训练。我不认为DataParallel
接近最优。从DP到DDP的转换很痛苦,但对我来说绝对值得
截至今天,在我看来,DDP的官方教程仍然一团糟。我亲自参加了这个教程。
我将强调一些在学习过程中让我感到困惑的地方。重要的是要获得这些点,不仅要使代码运行,还要确保它正确地训练。在没有运行时错误的情况下,可能会有一些细微的错误破坏训练。
- 在DDP中,我们为每个GPU生成一个进程。如果您的代码从
main.py
开始,并且您使用2个GPU,那么假设有人将调用python main.py --local_rank=0
和python main.py --local_rank=1
来生成两个python进程 - 每个进程接收其本地列组和全局池大小。使用它们来区分流程
- 每个进程独立地初始化其
Dataset
对象。他们从自己的数据加载器中收集自己的样本。那么,我们如何确保他们不会获得相同的数据点?将DistributedSampler
传递到数据加载器 - 每个进程独立执行正向、反向和损耗计算。他们步调一致地传达梯度
- 在
nn.parallel.DistributedDataParallel
中扭曲模型。然后PyTorch会为你做(4(
如果您不能在单个GPU上适应模型的所有层,那么您可以使用模型并行(该文章描述了在单个机器上的模型并行,如您所提到的layer0.to('cuda:0')
和layer1.to('cuda:1')
(。
如果可以,那么您可以尝试并行分布数据-每个工作程序将拥有整个模型(所有层(的自己的副本,并处理每个批次中的一小部分数据。建议使用DDP而不是DP,即使您只使用一台机器。
你有一些例子可以重现你遇到的问题吗?您是否尝试过用微小的输入运行代码,并添加打印语句来查看是否取得了进展?