model = RNN()
hn = torch.zeros(1,seq_len,hidden_num)
epochs = 250
clip_value = 100
loss = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
for epoch in range(epochs):
accu,num = 0.0,0
for x,y in data_collect(corpus_indice,batch_size,seq_len):
#-------------------------------------------------------------#
# 这里添加上一句话即可
hn.detach_()
#-------------------------------------------------------------#
output,hn = model(x,hn)
y = y.transpose(1,0).contiguous().view(-1)
ls = loss(output.view(-1,vocab_len),y)
optimizer.zero_grad()
ls.backward()
torch.nn.utils.clip_grad_value_(model.parameters(), clip_value)
optimizer.step()
accu += ls.item() * y.shape[0]
num += y.shape[0]
if epoch%50 == 0:
print("现在是第{}次epoch,loss的值为{}".format(epoch,math.exp(accu/num)))
print("完成")
因为每个iteration,都需要传入一个 h i h_i hi(上一个iteration的结果,如果在上一步执行backward()就会释放 h i h_i hi 的值),在第 i + 1 i+1 i+1步,我们需要传入 h i h_i hi 的值,计算它的梯度,而这个时候 h i h_i hi 的值已经被释放了,导致不能梯度不能回传。
解决办法
使用
hn.detach()
detach()的作用:
返回一个新的Variable,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个Variable永远不需要计算其梯度,不具有grad。
即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
这样我们就会继续使用这个新的Variable进行计算,后面当我们进行反向传播时,到该调用detach()的Variable就会停止,不能再继续向前进行传播