【问题标题】:Train a single pytorch model on multiple GPUs with some layers fixed?在多个 GPU 上训练单个 pytorch 模型并修复某些层?
【发布时间】:2020-03-26 19:43:31
【问题描述】:

我在使用 pytorch DistributedDataParallel 时遇到了一些问题。情况是:

  1. 我的模型是 A,它像往常一样在 单个 GPU 上进行了训练。假设A中有三层:

    class A(nn.module):
        def __init__(self):
            super(A,self).__init__()
            self.layer0 = layer0
            self.layer1 = layer1
            self.layer2 = layer2
    
        def forward(self,x):
            x=self.layer0(x)
            x=self.layer1(x)
            x=self.layer2(x)
            return x
    
  2. 现在我有了一些新数据。我想在多个 GPU 上微调 A。我需要将 A 包装为多 GPU 模型 B

  3. 但是有两个训练阶段。在第一阶段,我想修复layer0layer1B。在第二阶段,只修复layer0。那么layer1中的参数requires_grad应该在训练期间改变。但是,DistributedDataParalleldoc 说:

    您应该切勿在使用 DistributedDataParallel 封装模型后尝试更改模型的参数。

实际上,我尝试使用B.module 来引用包裹在B 中的A。但与单GPU模型相比,测试结果异常。也许这种方式是不允许的。

我该怎么办?有什么合适的方法来包装我的模型吗?保存和加载模型需要注意什么?

只需在具有多个 GPU 的单台机器上运行它,这样您就可以忽略使用多台机器的分布式情况。非常感谢。

2019.12.03 更新

按照@jodag 的建议,我尝试了DataParallel,但没有成功。这次我在包裹之后没有改变 B 中的任何东西(除了训练它)。为简单起见,我的代码是这样的(我引用了this):

class B(nn.DataParallel):
     def __getattr__(self, name):
        try:
            return super().__getattr__(name)
        except AttributeError:
            return getattr(self.module, name)
a = A()
b = B(a,device_ids=[0,1])
b = b.cuda()
trained_param = b.layer2.parameters()
# trained_param = [{'params':b.layer2.parameters()},{'params':b.layer1.parameters()}]
optimizer = optim.Adam(trained_param)
b.train()
...
for x, label in data_loader:
    optimizer.zero_grad()
    x = x.to(0) # This line can be commented.
    y = b(x)
    l = loss(y, label)
    l.backword()
    optimizer.step()


【问题讨论】:

  • DistributedDataParallel 在这里不是绝对必要的。您可以尝试将模型包装在 DataParallel 中,这会将模型分发到机器上的所有本地 GPU。
  • @jodag 谢谢。我试过了,不幸的是它表现得一样。查看更新。
  • 我关闭了这个问题,因为可能有其他原因导致它。我必须用我的代码调试它。这里提供的信息可能不足以解决问题。

标签: python machine-learning parallel-processing gpu pytorch


【解决方案1】:

如果您只尝试优化部分参数,为什么不尝试通过优化器而不是模型来控制它?
您可以将模型保持原样(包装在 DistributedDataParallel 中)并仅将其部分参数传递给相关的优化器。

【讨论】:

  • 是的,我试过了。首先,我在 A 的 layer1 和 layer2 中设置了requires_grad=True。然后它被包装为 B。在第一阶段,我将B.module.layer2.parameters() 传递给优化器。在第二阶段,我也通过了B.module.layer1.parameters()。我已经检查过优化器可以更改每个 GPU 中的权重并且它们是同步的。但如上所述,除了在单 GPU 上训练之外,结果比相同配置差得多。所以我请求帮助,什么是正确的实现。
  • @Kani 你能在不干涉required_grad的情况下做同样的事情吗?
  • 我尝试切换到DataParallel,但在包装后不更改required_grad,但不幸的是它的行为相同。查看更新。
  • @Kani 您期望的行为是什么,发生了什么让您认为它行为不端?
  • @jodag 当我使用单个 GPU 时,训练集的损失像往常一样下降,而测试集的精度在我的二分类任务中逐渐提高到 83%。当我使用两个 GPU 时,测试集上的输出都给出了相同的类标签(标签 0)。我检查了 label0 的输出分数总是大于 label1。但我没有改变批量大小或学习率或任何东西。它只是将数据从一个 GPU 移动到两个 GPU。我觉得结果应该差不多吧?
猜你喜欢
  • 2018-04-02
  • 2017-11-30
  • 2019-09-01
  • 2021-03-08
  • 2020-11-29
  • 2018-03-28
  • 1970-01-01
  • 2020-11-27
  • 1970-01-01
相关资源
最近更新 更多