浅析线性神经网络——线性回归问题

content

1. 线性回归[0]

1.1 回归(regression):[0]

1.2 线性回归的基本元素:[0]

1.3 线性模型:[0]

1.4 损失函数 [0]

2.基本优化算法[0]

2.1 梯度下降[0]

2.2 小批量随机梯度下降 [0]

3.矢量化加速[0]

4. 正态分布和平方损失[0]

Summarize[0]

1. 线性回归

1.1 回归(regression):

是一类可以对一个或多个自变量与因变量之间的关系进行建模的方法。

在自然科学和社会科学中,回归常用于表达输入和输出之间的关系。
        在机器学习领域中的大多数任务通常都与预测(prediction)有关。
当我们想要预测一个数值时,就涉及到回归。
常见的例子包括:预测价格(房屋、股票等)、预测住院时间(住院病人等)、预测需求(零售等)。
但并非所有预测都是回归问题。

1.2 线性回归的基本元素:

        线性回归(linear regression):可以追溯到19世纪初,它在回归的各种标准工具中最简单而且最流行。

线性回归基于一些简单的假设:

  • 假设自变量和因变量之间的关系是线性的,即可以表示为介质中元素的加权和,这里通常允许包含观测值的一些噪声;
  • 我们假设任何噪声都是相对正常的,即噪声服从正态分布。

1.3 线性模型:

        线性假设如下面的式子:y =  w1x1+w2x2+w3x3+b

  • 权重决定了每个特征对我们的预测值的影响。
  • b称为偏置(bias)、偏移量(offset)或截距(intercept)。偏置是指当所有特征都取值为0时,预测值应该为多少。
  • 在任何实际情况下,我们都需要偏置项。如果没有偏差项,我们模型的表达能力将受到限制。
  • 给定一个数据集,我们的目标是找到模型的权重和偏差,以使模型做出的预测与数据中的真实价格大致匹配。
  • 在机器学习领域,我们通常使用高维数据集,使用线性代数符号进行建模将
    更方便。

        当我们的输入包含个特征时,我们将预测结果\hat{y}(通常使用“尖角”符号表示的估计值)表示为:\hat{y} = w1x1+w2x2+···+wnxn+b,我们可以用点积形式来简洁地表达模型:\hat{y}=w⋅x+b.

        无论我们使用什么手段来观察特征X和标签y, 都可能会出现少量的观测误差。 因此,即使确信特征与标签的潜在关系是线性的, 我们也会加入一个噪声项来考虑观测误差带来的影响。

        在开始寻找最好的模型参数(model parameters)w\mathbf{w}w和bbb之前, 我们还需要两个东西: (1)一种模型质量的度量方式; (2)一种能够更新模型以提高模型预测质量的方法。

1.4 损失函数 

        在我们开始考虑如何用模型拟合(fit)数据之前,我们需要确定一个拟合程度的度量。 损失函数(loss function)能够量化目标的实际值与预测值之间的差距。 通常我们会选择非负数作为损失,且数值越小表示损失越小,完美预测时的损失为0。

回归问题中最常用的损失函数是平方误差函数。

当样本的预测值为\hat{y},其相应的真实标签为y时, 平方误差可以定义为以下公式: 

Loss = \frac{1}{2}\left ( \hat{y} -y\right )^{2}

        常数1/2​不会带来本质的差别,但这样在形式上稍微简单一些 (因为当我们对损失函数求导后常数系数为1)

我们为一维情况下的回归问题绘制图像:

        由于平方误差函数中的二次方项, 估计值和观测值之间较大的差异将导致更大的损失。 为了度量模型在整个数据集上的质量,我们需计算在训练集nnn个样本上的损失均值(也等价于求和)。 

1.5 学习数据

        理论上学习数据越多越好,我们通过最小化损失来学习参数(w、b)。损失是凸函数,所以最优解满足:梯度=0

2.基本优化算法

2.1 梯度下降

        我们用到一种名为梯度下降(gradient descent)的方法, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。w0—>w优

梯度下降最简单的用途是计算损失函数(数据集中所有样本的损失的平均值)相对于模型参数(这里也称为梯度)的导数。但实际上执行可能非常缓慢:我们必须在每次参数更新之前遍历整个数据集。

         因此,我们通常会在每次需要计算更新的时候随机抽取一小批样本, 这种变体叫做小批量随机梯度下降(minibatch stochastic gradient descent)。

2.2 小批量随机梯度下降 

        在每次迭代中,我们首先随机抽样一个小批量bbb, 它是由固定数量的训练样本组成的。 然后,我们计算小批量的平均损失关于模型参数的导数(也可以称为梯度)。 最后,我们将梯度乘以一个预先确定的正数η\etaη,并从当前参数的值中减掉。

我们用以下数学公式(∂ 表示偏导数)来表达这个更新过程:

        b表示每个小批量中的样本数,这也称为批量大小(batch size)。 η\etaη表示学习率(learning rate)。

        批量大小和学习率的值通常是手动预先指定,而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数(hyperparameter)。 

        调参(hyperparameter tuning)是选择超参数的过程。 超参数通常是我们根据训练迭代结果来调整的, 而训练迭代结果是在独立的验证数据集(validation dataset)上评估得到的。

