Backward()函數
Backward函數實際上是通過傳遞參數(默認情況下是1x1單位張量)來計算梯度的,它通過Backward圖一直到每個葉節點,每個葉節點都可以從調用的根張量追溯到葉節點。然後將計算出的梯度存儲在每個葉節點的.grad
中。請記住,在正向傳遞過程中已經動態生成了後向圖。backward函數僅使用已生成的圖形計算梯度,並將其存儲在葉節點中。
讓我們分析以下代碼:
import torch
# Creating the graph
x = torch.tensor(1.0, requires_grad = True)
z = x ** 3
z.backward() #Computes the gradient
print(x.grad.data) #Prints '3' which is dz/dx
需要注意的一件重要事情是,當調用z.backward()
時,一個張量會自動傳遞爲z.backward(torch.tensor(1.0))
。torch.tensor(1.0)
是用來終止鏈式法則梯度乘法的外部梯度。這個外部梯度作爲輸入傳遞給MulBackward
函數,以進一步計算x的梯度。傳遞到.backward()
中的張量的維數必須與正在計算梯度的張量的維數相同。例如,如果梯度支持張量x和y如下:
x = torch.tensor([0.0, 2.0, 8.0], requires_grad = True)
y = torch.tensor([5.0 , 1.0 , 7.0], requires_grad = True)
z = x * y
然後,要計算z
關於x
或者y
的梯度,需要將一個外部梯度傳遞給z.backward()
函數,如下所示:
z.backward(torch.FloatTensor([1.0, 1.0, 1.0])
z.backward()
會給出 RuntimeError: grad can be implicitly created only for scalar outputs
反向函數傳遞的張量就像梯度加權輸出的權值。從數學上講,這是一個向量乘以非標量張量的雅可比矩陣(本文將進一步討論),因此它幾乎總是一個維度的單位張量,與 backward
張量相同,除非需要計算加權輸出。
tldr :向後圖是由autograd類在向前傳遞過程中自動動態創建的。
Backward()
只是通過將其參數傳遞給已經生成的反向圖來計算梯度。
更多請看:https://mlog.club/article/25034
數學—雅克比矩陣和向量
從數學上講,autograd類只是一個雅可比向量積計算引擎。雅可比矩陣是一個非常簡單的單詞,它表示兩個向量所有可能的偏導數。它是一個向量相對於另一個向量的梯度。
注意:在這個過程中,PyTorch從不顯式地構造整個雅可比矩陣。直接計算JVP (Jacobian vector product)通常更簡單、更有效。
如果一個向量X = [x1, x2,…xn]通過f(X) = [f1, f2,…fn]來計算其他向量,則雅可比矩陣(J)包含以下所有偏導組合:
雅克比矩陣
上面的矩陣表示f(X)相對於X的梯度。
假設一個啓用PyTorch梯度的張量X:
X = [x1,x2,…,xn](假設這是某個機器學習模型的權值)
X經過一些運算形成一個向量Y
Y = f(X) = [y1, y2,…,ym]
然後使用Y計算標量損失l。假設向量v恰好是標量損失l關於向量Y的梯度,如下:
向量v稱爲grad_tensor
,並作爲參數傳遞給backward()
函數。
爲了得到損失的梯度l關於權重X的梯度,雅可比矩陣J是向量乘以向量v
這種計算雅可比矩陣並將其與向量v相乘的方法使PyTorch能夠輕鬆地爲非標量輸出提供外部梯度。