假设我有一个简单的单隐藏层网络,我正在以典型的方式进行培训:
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删除计算图以释放内存。因此,第二次尝试反向传播失败,因为图形已被删除。
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)
因此,这是发生的事情的时间表。