動手深度學習3-從零開始完成線性迴歸

在瞭解了線性迴歸的背景知識以後,咱們能夠動手實現該算法了。儘管強大的深度學習框架能夠減小大量重複性工做,可是過於依賴它提供的便利,會致使咱們很難深刻理解深度學習是如何工做的。所以本節將介紹如何只利用Tensor和autograd來實現一個線性迴歸的訓練。python

首先,導入本節內容須要的包或者模塊,其中matplotlib包能夠用於做圖,且設置成嵌入顯示。算法

%matplotlib inline
import torch
from IPython import display
from matplotlib import pyplot as plt
import numpy as np
import random
生成數據集

咱們構建一個簡單的人工訓練數據集,它可使咱們可以直觀比較學到的參數和模型參數的區別。
加入咱們的訓練數據集樣本爲1000,輸入個數爲(特徵數)爲2。咱們碎金生成批量的樣本特徵\[X∈{R}^{1000*2},\]咱們使用線性迴歸模型的真實權重\[W=[2,-3.4]^{T}\]和誤差b=4.2,以及一個隨機噪音項ϵ 來生成標籤
\[ y=Xw+b+ϵ,\]其中噪聲項 ϵ服從均值爲0,標準差爲0.01的正太分佈。噪音表明了數據彙總無心義的干擾。app

num_inputs =2   ## 特徵數量
num_examples=1000   # 樣本量
true_w=[2,-3.4]  # 真實的權重係數
true_b=4.2  # 真實的偏置量
features = torch.randn(num_examples,num_inputs,dtype=torch.float32)   # 生成隨機的特徵
labels = true_w[0]*features[:,0]+true_w[1]*features[:,1]+true_b  # 生成隨機的標籤
labels += torch.tensor(np.random.normal(0,0.01,size=labels.size()),dtype=torch.float32)  #在標籤上加上隨機噪聲項
print(features[0],labels[0])  # 查看第一個樣本
tensor([-0.4866,  0.9289]) tensor(0.0616)
def use_svg_display():
    display.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5,2.5)):
    use_svg_display()
    plt.rcParams['figure.figsize'] = figsize
    
    
    
    
## 能夠單獨寫一個代碼重複利用,好比d2lzh_pytorch 中加上這兩個函數
# import sys
# sys.path.append('..')
# from d2lzh_pytorch import *

set_figsize()
plt.scatter(features[:,1].numpy(),labels.numpy(),1)
<matplotlib.collections.PathCollection at 0x1215b51d0>

讀取數據
def data_iter(batch_size,features,labels):
    num_examples=len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)
    for i in range(0,num_examples,batch_size):
        j=torch.LongTensor(indices[i:min(i+batch_size,num_examples)])  # 最後一次可能不足一個batch
        yield features.index_select(0,j),labels.index_select(0,j)
batch_size=10
for X ,y in data_iter(batch_size,features,labels):
    print(X,y)
    break
tensor([[ 0.0097,  0.3166],
        [-0.9294, -0.5351],
        [ 0.5398,  0.4626],
        [ 0.5905,  0.9588],
        [ 0.1730, -0.3228],
        [ 1.3608, -0.8205],
        [ 1.5391, -0.6738],
        [-1.4577,  0.6428],
        [-1.4004,  0.3694],
        [-0.6668, -0.4032]]) tensor([ 3.1422,  4.1823,  3.7059,  2.1282,  5.6544,  9.7055,  9.5682, -0.9014,
         0.1326,  4.2385])
初始化模型參數
# 初始化w爲一個2行1列的tensor,b初始化爲0
w= torch.tensor(np.random.normal(0,0.01,(num_inputs,1)),dtype=torch.float32)
b = torch.zeros(1,dtype=torch.float32)
# 以後的訓練模型中,須要對這些參數來迭代參數的值,所以咱們要讓求導的參數設置爲True
w.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)
tensor([0.], requires_grad=True)
定義模型
def linreg(X,w,b):
    return torch.mm(X,w)+b
定義損失函數
def squared_loss(y_hat,y):
    return (y_hat-y.view(y_hat.size()))**2/2
定義優化算法
def sgd(params,lr,batch_size):
    for param in params:
        param.data -=lr* param.grad/batch_size   
# 注意這裏更改param時用的是param.data
訓練模型

在訓練中,咱們將屢次迭代模型的參數,在每次迭代中,咱們根據當前讀取的小批量數據樣本(特徵X,標籤y),經過調用反向傳播函數backward計算小批量的隨機梯度,並調用優化算法sgd迭代模型參數。
咱們以前設置的batch_size爲10,每一個小批量的損失\(l\)的形狀爲(10,1)。因爲變量\(l\)並非一個標量,咱們調用.sum()將其求和獲得一個標量,再運行\(l\).backward(),獲得該變量的有關模型參數的梯度。注意每次更新完參數後須要將參數的梯度清零框架

lr = 0.03
num_epochs=3
net = linreg
loss= squared_loss
for epoch in range(num_epochs):
    for X,y in data_iter(batch_size,features,labels):
        l =loss(net(X,w,b),y).sum()
        l.backward()
        sgd([w,b],lr,batch_size)
        
        w.grad.data.zero_()
        b.grad.data.zero_()
    trian_l= loss(net(features,w,b),labels)
    print('epoch %d loss %f'  %(epoch+1,trian_l.mean().item()))
epoch 1 loss 0.038065
epoch 2 loss 0.000144
epoch 3 loss 0.000050
print(true_w,'\n',w)
print(true_b,'\n',b)
[2, -3.4] 
 tensor([[ 1.9996],
        [-3.4005]], requires_grad=True)
4.2 
 tensor([4.1997], requires_grad=True)
相關文章
相關標籤/搜索