深度学习之线性回归从零实现

  • Post author:
  • Post category:其他


本节将介绍如何只利⽤

Tensor



autograd

来实现⼀个线性回归的训练。

⾸先,导⼊本节中实验所需的包或模块,其中的matplotlib包可⽤于作图,且设置成嵌⼊显示。

⾸先,导⼊本节中实验所需的包或模块:

import torch
from IPython import display
from matplotlib import pyplot as plt #matplotlib包可用于作图,且设置成嵌入显示
import numpy as np
import random

一、生成数据集

我们构造⼀个简单的⼈⼯训练数据集,它可以使我们能够直观⽐较学到的参数和真实的模型参数的区

别。设训练数据集样本数为1000,输⼊个数(特征数)为2。给定随机⽣成的批量样本特征

\(X \in R^{1000 \times 2}\)

,我们使⽤线性回归模型真实权

\(w = [2,-3.4]^T\)

和偏差

\(b = 4.2\)

,以及⼀个随机噪声项

\(\epsilon\)

来⽣成标签

\[y = Xw + b + \epsilon \]

其中噪声项

\(epsilon\)

服从均值为0、标准差为0.01的正态分布。噪声代表了数据集中⽆意义的⼲扰。下⾯,让我们⽣成数据集。


# 1.生成数据集
num_inputs = 2 #2个特征
num_examples = 1000 #训练集1000个样本数量
true_w = [2,-3.4] #两个特征的权重值
true_b = 4.2 # 偏差
features = torch.from_numpy(np.random.normal(0,1,(num_examples,num_inputs)))
# 下面两行是使用一个随机噪声生成标签$y = Xw+b+ \epsilon$
lables = true_w[0] = features[:,0] + true_w[1] * features[:,1] + true_b
lables += torch.from_numpy(np.random.normal(0,0.01,size=lables.size()))

#注意:`features`的每一行是一个长度为2的向量,而`lables`的每一行是一个长度为1的向量(标量)。
print(features[0],lables[0])

输出结果:

tensor([0.8702, 1.1407], dtype=torch.float64) tensor(1.2039, dtype=torch.float64)

绘制线性关系图:

# 通过生成第二个特征`features[:,1]和标签`lables`的散点图,可以更直观观察两者间的线性关系
# 若没有导入`/d2lzh_pytorch`包里添加下面两个函数,则需要在此添加
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 d21zh_pytorch import *
"""

set_figsize()
plt.scatter(features[:,1].numpy(),lables.numpy(),1);

输出结果:

二、读取数据

在训练模型的时候,我们需要遍历数据集并不断读取⼩批量数据样本。这⾥我们定义⼀个函数:它每次返回

batch_size

(批量⼤⼩)个随机样本的特征和标签。

batch_size = 10
#`data_iter`保存在d2lzh包中。
# 们读取第一个批量数据样本并打印。每个批量的特征形状为(10, 2),分别对应批量大小和输入个数;标签形状为批量大小。
for x,y in data_iter(batch_size,features,lables):
    print("输出x,y在data_iter中的数据")
    print(x,y)
    break

输出结果:

完整代码:

# -*- coding: utf-8 -*-
"""
Created on Fri Feb 21 01:30:34 2020

@author: Google
"""

# 导入所需模块或者包
import torch
from IPython import display
from matplotlib import pyplot as plt #matplotlib包可用于作图,且设置成嵌入显示
import numpy as np
import random
#import sys
#sys.path.append("..")
from d2lzh_pytorch import *

# 1.生成数据集
num_inputs = 2 #2个特征
num_examples = 1000 #训练集1000个样本数量
true_w = [2,-3.4] #两个特征的权重值
true_b = 4.2 # 偏差
features = torch.from_numpy(np.random.normal(0,1,(num_examples,num_inputs)))
# 下面两行是使用一个随机噪声生成标签$y = Xw+b+ \epsilon$
lables = true_w[0] = features[:,0] + true_w[1] * features[:,1] + true_b
lables += torch.from_numpy(np.random.normal(0,0.01,size=lables.size()))

#注意:`features`的每一行是一个长度为2的向量,而`lables`的每一行是一个长度为1的向量(标量)。
print(features[0],lables[0])

# 通过生成第二个特征`features[:,1]和标签`lables`的散点图,可以更直观观察两者间的线性关系
# 若没有导入`/d2lzh_pytorch`包里添加下面两个函数,则需要在此添加
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 d21zh_pytorch import *
"""

set_figsize()
plt.scatter(features[:,1].numpy(),lables.numpy(),1);


