pytoch 設置了requires_grad=True,但是計算梯度(grad)爲none

來源:AINLPer微信公衆號(點擊瞭解一下吧
編輯: ShuYini
校稿: ShuYini
時間: 2019-8-16

代碼示例

x_in=torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]]).view((1,1,3,3)).type(torch.FloatTensor)
y_out=torch.tensor([[19, 25],[37, 43]]).view(1,1,2,2).type(torch.FloatTensor)
c_core=torch.randn(2,2).view((1,1,2,2)).type(torch.FloatTensor)
c_core=c_core.requires_grad_()    
LR=0.01
# 定義一個損失函數
loss_fun=nn.MSELoss()
for i in range(10):
    y_pre=nn.functional.conv2d(x_in,c_core)
    loss=loss_fun(y_pre,y_out)
    print(c_core.grad)
    loss.backward()
    c_core=c_core-c_core.grad*LR
    print('the loss is:',loss)
print('c_core: ',c_core)

遇到的具體問題:

    針對這個問題,在pytoch中直接報出來的錯誤是:

TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'

    針對這個報出來的問題,定位到當計算到“”c_core=c_core-c_core.grad*LR“”這句話時報錯了,然後根據上面的輸出才判斷出來,原來c_core的grad爲None。

##解決思路
    後來經過查詢才發現,當計算梯度的時候,只有葉子節點纔會保留梯度,所有中間節點的grad在計算完backward()的時候爲了節約內存都會被清除掉。(葉子節點是自己最初定義的變量)。此時查看我定義的c_core,確實是我最初定義的變量啊。但是有一些細節被忽略了,就是下面這句話:

c_core=c_core-c_core.grad*LR

    其實上面這句話,已經對c_core做了改變,是經過計算得到的c_core,修改之後已經不是我們最初定義的變量了,而是成爲了中間節點。爲此怎麼辦呢?要保留中間節點其實很簡單。就是在調用backward之前,首先調用c_core.retain_grad()。
##最終的代碼修改爲:

x_in=torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]]).view((1,1,3,3)).type(torch.FloatTensor)
y_out=torch.tensor([[19, 25],[37, 43]]).view(1,1,2,2).type(torch.FloatTensor)
c_core=torch.randn(2,2).view((1,1,2,2)).type(torch.FloatTensor)
c_core=c_core.requires_grad_()    
LR=0.01
# 定義一個損失函數
loss_fun=nn.MSELoss()
for i in range(10):
    y_pre=nn.functional.conv2d(x_in,c_core)
    loss=loss_fun(y_pre,y_out)
    c_core.retain_grad()
    loss.backward()
    c_core=c_core-c_core.grad*LR
    print('the loss is:',loss)
print('c_core: ',c_core)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章