【问题标题】:RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=TrueRuntimeError: 试图第二次向后遍历图形,但缓冲区已被释放。指定retain_graph=True
【发布时间】:2020-07-15 20:23:41
【问题描述】:

我是 Python 和 PyTorch 的学生和初学者。我有一个非常基本的神经网络,我遇到了上面提到的 RunTimeError。重现错误的代码是这样的:

import torch 
from torch import nn
from torch import optim
import torch.nn.functional as F
import matplotlib.pyplot as plt

# Ensure Reproducibility
torch.manual_seed(0)

# Data Generation
x = torch.randn((100,1), requires_grad = True)
y = 1 + 2 * x + 0.3 * torch.randn(100,1)
# Shuffles the indices
idx = np.arange(100)
np.random.shuffle(idx)

# Uses first 80 random indices for train
train_idx = idx[:70]
# Uses the remaining indices for validation
val_idx = idx[70:]

# Generates train and validation sets
x_train, y_train = x[train_idx], y[train_idx]
x_val, y_val = x[val_idx], y[val_idx]

class OurFirstNeuralNetwork(nn.Module):
    def __init__(self):
        super(OurFirstNeuralNetwork, self).__init__()
        # Here we "define" our Neural Network Architecture
        self.fc1 = nn.Linear(1, 5)
        self.non_linearity_fc1 = nn.ReLU()
        self.fc2 = nn.Linear(5,1)
        #self.non_linearity_fc2 = nn.ReLU()

    def forward(self, x):
        # The forward pass
        # Here we define how activations "flow" between neurons. We've already discussed the "Sum" and "Transformation" steps of the forward pass.
        sum_fc1 = self.fc1(x)
        transformation_fc1 = self.non_linearity_fc1(sum_fc1)
        sum_fc2 = self.fc2(transformation_fc1)
        #transformation_fc2 = self.non_linearity_fc2(sum_fc2)
        # The transformation_fc2 is also the output of our model which symbolises the end of our forward pass. 
        return sum_fc2

# Instantiate the model and train

model = OurFirstNeuralNetwork()
print(model)
print(model.state_dict())
n_epochs = 1000
loss_fn = nn.MSELoss(reduction='mean')
optimizer = optim.Adam(model.parameters())

for epoch in range(n_epochs):


    model.train()
    optimizer.zero_grad()
    prediction = model(x_train)
    loss = loss_fn(y_train, prediction)
    print(epoch, loss)
    loss.backward(retain_graph=True)    
    optimizer.step()


print(model.state_dict())

一切都是基本和标准的,而且效果很好。

但是,当我取出“retain_graph=True”参数时,它会抛出 RunTimeError。通过阅读各种论坛,我了解到这与第一次迭代后图表被丢弃有关,但我看过很多教程和博客,其中loss.backward() 是要走的路,特别是因为它可以节省内存。但我无法从概念上理解为什么这对我不起作用。

如果我提出问题的方式与预期格式不符,我们将不胜感激,我深表歉意。我愿意接受反馈,并有义务提供更多细节或重新表述问题,以便每个人都更容易。提前谢谢!

【问题讨论】:

    标签: python machine-learning deep-learning pytorch


    【解决方案1】:

    您需要在optimizer.step() 之后添加optimizer.zero_grad() 以将渐变清零。

    为什么需要这样做?

    当您执行loss.backward() 时,torch 将计算参数的梯度并更新参数的.grad 属性。当您执行optimizer.step() 时,使用.grad 属性更新参数,即`parameter = parameter - lr*parameter.grad。

    由于您没有清除梯度并第二次向后调用,它将计算dl/d(updated param),这将需要通过第一遍的paramter.grad 进行反向传播。向后执行时,不会存储此梯度的计算图,因此您必须通过 retain_graph= True 才能消除错误。但是,我们不想这样做来更新参数。相反,我们想要清除梯度,并使用新的计算图重新开始,因此您需要使用 .zero_grad 调用将梯度归零。

    另见Why do we need to call zero_grad() in PyTorch?

    【讨论】:

    • 感谢您的解释,Umang 它非常棒,绝对完美,我希望这能奏效。但是,如果没有 retain_graph=True 参数,它仍然会引发完全相同的错误。如果使用 retain_graph=True,它可以正常工作。
    • 有什么特别的理由让requires_grad=True 输入x?这实际上导致了这里的问题。当您尝试在不清除渐变的情况下多次反向传播时。
    • 我将其设置为 true 因为否则 'grad_fn' 属性将不存在,但我认为这是必需的,以便 autograd 可以完成它的工作。如果我错了,请纠正我。
    • 所以.backward 将在不为输入设置 true 的情况下工作(因为您想要参数的渐变而不是输入)。如果你想让它与输入设置 grad true 一起工作,还请清除输入的渐变
    • 明白了!非常感谢您的及时回复和清晰的解释!
    猜你喜欢
    • 2020-10-06
    • 1970-01-01
    • 2018-06-24
    • 2021-11-18
    • 2021-03-11
    • 2020-11-07
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    相关资源
    最近更新 更多