Pytorch 微分

      在〈Pytorch 微分〉中尚無留言

Pytorch 微分

安裝套件

請先安裝如下套件

🔒 底下內容僅限會員閱讀。

立即登入

函數

假設函數為 $(f(x)=0.6x^2+5)$

圖形

如下代碼可畫出此函數之圖型

🔒 底下內容僅限會員閱讀。

立即登入

單點微分

函數微分後為 $(f'(x)=0.6*2x )$。當 x = 2 時,$(f'(2)= 0.6 *2 * 2 =  2.4 )$。如下代碼可計算 x = 2 時的導數。

🔒 底下內容僅限會員閱讀。

立即登入
  • 函數  : y = 0.6 * torch.square(x) + 5,設定函數為 $(f(x) = 0.6  x ^2 +5)$
  • 微分點 : x = torch.tensor([2.0]),求 x = 2.0 時的導數,一定要用浮點數,整數無法微分。
  • $(\frac{dy}{dx})$ : y 對 x 的微分,使用 requires_grad = True 宣告 x 是要微分的對像。
  • 微分 : y.backward(),開始計算 x = 2.0 時的微分值,結果置於 x.grad 中

多點微分

如果要計算多點 x 分別在 [1., 2., 3., 4.] 這 4 處的導數,x 就需宣告如下。

x = torch.tensor([1., 2., 3., 4.], requires_grad = True)

微分後的 x.grad 4 個值 [1.2000, 2.4000, 3.6000, 4.8000] 會再跟 y 的向量相乘,所以需在 y.backward() 裏需設定 4 個向量值,如下所示。

y.backward(torch.tensor[1,1,1,1])

 權重

x 導數跟 y 的向量相乘,好像是多此一舉,但看了下面的代碼,結果都會接近 4.8,這就是權限的概念

import torch
x=torch.tensor([1.,2.,3.,4.], requires_grad=True)
y=0.6 * torch.square(x) + 5
y.backward(torch.tensor([3.99,1.97,1.35,1]))
print(x.grad)

結果:
tensor([4.7880, 4.7280, 4.8600, 4.8000])

為了讓結果都接近 4.8,所以 y 的向量要填入不同的值,這些值就稱為權重(weight)。模型的訓練,絕大多數都是在計算這些權重(怎麼算,就先不用管)。

上百點的需求

如果要計算上百、千個 x 點的導數,在 y.backward() 裏要輸入 torch.tensor([1,1,1,1…….]) 輸入 100、1000 個 1,那簡直要人命,所以可以用 torch.ones_like(y) 是建立一個跟 y 一模一樣形狀的 tensor。完整代碼如下

import torch
x = torch.tensor([1.,2.,3.,4.], requires_grad=True)
y = troch.square(x)
y.backward(torch.ones_like(y))
print(x.grad)
結果 : 
tensor([2., 4., 6., 8.])

更直覺的方法

torch.ones_like(y) 蠻怪異的,所以可以變成如下比較好理解的方式,二者一模一樣。

import torch
x=torch.tensor([1.,2.,3.,4.], requires_grad=True)
y=0.6 * torch.square(x) + 5
y.sum().backward()
print(x.grad)

$(\sum)$微分

假設 $(f(x)=\sum_{i=1}^{4}a_ix^2+b_i )$,a 是 [0.1, 0.2, 0.3, 0.4] 的集合,b 是 [1, 2, 3, 4] 的集合。

$(f'(x)=\sum_{i=1}^{4}2a_ix = 2(0.1+0.2+0.3+0.4)x=2x)$,所以當 x = 2 時的微分值是 2*2 = 4,相關代碼如下

🔒 底下內容僅限會員閱讀。

立即登入

偏微分

偏微分其實只考慮單一層面的影響。比如我是賣便當的,影響我淨利的有菜價、人工成本、電價、瓦斯價、房屋租金。我現在只想知道,電價上升一塊錢,會影響我多少收益,這稱為斜率,也就是電價對淨利的偏微分。

假設公式為 $(f(x,y)=\sum_{i=1}^{n}a_ix^2+b_iy^2)$,a 是 [0.1, 0.2, 0.3, 0.4] 的集合,b 是 [1, 2, 3, 4] 的集合。

對 x 的偏微分為 $(\frac{f(x, y)}{\sigma x}=\sum_{i=1}^{4}2a_ix)$,其意是 x 升 1 單位,z 升多少。

對 y 的偏微分為 $(\frac{f(x, y)}{\sigma y}=\sum_{i=1}^{4}2b_iy)$,其意是 y 升 1 單位,z 升多少。

🔒 底下內容僅限會員閱讀。

立即登入

梯度下降

假設要使用梯度下降計算 $(y=x^2)$ 的極小值,x 一開始由 -5 開始逼近,經由基礎梯度下降的說明,每次逼近的公式為$(x_{t+1}=x_{t} – f'(x_t) * lr)$

先定義 x 張量,切記一定要寫 5. ,因為只有小數才能進行微分。

x=torch.tensor([-5.], requires_grad=True)

定義公式 $(y = x^2)$,這個公式在每次 x 變更時都需重新定義,所以一定要寫在迴圈中,然後用 y.backward() 進行微分。

因為 x 是標量,所以 y.backward() 不需給存放的位置

for i in range(epochs): 
    y=x.square() 
    y.backward()

接下來逼近 x ,但請注意 x 值只要一改變,就會被自動追蹤計算的過程,所以手動更改 x  值時,一定要放在 with torch.no_grad() 區塊中,這個目的是在告知 pytorch,區塊中的計算請不要追蹤。

如果不放在區塊中,只能重定 x = torch.tensor([ x – x.grad * lr], requires_grad = True),但這會影響效能。

另外在區塊中,只能寫 x -= …. ,如果寫成 x = x – x.grad * lr,是會出現錯誤的。

with torch.no_grad():
    x -= x.grad * lr#不可以寫成 x = x - x.grad *0.01

最後一定要清除 x.grad,如果不清除,前後的結果會累加進去

    x.grad.zero_()

完整代碼如下

🔒 底下內容僅限會員閱讀。

立即登入

detach

torch 的張量模式有時需轉成 numpy 格式進行計算或繪圖,此時可以用 .numpy() 進行轉換。

但張量若宣告為 requires_grad = True 時,在這狀態下處於追蹤模式,是不能轉成 numpy 格式的,必需使用 detach() 暫時分離追蹤模式。

如下代碼,x 宣告為追蹤模式,y 也隨之變成追蹤模式,所以都要先 detach 後才能轉成 numpy 格式,z 就不用分離了。

import torch
x=torch.tensor([1.,2.,3.,4.], requires_grad=True)
y=x.square()
z=torch.tensor([1.,2.,3.,4.])
print(x.detach().numpy())
print(y.detach().numpy())
print(z.numpy())

結果 :
[1. 2. 3. 4.]
[ 1.  4.  9. 16.]
[1. 2. 3. 4.]

torch.no_grad區塊

在 torch.no_grad 區塊是屬於分離狀態的,所以可以直接使用 numpy() 轉換,但如果脫離了區塊範圍,就要加上 detach() 方法

底下代碼藍色部份,分別是區塊內及區塊外的使用方法。

🔒 底下內容僅限會員閱讀。

立即登入

GPU運算

如果交由 GPU運算,要將 GPU 裏的變數轉成 numpy,需使用 .cpu() 將變數 copy 到主機版的 Ram, 後再轉成 numpy()。底下代碼藍色部份,分別是區塊內及區塊外的使用方法。

🔒 底下內容僅限會員閱讀。

立即登入

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *