2.5 計算圖
前兩小節對tensor進行了詳細介紹,知道了tensor是pytorch的核心資料結構,各類資料均以tensor來表示,並且tensor類中有許多屬性與求導/梯度有關,接下來我們將深入學習pytorch的自動求導模組——autograd。在autograd正式開始之前,需要瞭解一個重要概念——計算圖(Computational Graphs)。
在學習自動求導系統之前,需要瞭解計算圖的概念。計算圖(Computational Graphs)是一種描述運算的“語言”,它由節點(Node)和邊(Edge)構成。
節點表示資料,如標量,向量,矩陣,張量等;
邊表示運算,如加、減、乘、除、卷積、relu等;
記錄所有節點和邊的資訊,可以方便地完成自動求導,假設有這麼一個計算:
y = (x+ w) * (w+1)
將每一步細化為:
a = x + w
b = w + 1
y = a * b
得到計算圖如下:
有了計算圖,我們可以嘗試進行forward,帶入x,w的輸入資料,就得到結果y。
同樣的,如果需要獲取各參數的導數,也可以方便地獲得。
計算圖求導
假設我們要算y對w的導數,在計算圖中要怎麼做呢?
先來看w和y之間的關係,w會通過左邊這條路走到y,也會通過右邊這條路走到y,因此梯度也是一樣的,會經過這兩條路回饋回來。
所以y對w的偏導有兩條路徑,可以寫成以下形式, ∂y/∂w = ∂y/∂a ∂a/∂w + ∂y/∂b ∂b/∂w,然後可以通過計算圖依次求出。
如圖所示:
這樣我們得到 y對w的導數是5,我們可以拿紙和筆推一下,是否是一樣的。
我們發現,所有的偏微分計算所需要用到的資料都是基於w和x的,這裡,w和x就稱為葉子結點。
葉子結點是最基礎結點,其資料不是由運算生成的,因此是整個計算圖的基石,是不可輕易”修改“的。而最終計算得到的y就是根節點,就像一棵樹一樣,葉子在上面,根在下面。
葉子結點
葉子結點是最基礎的結點,其資料不是由運算生成的,因此是整個計算圖的基石,是不可輕易”修改“的。而最終計算得到的y就是根節點,就像一棵樹一樣,葉子在上面,根在下面。
張量有一個屬性是is_leaf, 就是用來指示一個張量是否為葉子結點的屬性。
我們通過代碼,實現以上運算,並查看該計算圖的葉子結點和梯度。
import torch
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)
b = torch.add(w, 1) # retain_grad()
y = torch.mul(a, b)
y.backward()
print(w.grad)
# 查看葉子結點
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
# 查看梯度
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
# 查看 grad_fn
print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)
Copy
tensor([5.]) is_leaf: True True False False False gradient: tensor([5.]) tensor([2.]) None None None grad_fn: None None
我們發現y就不是葉子結點了,因為它是由結點w和結點x通過乘法運算得到的。
補充知識點1:非葉子結點在梯度反向傳播結束後釋放
只有葉子節點的梯度得到保留,中間變數的梯度預設不保留;在pytorch中,非葉子結點的梯度在反向傳播結束之後就會被釋放掉,如果需要保留的話可以對該結點設置retain_grad()
補充知識點2:grad_fn是用來記錄創建張量時所用到的運算,在鏈式求導法則中會使用到。
思考一下y對w求導的過程,我們知道只要記錄下計算圖中的結點(資料)和邊(運算),就可以通過鏈式法則輕易的求取梯度。
所以在pytorch中,自動微分的關鍵就是記錄資料和該結點的運算。回想一下張量的結構當中其實就記錄了這兩個重要的東西。
在張量中,資料對應著data,結點的運算對應著grad_fn,大家現在應該明白為什麼結點的運算叫grad_fn而不叫fn了吧,因為這個運算是在求梯度的時候使用的。
靜態圖與動態圖
以上就是計算圖的簡單介紹。計算圖根據計算圖的搭建方式可以劃分為靜態圖和動態圖。
pytorch是典型的動態圖,TensorFlow是靜態圖(TF 2.x 也支援動態圖模式)。
動態圖和靜態圖的搭建方式有何不同,如何判斷和區分?
第一種判斷:這就要看運算,是在計算圖搭建之後,還是兩者同步進行
先搭建計算圖,再運算,這就是靜態圖機制。
而在運算的同時去搭建計算圖,這就是動態圖機制。
第二種判斷:也可以通過判斷運算過程中,計算圖是否可變動來區分靜態圖與動態圖。
在運算過程中,計算圖可變動的是動態圖;計算圖不可變,是靜止的,就是靜態圖。
下麵來看兩個示意圖。
圖1為pytorch的靜態圖示意,圖2為TensorFlow的靜態圖示意。
動態圖優點:
- 易理解:程式按照編寫命令的順序進行執行
- 靈活性:可依據模型運算結果來決定計算圖
靜態圖優點:
- 高效性:優化計算圖,提高運算效率(但在gpu時代,這一點對於初學者而言可忽略不計)
缺點:
- 晦澀性:需要學習 seesion, placeholder等概念,調試困難
以上是關於計算圖概念的介紹,下一小節將詳細剖析autograd機制及其常用的功能函數,請注意,下一節內容也非常豐富,可能需要多次閱讀以充分理解。
留言列表