PyTorch學習之 自動微分
autograd包
autograd 包是 PyTorch 中所有神經網絡的核心。該 autograd 軟件包爲 Tensors 上的所有操作提供自動微分。它是一個由運行定義的框架,這意味着以代碼運行方式定義你的後向傳播,並且每次迭代都可以不同。
Tensor的屬性設置
屬性 | 說明 |
---|---|
.requires_grad = True | 開始跟蹤針對 tensor 的所有操作 |
.backward() | 自動計算所有梯度 |
.grad | 張量的梯度將累積到其中 |
.deatch() | 停止tensor歷史記錄的追蹤 |
with.torch.no_grad() | 停止跟蹤歷史記錄和使用內存。在評估模型時,這是特別有用,因爲模型在訓練階段具有 requires_grad = True 的可訓練參數有利於調參,但在評估階段我們不需要梯度。 |
Function 類
Function類對於autograd非常重要,Tensor與Function構成一個非循環圖,它保存整個完整的計算過程的歷史信息。.grad_fn屬性保存着創建了張量的Function的引用。如果想計算導數,可以調用Tensor.backward()。
需要注意的是, 當tensor的是標量時, 不需要指定任何參數backward,但若有更多元素,則需要指定一個gradient參數來指定張量的形狀。
代碼
# -*- coding: UTF-8 -*-
"""
Modify: 2019-12-12
"""
import torch
#創建一個張量,設置requires_grad=True來跟蹤與它相關的計算
x = torch.ones(2, 2, requires_grad=True)
print(x)
#輸出
# tensor([[1., 1.],
# [1., 1.]], requires_grad=True)
#針對張量做一個操作
y = x + 2
print(y)
#輸出
# tensor([[3., 3.],
# [3., 3.]], grad_fn=<AddBackward0>)
#y作爲操作的結果被創建,所以它有grad_fn
print(y.grad_fn)
#輸出
#<AddBackward0 object at 0x0000023783F70588>
# 針對y做更多的操作
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標記
# 如果沒有提供相應的參數,輸入的標記默認爲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 0x00000261ADB56208>
# 梯度
#因爲輸出包含了一個標量,out.backward()等同於out.backward(torch.tensor(1.))
out.backward()
#打印梯度 d(out)/dx
print(x.grad)
#輸出
# tensor([[4.5000, 4.5000],
# [4.5000, 4.5000]])
# 下面來看一個雅可比向量積的例子
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000: # y.data.norm(input, p=2) 求y的範數
y = y * 2
print(y)
#輸出
#tensor([ -745.7645, -1334.8055, 385.1612], grad_fn=<MulBackward0>)
#現在在這種情況下,y 不再是一個標量。torch.autograd 不能夠直接計算整個雅可比,
#但是如果我們只想要雅可比向量積,只需要簡單的傳遞向量給 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])
#可以通過將代碼包裹在with torch.no_grad(),
#來停止對從跟蹤歷史中的.requires=True的張量自動求導
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
#輸出
# True
# True
# False