機器學習經典實例:使用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去驗證也可以發現的確就是這樣運算方法。