1. 程式人生 > 其它 >線性迴歸的從零開始實現

線性迴歸的從零開始實現

1 匯入實驗所需要的包

import torch
import numpy as np
import matplotlib.pyplot as plt
from torch import nn
from IPython import display
#解決核心掛掉
import os
os.environ["KMP_DUPLICATE_LIB_OK"]  =  "TRUE"

2 生成資料集

  將根據帶有噪聲的線性模型構造一個人造資料集。任務是使用這個有限樣本的資料集來恢復這個模型的引數。這裡使用低維資料,這樣可以很容易地將其視覺化。

  在下面的程式碼中, 將生成一個包含 1000 個樣本的資料集,每個樣本包含從標準正態分佈中取樣的 2 個特徵。合成數據集是一個矩陣 $\mathbf{X} \in \mathbb{R}^{1000 \times 2} $ 。


  使用線性模型引數 $ \mathbf{w}=[2,-3.4]^{\top}$ 、 $b=4.2$ 和噪聲項 $\epsilon$ 生成資料集及其標籤:

    $\mathbf{y}=\mathbf{X} \mathbf{w}+b+\epsilon$

  可以將 $\epsilon$ 視為捕獲特徵和標籤時的潛在觀測誤差。在這裡認為標準假設成立,即 $\epsilon $ 服從均值為 $0$ 的正態分佈。為了簡化問題, 我們將標準差設 為 $0.01 $ 。下面的程式碼生成合成資料集。

def get_random_data(w,b,num_example):
    X = torch.normal(0,1,(num_example,len(w)))
    
#X = torch.normal(0,1,(num_example,2)) Y = torch.matmul(X,w)+b #矩陣乘法,要求稍微低一點 Y += torch.normal(0,0.01,Y.shape) return X,Y.reshape(-1,1) true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = get_random_data(true_w, true_b, 1000)

torch.mm(mat1, mat2, out=None) → Tensor

torch.matmul(mat1, mat2, out=None) → Tensor

對矩陣mat1和mat2進行相乘。 如果mat1 是一個n×m張量,mat2 是一個 m×p 張量,將會輸出一個 n×p 張量out。

引數 :

mat1 (Tensor) – 第一個相乘矩陣

mat2 (Tensor) – 第二個相乘矩陣

features.shape, labels.shape

(torch.Size([1000, 2]), torch.Size([1000, 1]))

3 視覺化初始資料

# 設定圖的尺寸
plt.rcParams['figure.figsize'] = (8,3)
plt.subplot(1,2,1) #要生成兩行兩列,這是第一個圖plt.subplot('行','列','編號')
plt.scatter(features[:,1].detach().numpy(), labels.detach().numpy(),s=1);
plt.subplot(1,2,2) 
plt.scatter(features[:,0].detach().numpy(), labels.detach().numpy(),s=1);

      

labels.detach().numpy().shape
(1000, 1)

features[:,1].detach().numpy().shape
(1000,)

4讀取資料集

  在下面的程式碼中,我們定義一個 data_iter 函式, 該函式接收批量大小、特徵矩陣和標籤向量作為輸入,生成大小為 batch_size 的小批量。每個小批量包含一組特徵和標籤。

def data_iter(batch_size,features,labels):
    num_example = len(features)
    indices = list(range(num_example))
    np.random.shuffle(indices)
    for i in range(0, num_example, batch_size):
        batch_indices = torch.tensor(indices[i: min(i + batch_size, num_example)])
#         print("batch_indices=",batch_indices)
        yield features[batch_indices], labels[batch_indices]
        #採用yield 迴圈並沒有結束,而是暫時”停止“,返回的是一個迭代器
# next(data_iter(50,features,labels))
# next(data_iter(50,features,labels))

  測試一下:讀取第一個小批量資料樣本並列印。每個批量的特徵維度說明了批量大小和輸入特徵數。 同樣的,批量的標籤形狀與batch_size相等。

batch_size = 10

for X, y in data_iter(batch_size, features, labels):
    print("features=",X, '\nlabels=', y)
    break
features= tensor([[-1.3117,  0.0544],
        [-2.1899, -0.9396],
        [ 0.2574,  0.5958],
        [-0.1184,  0.9712],
        [ 1.2400,  0.7710],
        [ 1.2233,  0.3990],
        [-1.3850, -0.8254],
        [-3.0746,  0.2081],
        [ 0.3196, -0.3576],
        [-1.8893, -0.6696]]) 
labels= tensor([[ 1.3906],
        [ 3.0155],
        [ 2.6977],
        [ 0.6439],
        [ 4.0464],
        [ 5.2818],
        [ 4.2274],
        [-2.6520],
        [ 6.0649],
        [ 2.6800]])

5初始化模型引數

w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
b = torch.zeros(1,requires_grad=True)

6 定義模型

  需計算輸入特徵 $X$ 和模型權重 $w$ 的矩陣向量乘法後加上偏置 $b $。需要注意的是當我們用一個向量加一個標量時,標量會被加到向量的每個分量上。

def linear(X,w,b):
    return (torch.matmul(X,w)+b).reshape(-1,1)

7定義損失函式

def MSE_loss(y_hat,y):
    return ((y_hat- y )**2)/2

8定義優化演算法

def mini_batch_sgd(params,lr,batch_size):
    """小批量隨機梯度下降。"""
    #torch.no_grad() 是一個上下文管理器,被該語句 wrap 起來的部分將不會track 梯度。
    with torch.no_grad():
        for param in params:
            param -= lr * param.grad / batch_size
            param.grad.zero_()   #梯度清零

9訓練

lr = 0.003
num_epoch = 20
net = linear
loss = MSE_loss

for epoch in range(num_epoch):
    for X , y in data_iter(batch_size, features, labels):
        y_hat = net(X,w,b)
        cur_loss = loss(y_hat,y)
#         print("cur_loss = ",cur_loss)
        cur_loss.sum().backward()
#         print("cur_loss.sum()=",cur_loss.sum())
#         print(w.grad)
#         print(torch.no_grad())
        mini_batch_sgd([w, b], lr, batch_size)  # 使用引數的梯度更新引數
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

10 輸出權重和偏置

w.detach().numpy()
array([[ 1.9997293],
       [-3.4006505]], dtype=float32)
b.detach().numpy()
array([4.1997237], dtype=float32)

看完點個關注唄!!(總結不易)

因上求緣,果上努力~~~~ 作者:希望每天漲粉,轉載請註明原文連結:https://www.cnblogs.com/BlairGrowing/p/15421465.html