RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
梯度运算所需的变量之一已被就地操作修改
变量分配是就地操作,在网络的实现过程中,存在上下文使用某个变量,某些功能要求变量不能更改。因此可以采用clone操作进行避免
prob_g=score[:,:vocab_size].clone()#1,vocab_size
prob_c=score[:,vocab_size:].clone()#1,seq_size
问题代码
def forward():
score=F.softmax(torch.cat((score_g,score_c),dim=1),dim=1)
prob_g=score[:,:vocab_size]#1,vocab_size
prob_c=score[:,vocab_size:]#1,seq_size
if self.max_vocab_size>vocab_size:
padding=torch.zeros(1,self.max_vocab_size-vocab_size)
output1=torch.cat([prob_g,padding],1)
else:
output1=prob_g
#max_vocab_size的含义不是十分确定,具体代表的是啥,以及为啥要进行补充
seq_size=input_seq.shape[0]#input_seq在维度0上的size
one_hot=torch.zeros(pre_prob.size(0),max_vocab_size).scatter_(1,input_seq.view(-1,1),1)#根据input_seq中的索引,按照维度1的方向对torch.zero进行填充1
#将one_hot的seq_size改为max_length(pre_prob.size(0))
output1 +=torch.mm(prob_c,one_hot)
output1[output1==0]=1e-9
output1[0][2]=1e-9
output1=output1.log()
return output1,hidden,attn_weights,prob_c
for di in range(target_length):
decoder_output,decoder_hidden,decoder_attention,prob_c=decoder(
decoder_input,
decoder_hidden,
encoder_outputs,
input_tensor_clone,
pre_prob
)
pre_prob=prob_c.squeeze().long().detach()#求pre_prob中的梯度,不求prob_c中参数的梯度,不参与更新
topv,topi=decoder_output.topk(1)
decoder_input=topi.squeeze().detach()#去除topi的梯度更新,代表一个词
output_rec.append(topi.item())#直接索引就代表一个单词,直接进行拼接
loss=loss+criterion(decoder_output,target_tensor[di].view(1))
在decoder 的forward中返回值output1是由prob_g直接赋值,之后在loss的计算中使用了output1,由此出现了变量被就地修改的情况,使用clone()可以解决这个问题
修改后的代码如下:
def forward():
score_g=self.Wo(hidden).view(1,-1)#1,vocab_size
print('%%%%')
score_c=self.Wc(encoder_outputs)# seq_size,hidden_size
score_c=torch.tanh(score_c)#score_c相当于hj*Wc,取非线性函数,得到的值
score_c=torch.mm(score_c,hidden.view(-1,1)).view(1,-1)#hidden相当于st
print('!!!!')
score=F.softmax(torch.cat((score_g,score_c),dim=1),dim=1)
prob_g=score[:,:vocab_size].clone()#1,vocab_size
prob_c=score[:,vocab_size:].clone()#1,seq_size
if self.max_vocab_size>vocab_size:
padding=torch.zeros(1,self.max_vocab_size-vocab_size)
output1=torch.cat([prob_g,padding],1)
else:
output1=prob_g
#max_vocab_size的含义不是十分确定,具体代表的是啥,以及为啥要进行补充
seq_size=input_seq.shape[0]#input_seq在维度0上的size
one_hot=torch.zeros(pre_prob.size(0),max_vocab_size).scatter_(1,input_seq.view(-1,1),1)#根据input_seq中的索引,按照维度1的方向对torch.zero进行填充1
#将one_hot的seq_size改为max_length(pre_prob.size(0))
output1 +=torch.mm(prob_c,one_hot)
output1[output1==0]=1e-9
output1[0][2]=1e-9
output1=output1.log()
return output1,hidden,attn_weights,prob_c
原因
python的=赋值大概可以看做是将变量指向一个内存地址,在修改时,会直接修改指向的内存的数据。所以还会出现上述的情况
一个讨论上看到的讨论
测试代码
import numpy as np
a=np.arange(9).reshape((3,3))
print(a)
b=a[1:3,1:3]
print(b)
c=b
c[0][0]=1
print(c)
print(b)
print(a)