正在反向获取Pytork的运行时错误:再次尝试反向通过图形。。。当切片张量时

2024-04-24 21:34:22 发布

您现在位置:Python中文网/ 问答频道 /正文

在运行代码片段(PyTorch 1.7.1;Python 3.8)时

import numpy as np
import torch

def batch_matrix(vector_pairs, factor=2):
    baselen = len(vector_pairs[0]) // factor
    split_batch = []

    for j in range(factor):
        for i in range(factor):
            start_j = j * baselen
            end_j = (j+1) * baselen if j != factor - 1 else None
            start_i = i * baselen
            end_i = (i+1) * baselen if i != factor - 1 else None

            mini_pairs = vector_pairs[start_j:end_j, start_i:end_i, :]
            split_batch.append(mini_pairs)
    return split_batch

def concat_matrix(vectors_):
    vectors = vectors_.clone()
    seq_len, dim_vec = vectors.shape
    project_x = vectors.repeat((1, 1, seq_len)).reshape(seq_len, seq_len, dim_vec)
    project_y = project_x.permute(1, 0, 2)
    matrix = torch.cat((project_x, project_y), dim=-1)
    matrix_ = matrix.clone()

    return matrix_

if __name__ == "__main__":
    vector_list = []
    for i in range(10):
        vector_list.append(torch.randn((5,), requires_grad=True))
    vectors = torch.stack(vector_list, dim=0)
    pmatrix = concat_matrix(vectors)

    factor = np.ceil(vectors.shape[0]/6).astype(int)
    batched_feats = batch_matrix(pmatrix, factor=factor)

    for i in batched_feats:
        i = i + 5
        print(i.shape)
        summed = torch.sum(i)
        summed.backward()

我得到的输出和错误如下:

torch.Size([5, 5, 10])
torch.Size([5, 5, 10])
Traceback (most recent call last):
  File "/home/user/PycharmProjects/project/run.py", line 43, in <module>
    summed.backward()
  File "/home/user/anaconda3/envs/diff/lib/python3.8/site-packages/torch/tensor.py", line 221, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/user/anaconda3/envs/diff/lib/python3.8/site-packages/torch/autograd/__init__.py", line 130, in backward
    Variable._execution_engine.run_backward(
RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time.

我已经阅读了关于这个问题的所有现有帖子,但我自己无法解决它。向后传递retain_graph=True()修复了提供的代码段中的问题,但是,该代码段只是大型网络的一个过于简化的版本,其中retain_graph=True将错误更改为以下内容:

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [3000, 512]], which is output 0 of TBackward, is at version 3; expected version 2 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).

我尝试设置torch.autograd.set_detect_anomaly(True)并确定失败点,但所有尝试都失败了,错误依然存在

我怀疑如果我能理解当前情况下的错误原因,那么它将帮助我在实际的代码库中解决这个错误

因此,我想理解为什么backward()batched_feats中的前两个张量有效,而对第三个张量无效?如果有人能帮助我看到已释放的中间结果的重用,我将不胜感激

非常感谢


Tags: inprojecttrueforlenbatchtorchmatrix
1条回答
网友
1楼 · 发布于 2024-04-24 21:34:22

反向传播后,叶节点的梯度存储在其Tensor.grad属性中。默认情况下,会释放非叶节点(即错误所指的中间结果)的渐变,因为PyTorch假定您不需要它们。在您的示例中,叶节点是从torch.randn()创建的vector_list中的叶节点

默认情况下,多次连续调用backward()会通过求和累积梯度(这对于递归神经网络很有用)。当现有的中间结果被释放时,这是有问题的;叶节点的梯度没有改变;对backward()的调用涉及一些与前一个对backward()的调用相同的叶节点和中间结果。这就是你面临的问题;一些张量切片引用相同的基础张量,并且在调用backward()之间没有将所有相关梯度归零,但是隐式地将中间梯度归零

如果希望通过求和在叶节点中累积梯度,只需像这样向后调用:summed.backward(retain_graph = True)

但是,如果希望独立地计算批次的梯度(而不是w.r.t.vector_list中的叶节点),则可以在每次迭代开始时分离批次。这将防止渐变通过它们传播到vector_list中的公共叶节点(即它们在自己的图中自己成为叶节点)。分离张量将禁用其渐变,因此您必须手动重新启用它们:

for i in batched_feats:
    i = i.detach()
    i.requires_grad = True
    j = i + 5
    print(j.shape)
    summed = torch.sum(j)
    summed.backward()
    print(i.grad) # Prints the gradients stored in i

这是一些数据加载器的工作方式;它们从磁盘加载数据,将其转换为张量,执行增强/其他预处理,然后分离它们,以便它们可以作为新计算图中的叶节点。如果应用程序开发人员希望计算梯度w.r.t.数据张量,则不必保存中间结果,因为数据张量已分离,因此用作叶节点

相关问题 更多 >