【问题标题】:Pytorch - why does preallocating memory cause "trying to backward through the graph a second time"Pytorch - 为什么预分配内存会导致“试图第二次向后遍历图形”
【发布时间】:2019-03-20 19:24:36
【问题描述】:

假设我有一个简单的单层网络,我正在以典型方式进行训练:

    for x,y in trainData:
        optimizer.zero_grad()
        out = self(x)
        loss = self.lossfn(out, y)
        loss.backward()
        optimizer.step() 

这按预期工作,但如果我改为预先分配和更新输出数组,我会收到错误:

    out = torch.empty_like(trainData.tensors[1])
    for i,(x,y) in enumerate(trainData):
        optimizer.zero_grad()
        out[i] = self(x)
        loss = self.lossfn(out[i], y)
        loss.backward()
        optimizer.step()  

RuntimeError: 试图第二次向后遍历图形,但是 缓冲区已被释放。指定retain_graph=True 时 第一次向后调用。

在第二个版本中,Pytorch 再次尝试向后遍历图表是怎么回事?为什么这在第一个版本中不是问题? (注意即使我不zero_grad()也会出现这个错误)

【问题讨论】:

    标签: pytorch backpropagation tensor autograd autodiff


    【解决方案1】:

    该错误意味着程序正在尝试通过一组操作第二次反向传播。第一次通过一组操作进行反向传播时,pytorch 会删除计算图以释放内存。因此,您第二次尝试反向传播失败,因为该图已被删除。

    Here's详解同理。

    简答

    使用loss.backward(retain_graph=True)。这不会删除计算图。

    详细解答

    在第一个版本中,在每次循环迭代中,每次运行out = self(x) 都会生成一个新的计算图。

    Every loop's graph
    out = self(x) -> loss = self.lossfn(out, y)
    

    在第二个版本中,由于out被声明在循环之外,每个循环中的计算图都有一个父节点。

               - out[i] = self(x) -> loss = self.lossfn(out[i], y) 
    out[i] - | - out[i] = self(x) -> loss = self.lossfn(out[i], y) 
               - out[i] = self(x) -> loss = self.lossfn(out[i], y)
    

    因此,这是发生的时间线。

    1. 第一次迭代运行
    2. 计算图被删除,包括父节点
    3. 第二次迭代尝试反向传播,但由于找不到父节点而失败

    【讨论】:

      猜你喜欢
      • 2021-03-11
      • 2020-11-07
      • 2021-11-18
      • 1970-01-01
      • 2020-10-06
      • 2021-11-19
      • 2023-02-26
      • 2020-07-15
      • 1970-01-01
      相关资源
      最近更新 更多