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