• 教學 >
  • 使用 torch.autograd 進行自動微分
捷徑

學習基礎知識 || 快速入門 || 張量 || 資料集和資料載入器 || 轉換 || 建立模型 || 自動微分 || 最佳化 || 儲存和載入模型

使用 torch.autograd 進行自動微分

在訓練神經網路時,最常使用的演算法是**反向傳播**。在這個演算法中,參數(模型權重)會根據損失函數相對於給定參數的**梯度**進行調整。

為了計算這些梯度,PyTorch 有一個稱為 torch.autograd 的內建微分引擎。它支援針對任何計算圖自動計算梯度。

考慮最簡單的單層神經網路,輸入為 x,參數為 wb,以及一些損失函數。它可以在 PyTorch 中以以下方式定義

張量、函數和計算圖

這段程式碼定義了以下**計算圖**

在這個網路中,wb 是我們需要最佳化的**參數**。因此,我們需要能夠計算損失函數相對於這些變數的梯度。為此,我們設定這些張量的 requires_grad 屬性。

注意

您可以在建立張量時設定 requires_grad 的值,也可以稍後使用 x.requires_grad_(True) 方法設定。

我們應用於張量以建構計算圖的函數實際上是 Function 類別的物件。這個物件知道如何在*正向*方向計算函數,也知道在*反向傳播*步驟中如何計算其導數。反向傳播函數的參照儲存在張量的 grad_fn 屬性中。您可以在文件中找到更多關於 Function 的資訊。

計算梯度

為了最佳化神經網路中參數的權重,我們需要計算損失函數相對於參數的導數,也就是說,在 xy 的某些固定值下,我們需要 \(\frac{\partial loss}{\partial w}\)\(\frac{\partial loss}{\partial b}\)。為了計算這些導數,我們呼叫 loss.backward(),然後從 w.gradb.grad 中取得值。

注意

  • 我們只能取得計算圖中葉節點的 grad 屬性,這些節點的 requires_grad 屬性設定為 True。對於圖表中的所有其他節點,將無法使用梯度。
  • 出於效能原因,我們只能在給定圖表上使用 backward 進行一次梯度計算。如果需要在同一個圖表上進行多次 backward 呼叫,則需要將 retain_graph=True 傳遞給 backward 呼叫。

停用梯度追蹤

根據預設,所有具有 requires_grad=True 的張量都會追蹤其計算歷史記錄並支援梯度計算。但是,在某些情況下,我們不需要這樣做,例如,當我們已經訓練了模型,並且只想將其應用於一些輸入資料時,也就是說,我們只想透過網路進行*正向*計算。我們可以透過使用 torch.no_grad() 區塊包圍我們的計算程式碼來停止追蹤計算

另一種達到相同結果的方法是在張量上使用 detach() 方法

您可能想要停用梯度追蹤的原因有很多
  • 將神經網路中的某些參數標記為**凍結參數**。這是微調預先訓練的網路的常見情況。
  • 當您只進行正向傳遞時,可以**加快計算速度**,因為在不追蹤梯度的張量上進行計算會更有效率。

更多關於計算圖的資訊

從概念上講,autograd 會將資料(張量)和所有執行的運算(以及產生的新張量)的記錄保存在由 Function 物件組成的有向無環圖 (DAG) 中。在這個 DAG 中,葉節點是輸入張量,根節點是輸出張量。透過從根節點到葉節點追蹤這個圖表,您可以使用鏈式法則自動計算梯度。

在正向傳遞中,autograd 會同時執行兩件事

  • 執行請求的運算以計算結果張量
  • 在 DAG 中維護運算的*梯度函數*。

當在 DAG 根節點上呼叫 .backward() 時,就會開始反向傳遞。autograd 接著會

  • 從每個 .grad_fn 計算梯度,
  • 將它們累積在相應張量的 .grad 屬性中
  • 使用鏈式法則,一路傳播到葉節點張量。

注意

**DAG 在 PyTorch 中是動態的** 有一點需要注意,圖表是從頭開始重新建立的;每次呼叫 .backward() 後,autograd 都會開始填充一個新的圖表。這正是允許您在模型中使用控制流程語句的原因;您可以根據需要在每次迭代中更改形狀、大小和運算。

選讀:張量梯度和雅可比積

在許多情況下,我們有一個純量損失函數,並且需要計算相對於某些參數的梯度。但是,在某些情況下,輸出函數是一個任意張量。在這種情況下,PyTorch 允許您計算所謂的**雅可比積**,而不是實際的梯度。

對於向量函數 \(\vec{y}=f(\vec{x})\),其中 \(\vec{x}=\langle x_1,\dots,x_n\rangle\)\(\vec{y}=\langle y_1,\dots,y_m\rangle\)\(\vec{y}\) 相對於 \(\vec{x}\) 的梯度由**雅可比矩陣**給出

\[\begin{split}\begin{align}J=\left(\begin{array}{ccc} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}}\\ \vdots & \ddots & \vdots\\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{array}\right)\end{align}\end{split}\]

PyTorch 允許您針對給定的輸入向量 \(v=(v_1 \dots v_m)\) 計算**雅可比積** \(v^T\cdot J\),而不是計算雅可比矩陣本身。這是通過使用 \(v\) 作為參數調用 backward 來實現的。\(v\) 的大小應該與我們想要計算其乘積的原始張量的大小相同

請注意,當我們使用相同的參數第二次調用 backward 時,梯度的值會有所不同。發生這種情況是因為在進行 backward 傳播時,PyTorch 會**累積梯度**,也就是說,計算出的梯度值會添加到計算圖所有葉節點的 grad 屬性中。如果您想計算正確的梯度,則需要事先將 grad 屬性歸零。在實際訓練中,*優化器* 可以幫助我們做到這一點。

注意

之前我們是在沒有參數的情況下調用 backward() 函數。這基本上等同於調用 backward(torch.tensor(1.0)),這是在純量值函數(例如神經網路訓練期間的損失)的情況下計算梯度的有用方法。


延伸閱讀

# %%%%%%RUNNABLE_CODE_REMOVED%%%%%%

**腳本總執行時間:**(0 分鐘 0.022 秒)

由 Sphinx-Gallery 生成的圖庫


這有幫助嗎?
謝謝你

© Copyright 2017, PyTorch.

使用 Sphinx 建立,並使用由 Read the Docs 提供的 主題

文件

取得 PyTorch 的完整開發人員文件

檢視文件

教學

取得適用於初學者和進階開發人員的深入教學課程

檢視教學課程

資源

尋找開發資源並獲得問題的解答

檢視資源