PyTorch學習筆記之自動求導(AutoGrad)

 

1、使用PyTorch 計算梯度數值

         PyTorch 的 Autograd 模塊實現了深度學習的算法中的反向傳播求導數,在張量(Tensor類)上的所有操作, Autograd 都能爲他們自動提供微分,簡化了手動計算導數的複雜過程。

在04以前的版本中, Pytorch 使用 Variabe 類來自動計算所有的梯度 Variable 類主要包含三個屬性 Variable 所包含的 Tensor;grad:保存 data 對應的梯度,grad 也是個 Variable,而不是 Tensor,它和 data 的形狀一樣;grad_fn:指向一個 Function 對象,這個 Function 用來反向傳播計算輸入的梯度;

從 0.4 起, Variable 正式合併入 Tensor 類,通過 Variable 嵌套實現的自動微分功能已經整合進入了 Tensor 類中。雖然爲了的兼容性還是可以使用 Variable(tensor)這種方式進行嵌套,但是這個操作其實什麼都沒做。

以後的代碼建議直接使用 Tensor 類進行操作,因爲官方文檔中已經將 Variable 設置成過期模塊。

想通過 Tensor 類本身就支持了使用 autograd 功能,只需要設置 reques_grad=True;

Variable 類中的的 grad 和 grad_fn 屬性已經整合進入了 Tensor 類中。

 

2Autograd

  • 在張量創建時,通過設置 requires_grad 標識爲 True 來告訴 PyTorch 需要對該張量進行自動求導, PyTorch 會記錄該張量的每一步操作歷史並自動計算 。

 

  • PyTorch 會自動追蹤和記錄對與張量的所有操作,當計算完成後調用 .backward() 方法自動計算梯度並且將計算結果保存到 grad 屬性中。

 

在張量進行操作後,grad_fn 已經被賦予了一個新的函數,這個函數引用了一個創建了這個 Tensor 類的 Function 對象。 Tensor 和 Function 互相連接生成了一個非循環圖,它記錄並且編碼了完整的計算曆史。每個張量都有個 grad 血屬性,如果這個張量是用戶手動創建的那麼這個張量的 grad 是 None 下面我們來調用反向傳播函數,計算其梯度。

 

3、簡單自動求

       如果 Tensor 類表示的是一個標量(即它包含一個元素的張量),則不需要爲 backwad()(指定任何參數,但是如果它有更多的元素,則需要指定一個 gradient 參數,它是形狀匹配的張量。以上的 z.backward() 相當於是 z.backward(torch. Tensor(1.)) 的簡寫。這種參數常出現在圖像分類中的單標籤分類,輸出一個標量代表圖像的標籤。

 

4、複雜的自動求導

 

  • 我們的返回值不是一個標量,所以需要輸入一個大小相同的張量作爲參數,這裏我們用 ones_like 函數根據 x 生成一個張量;

 

  • 我們可以使用 with torch.no_grad() 上下文管理器臨時禁止對已設置 requires_grad = True 的張量進行自動求導。這個方法在測試集計算準確率的時候會經常用到,例如:

 

 使用.no_grad() 進行嵌套後,代碼不會跟蹤歷史記錄,也就是說保存這部分記錄會減少內存的使用量並且會加快少許的運算速度。

5 Autograd 過程解析

      爲了說明 Torch 的自動求導原理,我們來嘗試分析一下 PyTorch 的源代碼,雖然 Pytorch 的 Tensor和 TensorBase 都是使用 CPP 來實現的,但是可以使用一些 Python 的一些方法查看這些對象在 Python 的屬性和狀態。 Python 的 dir 返回參數的屬性、方法列表。z 是一個 Tensor 變量,看看裏面有哪些成員變量。

 

返回很多,我們直接排除掉一些 Python 中特殊方法(以開興和結束的)和私有方法(以開頭的,直接看幾個比較主的屬性:.is_leaf: 記錄是否是葉子節點。通過這個屬性來確定這個變量的類型在官方文檔中所說的" graphleaves"," leaf variables",都是指像 x,y 這樣的手動創建的、而非運算得到的變量,這些變量成爲創建變量。像 z 這樣的,是通過計算後得到的結果稱爲結果變量。

一個變量是創建變量還是結果變量是通過 .is_leaf() 來獲取的。

 

 x 是手動創建的沒有通過計算,所以他被認爲是一個葉子節點也就是一個創建變量,而 z 是通過x 與 y 的一系列計算得到的,所以不是葉子結點也就是結果變量爲什麼我們執行 z. backward(方法會更新 x.grad 和 y.grad 呢?. grad_fn 屬性記錄的就是這部分的操作,雖然 backward()方法也是CPP 實現的,但是可以通過 Python 來進行簡單的探索。

grad_fn: 記錄並且編碼了完整的計算曆史

 

grad_fn 是一個 AddBackward0 這個類也是用 cpp 來寫的,但是我們從名字裏就能夠大概知道,他是加法 (ADD) 的反向傳播。

 

next_functions 就是 grad_fn 的精華

 

next_functions 是一個 tuple of tuple of PowBackwardo and int

爲什麼是 2 個 tuple ?因爲我們的操作是 z = x**2+y**3剛纔的 addBackward() 是相加,而前面的操作是乘方PowBackward()。 tuple第一個元素就是 x 相關的操作記錄

 

當我們執行 z.backward 的時候。這個操作將調用 z 裏面的 grad_fn 這個屬性,執行求導的操作。

這個操作將遍歷 grad_fn 的 next_functions,然後分別取出裏面的 Function(Accumulategrad),執行求導操作。這部分是一個遞歸的過程直到最後美型爲葉子節點。

計算出結果以後,將結果保存到他們對應的 Variable 這個變量所引用的對象 ( x 和 y)的gad這個屬性裏面。

求導結束。所有的葉節點的 grad 變量都得到了相應的更新最終當我們執行完 c.backward()之後,a 和 b 裏面的 grad 值就得到了更新。

 

在 PyTorch 的反向圖計算中, Accumulategrad 類型代表的就是葉子節點類型,也就是計算圖終止節點。

Accumulategrad 類中有一個 . variable 屬性指向葉子節點。

 

這個 . variable 的屬性就是我們的生成的變量 x

 

6、擴展 Autograd

      如果需要目定義 autograd擴展新的功能,就需要擴展 Function類。因爲 Function使用 autograd來計算結果和梯度,並對操作歷史進行編碼。在 Function類中最主要的方法就是 forward0和 backward他們分別代表了前向專播和反向傳。

一個自定義的 Function 需要以下三個方法:

__init__( optional):如果這個操作需要額外的參數則需要定義這個 Function 的構造函數,不需要的話可以忽略。

forward():執行前向傳播的計算代碼

backward():反向傳播時梯度計算的代碼。參數的個數和 forward 返回值的個數一樣,每個參數代表傳回到此操作的梯度。

 

 

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