PyTorch學習筆記4--PyTorch自動微分


PyTorch所有神經網絡的核心是autograd自動微分。該 autograd 軟件包為 Tensors 上的所有操作提供自動微分。

計算圖 = Tensor + Function

PyTorch也是以計算圖為核心進行微分的。這與TensorFlow中是一致的。在計算圖中,圓圈/矩形等表示Tensor,而線條表示計算操作(TensorFlow里是Ops,PyTorch里是Function,本質相同)。在PyTorch里,TensorFunction互相連接並生成一個非循環圖,它表示和存儲了完整的計算歷史。 每個張量都有一個.grad_fn屬性,這個屬性引用了一個創建該Tensor的Function(除非這個張量是用戶手動創建的,即,這個張量的 grad_fn 是 None)。

  1. 要追蹤所有對於某張量的操作,設置其.requires_gradTrue即可。
  2. 要計算對某張量的梯度,得到某Tensor后對其調用 .backward(),這個張量的所有梯度將會自動積累到 .grad 屬性。
  3. 要阻止張量跟蹤歷史記錄,可以調用.detach()方法將其與計算歷史記錄分離,並禁止跟蹤它將來的計算記錄。

為了防止跟蹤歷史記錄(和使用內存),可以將代碼塊包裝在with torch.no_grad():中。 在評估模型時特別有用,因為模型可能具有requires_grad = True的可訓練參數,但是我們不需要梯度計算。

import torch
#--------------------------------------------
x = torch.ones(2, 2, requires_grad=True)
print(x)
# 新建全1矩陣,跟蹤計算記錄
# 打印結果為
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
#--------------------------------------------
y = x + 2
print(y)
print(y.grad_fn)
# 對張量x進行了操作,得到y,腦袋里思考這里形成了一個什么樣的計算圖
# 打印結果為(grad_fn被自動生成了,顯示了構建此Tensor的Function是加法)
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward>)
<AddBackward object at 0x00000232535FD860>
#--------------------------------------------
z = y * y * 3
out = z.mean()
print(z, out)
# 打印結果為
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward>) tensor(27., grad_fn=<MeanBackward1>)
#--------------------------------------------
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)
# .requires_grad_( ... ) 可以改變現有張量的 requires_grad屬性
# 運行結果為
False
True
<SumBackward0 object at 0x000002325360B438>

以上程序示范了如何使用requires_grad跟蹤Tensor的生成過程,也就是計算圖(模型)的生成過程:其中張量x是2x2的全1矩陣,張量y是2x2的全3矩陣,張量z是2x2的全27矩陣,張量out是標量,z的平均值。

因為\(out=\frac{1}{4} \sum_{i}z_{i}\),而\(z_{i} = 3(x_{i} + 2)^{2}\),因此\(\frac{\partial out}{\partial x_{i}} = \frac{3}{2}(x_{i}+2)\),所以\(\frac{\partial out}{\partial x_{i}}=4.5\)

# ...
# 當計算圖構建完成,可以開始計算梯度了,下面一行代碼自動完成梯度的計算:
out.backward() # out是標量,因此不需要為backward()函數指定參數,相當於out.backward(torch.tensor(1))
print(x.grad) # backward自動計算該Tensor的梯度,x.grad即為到x這里的梯度,指定了自變量為x而非y和z。
# 計算結果為
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

以上代碼講了y為標量情況下的求導方法。以下代碼介紹y為矢量情況下的求導方法。

x = torch.randn(3, requires_grad=True) #創建一個x, size為(1,3),初始化為正態隨機數。
y = x * 2 
while y.data.norm() < 1000: #求得 y^(2^(n))>=1000的最小值
    y = y * 2
print(y)
# 打印結果為
tensor([-920.6895, -115.7301, -867.6995], grad_fn=<MulBackward>)

gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients) #當y為矢量,需要對backward()函數指定參數,該參數指定了求導后的乘因子
print(x.grad)
# 打印結果為
tensor([ 51.2000, 512.0000,   0.0512])
# 如果gradients因子均為1,則結果應為tensor([ 512.0000, 512.0000,   512.0000])

如果.requires_grad=True但是你又不希望進行autograd的計算, 那么可以將變量包裹在 with torch.no_grad()中:

print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
	print((x ** 2).requires_grad)
# 打印結果為
True
True
False


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM