解决了PyTorch 使用torch.nn.DataParallel 进行多GPU训练的一个BUG:模型(参数)和数据不在相同设备上
2019-07-20 16:34
8639 查看
解决了PyTorch 使用torch.nn.DataParallel 进行多GPU训练的一个BUG:模型(参数)和数据不在相同设备上
博客地址:https://senyang-ml.github.io/2019/07/20/pytorch-multigpu/
解决了PyTorch 使用torch.nn.DataParallel 进行多GPU训练的一个BUG:
模型(参数)和数据不在相同设备上
使用torch.nn.DataParallel
进行多GPU训练时出现了一个BUG, 困扰许久:
RuntimeError: Expected tensor for argument #1 'input' to have the same device as tensor for argument #2 'weight'; but device 1 does not equal 0 (while checking arguments for cudnn_convolution)
这个错误表明,
input数据在
device 1上, 而模型的参数在
device 0上 (暗示数据是被拆分到了各个GPU上,但是BUG出现位置的此处参数可能没有成功复制到其他GPU上, 或者说, 还是调用了复制前的那个参数地址)
之前调试了好久, 也没有解决掉, 在Github上有一个issue和我的问题很像:
https://github.com/pytorch/pytorch/issues/8637
但是我还是没有找到自己的问题在哪里.
今天, 我又准备再此挑战这个难题
经过6个小时的
print调试法以及后面关键的VScode的
Debug功能, 我大功告成,找到了问题所在,原来
我的
A(nn.Module)类的
forward前向计算函数里面, 有一处调用了一个该类的列表
self.cell_fabrics, 其列表的元素是通过
self.cell_fabrics = [self.cell_1, self.cell_2,...,self.cell_n]来赋值的,其中每个
self.cell也是
nn.Module类
即用
self.cell_fabrics = [self.cell_0_0, self.cell_0_1, … , self.cell_3_0, self.cell_3_1,…, self.cell_5_0]这样的方式,将所有的
cell类放到
A类的一个
列表属性中, 而当整个
A类通过
torch.nn.DataParallel被复制了一份放到设备
cuda:1上时, 当该设备运行到下面代码段时:
def forward(self,x) for layer in self.cell_fabrics: for cell in layer: y = cell (x,)
x是在设备
cuda:1上面, 而 debug显示
cell中的参数明显都在
cuda:0上
也就是说:
此时 self.cell_fabrics
的列表中保存的各个对象 (self.cell
) 的地址,还是指向在没有进行torch.nn.DataParallel
之前的nn.module
的那些self.cell
, 而nn.DataParallel
类的nn.module
的参数都默认存放在device(type='cuda',index=0)
上 .
torch.nn.DataParallel(model,device_ids=[range(len(gpus))])的机制是, 将属于
nn.module类的
model以及其广播的所有
nn.module子类的上的所有参数,复制成
len(gpus)份,送到各个GPU上. 这种传播必须通过其子类通过注册(register)成为
nn.module的属性才得以完成, 其属性为列表中的元素是不会被复制的, 所以其属性中的元素还是存放在默认设备
device 0上
所以 在使用
torch.nn.DataParallel进行多GPU训练的时候, 请注意:所有属于模型参数的模块以及其子模块必须以
nn.Module的类型注册为模型的属性, 如果需要一个列表来批量存放子模块或者参数时, 请采用
nn.ModuleList或者
nn.ModuleDict这样的继承了
nn.Module的类来进行定义, 并且在
forward(self,)前向传播的过程中,需要直接调用属于
nn.Module,
nn.ModuleList或者
nn.ModuleDict这样的属性。
那么
torch.nn.DataParallel将会正常地将模型参数准确复制到多个GPU上, 并默认根据数据的
batchsize的大小平分成GPU的数量分别送到相应的GPU设备上,
运用多线程的方式, 同时对这些数据进行加工处理, 然后收集各个GPU上最终产生对模型的参数的梯度, 汇总到一起更新原模型的参数!
参考:
相关文章推荐
- TensorFlow学习实践(二):使用TFRecord格式数据和tf.data API进行模型训练和预测
- 解决pytorch中DataParallel后模型参数出现问题的方法
- 简单数据预测—使用Python训练回归模型并进行预测(转自蓝鲸网站分析博客)
- TensorFlow学习实践(三):使用TFRecord格式数据和tf.estimator API进行模型训练和预测
- 关于使用PyTorch设置多线程(threads)进行数据读取而导致GPU显存始终不释放的问题
- PyTorch使用cpu调用gpu训练的模型
- Linux 2.4.18的内核在使用S3C2410板的USB设备时碰到的一个Bug的解决办法
- 使用三种继承回归模型对美国波士顿房价训练数据进行学习,并对测试数据进行预测
- tensorflow-gpu 和cpu使用训练ssd模型感想(显卡内存不足解决办法)
- Caffe使用step by step:使用自己数据对已经训练好的模型进行finetuning
- PyTorch中使用预训练的模型初始化网络的一部分参数
- Caffe使用step by step:使用自己数据对已经训练好的模型进行finetuning
- tensorflow保存网络参数 使用训练好的网络参数进行数据的预测
- TensorFlow学习实践(一):使用TFRecord格式数据和队列进行模型训练和预测
- Ubuntu16.04下使用Pytorch+detectron的训练模型,进行图片的检测标框主要使用infer_simple.py
- TensorFlow学习实践(四):使用TFRecord格式数据和tf.contrib.slim API进行模型训练和预测
- 【神经网络与深度学习】Caffe使用step by step:使用自己数据对已经训练好的模型进行finetuning
- 使用keras框架训练一个简单的深度学习模型——(一)线性模型解决分类问题
- 使用 Pentaho data-integration (Kettle) 进行数据转换出现中文乱码时的解决办法
- 【Asp.Net从零开始】:使用LinqToData与QueryExtender对数据进行筛选性输出