DataParallel训练报错Expected all tensors to be on the same devices

项目场景:

在使用DataParallel进行多GPU分布式训练时显示数据不在同一GPU上


问题描述

在搭建模型的过程中同时使用了DataParallel,将模型副本同步到多个GPU上,训练数据已用.cuda(non_blocking=True)处理,但是还是报错

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:1 and cuda:0! 
(when checking argument for argument weight in method wrapper__cudnn_convolution)

原因分析:

参考链接: https://github.com/pytorch/pytorch/issues/3174
参考链接: https://zhuanlan.zhihu.com/p/560322701

定位错误后发现Linear的weight和bias始终在 cuda:0 上面,数据并行在cuda:0cuda:1上面,说明Linear没有被Dataparallel()函数拷贝。

查找原因后发现Dataparallel()会产生多个模型副本在不同的 GPU 上进行训练。但是它的__dict__s 只是浅拷贝。因此,它们的sub_i模块在不同的 GPU 上会有所不同,但self.subs会相同,并且始终指向 GPU0 上带有模块的列表。

因此,本文所使用的python的list定义的模块,即使使用add_module()手动注册了模块,但是仍旧不会被Dataparallel()所识别,定义的模块一直在GPU0上。


解决方案:

使用nn.ModuleList()或nn.Sequential()代替python的list。


补充:

1.链接: add_module函数的作用
2.链接: Pytorch中nn.ModuleList和nn.Sequential的用法和区别

3.如果使用python的list定义模块不进行add_module注册,如下代码所示,modlist中的卷积层和它们的 parameters 没有注册到网络中。
虽然可以使用 forward 来计算模型输出。但在训练时因为parameters不在网络中,所以其网络参数也不会被更新,也就是无法训练。

class net_modlist(nn.Module):
    def __init__(self):
        super(net_modlist, self).__init__()
        self.modlist = [
                       nn.Conv2d(1, 20, 5),
                       nn.ReLU(),
                        nn.Conv2d(20, 64, 5),
                        nn.ReLU()
                        ]
 
    def forward(self, x):
        for m in self.modlist:
            x = m(x)
        return x
 
net_modlist = net_modlist()
print(net_modlist)
#net_modlist()
for param in net_modlist.parameters():
    print(type(param.data), param.size())
#None
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值