機器學習經典實例:使用pytorch 完成線性迴歸分析

機器學習經典實例:使用pytorch 完成線性迴歸分析


0.總結

Get to the points first. The article comes from LawsonAbs!
  • pytorch中相關函數的使用
  • 線性迴歸、梯度下降的理解與計算

1.要求

  • 使用隨機生成的模擬數據去訓練一個函數模型
  • 數據集是點對,呈現的是一次線性函數關係

2.主要思路

這個案例帶有**“驗證”**的味道,即我們事先定義好一個函數模型,並根據這個模型隨機生成一些數據,然後給這些數據集加點兒噪聲,最後得到的數據集就是通常所說的訓練集。根據訓練集訓練一個一維函數模型,並使用隨機生成的數據測試模型的效果如何,最後用matplotlib展現擬合效果。

  • step1.事先定義一個函數,即我們的數據主要是服從這個函數模型,然後在其中加點兒噪聲就得到訓練的數據集了
  • step2.【因爲這裏是一維函數模型,所以我們就用一次線性函數爲這個問題的模型】令數據模型爲y=w*x+b。並隨機初始化w,b的值。
  • step3.事先定義好學習率 lr = 0.001
  • step4.採用梯度下降的方法更新參數,這裏沒有調用Autograd中的方法,而是自己計算梯度並更新
  • step5.每訓練完一批數據之後,就開始進行一次模擬驗證【對應if ii % 10 == 0:中的部分】

3.代碼

from __future__ import print_function
import torch as t
import numpy as np
from matplotlib import pyplot as plt
from IPython import display

t.manual_seed(1000)  # 設置隨機數種子,保證任何機器運行都相同
def get_fake_data(batch_size=8):
    # 從均勻分佈[0,1) 中抽出8*1的數據,並放大20倍【這裏的放大倍數是沒有影響的】
    x = t.rand(batch_size, 1) * 20;
    # print(x) # 其類似一個8行1列的向量
    # 添加隨機噪聲
    y = x * 2 + (1 + t.randn(batch_size, 1)) * 3
    return x, y

x, y = get_fake_data()
# 只不過是將tensor 轉換爲numpy
#plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())

# 隨機初始化參數
w = t.rand(1, 1) # => w是個tensor
b = t.zeros(1, 1) # => b也是個tensor
lr = 0.001  # learning rate


'''01.這裏的意思就是生成一個具有20000個數據對作爲樣本,然後用這20000個數據對去訓練一個函數模型出來'''
for ii in range(20000):
    x, y = get_fake_data() # 模擬出假的數據
    # forward: 計算loss
    #print(x.size()) # torch.Size([8, 1])
    #print(w.size()) # torch.Size([1, 1])
    y_pred = x.mm(w) + b.expand_as(y)
    loss = 0.5 * (y_pred - y) ** 2  # 均方誤差
    loss = loss.sum() # Returns the sum of all elements in the input tensor

    # backward: 手動計算梯度
    dloss = 1 # dloss是什麼?
    dy_pred = dloss * (y_pred - y)
    # print(x.size()) # torch.Size([8, 1])
    # print(dy_pred.size()) # torch.Size([8, 1])

    '''    
    01.dw = x.t().mm(dy_pred) 裏爲什麼有個x.t()操作? 是什麼意思?
    02.mm函數計算的是兩個tensor的乘積,但是如果要做矩陣乘積,顯然是無法相乘的。
    所以就需要轉換【轉置】。
    這裏的x.t()就是將x進行轉置操作。
    03.結合learning rate 調整參數
    '''
    dw = x.t().mm(dy_pred)
    db = dy_pred.sum()
    w.sub_(lr * dw)
    b.sub_(lr * db)

    # 每訓練100次就查看訓練的效果到底怎麼樣了
    if ii % 10 == 0:
        # 清空輸出 Clear the output of the current cell receiving output
        display.clear_output(wait=True)
        x = t.arange(0, 20).view(-1, 1)
        # print(x.dtype) # torch.int64 所以需要顯式的調用.float()將其轉換成float型
        # 其根本原因在於t.arange(0,20)是根據默認1爲步長來分配的,導致會出現int64
        # print(w.dtype)

        '''
        01.這裏再生成一批數據,就相當於測試集。讓這個測試集去表示訓練模型的具體效果如何
        02.plot是畫出直線,scatter是畫出離散的點。這樣就可以直觀地看出擬合的效果了
        03.爲了圖形更好看,所以設置了一下長度的限制。
        04.爲了不直接跳出圖形界面,暫緩了0.5s
        05.最後輸出了w,b的兩個參數值
        '''
        y = x.float().mm(w)+ b.expand_as(x)
        plt.plot(x.numpy(), y.numpy())  # predicted
        x2, y2 = get_fake_data(batch_size=20) # 這裏生成的數據是20個
        plt.scatter(x2.numpy(), y2.numpy())  # true data
        plt.xlim(0, 20) # 設置x軸,y軸的最大值
        plt.ylim(0, 41)
        plt.show()
        print("w=",w.item(), "b=",b.item())

