Mark Chang's Blog

Machine Learning, Deep Learning and Python

Torch NN Tutorial 4: Backward Propagation ( Part 1 : Overview & Linear Regression )

Introduction

本文以 Linear Regression 為例,介紹 Torch nn 如何進行 Backward Propagation。

Linear Regression 是以機器學習的方式,學出以下函數:

以 Gradient Descent 的方式來進行 Linear regression 的流程如下:

其中 為 training data, 為 golden value , 為 predicted value, 分別為 weight 和 bias 。 max_epoch 為 for 迴圈執行次數。

以下詳細講解整個流程,並實作之。

Linear Regression by Gradient Descent

首先,載入 nn 套件,並產生 Training Data

1
2
3
4
5
require 'nn'
x = torch.linspace(1,3,3):resize(3,1)
y = x*2+1
print(x)
print(y)

以上程式,假設 是由 產生出來的。而訓練的目標,是要讓

產生出來的 x[1,2,3]y[3,5,7] 如下:

1
2
3
4
5
6
7
8
9
 1
 2
 3
[torch.DoubleTensor of size 3x1]

 3
 5
 7
[torch.DoubleTensor of size 3x1]

為了方便以 batch 計算,將 xy 調整成 3x1 的大小。

建立完 training data 之後,可以開始進行 Linear Regression。

第一步,將 以隨機值初始化。

建立 nn.Linear ,命名為 l1 ,如下:

1
2
3
l1 = nn.Linear(1,1)
print(l1.weight)
print(l1.bias)

一開始, weightbias 會以隨機值初始化,結果如下:

1
2
3
4
5
 0.2055
[torch.DoubleTensor of size 1x1]

 0.7159
[torch.DoubleTensor of size 1]

再來是建立 loss function,命名為 c1

1
c1 = nn.MSECriterion()

由於 loss function 為 Mimimum Square Error,所以 criterion 採用 nn.MSECriterion

再來,這裡先講解 for 迴圈中進行的運算。

第三步算 linear 的 forward propagation :

的數值帶入以上公式,得出:

程式碼如下:

1
2
y_ = l1:forward(x)
print(y_)

結果如下:

1
2
3
4
 0.9214
 1.1269
 1.3325
[torch.DoubleTensor of size 3x1]

第四步,計算 coss function 的 forward propagation :

的數值帶入以上公式,得出:

如果輸入的值有多個維度,則 loss function 會將個維度的值,加起來平均,結果如下:

計算 值的程式碼如下:

1
2
j = c1:forward(y_,y)
print(j)

loss 值 j 如下:

1
17.147313377985

再來,要進行 backward propagation。

第五步,先將 歸零:

在程式中所對應的值,是 l1gradWeightgradBias 。在還沒歸零之前,這兩變數可能是任意值,印出這兩數的值,程式如下:

1
2
print(l1.gradWeight)
print(l1.gradBias)

結果如下:

1
2
3
4
5
6
7
1e-154 *
 -1.4917
[torch.DoubleTensor of size 1x1]

1e-154 *
-1.4917
[torch.DoubleTensor of size 1]

可用函式 zeroGradParameters 將這兩個值歸零,程式如下:

1
2
3
l1:zeroGradParameters()
print(l1.gradWeight)
print(l1.gradBias)

結果為0,表示已歸零:

1
2
3
4
5
 0
[torch.DoubleTensor of size 1x1]

 0
[torch.DoubleTensor of size 1]

第六步,計算 的值。

的數值帶入以上公式,得出:

由於 有三筆資料,每筆資料都會各算出一個微分結果。 程式中,計算此值的方式即是呼叫 c1backward ,如下:

1
2
dj_dy_ =c1:backward(y_,y)
print(dj_dy_)

得出的結果即是 ,結果如下:

1
2
3
4
-1.3857
-2.5820
-3.7784
[torch.DoubleTensor of size 3x1]

第七步,計算 的值:

先看 的數值,將 的值,以及先前算出的 值代入,即可算出它:

如果輸值為有多筆資料,則 的最終結果會將每筆的結果累加起來,如下:

的值是把 中的每筆資料結果累積起來。

以程式來計算此兩值。呼叫 l1backward ,輸入 backward 後,它與 相乘後結果分別為 ,此兩數分別儲存於 gradWeightgradBias

1
2
3
l1:backward(x, dj_dy_ )
print(l1.gradWeight)
print(l1.gradBias)

結果如下:

1
2
3
4
5
-17.8849
[torch.DoubleTensor of size 1x1]

-7.7461
[torch.DoubleTensor of size 1]

第八步,更新 weight 和 bias ,公式如下:

其中, 是指 learning rate 。令 ,更新 ,數值如下:

程式中,更新 l1weightbias 可以用 updateParameters ,它的輸入即是 。令 ,程式如下:

1
2
3
l1:updateParameters(0.02)
print(l1.weight)
print(l1.bias)

更新完後印出 weightbias 的值,結果如下:

1
2
3
4
5
 0.5632
[torch.DoubleTensor of size 1x1]

 0.8708
[torch.DoubleTensor of size 1]

把第三到第八步的 for 迴圈,串連起來。此 for 迴圈連續跑 500 次,每 50 次印出一次結果,程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i = 1,500 do
    y_ = l1:forward(x)
    j = c1:forward(y_,y)
    l1:zeroGradParameters()
    dj_dy_ =c1:backward(y_,y)
    l1:backward(x,dj_dy_)
    l1:updateParameters(0.02)
    if i%50 == 0 then
        print("i:" .. tostring(i)
           .. " loss:" .. tostring(j)
           .. " weight:" .. tostring(l1.weight[1][1])
           .. " bias:" .. tostring(l1.bias[1]) .. "\n")
    end
end

執行此程式,在訓練完 500 次以後,loss 會接近 0 ,而 weightbias 會接近 2 和 1 了。結果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
i:50 loss:0.015879173659737 weight:1.8543434015475 bias:1.3310995564975


i:100 loss:0.0098066687579948 weight:1.885537390716 bias:1.2602004152583


...

i:450 loss:0.00033602903432248 weight:1.9788119352928 bias:1.0481654513272


i:500 loss:0.00020752499774989 weight:1.9833490852405 bias:1.0378514430405

Materials

本次教學的完整程式碼於此:

https://github.com/ckmarkoh/torch_nn_tutorials/blob/master/4_backward_propagation_part_1.ipynb

Comments