在训练预定次数的迭代后(或直到满足其他一些停止条件),我们记录模型参数的估计值,用\hat{w},\hat{b}表示。

然而,即使我们的函数确实是线性且无噪声的,这些估计并没有真正最小化损失函数。因为该算法会使loss慢慢地向最小值收敛,但在有限的步数内不能很准确地达到最小值。

线性回归恰好是一个学习问题,在整个领域中只有一个最小值。但是对于像深度神经网络这样的复杂模型,损失平面通常包含多个最小值。

        深度学习实践者很少会去花费大力气寻找这样一组参数,使得在训练集上的损失达到最小。 事实上,更难做到的是找到一组参数,这组参数能够在我们从未见过的数据上实现较低的损失, 这一挑战被称为泛化(generalization)。

综上所述,算法的步骤如下:

  • 初始化模型参数的值,如随机初始化;
  • 从数据集中随机采样 mini-batches,并在负梯度方向更新参数,并迭代此步骤。

3.矢量化加速

        在训练我们的模型时,我们经常希望能够同时处理整个小批量的样本。 为了实现这一点,需要我们对计算进行矢量化, 从而利用线性代数库,而不是在Python中编写开销高昂的for循环。

我们将经常对运行时进行基准测试,因此我们定义了一个计时器:

class Timer:  #@save
    """记录多次运行时间"""
    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """启动计时器"""
        self.tik = time.time()

    def stop(self):
        """停止计时器并将时间记录在列表中"""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """返回平均时间"""
        return sum(self.times) / len(self.times)

    def sum(self):
        """返回时间总和"""
        return sum(self.times)

    def cumsum(self):
        """返回累计时间"""
        return np.array(self.times).cumsum().tolist()

        我们实例化两个全为1的10000维向量。 在一种方法中,我们将使用Python的for循环遍历向量; 在另一种方法中,我们将依赖对+的调用。

import math
import time
import numpy as np
import paddle
from paddle.tensor.random import rand
from matplotlib import pyplot as plt
from IPython import display

class Timer:  #@save
    """记录多次运行时间"""
    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """启动计时器"""
        self.tik = time.time()

    def stop(self):
        """停止计时器并将时间记录在列表中"""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """返回平均时间"""
        return sum(self.times) / len(self.times)

    def sum(self):
        """返回时间总和"""
        return sum(self.times)

    def cumsum(self):
        """返回累计时间"""
        return np.array(self.times).cumsum().tolist()

n = 10000
a = paddle.ones(shape=[n])
b = paddle.ones(shape=[n])

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

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

结果很明显,第二种方法比第一种方法快得多。向量化代码通常会导致数量级的加速。另外,我们将更多的数学运算放入库中,而不必自己编写尽可能多的计算,从而减少了出错的机会。

4. 正态分布和平方损失

接下来,我们通过对噪声分布做出假设来解释平方损失目标函数。

        正态分布和线性回归之间的关系很密切。 正态分布(normal distribution),也称为高斯分布(Gaussian distribution), 最早由德国数学家高斯(Gauss)应用于天文学研究。         简单的说,若随机变量x具有均值μ和方差\sigma ^{2}(标准差σ),其正态分布概率密度函数如下:

下面我们定义一个Python函数来计算正态分布: 

import math
import time
import numpy as np
import paddle
from paddle.tensor.random import rand
from matplotlib import pyplot as plt
from IPython import display

def normal(x, mu, sigma):
    p = 1 / math.sqrt(2 * math.pi * sigma**2)
    return p * np.exp(-0.5 / sigma**2 * (x - mu)**2)

def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()

def use_svg_display():  #@save
    """使用svg格式在Jupyter中显示绘图"""
    display.set_matplotlib_formats('svg')

def set_figsize(figsize=(3.5, 2.5)):  #@save
    """设置matplotlib的图表大小"""
    use_svg_display()
    plt.rcParams['figure.figsize'] = figsize


def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
    """绘制数据点"""
    if legend is None:
        legend = []

    set_figsize(figsize)
    axes = axes if axes else plt.gca()

    # 如果X有一个轴,输出True
    def has_one_axis(X):
        return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
                and not hasattr(X[0], "__len__"))

    if has_one_axis(X):
        X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        if len(x):
            axes.plot(x, y, fmt)
        else:
            axes.plot(y, fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)

# 再次使用numpy进行可视化
x = np.arange(-7, 7, 0.01)
print(x)

# 均值和标准差对
params = [(0, 1), (0, 2), (3, 1)]

plot(x, [normal(x, mu, sigma) for mu, sigma in params], xlabel='x',
         ylabel='p(x)', figsize=(4.5, 2.5),
         legend=[f'mean {mu}, std {sigma}' for mu, sigma in params])

Summarize

  • 机器学习模型中的关键元素是训练数据、损失函数、优化算法和模型本身。
  • 矢量化使数学变得更简单、更快。
  • 最小化目标函数相当于执行最大似然估计。
  • 线性回归模型也是一个简单的神经网络。
  • 梯度下降是通过沿逆梯度方向不断更新参数来解决的。
  • 小批量随机梯度下降是深度学习的默认解决方案算法。
  • 两个重要的超参数是批量大小和学习率。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2022年5月6日
下一篇 2022年5月6日

相关推荐