当模型包含张量运算时,Pytorch DataParallel 不起作用

Rav*_*euk 4 python-3.x pytorch

如果我的模型仅包含nn.DataParallelnn.Module等层nn.Linear,则 nn.DataParallel 工作正常。

x = torch.randn(100,10)

class normal_model(torch.nn.Module):
    def __init__(self):
        super(normal_model, self).__init__()
        self.layer = torch.nn.Linear(10,1)

    def forward(self, x):
        return self.layer(x)

model = normal_model()
model = nn.DataParallel(model.to('cuda:0'))
model(x)
Run Code Online (Sandbox Code Playgroud)

但是,当我的模型包含如下张量运算时

class custom_model(torch.nn.Module):
    def __init__(self):
        super(custom_model, self).__init__()
        self.layer = torch.nn.Linear(10,5)
        self.weight = torch.ones(5,1, device='cuda:0')
    def forward(self, x):
        return self.layer(x) @ self.weight

model = custom_model()
model = torch.nn.DataParallel(model.to('cuda:0'))
model(x) 
Run Code Online (Sandbox Code Playgroud)

它给了我以下错误

RuntimeError:在设备 1 上的副本 1 中捕获 RuntimeError。原始回溯(最近一次调用最后):文件“/opt/conda/lib/python3.6/site-packages/torch/nn/parallel/parallel_apply.py”,第 60 行,在 _worker 输出 = module(*input, **kwargs) 文件“/opt/conda/lib/python3.6/site-packages/torch/nn/modules/module.py”中,第 541 行,在调用 结果 = self 中.forward(*input, **kwargs) 文件“”,第 7 行,向前返回 self.layer(x) @ self.weight RuntimeError:参数位于不同的 GPU 上 /pytorch/aten/src/THC/generic/ THCTensorMathBlas.cu:277

当我们的模型中有一些张量运算时,如何避免这个错误?

Elg*_*oot 5

我没有经验DataParallel,但我认为这可能是因为你的张量不是模型参数的一部分。您可以通过编写以下内容来做到这一点:

torch.nn.Parameter(torch.ones(5,1))

请注意,初始化时不必将其移动到 GPU,因为现在调用时model.to('cuda:0')会自动完成。

我可以想象DataParallel使用模型参数将它们移动到适当的 GPU。

有关火炬张量和 之间的区别的更多信息,请参阅此答案torch.nn.Parameter

如果您不希望在训练期间通过反向传播更新张量值,可以添加requires_grad=False.

另一种可能有效的方法是重写该to方法,并在前向传递中初始化张量:

class custom_model(torch.nn.Module):
    def __init__(self):
        super(custom_model, self).__init__()
        self.layer = torch.nn.Linear(10,5)
    def forward(self, x):
        return self.layer(x) @ torch.ones(5,1, device=self.device)
    def to(self, device: str):
        new_self = super(custom_model, self).to(device)
        new_self.device = device
        return new_self
Run Code Online (Sandbox Code Playgroud)

或类似的东西:

class custom_model(torch.nn.Module):
    def __init__(self, device:str):
        super(custom_model, self).__init__()
        self.layer = torch.nn.Linear(10,5)
        self.weight = torch.ones(5,1, device=device)
    def forward(self, x):
        return self.layer(x) @ self.weight
    def to(self, device: str):
        new_self = super(custom_model, self).to(device)
        new_self.device = device
        new_self.weight = torch.ones(5,1, device=device)
        return new_self
Run Code Online (Sandbox Code Playgroud)