本文只针对单机多GPU使用dataparallel进行加速运算。
写在前边: dataparallel只存在于继承了nn.Modules类的forward()计算中。
大致流程如下:
import torch
model = Net() #初始化模型
for i, (input_datas, label_datas) in enumerate(data_loader):
#step 1: 数据放到GPU上
input_datas = input_datas.cuda() #默认是 gpu:0
label_datas = label_data.cuda() # 默认是 gpu:0
#step 2: 模型用DataParalle封装
model = torch.nn.DataParalle(model) # 此步会把模型复制N份,N为你机器可用的GPU数
output, state = model(input_datas) # 注意此处这样写会有问题
class Net(torch.nn.Modules):
...
def forward(self, ...):
#模型计算逻辑
output, state = lstm(input, state)
return output, state
上述代码如果在单张卡上没有任何问题,但是当我们想要通过DataParallel进行加速计算,就会报错。 仔细分析,DataParallel会把模型复制N份,把输入数据平均划分为N份, 同样的在模型进行完forward计算后会返回计算结果。此时需要注意!!!因为模型是在N个GPU上分别进行计算得到结果,在最后返回的时候,会把这N个GPU的结果进行concat 然后返回,所以返回的state并不是我们想要的结果,而是N个GPU所以的state进行了concat,因此会发现维度不一致问题。 这是需要非常小心的。
如何才能正确的进行并行计算呢,直觉上 只要我们不在最终返回的时候(main函数中)返回state就可以避免这个错误了。 具体我们可以在另外一个类的forward()中调用Net()模型, 此时这两个类都通过DataParallel进行了封装,都是N份,所以其维度都是N倍, 执行完lstm后就只返回outputs就可以了。
常见问题二:
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)
此问题是因为在使用DataParallel时候 数据和参数不在一个GPU上导致的,看提示说明data分配到了gpu:1上,而参数在gpu:0上。 主要我们在 data.cuda()的时候指定合适的GPU就可以了, 比如此处data.cuda(0) 就可以了。其实data.cuda()默认就是gpu:0。
感谢苏璐岩~