日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Pytorch学习之梯度计算backward函数

發布時間:2023/12/19 综合教程 29 生活家
生活随笔 收集整理的這篇文章主要介紹了 Pytorch学习之梯度计算backward函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Pytorch在梯度方面提供的功能,大多是為神經網絡而設計的。而官方文檔給出的定義和解釋比較抽象。以下將結合實例,總結一下自己對Pytorch中梯度計算backward函數的理解。

1. 簡單的神經網絡構建

首先我們看一個非常簡單的神經網絡。

假設x1,x2是神經網絡的中間層,y是我們的輸出層,Y是真實值,L是loss。w1和w2是對應于x1和x2的weight。
上圖用數學公式表示為:

(x2= w1 * x1)
(y = w2 * x2)
(L = Y - y)

通常我們會把x1,w1,w2,x2,y使用PyTorch的Tensor進行表示。L也可以用Tensor表示(維度可能與其他Tensor不同)。
其中,我們把需要自己設定的Tensor(即不是通過其他Tensor計算得來的)叫做葉子Tensor。比如x1,w1和w2就是所謂的葉子Tensor。
在pytorch中,我們把上述模型表示出來。

import torch
import numpy as np
 
x1 = torch.from_numpy( 2*np.ones((2, 2), dtype=np.float32) )
x1.requires_grad_(True)   #設置該tensor可被記錄操作用于梯度計算
w1 = torch.from_numpy( 5*np.ones((2, 2), dtype=np.float32) )
w1.requires_grad_(True)
print("x1 =", x1)
print("w1 =", w1)
 
x2 = x1 * w1
w2 = torch.from_numpy( 6*np.ones((2,2), dtype=np.float32) )
w2.requires_grad_(True)
print("x2 =", x2)
print("w2 =", w2)
 
y = x2 * w2
Y = torch.from_numpy( 10*np.ones((2,2), dtype=np.float32) )
print("y =", y)
print("Y =", Y)
 
L = Y - y
x1 = tensor([[2., 2.],
        [2., 2.]], requires_grad=True)
w1 = tensor([[5., 5.],
        [5., 5.]], requires_grad=True)
x2 = tensor([[10., 10.],
        [10., 10.]], grad_fn=<MulBackward0>)
w2 = tensor([[6., 6.],
        [6., 6.]], requires_grad=True)
y = tensor([[60., 60.],
        [60., 60.]], grad_fn=<MulBackward0>)
Y = tensor([[10., 10.],
        [10., 10.]])

上述代碼注意:

設置一個tensor的 requires_grad為True 會保存該Tensor是否記錄所有操作用于計算梯度,可直接在創建tensor時指定屬性requires_grad = True,也可以使用函數x.requires_grad_(True)。
通過運算得到的Tensor(非自己創建的tensor),會自動被賦值grad_fn屬性。該屬性表示梯度函數。

2. 反向傳播的梯度計算

上述前向傳播計算完成后,想要計算反向傳播(BP)的梯度。基本原理即為求導的鏈式法則。上述網絡的求導即為:

PyTorch提供了backward函數用于計算梯度 ,這一求解過程變為:

L.backward(torch.ones(2, 2, dtype=torch.float))

對于最后的Tensor L執行backward()函數,會計算之前參與運算并生成當前Tensor的葉子Tensor的梯度。其梯度值會保存在葉子Tensor的.grad屬性中。
比如上述網絡中,x1,w1和w2就是所謂的葉子Tensor。

print(x1.grad) # 查看L對于x1的梯度
print(w1.grad) # L對于w1的梯度
print(w2.grad)
tensor([[-30., -30.],
        [-30., -30.]])
tensor([[-12., -12.],
        [-12., -12.]])
tensor([[-10., -10.],
        [-10., -10.]])

1. backward函數的gradient參數解釋

gradient 在PyTorch的官方文檔上解釋的比較晦澀,我理解這個參數表示的是 網絡的輸出tensor(假設為L)對于當前調用backward()函數的Tensor(假設為Y)的導數,即(gradient = frac{partial L}{partial Y})。
(1) 比如在我上述的模型輸出tensor為L,當前調用backward的tensor也為為L,則gradient表示為(frac{partial L}{partial L}=1),也就是element全為1的Tensor。gradient維度需要 與 調用backward()函數的Tensor的維度相同。即L.backward(torch.ones(2, 2, dtype=torch.float))
(2) 又比如,假設我們不知道L關于y的函數表示,但知道L關于y的梯度(即(frac{partial L}{partial y}=-1))時,我們可以在特定位置,比如中間節點y調用backward函數,通過y.backward(-1 * torch.ones(2, 2, dtype=torch.float))來完成反向計算梯度過程。 這樣的設計通過鏈式法則,可以在特定位置求梯度值。
(3) 對于L為標量(常數)的情況,可不指定任何參數,默認參數為torch.tensor(1)。對于L為高于1維的情況,則需要明確指定backward()的第一個參數。

2. backward函數的其他注意點

(1) 默認同一個運算得到的Tensor僅能進行一次backward()。若要再次進行backward(),則要再次運算得到的Tesnor。
(2) 當多個Tensor從相同的源Tensor運算得到,這些運算得到的Tensor的backwards()方法將向源Tensor的grad屬性中進行數值累加。
比如上述實例中,假設有另一個tensor L2是通過對x1的運算得到的,那么L2.backward()執行后梯度結果將累加到x1.grad中。

print("x1.grad =",x1.grad) # 原來x1的梯度 
L2 = x1 * x1
L2.backward(torch.ones(2, 2, dtype=torch.float))
print("x1.grad =", x1.grad) # 計算L2的backward后梯度結果將累加到x1.grad中
x1.grad = tensor([[-26., -26.],
        [-26., -26.]])
x1.grad = tensor([[-22., -22.],
        [-22., -22.]])

(3) 只有葉子tensor(自己創建不是通過其他Tensor計算得來的)才能計算梯度。否則對于非葉子的x1執行L.backwar()后,x1.grad將為None。定義葉子節點時需注意要直接用torch創建且不能經過tensor計算。例如將實例中的x1定義改為x1 = 2 * torch.ones(2, 2, requires_grad=True, dtype=torch.float) 其實它已經做了tensor計算,x1將不再是葉子,表達式中torch.ones()才是葉子。

總結

以上是生活随笔為你收集整理的Pytorch学习之梯度计算backward函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。