pytorch-为什么预先分配内存会导致“尝试第二次向后浏览图形”

时间:2019-03-20 19:24:37

标签: pytorch backpropagation tensor autograd autodiff

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

    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:尝试第二次向后浏览图形,但是   缓冲区已被释放。指定keep_graph = True何时   第一次回叫。

Pytorch在第二个版本中试图再次向后浏览图形,这是怎么回事?为什么在第一个版本中这不是问题? (请注意,即使我没有zero_grad(),也会发生此错误)

1 个答案:

答案 0 :(得分:0)

该错误表示程序正在第二次尝试通过一组操作反向传播。第一次通过一组操作反向传播时,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. 第二次迭代尝试向后传播,但由于未找到父节点而失败