專題鏈接:https://blog.csdn.net/qq_33345365/category_12591348.html
本教程翻譯自微軟教程:https://learn.microsoft.com/en-us/training/paths/pytorch-fundamentals/
初次編輯:2024/3/2;最后編輯:2024/3/3
本教程第一篇:介紹pytorch基礎和張量操作
本教程第二篇:介紹了數據集與歸一化
本教程第三篇:介紹構建模型層的基本操作。
本教程第四篇:介紹自動微分相關知識,即本博客內容。
另外本人還有pytorch CV相關的教程,見專題:
https://blog.csdn.net/qq_33345365/category_12578430.html
自動微分
使用torch.autograd
自動微分 Automaic differentiation
在訓練神經網絡時,最常用的算法是反向傳播(back propagation)。在這個算法中,參數(模型權重)根據損失函數相對于給定參數的梯度進行調整。損失函數(loss function)計算神經網絡產生的預期輸出和實際輸出之間的差異。目標是使損失函數的結果盡可能接近零。該算法通過神經網絡向后遍歷以調整權重和偏差來重新訓練模型。這就是為什么它被稱為反向傳播。隨著時間的推移,通過反復進行這種回傳和前向過程來將損失(loss)減少到0的過程稱為梯度下降。
為了計算這些梯度,PyTorch具有一個內置的微分引擎,稱為torch.autograd
。它支持對任何計算圖進行梯度的自動計算。
考慮最簡單的單層神經網絡,具有輸入x
,參數w
和b
,以及某些損失函數。可以在PyTorch中如下定義:
import torchx = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b # z = x*w +b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
張量、函數與計算圖(computational graphs)
在這個網絡中,w
和b
是參數,他們會被損失函數優化。因此,需要能夠計算損失函數相對于這些變量的梯度。為此,我們將這些張量的requires_grad
屬性設置為True。
**注意:**您可以在創建張量時設置
requires_grad
的值,也可以稍后使用x.requires_grad_(True)
方法來設置。
我們將應用于張量的函數(function)用于構建計算圖,這些函數是Function
類的對象。這個對象知道如何在前向方向上計算函數,還知道在反向傳播步驟中如何計算其導數。反向傳播函數
的引用存儲在張量的grad_fn
屬性中。
print('Gradient function for z =',z.grad_fn)
print('Gradient function for loss =', loss.grad_fn)
輸出是:
Gradient function for z = <AddBackward0 object at 0x00000280CC630CA0>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward object at 0x00000280CC630310>
計算梯度
為了優化神經網絡中參數的權重,需要計算損失函數相對于參數的導數,即我們需要在某些固定的x
和y
值下計算 ? l o s s ? w \frac{\partial loss}{\partial w} ?w?loss?和 ? l o s s ? b \frac{\partial loss}{\partial b} ?b?loss?。為了計算這些導數,我們調用loss.backward()
,然后從w.grad
和b.grad
中獲取值。
loss.backward()
print(w.grad)
print(b.grad)
輸出是:
tensor([[0.2739, 0.0490, 0.3279],[0.2739, 0.0490, 0.3279],[0.2739, 0.0490, 0.3279],[0.2739, 0.0490, 0.3279],[0.2739, 0.0490, 0.3279]])
tensor([0.2739, 0.0490, 0.3279])
注意: 只能獲取計算圖中設置了
requires_grad
屬性為True
的葉節點的grad
屬性。對于計算圖中的所有其他節點,梯度將不可用。此外,出于性能原因,我們只能對給定圖執行一次backward
調用以進行梯度計算。如果我們需要在同一圖上進行多次backward
調用,我們需要在backward
調用中傳遞retain_graph=True
。
禁用梯度追蹤 Disabling gradient tracking
默認情況下,所有requires_grad=True
的張量都在跟蹤其計算歷史并支持梯度計算。然而,在某些情況下,我們并不需要這樣做,例如,當我們已經訓練好模型并且只想將其應用于一些輸入數據時,也就是說,我們只想通過網絡進行前向計算。我們可以通過將我們的計算代碼放在一個torch.no_grad()
塊中來停止跟蹤計算:
z = torch.matmul(x, w)+b
print(z.requires_grad)with torch.no_grad():z = torch.matmul(x, w)+b
print(z.requires_grad)
輸出是:
True
False
另外一種產生相同結果的方法是在張量上使用detach
方法:
z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)
有一些理由你可能想要禁用梯度跟蹤:
- 將神經網絡中的某些參數標記為凍結參數(frozen parameters)。這在微調預訓練網絡的情況下非常常見。
- 當你只進行前向傳播時,為了加速計算,因為不跟蹤梯度的張量上的計算更有效率。
計算圖的更多知識
概念上,autograd 在一個有向無環圖 (DAG) 中保留了數據(張量)和所有執行的操作(以及生成的新張量),這些操作由 Function 對象組成。在這個 DAG 中,葉子節點是輸入張量,根節點是輸出張量。通過從根節點到葉子節點追蹤這個圖,你可以使用鏈式法則(chain rule)自動計算梯度。
在前向傳播中,autograd 同時執行兩件事情:
- 運行所請求的操作以計算結果張量,并且
- 在 DAG 中維護操作的 梯度函數(gradient function)。
當在 DAG 根節點上調用 .backward()
時,反向傳播開始。autograd
然后:
- 從每個
.grad_fn
計算梯度, - 將它們累積在相應張量的
.grad
屬性中,并且 - 使用鏈式法則一直傳播到葉子張量。
PyTorch 中的 DAG 是動態的
一個重要的事情要注意的是,圖是從頭開始重新創建的;在每次 .backward()
調用之后,autograd 開始填充一個新的圖。這正是允許您在模型中使用控制流語句的原因;如果需要,您可以在每次迭代中更改形狀、大小和操作。
代碼匯總:
import torchx = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w) + b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)print('Gradient function for z =', z.grad_fn)
print('Gradient function for loss =', loss.grad_fn)loss.backward()
print(w.grad)
print(b.grad)z = torch.matmul(x, w) + b
print(z.requires_grad)with torch.no_grad():z = torch.matmul(x, w) + b
print(z.requires_grad)z = torch.matmul(x, w) + b
z_det = z.detach()
print(z_det.requires_grad)