1. 程式人生 > 程式設計 >pytorch的梯度計算以及backward方法詳解

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方法詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。