"""
2.读取数据:
在训练模型的时候,我们需要遍历数据集并不断读取⼩批量数据样本。这⾥我们定义⼀个函数:它每次
返回 batch_size (批量大小)个随机样本的特征和标签。
"""
batch_size = 10

#`data_iter`保存在d2lzh包中。
# 们读取第一个批量数据样本并打印。每个批量的特征形状为(10, 2),分别对应批量大小和输入个数;标签形状为批量大小。
for x,y in data_iter(batch_size,features,lables):
    print("输出x,y在data_iter中的数据")
    print(x,y)
    break

"""
3. 初始化模型参数
"""
# 我们将权重初始化成均值为0、标准差为0.01的正态随机数,偏差则初始化成0
w = torch.tensor(np.random.normal(0,0.01,(num_inputs,1)),dtype = torch.float32)
b = torch.zeros(1,dtype = torch.float32)

# 后续的模型训练中,需要对这些参数梯度求迭代参数的值,因此要使`requires_grad=True`
w.requires_grad_(requires_grad = True)
b.requires_grad_(requires_grad = True)


"""
4.定义模型
"""
# 下面是线性回归的矢量计算表达式的实现,使用`mm`函数做矩阵乘法
def linreg(z,w,b): # 本函数已保存在d2lzh_pytorch包中方便以后使用
    z = torch.tensor(z, dtype=torch.float32)
    return torch.mm(z,w)+b

"""
5.定义损失函数
"""
# 使用`平方损失`做线性回归的损失函数。将真实值`y`变形成预测值`y_hat`的形状。
#以下函数的返回结果也将和`y_hat`的形状相同
def squared_loss(y_hat,y): # 本函数已保存在d2lzh_pytorch包中方便以后使用
    # 注意:此处返回的是向量,并且pytorch中的MSELoss并没有除以2
    return (y_hat - y.view(y_hat.size())) ** 2/2

"""
6.定义优化算法
"""
# 以下的`sgd`函数实现小批量随机梯度下降算法,通过不断迭代来优化损失函数。
# 这里自动求梯度模块计算得来的梯度是一个批量样本的梯度和,通过将它除以批量大小来得到平均值
def sgd(params,lr,batch_size): # 本函数已保存在d2lzh_pytorch包中方便以后使用
    for param in params:
        param.data -= lr * param.grad / batch_size #更改param时用的param.data


"""
7.训练模型
"""
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,lables):
        l = loss(net(x,w,b),y).sum()
        l.backward()
        sgd([w,b],lr,batch_size)
        
        # 进行梯度清零
        w.grad.data.zero_()
        b.grad.data.zero_()
    train_l = loss(net(features,w,b),lables)
    print('epoch %d,loss %f' % (epoch + 1,train_l.mean().item()))

运行结果:

三、自我总结:

在第4步:定义模型中,原代码:

"""
4.定义模型
"""
# 下面是线性回归的矢量计算表达式的实现,使用`mm`函数做矩阵乘法
def linreg(z,w,b): # 本函数已保存在d2lzh_pytorch包中方便以后使用
    return torch.mm(z,w)+b

运行过程中,会报错:

Traceback (most recent call last):

  File "<ipython-input-9-386f60e0227d>", line 1, in <module>
    runfile('F:/CodeStore/DL_Pytorch/3.2PracticeOfLinerRegression.py', wdir='F:/CodeStore/DL_Pytorch')

  File "D:\InstallSoftware\Anaconda\envs\spyder_py3.5\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 678, in runfile
    execfile(filename, namespace)

  File "D:\InstallSoftware\Anaconda\envs\spyder_py3.5\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 106, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "F:/CodeStore/DL_Pytorch/3.2PracticeOfLinerRegression.py", line 114, in <module>
    l = loss(net(x,w,b),y).sum()

  File "F:/CodeStore/DL_Pytorch/3.2PracticeOfLinerRegression.py", line 83, in linreg
    return torch.mm(z,w)+b

RuntimeError: Expected object of scalar type Double but got scalar type Float for argument #2 'mat2' in call to _th_mm

问题:类型错误,于是添加

z = torch.tensor(z, dtype=torch.float32)

,将数据类型统一。改后的代码:

"""
4.定义模型
"""
# 下面是线性回归的矢量计算表达式的实现,使用`mm`函数做矩阵乘法
def linreg(z,w,b): # 本函数已保存在d2lzh_pytorch包中方便以后使用
    z = torch.tensor(z, dtype=torch.float32)
    return torch.mm(z,w)+b

"""



版权声明:本文为MumuziD原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。