PyTorch Autograd自動求導(dǎo)

2023-01-30 16:29 更新

原文:?https://///pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html
譯者:?bat67
驗證者:?FontTian
作者:??Soumith Chintala

PyTorch中,所有神經(jīng)網(wǎng)絡(luò)的核心是autograd包。先簡單介紹一下這個包,然后訓(xùn)練我們的第一個的神經(jīng)網(wǎng)絡(luò)。 autograd包為張量上的所有操作提供了自動求導(dǎo)機(jī)制。它是一個在運(yùn)行時定義(define-by-run)的框架,這意味著反向傳播是根據(jù)代碼如何運(yùn)行來決定的,并且每次迭代可以是不同的. 讓我們用一些簡單的例子來看看吧。

張量

torch.Tensor是這個包的核心類。如果設(shè)置它的屬性?.requires_gradTrue,那么它將會追蹤對于該張量的所有操作。當(dāng)完成計算后可以通過調(diào)用.backward(),來自動計算所有的梯度。這個張量的所有梯度將會自動累加到.grad屬性. 要阻止一個張量被跟蹤歷史,可以調(diào)用.detach()方法將其與計算歷史分離,并阻止它未來的計算記錄被跟蹤。

為了防止跟蹤歷史記錄(和使用內(nèi)存),可以將代碼塊包裝在with torch.no_grad():中。在評估模型時特別有用,因為模型可能具有requires_grad = True的可訓(xùn)練的參數(shù),但是我們不需要在此過程中對他們進(jìn)行梯度計算。 還有一個類對于autograd的實現(xiàn)非常重要:Function。 TensorFunction互相連接生成了一個非循環(huán)圖,它編碼了完整的計算歷史。每個張量都有一個.grad_fn屬性,它引用了一個創(chuàng)建了這個TensorFunction(除非這個張量是用戶手動創(chuàng)建的,即這個張量的grad_fnNone)。 如果需要計算導(dǎo)數(shù),可以在Tensor上調(diào)用.backward()。如果Tensor是一個標(biāo)量(即它包含一個元素的數(shù)據(jù)),則不需要為backward()指定任何參數(shù),但是如果它有更多的元素,則需要指定一個gradient參數(shù),它是形狀匹配的張量。

import torch

創(chuàng)建一個張量并設(shè)置requires_grad=True用來追蹤其計算歷史

x = torch.ones(2, 2, requires_grad=True)
print(x)

輸出:

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

對這個張量做一次運(yùn)算:

y = x + 2
print(y)

輸出:

tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)

y是計算的結(jié)果,所以它有grad_fn屬性。

print(y.grad_fn)

輸出:

<AddBackward0 object at 0x7f1b248453c8>

對y進(jìn)行更多操作

z = y * y * 3
out = z.mean()


print(z, out)

輸出:

tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)

.requires_grad_(...)?原地改變了現(xiàn)有張量的?requires_grad?標(biāo)志。如果沒有指定的話,默認(rèn)輸入的這個標(biāo)志是False

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)

輸出:

False
True
<SumBackward0 object at 0x7f1b24845f98>

梯度

因為out是一個標(biāo)量。所以讓我們直接進(jìn)行反向傳播,out.backward()out.backward(torch.tensor(1.))等價

out.backward()

輸出導(dǎo)數(shù)d(out)/dx

print(x.grad)

輸出:

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

計算過程如下,實質(zhì)就是一個標(biāo)量函數(shù)對于各個分量求偏導(dǎo)數(shù)

數(shù)學(xué)上,若有向量值函數(shù)y=f(x),那么y相對于x的梯度是一個雅各比矩陣:

通常來說,torch.autograd是計算雅各比向量積的一個“引擎”。也就是說,給定任意向量V= 計算乘積J.v。如果v恰好是一個標(biāo)量函數(shù)即V= 根據(jù)鏈?zhǔn)椒▌t,雅克比向量積應(yīng)該是l對x的導(dǎo)數(shù)

雅可比向量積的這一特性使得將外部梯度輸入到具有非標(biāo)量輸出的模型中變得非常方便。 現(xiàn)在我們來看一個雅可比向量積的例子:

x = torch.randn(3, requires_grad=True)


y = x * 2
while y.data.norm() < 1000:
    y = y * 2


print(y)

輸出:

tensor([-278.6740,  935.4016,  439.6572], grad_fn=<MulBackward0>)

在這種情況下,y不再是標(biāo)量。torch.autograd不能直接計算完整的雅可比矩陣,但是如果我們只想要雅可比向量積,只需將這個向量作為參數(shù)傳給backward

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)


print(x.grad)

輸出:

tensor([4.0960e+02, 4.0960e+03, 4.0960e-01])

為了防止跟蹤歷史記錄(和使用內(nèi)存),可以將代碼塊包裝在with torch.no_grad():中。在評估模型時特別有用,因為模型可能具有requires_grad = True的可訓(xùn)練的參數(shù),但是我們不需要在此過程中對他們進(jìn)行梯度計算。 也可以通過將代碼塊包裝在?with torch.no_grad():?中,來阻止autograd跟蹤設(shè)置了?.requires_grad=True?的張量的歷史記錄。

print(x.requires_grad)
print((x ** 2).requires_grad)


with torch.no_grad():
    print((x ** 2).requires_grad)

輸出:

True
True
False

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號