pytorch反向傳播,detach(),葉子張量,inplace操作,動態圖,求導


參考一

淺談 PyTorch 中的 tensor 及使用

該博文分為以下6個部分:

  1. tensor.requires_grad
  2. torch.no_grad()
  3. 反向傳播及網絡的更新
  4. tensor.detach()
  5. CPU and GPU
  6. tensor.item()

torch.detach()和torch.data的區別是,在求導時,torch.detach()會檢查張量的數據是否發生變化,而torch.data則不會去檢查。

參考二

PyTorch 的 Autograd

該博文講了backward()、葉子張量、inplace操作、動態圖和靜態圖的區別等,概要如下:

  1. 在我們做正向傳播的時候,需要求導的變量除了執行 forward()操作之外,還會同時會為反向傳播做一些准備,為反向計算圖添加一個Function節點。
  2. 如何判斷是否是葉子張量:當這個tensor是用戶創建的時候,它是一個葉子節點,當這個tensor是由其他運算操作產生的時候,它就不是一個葉子節點。
  3. 只有葉子張量的導數結果才會被最后保留下來,其他張量的導數用完就被釋放。也就是說,在整個計算圖的backward()完成之后,葉子張量的grad是有數值的,而其他張量的grad是None。
  4. inplace指的是在不更改變量的內存地址的情況下,直接修改變量的值。
  5. 如果一個變量同時參與了正向傳播和反向傳播,那么最好不要對它使用inplace操作,因為inplace操作可能會引起反響傳播時報錯。
  6. 所謂動態圖,就是每次當我們搭建完一個計算圖,然后在反向傳播結束之后,整個計算圖就在內存中被釋放了。如果想再次使用的話,必須從頭再搭一遍。而以TensorFlow為代表的靜態圖,每次都先設計好計算圖,需要的時候實例化這個圖,然后送入各種輸入,重復使用,只有當會話結束的時候創建的圖才會被釋放。
  7. 變量.grad_fn表明該變量是怎么來的,用於指導反向傳播。例如loss = a+b,則loss.gard_fn為<AddBackward0 at 0x7f2c90393748>,這個grad_fn可指導怎么求a和b的導數

實例

import torch

input = torch.tensor([[1., 2.], [3., 4.]], requires_grad=False)
w1 = torch.tensor(2.0, requires_grad=True)
w2 = torch.tensor(3.0, requires_grad=True)

l1 = input * w1
l2 = l1 + w2
loss = l2.mean()
loss.backward()

print(input.grad)  # 輸出:None
print(w1.grad)  # 輸出:tensor(2.5)
print(w2.grad)  # 輸出:tensor(1.)
print(l1.grad, l2.grad, loss.grad)  # 輸出: None None None
# 因為l1, l2, loss都是非葉子張量,所以它們的導數不會被保存,即它們的.grad為None

print(l1.grad_fn)      # 輸出:<MulBackward0 object at 0x7f10feeb1a20> 表明l1是由相乘得來的,用於指導向后求導
print(loss.grad_fn)    # 輸出:<MeanBackward1 object at 0x7f10feeb1a20>

我們可以手動求導驗證一下w1和w2的導數對不對:

說明程序求導結果是對的。

如果我們把input的requires_grad改為True,則input也變為葉子張量了,loss需要對齊求導,並且導數會被保存:

import torch

input = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
w1 = torch.tensor(2.0, requires_grad=True)
w2 = torch.tensor(3.0, requires_grad=True)

l1 = input * w1
l2 = l1 + w2
loss = l2.mean()
loss.backward()

print(input.grad)  # 輸出:tensor([[0.5000, 0.5000],
                   #              [0.5000, 0.5000]])
print(w1.grad)     # 輸出:tensor(2.5000)
print(w2.grad)     # 輸出:tensor(1.)
print(l1.grad, l2.grad, loss.grad)   # 輸出: None None None
# 因為l1, l2, loss都是非葉子張量,所以它們的梯度不會被保存,即它們的.grad為None

我們可以手動求導驗證一下:

說明程序求導結果是對的。

 


免責聲明!

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



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