上面這段代碼在pycharm中的執行結果就是:

  • 屏幕上會彈出若干幅圖形,這些圖形由兩部分構成:
    (1)訓練得到的函數模型
    (2)真實數據(其實就是我們模擬生成的數據)的一個個參數點座標
  • 底部會打印出參數w,b的值。

運行結果和一部分的參數展示:
在這裏插入圖片描述

4.難點分析

  • tensor【其實就是矩陣】間的相互運算
  • pytorch函數的學習。
    這裏我都在文章中的代碼中進行了詳細的註釋。
  • 梯度下降的理解與計算
4.1 看看到底是怎麼運算?

我覺得新手最容易懷疑的問題就是:y=w*x+b,這個乘與加的過程到底是什麼樣的?這裏我就把數據拿出來,專門做個解釋。

  • 函數模型
    y = x*w + b

  • 數據

x = tensor([[ 8.8605],
        [13.1534],
        [ 8.5220],
        [ 6.9218],
        [13.6363],
        [16.2603],
        [ 4.5726],
        [12.9265]])
w = tensor([[0.3915]])

我們手動相乘一下,就得到了如下的結果:

x*w = tensor([[3.46888575],
[5.1495561],
[]...
])

實際計算機運算得到的x*w值如下:

tensor([[3.4685],
        [5.1490],
        [3.3360],
        [2.7096],
        [5.3380],
        [6.3652],
        [1.7900],
        [5.0602]])

然後再加上b的值【這裏是0矩陣】,最後就成了y_pred的值【即y的預測值】。可以發現二者是相同的。【計算機應該不會算錯的】

而此時生成的y的值爲:

y = tensor([[24.2896],
        [23.1069],
        [21.5958],
        [12.2041],
        [35.8736],
        [36.4838],
        [14.5665],
        [28.4940]])

可以看到他們的之間的loss太大了,現在的問題就是調整這個w,b去減少loss。這是後話,不說了。

4.2 具體函數的使用
  • expand_as()
    把一個tensor變成和函數括號內一樣形狀的tensor,用法與 expand()類似
    具體實例:
>>> import torch as t
>>> x=t.rand(3,4)
>>> print(x.size())
torch.Size([3, 4])
>>> print(x)
tensor([[0.7740, 0.1354, 0.3477, 0.7286],
        [0.3327, 0.4944, 0.3491, 0.1855],
        [0.3790, 0.8667, 0.6716, 0.2647]])
>>> b=t.zeros(1,1)
>>> print(b)
tensor([[0.]])
>>> print(b.size())
torch.Size([1, 1])
>>> b=b.expand_as(a)
>>> print(b.size())
torch.Size([2, 3])
>>> print(b)
tensor([[0., 0., 0.],
        [0., 0., 0.]])
  • 平方運算【**2
    這裏我們在loss函數中用到了平方運算。是將(y_pred-y)**2,這裏的y是一個tensor,相當於一個8行一列的數組,其平方運算就是直接將tensor的每位直接對應相乘,然後得到的結果。示例如下:
import torch as t
x=t.rand(8,1) * 10
print("x=",x)
y=x**2
print("y=(x**2)=",y)

在這裏插入圖片描述當二維或者更加高維的tensor去驗證也可以發現的確就是這樣運算方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章