PyTorch使用自動微分模塊的方法和理解
自動微分(Autograd)模塊對張量做了進一步的封裝,具有自動求導(dǎo)功能。自動微分模塊是構(gòu)成神經(jīng)網(wǎng)絡(luò)訓(xùn)練的必要模塊,在神經(jīng)網(wǎng)絡(luò)的反向傳播過程中,Autograd 模塊基于正向計算的結(jié)果對當前的參數(shù)進行微分計算,從而實現(xiàn)網(wǎng)絡(luò)權(quán)重參數(shù)的更新。
?? 梯度基本計算
我們使用 backward 方法、grad 屬性來實現(xiàn)梯度的計算和訪問.
import torch
1.1 單標量梯度的計算
# y = x**2 + 20
def test01():
# 定義需要求導(dǎo)的張量
# 張量的值類型必須是浮點類型
x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
# 變量經(jīng)過中間運算
f = x ** 2 + 20
# 自動微分
f.backward()
# 打印 x 變量的梯度
# backward 函數(shù)計算的梯度值會存儲在張量的 grad 變量中
print(x.grad)1.2 單向量梯度的計算
# y = x**2 + 20
def test02():
# 定義需要求導(dǎo)張量
x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)
# 變量經(jīng)過中間計算
f1 = x ** 2 + 20
# 注意:
# 由于求導(dǎo)的結(jié)果必須是標量
# 而 f 的結(jié)果是: tensor([120., 420.])
# 所以, 不能直接自動微分
# 需要將結(jié)果計算為標量才能進行計算
f2 = f1.mean() # f2 = 1/2 * x
# 自動微分
f2.backward()
# 打印 x 變量的梯度
print(x.grad)1.3 多標量梯度計算
# y = x1 ** 2 + x2 ** 2 + x1*x2
def test03():
# 定義需要計算梯度的張量
x1 = torch.tensor(10, requires_grad=True, dtype=torch.float64)
x2 = torch.tensor(20, requires_grad=True, dtype=torch.float64)
# 經(jīng)過中間的計算
y = x1**2 + x2**2 + x1*x2
# 將輸出結(jié)果變?yōu)闃肆?
y = y.sum()
# 自動微分
y.backward()
# 打印兩個變量的梯度
print(x1.grad, x2.grad)1.4 多向量梯度計算
def test04():
# 定義需要計算梯度的張量
x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
x2 = torch.tensor([30, 40], requires_grad=True, dtype=torch.float64)
# 經(jīng)過中間的計算
y = x1 ** 2 + x2 ** 2 + x1 * x2
print(y)
# 將輸出結(jié)果變?yōu)闃肆?
y = y.sum()
# 自動微分
y.backward()
# 打印兩個變量的梯度
print(x1.grad, x2.grad)
if __name__ == '__main__':
test04()1.5 運行結(jié)果??
tensor(20., dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor(40., dtype=torch.float64) tensor(50., dtype=torch.float64)
tensor([1300., 2800.], dtype=torch.float64, grad_fn=<AddBackward0>)
tensor([50., 80.], dtype=torch.float64) tensor([ 70., 100.], dtype=torch.float64)
?? 控制梯度計算
我們可以通過一些方法使得在 requires_grad=True 的張量在某些時候計算不進行梯度計算。
import torch
2.1 控制不計算梯度
def test01():
x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
print(x.requires_grad)
# 第一種方式: 對代碼進行裝飾
with torch.no_grad():
y = x ** 2
print(y.requires_grad)
# 第二種方式: 對函數(shù)進行裝飾
@torch.no_grad()
def my_func(x):
return x ** 2
print(my_func(x).requires_grad)
# 第三種方式
torch.set_grad_enabled(False)
y = x ** 2
print(y.requires_grad)2.2 注意: 累計梯度
def test02():
# 定義需要求導(dǎo)張量
x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)
for _ in range(3):
f1 = x ** 2 + 20
f2 = f1.mean()
# 默認張量的 grad 屬性會累計歷史梯度值
# 所以, 需要我們每次手動清理上次的梯度
# 注意: 一開始梯度不存在, 需要做判斷
if x.grad is not None:
x.grad.data.zero_()
f2.backward()
print(x.grad)2.3 梯度下降優(yōu)化最優(yōu)解
def test03():
# y = x**2
x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
for _ in range(5000):
# 正向計算
f = x ** 2
# 梯度清零
if x.grad is not None:
x.grad.data.zero_()
# 反向傳播計算梯度
f.backward()
# 更新參數(shù)
x.data = x.data - 0.001 * x.grad
print('%.10f' % x.data)
if __name__ == '__main__':
test01()
test02()
test03()2.4 運行結(jié)果??
True
False
False
False
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
?? 梯度計算注意
當對設(shè)置 requires_grad=True 的張量使用 numpy 函數(shù)進行轉(zhuǎn)換時, 會出現(xiàn)如下報錯:
Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
此時, 需要先使用 detach 函數(shù)將張量進行分離, 再使用 numpy 函數(shù).
注意: detach 之后會產(chǎn)生一個新的張量, 新的張量作為葉子結(jié)點,并且該張量和原來的張量共享數(shù)據(jù), 但是分離后的張量不需要計算梯度。
import torch
3.1 detach 函數(shù)用法
def test01():
x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
# Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
# print(x.numpy()) # 錯誤
print(x.detach().numpy()) # 正確3.2 detach 前后張量共享內(nèi)存
def test02():
x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
# x2 作為葉子結(jié)點
x2 = x1.detach()
# 兩個張量的值一樣: 140421811165776 140421811165776
print(id(x1.data), id(x2.data))
x2.data = torch.tensor([100, 200])
print(x1)
print(x2)
# x2 不會自動計算梯度: False
print(x2.requires_grad)
if __name__ == '__main__':
test01()
test02()3.3 運行結(jié)果??
10. 20.]
140495634222288 140495634222288
tensor([10., 20.], dtype=torch.float64, requires_grad=True)
tensor([100, 200])
False
?? 小節(jié)
本小節(jié)主要講解了 PyTorch 中非常重要的自動微分模塊的使用和理解。我們對需要計算梯度的張量需要設(shè)置 requires_grad=True 屬性,并且需要注意的是梯度是累計的,在每次計算梯度前需要先進行梯度清零。
到此這篇關(guān)于PyTorch使用自動微分模塊的文章就介紹到這了,更多相關(guān)PyTorch自動微分模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Python 中JSONDecodeError: Expecting value:&n
這篇文章主要介紹了解決Python 中JSONDecodeError: Expecting value: line 1 column 1 (char 0)錯誤問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
注意import和from import 的區(qū)別及說明
這篇文章主要介紹了注意import和from import 的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
Python編寫車票訂購系統(tǒng)?Python實現(xiàn)快遞收費系統(tǒng)
這篇文章主要為大家詳細介紹了Python編寫車票訂購系統(tǒng),Python實現(xiàn)快遞收費系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
Python學(xué)習(xí)小技巧之利用字典的默認行為
這篇文章主要給大家介紹了Python學(xué)習(xí)小技巧之利用字典的默認行為的相關(guān)資料,文中介紹的非常詳細,對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-05-05
Python圖像濾波處理操作示例【基于ImageFilter類】
這篇文章主要介紹了Python圖像濾波處理操作,結(jié)合實例形式分析了Python基于ImageFilter類實現(xiàn)的濾波處理相關(guān)操作技巧,需要的朋友可以參考下2019-01-01
為Python的Tornado框架配置使用Jinja2模板引擎的方法
Jinja2是人氣Web框架Flask中的內(nèi)置模板引擎,而且與Django的模板引擎比較類似,這里我們就來看一下為Python的Tornado框架配置使用Jinja2模板引擎的方法2016-06-06

