pytorch多GPU训练以及多线程加载数据

更正说明:

时间 2018/01/23

现在我所测试得到的dataParallel只能有效的进行前向传播,不能后向传播。下面的关于后向传播的原因我没有在代码层面进行分析,所以下面的记录部分(前面传播)是正确的。

不过可以得出的结论有:Dataparallel不支持自动的后向传播;Variable的grad_fn不能修改;Variable只有叶节点(在pytorch中计算图的倒着来的,叶节点就是初始输入节点)可以修改requires_grad属性,因此尝试从中间开始记录“计算图”的计划落空(希望不要引起误解,requires_grad属性并不是用来决定是否保留subgraph的,但有点联系;更何况网络中的参数也是叶节点,不单单是输入,比如图片);

目前就是这样,搞清楚了再来记录下来。


pytorch多GPU训练

时间2018/01/22

pytorch支持多GPU训练,官方文档(pytorch 0.30)推荐使用DataParallel。但是这儿踩了一个很大的坑。

pytorch使用gpu的踩坑记录:

按照其官方网站上的说明,把神经网络结构做成了DataParallel对象,顺利的通过了前向传播,但是在后向传播进行梯度更新的时候出先了错误。后向计算以更新梯度时,因为grad_fn在dataparallel中,所以也要将更新梯度的方法放入到dataparallel中去。但是遗憾的是DataParallel计算得到的Variable中的属性grad_fn为torch.nn.parallel._function,而普通的网络所得到的对应grad_fn为torch.autograd.function。而前者不能用于backward(),所以最直接的想法是想修改计算图,但这样一点也不简单。

关于Variable和DataParallel:

简单的一提,这能帮助理解。Variable包含的的三个相关的项是data(记录数据Tensor),grad(记录梯度,以便后向传播),grad_fn(有人称为creator)。最后一个组成了计算所用的有向图。

DataParallel是torch.nn下的一个类,需要制定的参数是module(可以多gpu运行的类函数)和input(数据集),module需要有parameter方法,input数据需要是Variable类型,默认沿着0轴(参数dim,可修改)将input分成多份。

所以,pytorch(0.2.0)的多GPU训练方法:

将net和loss 以及nn.optim统统放入到新的自定义类中。但注意,DataParallel的参数module需要有paramer方法,看源码也看不明白parameter用来干嘛,有什么作用。但是踩坑过程中,继承nn.module的类和torch.nn.optim类都可以放入dataparallel中去,所以自定义类直接继承自nn.module就好,不管了。反正整个网络的前向后向传播都是在这个dataparallel中完成的。代码如下:

class train_parallel_module(nn.Module):#自定义类,继承自nn.Module,有人研究清楚了parameter欢迎讨论下啊
    """
    the net was used for DataParallel(module)
    """

    def __init__(self, net, optimizer, loss):#三个变量,见名知意
        super(train_parallel_module, self).__init__()
        self.net = net
        self.optim = optimizer
        self.loss = loss

    def forward(self, img, gt_heatmap):#img和gt_heatmap将沿着0轴分成等份。
        predicted = self.net(img)#前向传播
        l = self.loss(gt_heatmap, predicted)#loss计算

        # compute gradient and do SGD step
        self.optim.zero_grad()  # 后向传播
        l.backward()
        self.optim.step()  
        return l #结果返回,用于打印迭代的loss

调用时的代码:

# module for DataParallel
module = train_parallel_module(net, optimizer, loss)
module_parallel = nn.DataParallel(module, device_ids=device_ids)

imgs = Variable(imgs, requires_grad=True).cuda(device_ids[0])  # device_ids[0]
gt_heatmaps = Variable(gt_heatmaps).cuda(device_ids[0])
l = module_parallel(imgs, gt_heatmaps) # 在这儿调用
print 'loss is: {:.3f},and iter is {} with time {}'. \
    format(l.data[0], batch_iteration, time.time() - t)
既然说到了GPU,顺便说一下加载数据时的多进程吧:
data_loader = data.DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=6,
                                  pin_memory=True, drop_last=True, collate_fn=patch_data) #num_workers就是使用多进程
顺便记录下遇到的奇怪问题:

使用预训练的VGG网络,我需要再原有的结构上新增一个skip connection结构,我的skip结构conv4_3 feature map上运算会出现in_place原地操作错误,导致backward时候出错。而使用接下来的一层ReLu的skip结构则没有这种error出现。





  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
首先,需要使用`multiprocessing`库中的`Pool`类来创建一个多进程池。然后,可以使用`Pool`的`apply_async`方法来异步执行函数,将不同的模型加载到不同的GPU上。 具体实现步骤如下: 1. 导入必要的库和模块: ```python import torch from multiprocessing import Pool ``` 2. 定义一个加载模型的函数: ```python def load_model(model_path, device): # 加载模型 model = torch.load(model_path) # 将模型移动到指定的设备 model.to(device) return model ``` 3. 创建一个多进程池: ```python pool = Pool(processes=2) # 创建一个包含2个进程的进程池 ``` 4. 使用`apply_async`方法异步执行函数,将不同的模型加载到不同的GPU上: ```python model_path_1 = 'model_1.pth' model_path_2 = 'model_2.pth' result_1 = pool.apply_async(load_model, args=(model_path_1, 'cuda:0')) result_2 = pool.apply_async(load_model, args=(model_path_2, 'cuda:1')) model_1 = result_1.get() model_2 = result_2.get() # 加载完成后,可以关闭进程池 pool.close() pool.join() ``` 在上面的代码中,我们创建了一个进程池,其中包含了2个进程。接着,使用`apply_async`方法异步执行函数`load_model`,将不同的模型加载到不同的GPU上。这里我们假设有两个模型,分别为`model_1.pth`和`model_2.pth`,并且要将它们分别加载到`cuda:0`和`cuda:1`设备上。`apply_async`方法会立即返回一个`AsyncResult`对象,表示异步执行的结果。我们可以使用`get`方法来获取结果,这个方法会阻塞当前进程,直到异步执行的结果返回。最后,记得关闭进程池。 注意,如果要使用多个GPU,需要使用`torch.nn.DataParallel`或`torch.nn.parallel.DistributedDataParallel`来实现模型的并行运算。具体实现方式可以参考PyTorch官方文档。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值