这个问题出现的原因很多,网上也有很多的举例情况,但大部分说的是如做加法时没有设置新变量或是ReLU没有设置成inplace=False。他们所给出的方法也大多是粗暴地设置DDP的参数broadcast_buffers=False。然而,如果设置broadcast_buffers=False,你会发现训练出来的模型在eval()模式下很可能会有严重错误。
在此,我给出其中一种可能的报错根本的原因,并且能够在不设置broadcast_buffers=False的情况下从根本上完美解决报错:如果你在某一次反向传播loss.backward() 前多次调用同一模型,在DDP框架下就会报错RuntimeError: one of the variables needed for gradient computation has been modified by an inplace。
下面举个简单的例子:
a = model(input1)
b = model(input2)
loss = criterion(a, b)
loss.backward()
如上的例子中,如果你的model是使用DDP框架进行多卡训练的,并且为了正确同步模型参数你设置了broadcast_buffers=True(默认的),由于在 loss.backward() 前两次调用了该model,那么报错RuntimeError: one of the variables needed for gradient computation has been modified by an inplace是必然出现的。
也就是说,只要你只调用一次model就能够避免这一错误,那么将代码如下重构:
inputs = torch.cat([input1, input2], dim=0)
outputs = model(inputs)
a, b = torch.chunk(outputs, 2, dim=0)
loss = criterion(a, b)
loss.backward()
这样,你就只调用了一次model,就不会报错了。另外,该方法相较于之前的方法少调用了一次模型,训练效率也有大幅提升。