pytorch的梯度計算以及backward方法詳解
基礎知識
tensors:
tensor在pytorch裡面是一個n維陣列。我們可以通過指定引數reuqires_grad=True來建立一個反向傳播圖,從而能夠計算梯度。在pytorch中一般叫做dynamic computation graph(DCG)——即動態計算圖。
import torch import numpy as np # 方式一 x = torch.randn(2,2,requires_grad=True) # 方式二 x = torch.autograd.Variable(torch.Tensor([2,3]),requires_grad=True) #方式三 x = torch.tensor([2,3],requires_grad=True,dtype=torch.float64) # 方式四 x = np.array([1,dtype=np.float64) x = torch.from_numpy(x) x.requires_grad = True # 或者 x.requires_grad_(True)
note1:在pytorch中,只有浮點型別的數才有梯度,故在方法四中指定np陣列的型別為float型別。為什麼torch.Tensor中不需要呢,可以通過以下程式碼驗證
import torch import numpy as np a = torch.Tensor([2,3]) print(a.dtype) # torch.floaat32 b = torch.tensor([2,3]) print(b.dtype) # torch.int64 c = np.array(2,3) print(c.dtype) # int64
note2pytorch中tensor與Tensor的區別是什麼?這兩個看起來如此相似。
首先,torch.Tensor是一個類,所有的tensor都是Tensor的一個例項;而torch.tensor是一個函式。這也說明了為什麼使用torch.Tensor()沒有問題而torch.tensor()卻有問題。
其次,torch.tensor主要是將一個data封裝成tensor,並且可以指定requires_grad。
torch.tensor(data,dtype=None,device=None,requires_grad=False) - > Tensor
最後,我們更多地使用torch.tensor,我們可以通過使用torch.tensor(())來達到與torch.Tensor()同樣的效果。
具體可參考torch.tensor與torch.Tensor的區別
Dynamic Computational graph
我們來看一個計算圖
我們 來看一個計算圖 解釋一下各個屬性的含義,
data: 變數中儲存的值,如x中儲存著1,y中儲存著2,z中儲存著3
requires_grad:該變數有兩個值,True 或者 False,如果為True,則加入到反向傳播圖中參與計算。
grad:該屬性儲存著相關的梯度值。當requires_grad為False時,該屬性為None。即使requires_grad為True,也必須在呼叫其他節點的backward()之後,該變數的grad才會儲存相關的梯度值。否則為None
grad_fn:表示用於計算梯度的函式。
is_leaf:為True或者False,表示該節點是否為葉子節點。
當呼叫backward函式時,只有requires_grad為true以及is_leaf為true的節點才會被計算梯度,即grad屬性才會被賦予值。
梯度計算
examples
運算結果變數的requires_grad取決於輸入變數。例如:當變數z的requires_grad屬性為True時,為了求得z的梯度,那麼變數b的requires_grad就必須為true了,而變數x,y,a的requires_grad屬性都為False。
將事先建立的變數,如x、y、z稱為建立變數;像a、b這樣由其他變數運算得到的稱為結果變數。
from torch.autograd import Variable x = Variable(torch.randn(2,2)) y = Variable(torch.randn(2,2)) z = Variable(torch.randn(2,2),requires_grad=True) a = x+y b = a+z print(x.requires_grad,y.requires_grad,z.requires_grad) # False,False,True print(a.requires_grad,b.requires_grad) # False,True print(x.requires_grad) # True print(a.requires_grad) # True
呼叫backward()計算梯度
import torch as t from torch.autograd import Variable as v a = v(t.FloatTensor([2,requires_grad=True) b = a + 3 c = b * b * 3 out = c.mean() out.backward(retain_graph=True) # 這裡可以不帶引數,預設值為‘1',由於下面我們還要求導,故加上retain_graph=True選項 print(a.grad) # tensor([15.,18.])
backward中的gradient引數使用
a. 最後的結果變數為標量(scalar)
如第二個例子,通過呼叫out.backward()實現對a的求導,這裡預設呼叫了out.backward(gradient=None)或者指定為out.backward(gradient=torch.Tensor([1.0])
b. 最後的結果變數為向量(vector)
import torch from torch.autograd import Variable as V m = V(torch.FloatTensor([2,requires_grad=True) # 注意這裡有兩層括號,非標量 n = V(torch.zeros(2)) n[0] = m[0] ** 2 n[1] = m[1] ** 3 n.backward(gradient=torch.Tensor([1,1]),retain_graph=True) print(m.grad)
結果為:
tensor([ 4.,27.])
如果使用n.backward()的話,那麼就會報如下的錯:RuntimeError: grad can be implicitly created only for scalar outputs
注意:這裡的gradient的維度必須與n的維度相同。其中的原理如下:
在執行z.backward(gradient)的時候,如果z不是一個標量,那麼先構造一個標量的值:L = torch.sum(z*gradient),再計算關於L對各個leaf Variable的梯度。
以上這篇pytorch的梯度計算以及backward方法詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。