深度學習之PyTorch學習_2.3 自動求梯度

2.3 自動求梯度

2.3.1 屬性跟蹤

Tensor 中的屬性.requires_grad 是用來跟蹤所有操作的,深一步的作用是用來進行梯度傳播,目前可以將其理解爲操作的跟蹤,即對Tensor進行的操作進行描述。

需要創建一個Tensor並將其requires_grad = True

import torch
x = torch.ones(2,2,requires_grad = True)
print(x)
print(x.grad_fn)
# .grad_fn 用來顯示操作的類型
# 此時 x 剛被創建 所以操作類型爲 None
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
None
y = x + 2
print(y)
print(y.grad_fn)
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)
<AddBackward0 object at 0x0000022A5C33F198>

y 是通過x創建的 所以y的操作類型顯示的是加法操作 AddBackward0

直接創建的x 成爲葉子節點,葉子結點對應的grad_fn 是 None

z = y * y * 3
out = z.mean()
print(z)
print(out)
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>)
tensor(27., grad_fn=<MeanBackward0>)

可以通過.requires_grad_() 來改變 requires_grad的屬性

a = torch.randn(2,2)
a = a * 5
print(a)
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
tensor([[ 6.1521, -4.8040],
        [-0.3007,  6.0043]])
False
True
<SumBackward0 object at 0x0000022A5C04E828>

2.3.2 梯度

print(out)
tensor(27., grad_fn=<MeanBackward0>)
out.backward() # .backward() 只能在第一次運行 之後運行必須重新運行前面的步驟
print(x.grad)
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

這裏的梯度計算就是求out 對x 的偏導
在這裏插入圖片描述

grad反向傳播過程中是累加的,所以每次方向傳播前需要將梯度清零 .grad.data.zero_()

out2 = x.sum()
out2.backward()
print(x.grad)

out3 = x.sum()
x.grad.data.zero_() # 將之前的梯度清零
out3.backward()
print(x.grad)
tensor([[5.5000, 5.5000],
        [5.5000, 5.5000]])
tensor([[1., 1.],
        [1., 1.]])

目前只允許標量對張量求導,求導結果是和自變量相同的張量

如果是對張量求導,則需要引入一個相同張量加權成標量

具體操作如下例

x = torch.tensor([1.0,2.0,3.0,4.0], requires_grad = True)
y = 2 * x
z = y.view(2,2)
print(z)
tensor([[2., 4.],
        [6., 8.]], grad_fn=<ViewBackward>)

可以看出 z 不是一個標量,所以在調用backward時需要傳入一個和z相同的權重向量進行加權求和得到一個標量

v = torch.tensor([[1.0,0.1],[0.01,0.001]],dtype = torch.float)
z.backward(v)
print(x.grad)
tensor([2.0000, 0.2000, 0.0200, 0.0020])

這裏的z.backward(v)計算過程如下,摘自原文
在這裏插入圖片描述

如何中斷梯度追蹤

在計算過程中執行torch.no_grad(): 下的計算不會被追蹤,求導時也不會被記錄

x = torch.tensor(1.0,requires_grad = True)
y1 = x ** 2
with torch.no_grad():
    y2 = x ** 3
y3 = y1 + y2

print(x.requires_grad)
print(y1, y1.requires_grad)
print(y2, y2.requires_grad)
print(y3, y3.requires_grad)

True
tensor(1., grad_fn=<PowBackward0>) True
tensor(1.) False
tensor(2., grad_fn=<AddBackward0>) True

可以看出 y2 的計算沒有被跟蹤

y3.backward()
print(x.grad)

tensor(2.)

如何修改Tensor 的值 而不影響反向傳播 即梯度計算 可以利用Tensor.data

x = torch.ones(1,requires_grad = True)

print(x.data)
print(x.data.requires_grad) 

y = x * 2
x.data *= 100

y.backward()
print(x)
print(x.grad)
# 

tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])

【總結】

  1. 如何跟蹤計算過程的屬性 requires_grad = True
  2. 梯度是如何計算的 .backward() 就是求偏導數
  3. 標量對張量求導 張量對張量求導
  4. 中斷梯度跟蹤 torch.no_grad()
  5. 改變tensor 不改變梯度 .data
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章