【pytorch实现】简单线性回归

回归问题是连续值问题,即线性回归输出的是连续值。
分类问题输出是离散值。
1.线性回归基本要素
模型:构建一个通过输入计算输出的线性关系表达式,y^=x1w1+x2w2+b,
其中 w1 和 w2 是权重(weight), b 是偏差(bias),且均为标量。它们是线性回归模型的参数(parameter)。模型输出 y^ 是线性回归对真实值 y 的预测或估计。我们通常允许它们之间有一定误差。
模型训练:即给上述模型(表达式)输入数据(样本特征)来推测使得预测值与真实值误差尽可能小的参数(parameter)。
模型训练涉及的3个要素:
a.训练数据
输入模型的是数据被称为训练数据集(training data set)或训练集(training set),庞大数据中的一个是一个样本(sample),其真实值叫做标签(label),用来预测标签的因素叫作特征(feature)。特征用来表征样本的特点。
y^(i)=x(i)1w1+x(i)2w2+b.
第i个样本的线性回归模型表达式。
b.损失函数
通常会选取一个非负数来衡量预测值与真实值的误差。可以用平方数:
在这里插入图片描述
该式表示第i个样本的误差函数,函数值越小,误差越小。
其中常数 1/2 是方便求导。这个误差只与模型参数相关,因此将它记为以模型参数为参数的函数。在机器学习里,将衡量误差的函数称为损失函数(loss function)。这里使用的平方误差函数也称为平方损失(square loss)。
通常,用训练数据集中所有样本误差的平均值来衡量模型预测的质量,即:
在这里插入图片描述
(该式中样本只取了两个特征。)
模型训练的目标就是希望找出一组模型参数,来使训练样本平均损失最小
c.优化算法

当模型和损失函数形式较为简单时,上误差最小化问题的解可以直接用公式表达出来。这类解叫作解析解(analytical solution)。线性回归和平方误差就属于这个范畴。然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫作数值解(numerical solution)。

在求数值解的优化算法中有一个叫做小批量随机梯度下降(mini-batch stochastic gradient descent)的算法。
算法过程:
先对模型参数随机初始化,然后多次迭代参数值使得每次迭代都在尽可能的减少损失值,在每次迭代的过程中,先随机均匀的选取一个B小批量(mini-batch),这个B是由相同数目的训练数据样本所组成,然后求小批量中数据样本的平均损失关于模型参数的导数(梯度),最后用此结果与预先设定的一个正数的乘积作为模型参数在本次迭代的减小量。
即模型的每个参数将作如下迭代:
在这里插入图片描述
在上式中, |B| 代表每个小批量中的样本个数(批量大小,batch size), η 称作学习率(learning rate)并取正数。这里的批量大小和学习率的值是人为设定的,并不是通过模型训练学出的,因此叫作超参数(hyperparameter)。我们通常所说的“调参”指的正是调节超参数,例如通过反复试错来找到超参数合适的值。
模型预测
模型训练完成后,就可以使用学出的线性回归模型来估算训练数据集以外的数据的标签。这里的估算也叫作模型预测、模型推断或模型测试。
2.线性回归的表示方法
神经网络图
在这里插入图片描述
这是一个线性回归模型,神经网络图隐去了模型参数权重和偏差。
图中,输入层的输入个数为2。输入个数也叫特征数或特征向量维度。由于输入层并不涉及计算,按照惯例,故该图所示的神经网络的层数为1。所以,线性回归是一个单层神经网络。输出层中负责计算 o 的单元又叫神经元。在线性回归中, o 的计算依赖于 x1 和 x2 。也就是说,输出层中的神经元和输入层中各个输入完全连接。因此,这里的输出层又叫全连接层(fully-connected layer)或稠密层(dense layer)
矢量计算表达式
在模型训练或预测时,常常会同时处理多个数据样本并用到矢量计算。
下面定义两个1000维的向量做加法。
代码:

from d2l import torch as d2l
import math
import torch
import numpy as np
import time
n = 10000
a = d2l.ones(n)
b = d2l.ones(n)

为了对比标量和矢量运算运行时间,先定义一个类:

class Timer:  #@save
    """Record multiple running times."""
    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """Start the timer."""
        self.tik = time.time()

    def stop(self):
        """Stop the timer and record the time in a list."""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """Return the average time."""
        return sum(self.times) / len(self.times)

    def sum(self):
        """Return the sum of time."""
        return sum(self.times)

    def cumsum(self):
        """Return the accumulated time."""
        return np.array(self.times).cumsum().tolist()

然后分别测试:

c = d2l.zeros(n)
timer = Timer()
for i in range(n):
    c[i] = a[i] + b[i]
f'{timer.stop():.5f} sec'


timer.start()
d = a + b
f'{timer.stop():.5f} sec'

结果:

'0.11748 sec'

'0.00025 sec'

可以看到后者比前者更省时。因此,应该尽可能采用矢量计算,以提升计算效率。
当数据样本数为 n ,特征数为 d 时,线性回归的矢量计算表达式为:
y^=Xw+b,
其中模型输出 维度y^(n,1), 批量数据样本特征的维度 X(n,d) ,权重维度 w(d,1) , 偏差 b∈R 。设模型参数 θ=[w1,w2,b]⊤ ,可以重写损失函数为:
在这里插入图片描述
小批量随机梯度下降的迭代步骤将相应地改写为
在这里插入图片描述
其中梯度是损失关于3个为标量的模型参数的偏导数组成的向量:
在这里插入图片描述

手动@小宋是呢

猜你喜欢

转载自blog.csdn.net/laozaoxiaowanzi/article/details/107402957