pytorch中反向傳播的loss.backward(retain_graph=True)報錯


RNN和LSTM模型中的反向傳播方法,在loss.backward()處的問題,

更新完pytorch版本后容易出現問題。

問題1.使用loss.backward()報錯

Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.
(torchenv) star@lab407-1:~/POIRec/STPRec/Flashback_code-master$ python train.py

問題2.使用loss.backward(retain_graph=True)

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

 

解決措施:

關於loss.backward()以及其參數retain_graph的一些坑
首先,loss.backward()這個函數很簡單,就是計算與圖中葉子結點有關的當前張量的梯度
使用呢,當然可以直接如下使用

optimizer.zero_grad() 清空過往梯度;
loss.backward() 反向傳播,計算當前梯度;
optimizer.step() 根據梯度更新網絡參數

or這種情況
for i in range(num):
loss+=Loss(input,target)
optimizer.zero_grad() 清空過往梯度;
loss.backward() 反向傳播,計算當前梯度;
optimizer.step() 根據梯度更新網絡參數

 


但是,有些時候會出現這樣的錯誤:RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed

這個錯誤的意思就是,Pytorch的機制是每次調用.backward()都會free掉所有buffers,模型中可能有多次backward(),而前一次backward()存儲在buffer中的梯度,會因為后一次調用backward()被free掉,因此,這里需要用到retain_graph=True這個參數
使用這個參數,可以讓前一次的backward()的梯度保存在buffer內,直到更新完成,但是要注意,如果你是這樣寫的:

optimizer.zero_grad() 清空過往梯度;
loss1.backward(retain_graph=True) 反向傳播,計算當前梯度;
loss2.backward(retain_graph=True) 反向傳播,計算當前梯度;
optimizer.step() 根據梯度更新網絡參數

那么你可能會出現內存溢出的情況,並且,每一次迭代會比上一次更慢,越往后越慢(因為你的梯度都保存了,沒有free)
解決的方法,當然是這樣:

optimizer.zero_grad() 清空過往梯度;
loss1.backward(retain_graph=True) 反向傳播,計算當前梯度;
loss2.backward() 反向傳播,計算當前梯度;
optimizer.step() 根據梯度更新網絡參數

即:最后一個backward()不要加retain_graph參數,這樣每次更新完成后會釋放占用的內存,也就不會出現越來越慢的情況了。

這里有人就會問了,我又沒有這么多 loss,怎么還會出現這種錯誤呢?這里可能是因為,你用的模型本身有問題,LSTM和GRU都會出現這樣的問題,問題存在與hidden unit,這個東東也參與了反向傳播,所以導致了有多個backward(),
這里其實我也挺費解,為什么存在多個backward()呢?難道是,我的LSTM網絡是N to N,即輸入N和,輸出N個,然后和N個label進行計算loss,再進行回傳,這里,可以思考一下BPTT,即,如果是N to 1,那么梯度更新需要時間序列所有的輸入以及隱藏變量計算梯度,然后從最后一個向前傳,所以只有一個backward(), 而N to N 以及 N to M 都會出現多個loss需要進行backward()的情況,如果還是兩個方向(一個從輸出到輸入,一個沿着時間)一直進行傳播,那么其實會有重疊的部分,所以解決的方法也就很明了了,利用detach()函數,切斷其中重疊的反向傳播,(這里僅是我的個人理解,若有誤還請評論指出,大家共同探討)切斷的方式有三種,如下:

hidden.detach_()
hidden = hidden.detach()
hidden = Variable(hidden.data, requires_grad=True)

 

 

參考:

https://blog.csdn.net/a845717607/article/details/104598278/

 

解決措施二:核心思想是將optimizer.step()往后移動

 

參考:https://www.cnblogs.com/js2hou/p/13923089.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM