pytorch - Pytorch - 为什么预分配内存会导致“尝试第二次向后遍历图形”
问题描述
假设我有一个简单的单层网络,我正在以典型的方式进行训练:
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 会删除计算图以释放内存。因此,您第二次尝试反向传播它会失败,因为该图已被删除。
这是相同的详细说明。
简短的回答
使用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)
因此,这是发生的时间线。
- 第一次迭代运行
- 计算图被删除,包括父节点
- 第二次迭代尝试反向传播但失败,因为它没有找到父节点
推荐阅读
- nestjs - 我应该使用哪一层来分解资源的存在性检查?
- sql - 如何在删除行后更新“行号”列值 1..N?
- javascript - 如何在 tinyMCE 5.0.11 版中设置每行的最大字符数?
- java - Spring Security - 403 禁止除 ROLE_USER 之外的每个角色
- python - ModuleNotFoundError:没有模块名称'src'
- python - 用于训练“分类输入”到“分类输出”模型的损失函数和数据格式?
- android - setOnClickListener 未按预期工作
- java - Android 从 DateTime 中删除偏移量/时区
- bash - Bash - 正确清除最后一个输出
- reactjs - 在 Reactjs 中为电子邮件编写验证