PyTorch學(xué)習(xí)筆記(三):自動求導(dǎo)Autograd

現(xiàn)代神經(jīng)網(wǎng)絡(luò)依靠反向傳播(Back Propogation)算法來對模型進行優(yōu)化,其本質(zhì)是大規(guī)模鏈?zhǔn)角髮?dǎo)。因此,能夠?qū)νㄟ^編程來對網(wǎng)絡(luò)參數(shù)進行求導(dǎo)是非常重要的。目前的深度學(xué)習(xí)框架神經(jīng)網(wǎng)絡(luò)如PyTorch和TensorFlow等都實現(xiàn)了自動求梯度的功能。

計算圖

計算圖(Computation Graph)是現(xiàn)代深度學(xué)習(xí)框架的核心,其為高效自動求導(dǎo)算法——反向傳播(Back Propogation)提供了理論支持。如下所示,計算圖是一種特殊的有向無環(huán)圖(DAG),用于記錄算子與變量之間的關(guān)系。

計算圖

計算圖具有兩個優(yōu)勢:
a. 使用非常簡單的函數(shù)就可以組合成一個極其復(fù)雜的模型;
b. 可以實現(xiàn)自動微分。

在PyTorch中,通過記錄算子與變量之間的關(guān)系可以生成表達(dá)式對應(yīng)的計算圖。對于表達(dá)式y = wx + b,其中w、xb是變量,+=是算子。有DAG中,wxb是葉子節(jié)點(leaf node),這些節(jié)點通常由用戶自己創(chuàng)建,不依賴于其他變量。y稱為根節(jié)點,是計算圖的最終目標(biāo)。

>>> x = torch.ones(2, 2)
>>> w = torch.rand(2, 2, requires_grad=True)
>>> b = torch.rand(2, 2, requires_grad=True)
>>> y = w * x + b
>>> x.is_leaf, w.is_leaf, b.is_leaf
(True, True, True)
>>> y.is_leaf
False
>>>

自動求導(dǎo)

在創(chuàng)建tensor的時候指定requires_grad參數(shù)或者使用requires_grad_()函數(shù)來指定是否對該參數(shù)進行自動求導(dǎo)。

>>> x = torch.ones(2, 2)
>>> w = torch.rand(2, 2, requires_grad=True)
>>> b = torch.rand(2, 2, requires_grad=True)
>>> y = w * x + b

x.requires_grad未指定自動求導(dǎo),因此是False,w.requires_gradb.requires_grad為我們的求導(dǎo)對象,因此是True。雖然未指定y.requires_grad為True,但由于y依賴于需要求導(dǎo)的w,因此y.requires_grad為True。

>>> x.requires_grad, b.requires_grad, w.requires_grad
(False, True, True)
>>> y.requires_grad
True

有了計算圖之后,對根節(jié)點調(diào)用backward()函數(shù)進行反向傳播,就能夠得到各個需要求導(dǎo)的葉子的導(dǎo)數(shù),通過grad屬性即可得到。

>>> y = w * x + b
>>> y.backward()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "F:\ProgramData\Anaconda3\lib\site-packages\torch\tensor.py", line 102, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "F:\ProgramData\Anaconda3\lib\site-packages\torch\autograd\__init__.py", line 84, in backward
    grad_tensors = _make_grads(tensors, grad_tensors)
  File "F:\ProgramData\Anaconda3\lib\site-packages\torch\autograd\__init__.py", line 28, in _make_grads
    raise RuntimeError("grad can be implicitly created only for scalar outputs")
RuntimeError: grad can be implicitly created only for scalar outputs

如果對非標(biāo)量y求導(dǎo),函數(shù)需要額外指定grad_tensors,grad_tensors的shape必須和y的相同。

>>> weights = torch.ones(2, 2)
>>> y.backward(weights, retain_graph=True)
>>> w.grad
tensor([[1., 1.],
        [1., 1.]])

此外,PyTorch中梯度是累加的,每次反向傳播之后,當(dāng)前的梯度值會累加到舊的梯度值上。

>>> y.backward(weights, retain_graph=True)
>>> w.grad
tensor([[2., 2.],
        [2., 2.]])
>>> y.backward(weights, retain_graph=True)
>>> w.grad
tensor([[3., 3.],
        [3., 3.]])

要清空變量當(dāng)前的梯度,可以使用zero()zero_()函數(shù)。

>>> w.grad.zero_()
tensor([[0., 0.],
        [0., 0.]])
>>> w.grad
tensor([[0., 0.],
        [0., 0.]])

PS:在我們使用PyTorch構(gòu)建網(wǎng)絡(luò)時,Model會在反向傳播時會自行處理梯度更新問題,上述知識有助于理解PyToch中的自動求導(dǎo)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容