點選這裡了解反向傳播算法
1. torch.Tensor.backward()
(1)函數的作用
- 擷取計算圖中某個tensor的葉子節點的梯度(無法擷取非葉子節點的梯度)
計算圖:一個函數構成了一個計算圖,計算圖的根節點是函數的輸出,葉子節點是函數的輸入
葉子節點:圖結構中沒有子節點的節點
上述代碼定義了一個複合函數:
x1 = 1, x2 = 2
y1 = x1 + 1, y2 = x2 + 1
z = 0.5 * (y1^2 + y2^2)
z.backward()
表示對
z
的葉子節點求導,也就是對
x1
和
x2
求導,依據鍊式求導法則,可以求得兩者梯度分别為
2
和
3
,與輸出一緻。值得注意,
y1
和
y2
是函數
z
的中間變量(非葉子節點),是以其導數值為
None
(2)參數解釋
-
:對調用backward()的非标量提供父節點的梯度資訊gradient(Tensor or None)
①函數
z
的值為标量(scalar)時,反向對函數的葉子節點求導,不需要gradient參數(設定為
None
),如上所示
②函數
z
的值為非标量(no-scalar)時,需要與函數值形狀相同的tensor作為gradient的梯度,這裡gradient參數表示函數
z
的父節點傳遞至
z
的梯度(下述代碼中将該梯度指派為)
上述代碼定義了一個複合函數:
x1 = 1, x2 = 2
y1 = x1 + 1, y2 = x2 + 1
z1 = y1^2, z2 = y2^2
其中,
z1
關于
x1
的導數值是
4
,再乘以父節點傳回的梯度
1
,最終計算出的
z1
關于
x1
的導數值是
4
z2
關于
x2
的導數值是
6
,再乘以父節點傳回的梯度
0.1
,最終計算出的
z1
關于
x1
的導數值是
0.6
-
:用于多次反向傳播時累加梯度資訊retain_graph (bool, optional)
①一般情況下,進行一次反向傳播更新各個參數後,參數的梯度資訊會被釋放,再前向傳播計算損失值,再反向傳播,即一次反向傳播和一次前向傳播是交替出現的,但是在有些網絡中會存在多個子網絡對同一個參數進行反向傳播累加梯度值再更新該參數的情況,這種情況下,就不能在一次反向傳播結束後就立即釋放梯度資訊了,retain_graph參數就是用來處理這種情況的,retain_graph的預設參數與create_graph相同。當retain_graph為
True
時,保留葉子節點的梯度資訊。
經過計算可以發現,在第二次反向傳播時,确實累加了第一次反向傳播時葉子節點的梯度資訊
-
:用于高階求導create_graph (bool, optional)
import torch
x = torch.tensor([1.0], dtype=torch.float32, requires_grad=True)
y = x + 1
z = x + y**2
z.backward(retain_graph=False, create_graph=True)
print(x.grad) # 輸出[5.0]
torch.autograd.backward(x.grad)
print(x.grad) # 輸出[7.0]
從輸出可以判斷,确實求出了關于
z
的二階導數,但令我疑惑的是,為什麼第二次的輸出值是一階導和二階導的累加值,我明明将
x
參數設定成
retain_graph
了呀
False
2. torch.autograd.backward()
(1)函數的作用
- 計算某tensor葉子節點的梯度
- 若該tensor為标量,則無需
參數,若tensor為非标量,則需提供grad_tensors
參數,grad_tensors
參數形狀必須與該tensor形狀相同(可将傳入的grad_tensors
grad_tensors
參數視為該tensor父節點回傳的梯度)
①tensor為标量
②tensor為非标量(不傳入
參數,報錯) ③tensor為非标量(正确傳入grad_tensors
參數)grad_tensors
import torch
x = torch.tensor([1.0, 2.0], dtype=torch.float32, requires_grad=True)
y = x + 1
z = x + y
w = torch.autograd.backward(z, grad_tensors=torch.tensor([0.1, 0.2], dtype=torch.float32))
print(x.grad)
print(y.grad)
(2)參數解釋
-
需要計算葉子節點梯度的tensortensors (sequence of Tensor)
-
計算非标量tensor葉子節點的梯度時需要提供該參數grad_tensors (sequence of (Tensor or None))
-
是否保留反向傳播的梯度資訊以便二次反向傳播時累加梯度,預設值與傳入的retain_graph (bool, optional)
值相同create_graph
import torch
x = torch.tensor([1.0], dtype=torch.float32, requires_grad=True)
y = x + 1
z = x + y
torch.autograd.backward(z, retain_graph=True) # 将retain_graph參數設定為,True以便下一次反向傳播時累加梯度
print(x.grad) # 輸出為[2.0]
torch.autograd.backward(z)
print(x.grad) # 輸出為[4.0]
-
用于儲存計算圖以便計算高階導數create_graph (bool, optional)
import torch
x = torch.tensor([1.0], dtype=torch.float32, requires_grad=True)
y = x + 1
z = x + y**2
torch.autograd.backward(z, create_graph=True)
print(x.grad) # 輸出[5.0]
torch.autograd.backward(x.grad) # 再上次建構的反向傳播的計算圖上再次反向傳播
print(x.grad) # 輸出[7.0],這裡的輸出是x的一階導與二階導的累加值
import torch
x = torch.tensor([1.0], dtype=torch.float32, requires_grad=True)
y = x + 1
z = x + y**2
torch.autograd.backward(z, retain_graph=False, create_graph=True) # 将retain_graph設定為True也沒用
print(x.grad) # 輸出[5.0]
torch.autograd.backward(x.grad)
print(x.grad) # 輸出[7.0]
我也不清楚為啥将設定為
create_graph
後再次對
True
反向傳播求出的值是一階導和二階導的累加值,歡迎懂的朋友指正
x.grad