網(wǎng)站建設(shè)功能要求廣州seo招聘信息
目錄
1. 梯度基本計算
2. 控制梯度計算
3. 梯度計算注意
4. 小節(jié)
個人主頁:Icomi
專欄地址:PyTorch入門
在深度學(xué)習(xí)蓬勃發(fā)展的當(dāng)下,PyTorch 是不可或缺的工具。它作為強(qiáng)大的深度學(xué)習(xí)框架,為構(gòu)建和訓(xùn)練神經(jīng)網(wǎng)絡(luò)提供了高效且靈活的平臺。神經(jīng)網(wǎng)絡(luò)作為人工智能的核心技術(shù),能夠處理復(fù)雜的數(shù)據(jù)模式。通過 PyTorch,我們可以輕松搭建各類神經(jīng)網(wǎng)絡(luò)模型,實現(xiàn)從基礎(chǔ)到高級的人工智能應(yīng)用。接下來,就讓我們一同走進(jìn) PyTorch 的世界,探索神經(jīng)網(wǎng)絡(luò)與人工智能的奧秘。本系列為PyTorch入門文章,若各位大佬想持續(xù)跟進(jìn),歡迎與我交流互關(guān)。
咱們已經(jīng)見識了 PyTorch 為張量封裝的眾多實用計算函數(shù),這些函數(shù)就像我們在數(shù)據(jù)處理旅程中的得力助手,幫我們解決了不少計算難題。但深度學(xué)習(xí)的探索之旅永無止境,接下來,我們要踏入一個更為關(guān)鍵且神奇的領(lǐng)域 —— 自動微分(Autograd)模塊。
想象一下,我們構(gòu)建的神經(jīng)網(wǎng)絡(luò)就像一臺超級復(fù)雜的智能機(jī)器,它能從海量的數(shù)據(jù)中學(xué)習(xí)規(guī)律,做出精準(zhǔn)的預(yù)測。而在這臺 “智能機(jī)器” 的運行過程中,參數(shù)的調(diào)整就如同精細(xì)地調(diào)校機(jī)器的各個零部件,讓它能不斷優(yōu)化性能。這時,自動微分(Autograd)模塊就如同一位無比精準(zhǔn)的 “調(diào)校大師”,對張量做了進(jìn)一步的封裝,賦予了它們一項極為強(qiáng)大的能力 —— 自動求導(dǎo)。
自動微分模塊可不是一個普通的工具,它可是構(gòu)成神經(jīng)網(wǎng)絡(luò)訓(xùn)練的必要模塊,就如同發(fā)動機(jī)對于汽車的重要性一樣。在神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程中,我們可以把它看作是一個幕后英雄,默默地推動著整個網(wǎng)絡(luò)的優(yōu)化進(jìn)程。
具體來說,在神經(jīng)網(wǎng)絡(luò)的反向傳播過程中,這個 “調(diào)校大師” Autograd 模塊會基于正向計算的結(jié)果對當(dāng)前的參數(shù)進(jìn)行微分計算。這就好比在我們駕駛一輛汽車時,根據(jù)當(dāng)前行駛的路線和目的地,通過精確計算來調(diào)整方向盤的角度和油門的力度。Autograd 模塊通過這種微分計算,精確地算出每個參數(shù)對最終結(jié)果的影響程度,從而實現(xiàn)網(wǎng)絡(luò)權(quán)重參數(shù)的更新,讓神經(jīng)網(wǎng)絡(luò)能夠不斷學(xué)習(xí)和進(jìn)步,變得越來越 “聰明”。
????????接下來我們要深入學(xué)習(xí)這個自動微分(Autograd)模塊,掌握它的原理和使用方法,這將為我們理解神經(jīng)網(wǎng)絡(luò)的訓(xùn)練機(jī)制打開一扇關(guān)鍵的大門。
1. 梯度基本計算
我們使用 backward 方法、grad 屬性來實現(xiàn)梯度的計算和訪問.
import torch# 1. 單標(biāo)量梯度的計算
# 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)# 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é)果必須是標(biāo)量# 而 f 的結(jié)果是: tensor([120., 420.])# 所以, 不能直接自動微分# 需要將結(jié)果計算為標(biāo)量才能進(jìn)行計算f2 = f1.mean() # f2 = 1/2 * x# 自動微分f2.backward()# 打印 x 變量的梯度print(x.grad)# 3. 多標(biāo)量梯度計算
# 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)闃?biāo)量y = y.sum()# 自動微分y.backward()# 打印兩個變量的梯度print(x1.grad, x2.grad)# 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 * x2print(y)# 將輸出結(jié)果變?yōu)闃?biāo)量y = y.sum()# 自動微分y.backward()# 打印兩個變量的梯度print(x1.grad, x2.grad)if __name__ == '__main__':test04()
2. 控制梯度計算
我們可以通過一些方法使得在 requires_grad=True 的張量在某些時候計算不進(jìn)行梯度計算。
import torch# 1. 控制不計算梯度
def test01():x = torch.tensor(10, requires_grad=True, dtype=torch.float64)print(x.requires_grad)# 第一種方式: 對代碼進(jìn)行裝飾with torch.no_grad():y = x ** 2print(y.requires_grad)# 第二種方式: 對函數(shù)進(jìn)行裝飾@torch.no_grad()def my_func(x):return x ** 2print(my_func(x).requires_grad)# 第三種方式torch.set_grad_enabled(False)y = x ** 2print(y.requires_grad)# 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 + 20f2 = f1.mean()# 默認(rèn)張量的 grad 屬性會累計歷史梯度值# 所以, 需要我們每次手動清理上次的梯度# 注意: 一開始梯度不存在, 需要做判斷if x.grad is not None:x.grad.data.zero_()f2.backward()print(x.grad)# 3. 梯度下降優(yōu)化最優(yōu)解
def test03():# y = x**2x = 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.gradprint('%.10f' % x.data)if __name__ == '__main__':test01()test02()test03()
3. 梯度計算注意
當(dāng)對設(shè)置 requires_grad=True 的張量使用 numpy 函數(shù)進(jìn)行轉(zhuǎn)換時, 會出現(xiàn)如下報錯:
Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
此時, 需要先使用 detach 函數(shù)將張量進(jìn)行分離, 再使用 numpy 函數(shù).
注意: detach 之后會產(chǎn)生一個新的張量, 新的張量作為葉子結(jié)點,并且該張量和原來的張量共享數(shù)據(jù), 但是分離后的張量不需要計算梯度。
import torch# 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()) # 正確# 2. detach 前后張量共享內(nèi)存
def test02():x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)# x2 作為葉子結(jié)點x2 = x1.detach()# 兩個張量的值一樣: 140421811165776 140421811165776print(id(x1.data), id(x2.data))x2.data = torch.tensor([100, 200])print(x1)print(x2)# x2 不會自動計算梯度: Falseprint(x2.requires_grad)if __name__ == '__main__':test01()test02()
4. 小節(jié)
本小節(jié)主要講解了 PyTorch 中非常重要的自動微分模塊的使用和理解。我們對需要計算梯度的張量需要設(shè)置 requires_grad=True 屬性,并且需要注意的是梯度是累計的,在每次計算梯度前需要先進(jìn)行梯度清零。