iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 2
1
AI & Data

深度學習裡的冰與火之歌 : Tensorflow vs PyTorch系列 第 2

Day 2 動態計算圖:PyTorch's autograd

在上篇文章我們簡單的介紹了 PyTorch 和 Tensorflow 的基本不同,現在我們要用使用者的角度來檢視兩個框架的不同。今天,先來看看 PyTorch 如何實踐動態計算圖。

如何記憶動態資訊

關於自動微分的實作,PyTorch 將之包裝在一個名叫 autograd 的模組。在 autograd 模組中,計算圖其實是由許多 Function 節點所組成。計算圖中 Function 節點的建立和表示計算步驟的前後連結,可以在正向傳遞中完成。在正向傳遞中,autograd 會為每一個需要計算梯度的 torch.Tensor 對象建立一個 Function 物件,以附加的方式成為該物件屬性。此函數附加到 torch.Tensor 物件,將會在反向過程中計算梯度時所需的。雖然,這個 Function 物件名為函數,但這個 Function 在正向傳播中只是一個表示式(“expression”),需要在反向傳播時,依賴 apply() 方法執行。

但有一點需要注意的是,由於藉由運行流程所定義的計算圖,雖然具有靈活性,但每次迭代都需要重新創建計算圖,並需要使用者明確定義運算的邏輯,方能知道如何運行計算圖。這種行為的好處是我們可以根據不同的條件,使用不同的計算圖。但缺點是效能較差,因為需要在每次迭代中重新創建計算圖,也無法事先對整張計算圖做最佳化。

動態計算圖的實踐

如前所述,反向傳播步驟是根據使用者如何正向運行的方式確定的,並且在每次迭代中可以不同。 所以現在我們來看看 PyTorch 的 autograd 如何被實踐的。首先,在這個模組中的主要元素包括:

  1. PyTorch Tensor 物件:為了能夠進行反向傳播計算,必須將該物件的 requires_grad 方法設置為True,方可以使用 backwards 的方法來計算並累積梯度。
  2. PyTorch Function 物件,將被創建並附加到 Tensor 物件屬性,如前所述這 Tensor 物件需要 requres_grad = True。可以通過呼叫 Tensorgrad_fn 屬性來存取附加的 Funciton 物件。 Funciton 將提供如何計算歷史記錄中的梯度的訊息。

為了執行反向傳播,應該呼叫元素 1 中的 backward()方法,開始反向計算。如果 Tensor 是數值,則在呼叫 backward() 時不需要指定任何參數。但當 Tensor 是一個多維向量時,則要給定初始值。

要停止回溯計算歷史或不納入特定一個 Tensor 物件於計算圖,可以使用以下兩個方法:

1.要 exclude 一個 Tensor 物件,可以呼叫 detach() 方法。爾後,在該 Tensor 上運行的任何後續操作,都將被忽略,不會被紀錄。
2.要 exlude 一段程式碼,可以在with torch.no_grad() context manager 中編寫這段程式碼。

以下是一個簡單的計算圖,介紹如何用 PyTorch 建立計算圖。

x = torch.ones(2, 2, requires_grad=True)
print(x) #grad_fn is None
>>> tensor([[1., 1.], [1., 1.]],   
... requires_grad=True)

y = x + 2
print(y)

>>> tensor([[3., 3.],
...         [3., 3.]], grad_fn=<AddBackward0>)

print(y.grad_fn)
print(x.grad_fn)

>>> <AddBackward0 object at 0x7f2caf39b1d0> #y.grad_fn
>>> None #x.grad_fn

真的!那怎麼進行反向傳播?

與 optimizer 和 loss 一起使用時,進行反向傳播的步驟是:

  1. 呼叫 optimizer 的 zero_grad 方法,將所有參數的梯度緩衝區(buffer)歸零
  2. 呼叫 loss 的 backward() 方法開始進行反向傳播
  3. 呼叫 optimizer 的 step() 方法來更新權重。

在這裡,optimizer 是一個 torch.nn.optim 中任一類別的物件。而 loss 則是一個 torch.Tensor 物件,其 requires_grad 為 True.

optimizer.zero_grad()
# forward implementation
# ...
loss.backwards()
optimizer.step()

loss.backwards()被呼叫時會發生什麼?使用者可以試著通過呼叫grad_fn及其next_functions方法,動態回溯。

最佳實踐方法:

不要在計算圖中使用 in-place operation。 PyTorch 有一種函數屬於 in-place operation 的計算。這種 in-place operation 的計算和 numpy 有點相近,也就是在不重新安置記憶體的情況下進行該 operation。這樣的 operation 不適合 autograd module,因為 autograd 需要經常性的釋放或重新使用 附加在 Tensor 物件上的緩衝區。

原因包括:
1.in-place operation 將覆蓋 Tensor 所持有的值。
2.in-place operation 需要將計算圖重寫,這意味著在計算圖中若有一個 in-place operation,那每次進行該 operation 需要重新建立 Function 的擁有者和輸入。

規則是:

  1. 如果是需要進行梯度計算的 Tensor 物件,不能對他進行 in-place operation
  2. 如果是計算圖的葉節點,如大多數的參數,則不能對他進行 in-place operation

Reference:

[1] PyTorch 官方文件
[2] 更詳盡的 autograd 中文介紹


上一篇
Day 1 類神經網路和計算圖語言
下一篇
Day 3 靜態計算圖:Tensorflow
系列文
深度學習裡的冰與火之歌 : Tensorflow vs PyTorch31

尚未有邦友留言

立即登入留言