
PyTorch中,所有神經網絡的核心是 autograd 包。autograd 包為張量上的所有操作提供了自動求導機制。它是一個在運行時定義(define-by-run)的框架,這意味著反向傳播是根據代碼如何運行來決定的,並且每次迭代可以是不同的。
張量

張量:n維向量
torch.Tensor 是這個包的核心類。如果設置它的屬性 .requires_grad 為 True,那麼它將會追蹤對於該張量的所有操作。當完成計算後可以通過調用 .backward(),來自動計算所有的梯度。這個張量的所有梯度將會自動累加到.grad屬性。
<code>x = torch.ones(2, 2, requires_grad=True #創建一個張量並設置requires_grad=True用來追蹤其計算歷史 print(x)/<code>
要阻止一個張量被跟蹤歷史,可以調用 .detach() 方法將其與計算歷史分離,並阻止它未來的計算記錄被跟蹤。
為了防止跟蹤歷史記錄(和使用內存),可以將代碼塊包裝在 with torch.no_grad(): 中。在評估模型時特別有用,因為模型可能具有 requires_grad = True 的可訓練的參數,但是我們不需要在此過程中對他們進行梯度計算。
還有一個類對於autograd的實現非常重要:Function。
Tensor 和 Function 互相連接生成了一個無圈圖(acyclic graph),它編碼了完整的計算歷史。每個張量都有一個 .grad_fn 屬性,該屬性引用了創建 Tensor 自身的Function(除非這個張量是用戶手動創建的,即這個張量的 grad_fn 是 None )。
如果需要計算導數,可以在 Tensor 上調用 .backward()。如果 Tensor 是一個標量(即它包含一個元素的數據),則不需要為 backward() 指定任何參數,但是如果它有更多的元素,則需要指定一個 gradient 參數,該參數是形狀匹配的張量。
<code>y = x + 2 # 對這個張量做一次運算/<code>
y是計算的結果,所以它有grad_fn屬性。
<code>z = y * y * 3 # 對y進行更多操作 out = z.mean()# print(z, out)/<code>
.requires_grad_(...) 原地改變了現有張量的 requires_grad 標誌。如果沒有指定的話,默認輸入的這個標誌是 False。
<code>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)/<code>
梯度
梯度:方向導數,函數在該點處沿著該方向(此梯度的方向)變化最快,變化率最大(為該梯度的模)。
現在開始進行反向傳播,因為 out 是一個標量,因此 out.backward() 和out.backward(torch.tensor(1.)) 等價。
<code>out.backward()/<code>
輸出導數 d(out)/dx
<code>print(x.grad)/<code>
我們的得到的是一個數取值全部為4.5的矩陣。
計算步驟:
數學上,若有向量值函數 y =f(x ),那麼 y 相對於 x 的梯度是一個雅可比矩陣:
通常來說,torch.autograd 是計算雅可比向量積的一個“引擎”。根據鏈式法則,雅可比向量積:
雅可比向量積的這一特性使得將外部梯度輸入到具有非標量輸出的模型中變得非常方便。
現在我們來看一個雅可比向量積的例子:
<code>x = torch.randn(3, requires_grad=True) y = x * 2 while y.data.norm() < 1000: y = y * 2 print(y)/<code>
在這種情況下,y 不再是標量。torch.autograd 不能直接計算完整的雅可比矩陣,但是如果我們只想要雅可比向量積,只需將這個向量作為參數傳給 backward:
<code>v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float) y.backward(v) print(x.grad)/<code>
也可以通過將代碼塊包裝在 with torch.no_grad(): 中,來阻止
autograd跟蹤設置了 .requires_grad=True 的張量的歷史記錄。<code>print(x.requires_grad) print((x ** 2).requires_grad) with torch.no_grad(): print((x ** 2).requires_grad)/<code>