Autograd 自動求導機制
PyTorch 中所有神經網絡的核心是
autograd
包。
autograd
包為張量上的所有操作提供了自動求導。它是一個在運作時定義的架構,可以通過代碼的運作來決定反向傳播的過程,并且每次疊代可以是不同的。
通過一些示例來了解
Tensor 張量
torch.tensor
是這個包的核心類。
- 設定
為.requires_grad
,會追蹤所有對于該張量的操作。計算完成後調用True
,可以自動計算所有的梯度,并自動累計到.backward()
屬性中.grad
事實上即使為
.requires_grad
并不意味着
True
一定不為
.grad
None
- 可以調用
将該張量與計算曆史記錄分離,并禁止跟蹤它将來的計算記錄.detach()
- 為防止跟蹤曆史記錄(和使用記憶體),可以将代碼塊包裝在
中。這在評估模型時特别有用,因為模型可能具有with torch.no_grad():
的可訓練參數,但是我們不需要梯度計算。requires_grad = True
Function類
Tensor
和
Function
互相連接配接并生成一個非循環圖,它表示和存儲了完整的計算曆史。
每個張量都有一個
.grad_fn
屬性,這個屬性引用了一個建立了
Tensor
的
Function
(除非這個張量是使用者手動建立的,即,這個張量的
grad_fn
是
None
)
leaf Tensors 葉張量中有一屬性
Tensor
,當它為
is_leaf
有兩種情況:
True
- 按照慣例,
的 Tensor
requires_grad = False
且由使用者建立的 Tensor。這意味着它們不是操作的結果且
requires_grad = True
隻有leaf Tensors葉張量在反向傳播時才會将本身的
grad_fn = None
傳入
grad
的運算中。要想得到non-leaf Tensors非葉張量在反向傳播時的
backward()
,可以使用
grad
retain_grad()
如果需要計算導數,可以在
Tensor
上調用
.backward()
:若
Tensor
是一個标量(即包含一個元素資料)則不需要為
backward()
指定任何參數, 但是如果它有更多的元素,需要指定一個
gradient
參數來比對張量的形狀。
x = torch.ones(2, 2, requires_grad=True)
print(x)
# Output:
# tensor([[1., 1.],
# [1., 1.]], requires_grad=True)
y = x + 2
print(y)
# Output:
# tensor([[3., 3.],
# [3., 3.]], grad_fn=<AddBackward0>)
此時,
y
已經被計算出來,
grad_fn
已經自動生成了
>>> print(y.grad_fn)
<AddBackward0 object at 0x0000013D6C2AB848>
對y進行操作
z = y * y * 3
out = z.mean()
print(z, out)
# Output:
# tensor([[27., 27.],
# [27., 27.]], grad_fn=<MulBackward0>) # tensor(27., grad_fn=<MeanBackward0>)
.requires_grad_( ... )
可以改變現有張量的
requires_grad
屬性。 如果沒有指定的話,預設輸入的flag是
False
Gradients 梯度
現在開始反向傳播
因為
out
是一個标量,是以不需要為
backward()
指定任何參數:
out.backward()
print(x.grad)
# Output:
# tensor([[4.5000, 4.5000],
# [4.5000, 4.5000]])

現在讓我們來看一個vector-Jacobian product的例子
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
# Output:
# tensor([ 293.4463, 50.6356, 1031.2501], grad_fn=<MulBackward0>)
此處 y.data.norm()
指y的範數,即(y_1^2 + … + y_n2)(1/2)
在這個情形中,y不再是個标量。
torch.autograd
無法直接計算出完整的雅可比行列,但是如果我們隻想要vector-Jacobian product,隻需将向量作為參數傳入
backward
:
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
# Output:
# tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
如果
.requires_grad=True
但是你又不希望進行autograd的計算, 那麼可以将變量包裹在
with torch.no_grad()
中:
print(x.requires_grad) # True
print((x ** 2).requires_grad) # True
with torch.no_grad():
print((x ** 2).requires_grad) # False