遇到 RuntimeError:梯度计算所需的变量之一已被就地操作修改

Posted

技术标签:

【中文标题】遇到 RuntimeError:梯度计算所需的变量之一已被就地操作修改【英文标题】:Encounter the RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation 【发布时间】:2020-01-03 03:42:34 【问题描述】:

调用 .backward() 时出现以下错误:

代码如下:

for i, j, k in zip(X, Y, Z):
    A[:, i, j] = A[:, i, j] + k

我尝试过 .clone()、torch.add() 等等。

请帮忙!

【问题讨论】:

XYZ 是什么?它们是数字列表还是张量列表?它们是涉及参数的操作的结果吗? X 和 Y 是叶张量。 Z 是前一层产生的非叶张量。 很好,X,Y 中是否有重复的索引? (例如,对 (1,1) 是否出现两次或多次?) 是的,这就是我需要总结它们的原因。例如:(3, 9, 0.5), (3, 9, 0.4) 应该导致 (3, 9, 0.9) A.shape: ([32, 300, 300]), X.shape, Y.shape: ([32, 200]) 和 Z.shape: ([32, 200, 1] )。 【参考方案1】:

在 cmets 之后,我对您想要完成的任务感到有些困惑。您提供的代码使用您在 cmets 中提供的尺寸给了我一个错误

Traceback (most recent call last):
    A[:, i, j] = A[:, i, j] + k
RuntimeError: The size of tensor a (32) must match the size of tensor b (200) at non-singleton dimension 0

但这就是我认为你想要做的,如果这是错误的,请在 cmets 中纠正我......

给定张量 XYZXYZ 的每个条目对应于坐标 (x,y) 和值 z。您想要的是在坐标 (x,y) 处将 z 添加到 A。在大多数情况下,批次维度保持独立,尽管您发布的代码中的情况尚不清楚。现在这就是我假设你想要做的。

例如,假设A 包含全零,形状为 3x4x5,X,Y 的形状为 3x3,Z 的形状为 3x3x1。对于此示例,我们假设 A 包含所有零开始,XYZ 具有以下值

X = tensor([[1, 2, 3],
            [1, 2, 3],                                
            [2, 2, 2]])                               
Y = tensor([[1, 2, 3],                                
            [1, 2, 3],                                                        
            [1, 1, 1]])             
Z = tensor([[[0.1], [0.2], [0.3]],
            [[0.4], [0.5], [0.6]],
            [[0.7], [0.8], [0.9]]])

那么我们期望A在操作后有以下值

A = tensor([[[0,   0,   0,   0,   0],                                                                                                                                                                          
             [0,   0.1, 0,   0,   0],                                                                                                                                                                      
             [0,   0,   0.2, 0,   0],                                                                                                                                                                      
             [0,   0,   0,   0.3, 0]],                                                                                                                                                                   

            [[0,   0,   0,   0,   0],                                                                                                                                                                      
             [0,   0.4, 0,   0,   0],                                                                                                                                                                      
             [0,   0,   0.5, 0,   0],                                                                                                                                                                      
             [0,   0,   0,   0.6, 0]],                                                                                                                                                                   

            [[0,   0,   0,   0,   0],                                                                                                                                                                    
             [0,   0,   0,   0,   0],                                                                                                                                                                    
             [0,   2.4, 0,   0,   0],                                                                                                                                                                    
             [0,   0,   0,   0,   0]]])

为了实现这一点,我们可以使用index_add 函数,它允许我们添加到索引列表中。由于这只支持一维操作,我们首先需要将X,Y 转换为扁平张量A 的线性索引。之后我们可以取消展平到原来的形状。

layer_size = A.shape[1] * A.shape[2]                                                                                                                                                                       
index_offset = torch.arange(0, A.shape[0] * layer_size, layer_size).unsqueeze(1)                                                                                                                           
indices = (X * A.shape[2] + Y) + index_offset                                                                                                                                                              
A = A.view(-1).index_add(0, indices.view(-1), Z.view(-1)).view(A.shape)

【讨论】:

谢谢!事实上,这些对并不是唯一的,这就是我需要总结它们的原因。例如:(3, 9, 0.5), (3, 9, 0.4) 应该导致 (3, 9, 0.9) @natasha_667 我用一个也适用于非唯一情况的解决方案更新了答案。 谢谢!我在这里尝试过,但在尺寸方面出现错误。我会真诚的,我还不明白你的解决方案!以下是实际尺寸:A.shape: ([32, 300, 300]), X.shape, Y.shape: ([32, 200]) 和 Z.shape: ([32, 200, 1])。 我明白了,我担心 X 和 Y 上可能存在批量维度。我需要再次更新。第三次魅力! @natasha_667 我已经更新了答案,如果这回答了你的问题,请告诉我

以上是关于遇到 RuntimeError:梯度计算所需的变量之一已被就地操作修改的主要内容,如果未能解决你的问题,请参考以下文章

RuntimeError:梯度计算所需的变量之一已被就地操作修改:PyTorch 错误

Pytorch LSTM-VAE Sentence Generator:RuntimeError:梯度计算所需的变量之一已被就地操作修改

错误:梯度计算所需的变量之一已被就地操作修改

找不到就地操作:梯度计算所需的变量之一已被就地操作修改

pytorch 后向误差,由就地操作修改的梯度计算变量之一

梯度计算所需的变量之一已通过就地操作进行了修改: