PyTorch的计算图和自动求导机制
文章目錄
- PyTorch的計算圖和自動求導機制
- 自動求導機制簡介
- 自動求導機制實例
- 梯度函數(shù)的使用
- 計算圖構(gòu)建的啟用和禁用
- 總結(jié)
PyTorch的計算圖和自動求導機制
自動求導機制簡介
PyTorch會根據(jù)計算過程自動生成動態(tài)圖,然后根據(jù)動態(tài)圖的創(chuàng)建過程進行反向傳播,計算每個節(jié)點的梯度值。
為了能夠記錄張量的梯度,首先需要在創(chuàng)建張量的時候設置一個參數(shù)requires_grad=True,意味著這個張量將會加入到計算圖中,作為計算圖的葉子節(jié)點參與計算,最后輸出根節(jié)點。
對于PyTorch來說,每個張量都有一個grad_fn方法,包含創(chuàng)建該張量的運算的導數(shù)信息。在反向傳播的過程中,通過傳入后一層的神經(jīng)網(wǎng)絡的梯度,該函數(shù)會計算出參與運算的所有張量的梯度。
同時,PyTorch提供了一個專門用來做自動求導的包torch.autograd。它包含兩個重要的函數(shù),即torch.autograd.bakward和torch.autograd.grad。
torch.autograd.bakward通過傳入根節(jié)點的張量以及初始梯度張量,可以計算產(chǎn)生該根節(jié)點的所有對應葉子節(jié)點的梯度。當張量為標量張量時,可以不傳入梯度張量,這是默認會設置初始梯度張量為1.當計算梯度張量時,原先建立起來的計算圖會被自動釋放,如果需要再次做自動求導,因為計算圖已經(jīng)不存在,就會報錯。如果要在反向傳播的時候保留計算圖,可以設置retain_graph=True。
另外,在自動求導的時候默認不會建立反向傳播的計算圖,如果需要在反向傳播的計算的同時建立梯度張量的計算圖,可以設置create_graph=True。對于一個可求導的張量來說,也可以調(diào)用該張量內(nèi)部的backward方法。
自動求導機制實例
定義一個函數(shù)f(x)=x2,則它的導數(shù)f’(x)=2x。于是可以創(chuàng)建一個可導的張量來測試具體的導數(shù)。
t1 = torch.randn(3, 3, requires_grad=True) # 定義一個3×3的張量 print(t1)t2 = t1.pow(2).sum() # 計算張量的所有分量的平方和 t2.backward() # 反向傳播 print(t1.grad) # 梯度是原始分量的2倍t2 = t1.pow(2).sum() # 再次計算張量的所有分量的平方和 t2.backward() # 再次反向傳播 print(t1.grad) # 梯度累積print(t1.grad.zero_()) # 單個張量清零梯度的方法得到的結(jié)果:
tensor([[-1.8170, -1.4907, 0.4560],[ 0.9244, 0.0798, -1.2246],[ 1.7800, 0.0367, -2.5998]], requires_grad=True) tensor([[-3.6340, -2.9814, 0.9120],[ 1.8488, 0.1597, -2.4492],[ 3.5600, 0.0735, -5.1996]]) tensor([[ -7.2681, -5.9628, 1.8239],[ 3.6975, 0.3193, -4.8983],[ 7.1201, 0.1469, -10.3992]]) tensor([[0., 0., 0.],[0., 0., 0.],[0., 0., 0.]])需要注意的一點是: 張量綁定的梯度張量在不清空的情況下會逐漸累積。這在例如一次性求很多Mini-batch的累積梯度時是有用的,但在一般情況下,需要注意將張量的梯度清零。
梯度函數(shù)的使用
如果不需要求出當前張量對所有產(chǎn)生該張量的葉子節(jié)點的梯度,可以使用torch.autograd.grad函數(shù)。
這個函數(shù)的參數(shù)是兩個張量,第一個張量是計算圖的張量列表,第二個參數(shù)是需要對計算圖求導的張量。最后輸出的結(jié)果是第一個張量對第二個張量求導的結(jié)果。
這個函數(shù)不會改變?nèi)~子節(jié)點的grad屬性,同樣該函數(shù)在反向傳播求導的時候釋放計算圖,如果要保留計算圖需要設置retain_graph=True。
另外有時候會碰到一種情況:求到的兩個張量之間在計算圖上沒有關(guān)聯(lián)。在這種情況下需要設置allow_unused=True,結(jié)果會返回分量全為0的梯度張量。
t1 = torch.randn(3, 3, requires_grad=True) print(t1)t2 = t1.pow(2).sum() print(torch.autograd.grad(t2, t1))得到的結(jié)果為:
tensor([[ 0.5952, 0.1209, 0.5190],[ 0.4602, -0.6943, -0.7853],[-0.1460, -0.1406, -0.7081]], requires_grad=True) (tensor([[ 1.1904, 0.2418, 1.0379],[ 0.9204, -1.3885, -1.5706],[-0.2919, -0.2812, -1.4161]])計算圖構(gòu)建的啟用和禁用
由于計算圖的構(gòu)建需要消耗內(nèi)存和計算資源,在一些情況下計算圖并不是必要的,所以可以使用torch.no_grad這個上下文管理器,對該管理器作用域中的神經(jīng)網(wǎng)絡計算不構(gòu)建任何的計算圖。
還有一種情況是對于一個張量,在反向傳播的時候可能不需要讓梯度通過這個張量的節(jié)點,也就是新建的計算圖需要和原來的計算圖分離,使用張量的detach方法,可以返回一個新的張量,該張量會成為一個新的計算圖的葉子結(jié)點。
總結(jié)
PyTorch使用動態(tài)計算圖,該計算圖的特點是靈活。雖然在構(gòu)件計算圖的時候有性能開銷,但PyTorch本身的優(yōu)化抵消了一部分開銷,盡可能讓計算圖的構(gòu)建和釋放過程代價最小,因此,相對于靜態(tài)圖的框架來說,PyTorch本身的運算速度并不慢。有了計算圖之后,就可以很方便地通過自動微分機制進行反向傳播的計算,從而獲得計算圖葉子節(jié)點的梯度。在訓練深度學習模型的時候,可以通過對損失函數(shù)的反向傳播,計算所有參數(shù)的梯度,隨后在優(yōu)化器中優(yōu)化這些梯度。
總結(jié)
以上是生活随笔為你收集整理的PyTorch的计算图和自动求导机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyTorch模块类
- 下一篇: PyTorch的损失函数和优化器