PyTorch中backward()函數的gradient參數作用


這篇文章講得比較清晰,特地備份一下: pytorch中backward函數的gradient參數作用

問題引入

在深度學習中,經常需要對函數求梯度(gradient)。PyTorch提供的autograd包能夠根據輸入和前向傳播過程自動構建計算圖,並執行反向傳播。

PyTorch中,torch.Tensor是存儲和變換數據的主要工具。如果你之前用過NumPy,你會發現TensorNumPy的多維數組非常類似。

然而,Tensor提供GPU計算和自動求梯度等更多功能,這些使Tensor更加適合深度學習。

PyTorchtensor這個單詞一般可譯作張量,張量可以看作是一個多維數組。標量可以看作是零維張量,向量可以看作一維張量,矩陣可以看作是二維張量。

如果將PyTorch中的tensor屬性requires_grad設置為True,它將開始追蹤(track)在其上的所有操作(這樣就可以利用鏈式法則進行梯度傳播了)。

完成計算后,可以調用backward()來完成所有梯度計算。此tensor的梯度將累積到grad屬性中。 如下:

import torch

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x ** 2 + 2
z = torch.sum(y)
z.backward()
print(x.grad)

輸出:

tensor([2., 4., 6.])

下面先解釋下這個grad怎么算的。

導數、偏導數的簡單計算

從數學定義上講,求導或者求偏導大多是函數對自變量而言。但是在很多機器學習的資料和開源庫都會看到說標量對向量求導。

先簡單解釋下上面的例子:

\(x=[x_1,x_2,x_3]\) ,則

\[z=x_1^2+x_2^2+x_3^2+6 \]

由求偏導的數學知識,可知:

\[\frac{\partial z}{\partial x_1}=2x_1 \]

\[\frac{\partial z}{\partial x_2}=2x_2 \]

\[\frac{\partial z}{\partial x_3}=2x_3 \]

然后把\(x_1=1.0\),\(x_2=2.0\),\(x_3=3.0\)代入得到:

\[(\frac{\partial z}{\partial x_1},\frac{\partial z}{\partial x_2},\frac{\partial z}{\partial x_3})=(2x_1,2x_2,2x_3)=(2.0,4.0,6.0) \]

可見結果與PyTorch的輸出一致。這時再反過來想想,其實所謂的標量對向量求導,本質上是函數對各個自變量求導,這里只是把各個自變量看成一個向量,和數學上的定義並不沖突。

backward的gradient參數作用

在上面調用z.backward()時,是可以傳入一些參數的,如下所示:

不知道你是怎么理解這里的gradient參數的,有深入理解這個參數的朋友歡迎評論區分享你的高見!

同樣,先看下面的例子。已知

\[y_1=x_1x_2x_3 \]

\[y_2=x_1+x_2+x_3 \]

\[y_3=x_1+x_2x_3 \]

\[A=f(y_1,y_2,y_3) \]

其中函數\(f(y_1,y_2,y_3)\)的具體定義未知,現在求

\[\frac{\partial A}{\partial x_1}=? \]

\[\frac{\partial A}{\partial x_2}=? \]

\[\frac{\partial A}{\partial x_3}=? \]

根據多元復合函數的求導法則,有:

\[\frac{\partial A}{\partial x_1}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_1}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_1}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_1} \]

\[\frac{\partial A}{\partial x_2}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_2}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_2}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_2} \]

\[\frac{\partial A}{\partial x_3}=\frac{\partial A}{\partial y_1}\frac{\partial y_1}{\partial x_3}+\frac{\partial A}{\partial y_2}\frac{\partial y_2}{\partial x_3}+\frac{\partial A}{\partial y_3}\frac{\partial y_3}{\partial x_3} \]

上面3個等式可以寫成矩陣相乘的形式,如下:

\[[\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}]= [\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}] \left[ \begin{matrix} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \frac{\partial y_1}{\partial x_3} \\ \frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \frac{\partial y_2}{\partial x_3} \\ \frac{\partial y_3}{\partial x_1} & \frac{\partial y_3}{\partial x_2} & \frac{\partial y_3}{\partial x_3} \end{matrix} \right] \]

其中

\[\left[ \begin{matrix} \frac{\partial y_1}{\partial x_1} & \frac{\partial y_1}{\partial x_2} & \frac{\partial y_1}{\partial x_3} \\ \frac{\partial y_2}{\partial x_1} & \frac{\partial y_2}{\partial x_2} & \frac{\partial y_2}{\partial x_3} \\ \frac{\partial y_3}{\partial x_1} & \frac{\partial y_3}{\partial x_2} & \frac{\partial y_3}{\partial x_3} \end{matrix} \right] \]

叫作雅可比(Jacobian)式。雅可比式可以根據已知條件求出。

現在只要知道\([\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}]\)的值,哪怕不知道\(f(y_1,y_2,y_3)\)的具體形式也能求出來\([\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}]\)

那現在的問題是怎么樣才能求出

\[[\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}] \]

答案是由PyTorchbackward函數的gradient參數提供。這就是gradient參數的作用。

比如,我們傳入gradient參數為torch.tensor([0.1, 0.2, 0.3], dtype=torch.float),並且假定\(x_1=1\),\(x_2=2\),\(x_3=3\),按照上面的推導方法:

\[\begin{split} [\frac{\partial A}{\partial x_1},\frac{\partial A}{\partial x_2},\frac{\partial A}{\partial x_3}] &=[\frac{\partial A}{\partial y_1},\frac{\partial A}{\partial y_2},\frac{\partial A}{\partial y_3}] \left[ \begin{matrix} x_2x_3 & x_1x_3 & x_1x_2 \\ 1 & 1 & 1 \\ 1 & x_3 & x_2 \end{matrix} \right] &=[0.1,0.2,0.3] \left[ \begin{matrix} 6 & 3 & 2 \\ 1 & 1 & 1 \\ 1 & 3 & 2 \end{matrix} \right] &=[1.1,1.4,1.0] \end{split} \]

緊接着可以用代碼驗證一下:

import torch

x1 = torch.tensor(1, requires_grad=True, dtype=torch.float)
x2 = torch.tensor(2, requires_grad=True, dtype=torch.float)
x3 = torch.tensor(3, requires_grad=True, dtype=torch.float)

x = torch.tensor([x1, x2, x3])
y = torch.randn(3)

y[0] = x1 * x2 * x3
y[1] = x1 + x2 + x3
y[2] = x1 + x2 * x3

y.backward(torch.tensor([0.1, 0.2, 0.3], dtype=torch.float))

print(x1.grad, x2.grad, x3.grad)

輸出:

tensor(1.1000) tensor(1.4000) tensor(1.)

由此可見,推導和代碼運行結果一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM