3.1. 线性回归
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 Colab 中打开 Notebook
在 SageMaker Studio Lab 中打开 Notebook

每当我们想预测一个数值时,就会出现回归(regression)问题。常见的例子包括预测价格(房屋、股票等)、预测住院时间(医院的病人)、预测需求(零售额)等等。并非所有的预测问题都是经典的回归问题。在后面的章节中,我们将介绍分类问题,其目标是预测一组类别中的成员关系。

作为一个例子,假设我们希望根据房屋的面积(平方英尺)和房龄(年)来估计房屋价格(美元)。为了开发一个预测房价的模型,我们需要掌握包括每栋房屋的销售价格、面积和房龄在内的数据。在机器学习的术语中,该数据集称为训练数据集(training dataset)或训练集(training set),每行(此处是与一次销售相关的数据)称为一个样本(example)(或数据点实例样本)。我们试图预测的事物(价格)称为标签(label)或目标(target)。预测所依据的变量(房龄和面积)称为特征(feature)或协变量(covariate)。

%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l
%matplotlib inline
import math
import time
from mxnet import np
from d2l import mxnet as d2l
%matplotlib inline
import math
import time
from jax import numpy as jnp
from d2l import jax as d2l
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
%matplotlib inline
import math
import time
import numpy as np
import tensorflow as tf
from d2l import tensorflow as d2l

3.1.1. 基础

线性回归是解决回归问题的标准工具中最简单、最流行的一种。线性回归可以追溯到19世纪初 (Gauss, 1809, Legendre, 1805),它源于一些简单的假设。首先,我们假设特征 \(\mathbf{x}\) 和目标 \(y\) 之间的关系是近似线性的,即条件均值 \(E[Y \mid X=\mathbf{x}]\) 可以表示为特征 \(\mathbf{x}\) 的加权和。这种设定允许目标值由于观测噪声而偏离其期望值。其次,我们可以假设任何此类噪声都表现良好,遵循高斯分布。通常,我们用 \(n\) 来表示数据集中的样本数量。我们用上标来枚举样本和目标,用下标来索引坐标。更具体地说,\(\mathbf{x}^{(i)}\) 表示第 \(i^{\textrm{th}}\) 个样本,\(x_j^{(i)}\) 表示其第 \(j^{\textrm{th}}\) 个坐标。

3.1.1.1. 模型

每个解决方案的核心都是一个模型,它描述了如何将特征转换为对目标的估计。线性假设意味着目标的期望值(价格)可以表示为特征(面积和房龄)的加权和:

(3.1.1)\[\textrm{价格} = w_{\textrm{面积}} \cdot \textrm{面积} + w_{\textrm{房龄}} \cdot \textrm{房龄} + b.\]

在这里,\(w_{\textrm{area}}\)\(w_{\textrm{age}}\) 被称为权重(weights),而 \(b\) 被称为偏置(bias)(或偏移(offset)、截距(intercept))。权重决定了每个特征对我们预测的影响。偏置决定了当所有特征都为零时估计值的值。尽管我们永远不会看到任何面积恰好为零的新建房屋,但我们仍然需要偏置,因为它允许我们表达特征的所有线性函数(而不仅仅是限制我们于通过原点的线)。严格来说,(3.1.1) 是输入特征的仿射变换(affine transformation),其特点是通过加权和对特征进行线性变换(linear transformation),并通过加偏置进行平移(translation)。给定一个数据集,我们的目标是选择权重 \(\mathbf{w}\) 和偏置 \(b\),使得平均而言,我们模型的预测尽可能接近数据中观察到的真实价格。

在通常只关注少数特征的数据集的学科中,像 (3.1.1) 这样明确地以长形式表示模型是很常见的。在机器学习中,我们通常处理高维数据集,使用紧凑的线性代数表示法更为方便。当我们的输入由 \(d\) 个特征组成时,我们可以为每个特征分配一个索引(在 \(1\)\(d\) 之间),并将我们的预测 \(\hat{y}\)(通常,“帽子”符号表示估计值)表示为:

(3.1.2)\[\hat{y} = w_1 x_1 + \cdots + w_d x_d + b.\]

将所有特征收集到一个向量 \(\mathbf{x} \in \mathbb{R}^d\) 中,并将所有权重收集到一个向量 \(\mathbf{w} \in \mathbb{R}^d\) 中,我们可以通过 \(\mathbf{w}\)\(\mathbf{x}\) 之间的点积来紧凑地表达我们的模型:

(3.1.3)\[\hat{y} = \mathbf{w}^\top \mathbf{x} + b.\]

(3.1.3) 中,向量 \(\mathbf{x}\) 对应单个样本的特征。我们通常会发现通过设计矩阵(design matrix) \(\mathbf{X} \in \mathbb{R}^{n \times d}\) 来指代我们整个数据集的 \(n\) 个样本的特征会很方便。在这里,\(\mathbf{X}\) 包含每个样本的一行和每个特征的一列。对于一组特征 \(\mathbf{X}\),预测 \(\hat{\mathbf{y}} \in \mathbb{R}^n\) 可以通过矩阵-向量乘积来表示:

(3.1.4)\[{\hat{\mathbf{y}}} = \mathbf{X} \mathbf{w} + b,\]

其中在求和过程中应用了广播机制(2.1.4节)。给定训练数据集 \(\mathbf{X}\) 的特征和相应的(已知的)标签 \(\mathbf{y}\),线性回归的目标是找到权重向量 \(\mathbf{w}\) 和偏置项 \(b\),使得对于从与 \(\mathbf{X}\) 相同分布中抽样的新数据样本的特征,新样本的标签将(在期望中)以最小的误差被预测。

即使我们相信给定 \(\mathbf{x}\) 预测 \(y\) 的最佳模型是线性的,我们也不会期望在现实世界的数据集中找到 \(n\) 个样本,其中对于所有的 \(1 \leq i \leq n\)\(y^{(i)}\) 完全等于 \(\mathbf{w}^\top \mathbf{x}^{(i)}+b\)。例如,无论我们使用什么仪器来观察特征 \(\mathbf{X}\) 和标签 \(\mathbf{y}\),都可能存在少量的测量误差。因此,即使我们确信潜在关系是线性的,我们也会引入一个噪声项来解释这些误差。

在我们开始寻找最佳参数(或模型参数\(\mathbf{w}\)\(b\) 之前,我们还需要两样东西:(i)一个给定模型的质量度量;以及(ii)一个更新模型以提高其质量的程序。

3.1.1.2. 损失函数

自然地,将我们的模型与数据拟合需要我们认同某种衡量拟合度(或者说,不拟合度)的标准。损失函数(loss functions)量化了目标的真实值和预测值之间的距离。损失通常是一个非负数,值越小越好,完美的预测会产生0的损失。对于回归问题,最常见的损失函数是平方误差。当我们对样本 \(i\) 的预测是 \(\hat{y}^{(i)}\),对应的真实标签是 \(y^{(i)}\) 时,平方误差(squared error)由以下公式给出:

(3.1.5)\[l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2.\]

常数 \(\frac{1}{2}\) 并没有实际的区别,但它在符号上很方便,因为当我们对损失求导时它会抵消掉。由于训练数据集是给定的,因此不受我们控制,所以经验误差只是模型参数的函数。在 图 3.1.1 中,我们可视化了一个一维输入问题中线性回归模型的拟合情况。

../_images/fit-linreg.svg

图 3.1.1 将线性回归模型拟合到一维数据。

请注意,由于其二次形式,估计值 \(\hat{y}^{(i)}\) 和目标值 \(y^{(i)}\) 之间的巨大差异会导致对损失的贡献更大(这种二次性可能是一把双刃剑;虽然它鼓励模型避免大的错误,但也可能导致对异常数据过度敏感)。为了衡量模型在整个 \(n\) 个样本的数据集上的质量,我们只需对训练集上的损失进行平均(或等效地,求和):

(3.1.6)\[L(\mathbf{w}, b) =\frac{1}{n}\sum_{i=1}^n l^{(i)}(\mathbf{w}, b) =\frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2.\]

在训练模型时,我们寻求使所有训练样本的总损失最小化的参数(\(\mathbf{w}^*, b^*\)):

(3.1.7)\[\mathbf{w}^*, b^* = \operatorname*{argmin}_{\mathbf{w}, b}\ L(\mathbf{w}, b).\]

3.1.1.3. 解析解

与我们将要介绍的大多数模型不同,线性回归给我们提供了一个惊人简单的优化问题。具体来说,我们可以通过应用一个简单的公式来解析地找到最优参数(在训练数据上评估)。首先,我们可以通过在设计矩阵中附加一列全为1的列,将偏置 \(b\) 纳入参数 \(\mathbf{w}\) 中。然后我们的预测问题是最小化 \(\|\mathbf{y} - \mathbf{X}\mathbf{w}\|^2\)。只要设计矩阵 \(\mathbf{X}\) 具有满秩(没有特征线性依赖于其他特征),那么损失曲面上就只有一个临界点,它对应于整个域上的损失最小值。将损失对 \(\mathbf{w}\) 求导并令其等于零,得到:

(3.1.8)\[\begin{aligned} \partial_{\mathbf{w}} \|\mathbf{y} - \mathbf{X}\mathbf{w}\|^2 = 2 \mathbf{X}^\top (\mathbf{X} \mathbf{w} - \mathbf{y}) = 0 \textrm{ 因此 } \mathbf{X}^\top \mathbf{y} = \mathbf{X}^\top \mathbf{X} \mathbf{w}. \end{aligned}\]

解出 \(\mathbf{w}\) 为我们提供了优化问题的最优解。请注意,这个解

(3.1.9)\[\mathbf{w}^* = (\mathbf X^\top \mathbf X)^{-1}\mathbf X^\top \mathbf{y}\]

只有当矩阵 \(\mathbf X^\top \mathbf X\) 是可逆的时候,即当设计矩阵的列是线性无关的时候才是唯一的 (Golub and Van Loan, 1996)

虽然像线性回归这样的简单问题可能存在解析解,但你不应该习惯于这样的好运。尽管解析解可以进行很好的数学分析,但对解析解的要求是如此严格,以至于它会排除几乎所有深度学习中令人兴奋的方面。

3.1.1.4. 小批量随机梯度下降

幸运的是,即使在无法解析求解模型的情况下,我们通常仍然可以在实践中有效地训练模型。此外,对于许多任务,那些难以优化的模型结果要好得多,以至于弄清楚如何训练它们最终是值得的。

优化几乎所有深度学习模型的关键技术,我们将在本书中反复使用,是通过迭代地更新参数来减小误差,更新方向是增量地降低损失函数的方向。这个算法被称为梯度下降(gradient descent)。

梯度下降最朴素的应用是取损失函数的导数,这个损失函数是在数据集中每个样本上计算的损失的平均值。在实践中,这可能非常慢:我们必须遍历整个数据集才能进行一次更新,即使更新步骤可能非常强大 (Liu and Nocedal, 1989)。更糟糕的是,如果训练数据中存在大量冗余,那么完整更新的好处是有限的。

另一个极端是一次只考虑一个样本,并根据一次观测进行更新。由此产生的算法,随机梯度下降(stochastic gradient descent,SGD),可以是一种有效的策略 (Bottou, 2010),即使对于大型数据集也是如此。不幸的是,SGD在计算和统计上都有缺点。一个问题是处理器乘法和加法比从主内存移动数据到处理器缓存快得多。执行矩阵-向量乘法比执行相应数量的向量-向量运算要高效一个数量级。这意味着一次处理一个样本可能比处理一个完整的批次花费更长的时间。第二个问题是,某些层,如批量归一化(将在 8.5节 中描述),只有在我们一次可以访问多个观测值时才能很好地工作。

解决这两个问题的办法是选择一个中间策略:不是采用完整的批次或一次只采用一个样本,而是采用一个小批量(minibatch)的观测值 (Li et al., 2014)。所述小批量的具体大小取决于许多因素,如内存量、加速器数量、层的选择以及总数据集大小。尽管如此,一个介于32和256之间的数字,最好是 \(2\) 的大次方的倍数,是一个很好的起点。这引出了小批量随机梯度下降(minibatch stochastic gradient descent)。

在其最基本的形式中,在每次迭代 \(t\) 中,我们首先随机抽样一个由固定数量 \(|\mathcal{B}|\) 的训练样本组成的小批量 \(\mathcal{B}_t\)。然后,我们计算小批量上平均损失相对于模型参数的导数(梯度)。最后,我们将梯度乘以一个预定的小的正值 \(\eta\),称为学习率(learning rate),并从当前参数值中减去所得项。我们可以将更新表示如下:

(3.1.10)\[(\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}_t} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b).\]

总结一下,小批量SGD的过程如下:(i)初始化模型参数的值,通常是随机的;(ii)从数据中迭代地抽样随机小批量,沿着负梯度方向更新参数。对于二次损失和仿射变换,这有一个闭式展开:

(3.1.11)\[\begin{split}\begin{aligned} \mathbf{w} & \leftarrow \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}_t} \partial_{\mathbf{w}} l^{(i)}(\mathbf{w}, b) && = \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}_t} \mathbf{x}^{(i)} \left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)\\ b &\leftarrow b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}_t} \partial_b l^{(i)}(\mathbf{w}, b) && = b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}_t} \left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right). \end{aligned}\end{split}\]

由于我们选择了一个小批量 \(\mathcal{B}\),我们需要按其大小 \(|\mathcal{B}|\) 进行归一化。小批量大小和学习率通常是用户定义的。这种在训练循环中不被更新的可调参数称为超参数(hyperparameters)。它们可以通过多种技术自动调整,例如贝叶斯优化 (Frazier, 2018)。最终,解决方案的质量通常在单独的验证数据集(validation dataset)或验证集(validation set)上进行评估。

在训练了预定数量的迭代次数后(或直到满足其他停止标准),我们记录估计的模型参数,记为 \(\hat{\mathbf{w}}, \hat{b}\)。请注意,即使我们的函数是真正的线性和无噪声的,这些参数也不会是损失的精确最小化者,甚至不是确定性的。虽然算法缓慢地收敛到最小化者,但它通常不会在有限的步数内精确地找到它们。此外,用于更新参数的小批量 \(\mathcal{B}\) 是随机选择的。这打破了确定性。

线性回归恰好是一个具有全局最小值的学习问题(只要 \(\mathbf{X}\) 是满秩的,或者等价地,只要 \(\mathbf{X}^\top \mathbf{X}\) 是可逆的)。然而,深度网络的损失曲面包含许多鞍点和极小值。幸运的是,我们通常不关心找到一组精确的参数,而只关心任何能导致准确预测(从而低损失)的参数集。在实践中,深度学习从业者很少费力去寻找在训练集上最小化损失的参数 (Frankle and Carbin, 2018, Izmailov et al., 2018)。更艰巨的任务是找到能在以前未见过的数据上做出准确预测的参数,这个挑战称为泛化(generalization)。我们将在本书中反复回到这些主题。

3.1.1.5. 预测

给定模型 \(\hat{\mathbf{w}}^\top \mathbf{x} + \hat{b}\),我们现在可以对一个新的样本进行预测,例如,根据其面积 \(x_1\) 和房龄 \(x_2\) 预测一个以前未见过的房屋的销售价格。深度学习从业者已将预测阶段称为推断(inference),但这有点用词不当——推断广义上指基于证据得出的任何结论,包括参数值和未见实例的可能标签。如果说有什么不同的话,在统计学文献中,推断更常指参数推断,当深度学习从业者与统计学家交谈时,这种术语的重载会造成不必要的混淆。在下文中,我们将尽可能地坚持使用预测

3.1.2. 矢量化加速

在训练我们的模型时,我们通常希望同时处理整个小批量的样本。要高效地做到这一点,需要我们对计算进行矢量化,并利用快速的线性代数库,而不是在Python中编写代价高昂的for循环。

为了说明为什么这如此重要,让我们考虑两种添加向量的方法。首先,我们实例化两个包含全1的10000维向量。在第一种方法中,我们用Python的for循环遍历向量。在第二种方法中,我们依赖于对 + 的单次调用。

n = 10000
a = torch.ones(n)
b = torch.ones(n)
n = 10000
a = np.ones(n)
b = np.ones(n)
[22:06:52] ../src/storage/storage.cc:196: Using Pooled (Naive) StorageManager for CPU
n = 10000
a = jnp.ones(n)
b = jnp.ones(n)
n = 10000
a = tf.ones(n)
b = tf.ones(n)

现在我们可以对工作负载进行基准测试。首先,我们使用for循环逐个坐标地相加。

c = torch.zeros(n)
t = time.time()
for i in range(n):
    c[i] = a[i] + b[i]
f'{time.time() - t:.5f} sec'
'0.17802 sec'
c = np.zeros(n)
t = time.time()
for i in range(n):
    c[i] = a[i] + b[i]
f'{time.time() - t:.5f} sec'
'4.71889 sec'
# JAX arrays are immutable, meaning that once created their contents
# cannot be changed. For updating individual elements, JAX provides
# an indexed update syntax that returns an updated copy
c = jnp.zeros(n)
t = time.time()
for i in range(n):
    c = c.at[i].set(a[i] + b[i])
f'{time.time() - t:.5f} sec'
'22.65637 sec'
c = tf.Variable(tf.zeros(n))
t = time.time()
for i in range(n):
    c[i].assign(a[i] + b[i])
f'{time.time() - t:.5f} sec'
'13.09047 sec'

或者,我们依赖重载的 + 运算符来计算按元素求和。

t = time.time()
d = a + b
f'{time.time() - t:.5f} sec'
'0.00036 sec'
t = time.time()
d = a + b
f'{time.time() - t:.5f} sec'
'0.00053 sec'
t = time.time()
d = a + b
f'{time.time() - t:.5f} sec'
'0.01782 sec'
t = time.time()
d = a + b
f'{time.time() - t:.5f} sec'
'0.00030 sec'

第二种方法比第一种快得多。矢量化代码通常会带来数量级的速度提升。此外,我们将更多的数学运算推给库,因此我们不必自己编写那么多计算,从而减少了出错的可能性并增加了代码的可移植性。

3.1.3. 正态分布和平方损失

到目前为止,我们已经给出了平方损失目标的一个相当功能性的动机:当潜在模式是真正线性时,最优参数返回条件期望 \(E[Y\mid X]\),并且损失对异常值分配大的惩罚。我们还可以通过对噪声分布进行概率假设,为平方损失目标提供更正式的动机。

线性回归发明于19世纪初。虽然高斯或勒让德谁先想到这个想法一直存在争议,但高斯也发现了正态分布(也称为高斯分布)。事实证明,正态分布和带有平方损失的线性回归有着比共同的起源更深的联系。

首先,回想一下,均值为 \(\mu\)、方差为 \(\sigma^2\)(标准差为 \(\sigma\))的正态分布表示为:

(3.1.12)\[p(x) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp\left(-\frac{1}{2 \sigma^2} (x - \mu)^2\right).\]

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

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

我们现在可以可视化正态分布。

# Use NumPy again for visualization
x = np.arange(-7, 7, 0.01)

# Mean and standard deviation pairs
params = [(0, 1), (0, 2), (3, 1)]
d2l.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])
../_images/output_linear-regression_d0729f_78_0.svg
# Use NumPy again for visualization
x = np.arange(-7, 7, 0.01)

# Mean and standard deviation pairs
params = [(0, 1), (0, 2), (3, 1)]
d2l.plot(x.asnumpy(), [normal(x, mu, sigma).asnumpy() 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])
../_images/output_linear-regression_d0729f_81_0.svg
# Use JAX NumPy for visualization
x = jnp.arange(-7, 7, 0.01)
# Mean and standard deviation pairs
params = [(0, 1), (0, 2), (3, 1)]
d2l.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])
../_images/output_linear-regression_d0729f_84_0.svg
# Use NumPy again for visualization
x = np.arange(-7, 7, 0.01)

# Mean and standard deviation pairs
params = [(0, 1), (0, 2), (3, 1)]
d2l.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])
../_images/output_linear-regression_d0729f_87_0.svg

请注意,改变均值对应于沿 \(x\) 轴的平移,而增加方差会使分布变宽,降低其峰值。

激励带有平方损失的线性回归的一种方法是,假设观测值来自有噪声的测量,其中噪声 \(\epsilon\) 服从正态分布 \(\mathcal{N}(0, \sigma^2)\)

(3.1.13)\[y = \mathbf{w}^\top \mathbf{x} + b + \epsilon \textrm{ 其中 } \epsilon \sim \mathcal{N}(0, \sigma^2).\]

因此,我们现在可以通过以下方式写出对于给定 \(\mathbf{x}\) 看到特定 \(y\)可能性(likelihood):

(3.1.14)\[P(y \mid \mathbf{x}) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp\left(-\frac{1}{2 \sigma^2} (y - \mathbf{w}^\top \mathbf{x} - b)^2\right).\]

因此,似然函数可以分解。根据最大似然原理(principle of maximum likelihood),参数 \(\mathbf{w}\)\(b\) 的最佳值是使整个数据集的似然最大化的那些值:

(3.1.15)\[P(\mathbf y \mid \mathbf X) = \prod_{i=1}^{n} p(y^{(i)} \mid \mathbf{x}^{(i)}).\]

等式成立是因为所有的 \((\mathbf{x}^{(i)}, y^{(i)})\) 对都是相互独立地抽取的。根据最大似然原理选择的估计器称为最大似然估计器。虽然最大化许多指数函数的乘积可能看起来很困难,但我们可以通过最大化似然的对数来显著简化问题,而不会改变目标。由于历史原因,优化更多地表示为最小化而不是最大化。所以,在不改变任何东西的情况下,我们可以最小化负对数似然,我们可以表示如下:

(3.1.16)\[-\log P(\mathbf y \mid \mathbf X) = \sum_{i=1}^n \frac{1}{2} \log(2 \pi \sigma^2) + \frac{1}{2 \sigma^2} \left(y^{(i)} - \mathbf{w}^\top \mathbf{x}^{(i)} - b\right)^2.\]

如果我们假设 \(\sigma\) 是固定的,我们可以忽略第一项,因为它不依赖于 \(\mathbf{w}\)\(b\)。第二项与前面介绍的平方误差损失相同,只是有一个乘法常数 \(\frac{1}{\sigma^2}\)。幸运的是,解也不依赖于 \(\sigma\)。因此,在加性高斯噪声的假设下,最小化均方误差等价于线性模型的最大似然估计。

3.1.4. 作为神经网络的线性回归

虽然线性模型不足以表达我们将在本书中介绍的许多复杂网络,但(人工)神经网络足够丰富,可以将线性模型包含为其中每个特征由一个输入神经元表示,并且所有这些神经元都直接连接到输出的网络。

图 3.1.2 将线性回归描绘成一个神经网络。该图突出了连接模式,例如每个输入如何连接到输出,但没有显示权重或偏置的具体值。

../_images/singleneuron.svg

图 3.1.2 线性回归是一个单层神经网络。

输入是 \(x_1, \ldots, x_d\)。我们将 \(d\) 称为输入层中的输入数量特征维度。网络的输出是 \(o_1\)。因为我们只是试图预测一个单一的数值,所以我们只有一个输出神经元。请注意,输入值都是给定的。只有一个计算出的神经元。总之,我们可以将线性回归看作一个单层全连接神经网络。我们将在后面的章节中遇到具有更多层的网络。

3.1.4.1. 生物学

由于线性回归早于计算神经科学,用神经网络来描述线性回归似乎有些不合时宜。然而,当控制论者和神经生理学家沃伦·麦卡洛克和沃尔特·皮茨开始开发人工神经元模型时,它们是一个自然的起点。请看 图 3.1.3 中生物神经元的卡通图,它由树突(输入终端)、细胞核(CPU)、轴突(输出线)和轴突末梢(输出终端)组成,通过突触实现与其他神经元的连接。

../_images/neuron.svg

图 3.1.3 真实的神经元(来源:美国国家癌症研究所的监测、流行病学和最终结果(SEER)计划的“解剖学和生理学”)。

来自其他神经元(或环境传感器)的信息 \(x_i\) 在树突中接收。具体来说,该信息由突触权重 \(w_i\) 加权,决定输入的影响,例如通过乘积 \(x_i w_i\) 激活或抑制。来自多个来源的加权输入在细胞核中聚合成加权和 \(y = \sum_i x_i w_i + b\),可能经过一个函数 \(\sigma(y)\) 的非线性后处理。然后,这些信息通过轴突发送到轴突末梢,在那里到达其目的地(例如,像肌肉这样的执行器)或通过其树突被馈送到另一个神经元。

当然,许多这样的单元可以组合起来,只要它们有正确的连接和学习算法,就能产生比任何一个神经元单独能表达的更有趣和复杂的行为,这个高层次的想法来自于我们对真实生物神经系统的研究。与此同时,今天深度学习的大多数研究都从更广泛的来源汲取灵感。我们引用 Russell and Norvig (2016) 的观点,他们指出,尽管飞机可能受到鸟类的启发,但鸟类学在过去几个世纪里并不是航空创新的主要驱动力。同样,今天深度学习的灵感同样或更多地来自数学、语言学、心理学、统计学、计算机科学和许多其他领域。

3.1.5. 小结

在本节中,我们介绍了传统的线性回归,其中线性函数的参数被选择以最小化训练集上的平方损失。我们还通过一些实际考虑和将线性回归解释为在线性度和高斯噪声假设下的最大似然估计来激励这种目标选择。在讨论了计算考虑和与统计学的联系之后,我们展示了如何将这种线性模型表示为简单的神经网络,其中输入直接连接到输出。虽然我们很快将超越线性模型,但它们足以介绍我们所有模型所需的大部分组件:参数形式、可微目标、通过小批量随机梯度下降进行优化,以及最终在以前未见过的数据上进行评估。

3.1.6. 练习

  1. 假设我们有一些数据 \(x_1, \ldots, x_n \in \mathbb{R}\)。我们的目标是找到一个常数 \(b\),使得 \(\sum_i (x_i - b)^2\) 最小化。

    1. \(b\) 的最优值的解析解。

    2. 这个问题及其解与正态分布有什么关系?

    3. 如果我们将损失从 \(\sum_i (x_i - b)^2\) 改为 \(\sum_i |x_i-b|\) 呢?你能找到 \(b\) 的最优解吗?

  2. 证明可以用 \(\mathbf{x}^\top \mathbf{w} + b\) 表示的仿射函数等价于 \((\mathbf{x}, 1)\) 上的线性函数。

  3. 假设您想找到 \(\mathbf{x}\) 的二次函数,即 \(f(\mathbf{x}) = b + \sum_i w_i x_i + \sum_{j \leq i} w_{ij} x_{i} x_{j}\)。您将如何在深度网络中构建它?

  4. 回想一下,线性回归问题可解的条件之一是设计矩阵 \(\mathbf{X}^\top \mathbf{X}\) 具有满秩。

    1. 如果不是这种情况会发生什么?

    2. 你该如何解决这个问题?如果在 \(\mathbf{X}\) 的所有条目上添加少量坐标独立的的高斯噪声会发生什么?

    3. 在这种情况下,设计矩阵 \(\mathbf{X}^\top \mathbf{X}\) 的期望值是什么?

    4. \(\mathbf{X}^\top \mathbf{X}\) 不是满秩时,随机梯度下降会发生什么?

  5. 假设控制加性噪声 \(\epsilon\) 的噪声模型是指数分布。也就是说,\(p(\epsilon) = \frac{1}{2} \exp(-|\epsilon|)\)

    1. 写出模型下数据的负对数似然 \(-\log P(\mathbf y \mid \mathbf X)\)

    2. 你能找到一个封闭形式的解吗?

    3. 建议一个解决此问题的小批量随机梯度下降算法。可能会出什么问题(提示:当我们不断更新参数时,在驻点附近会发生什么)?你能解决这个问题吗?

  6. 假设我们想通过组合两个线性层来设计一个具有两层的神经网络。也就是说,第一层的输出成为第二层的输入。为什么这种朴素的组合不起作用?

  7. 如果你想用回归对房屋或股票价格进行实际的价格估计,会发生什么?

    1. 证明加性高斯噪声假设是不合适的。提示:我们能有负价格吗?波动呢?

    2. 为什么对价格的对数进行回归会更好,即 \(y = \log \textrm{price}\)

    3. 在处理仙股(即价格非常低的股票)时你需要担心什么?提示:你可以在所有可能的价格进行交易吗?为什么这对便宜的股票来说是个更大的问题?更多信息请回顾著名的期权定价布莱克-斯科尔斯模型 (Black and Scholes, 1973)

  8. 假设我们想用回归来估计杂货店出售的苹果数量

    1. 高斯加性噪声模型有什么问题?提示:你卖的是苹果,不是石油。

    2. 泊松分布 捕捉了计数的分布。它由 \(p(k \mid \lambda) = \lambda^k e^{-\lambda}/k!\) 给出。这里 \(\lambda\) 是速率函数,\(k\) 是你看到的事件数。证明 \(\lambda\) 是计数 \(k\) 的期望值。

    3. 设计一个与泊松分布相关的损失函数。

    4. 设计一个用于估计 \(\log \lambda\) 的损失函数。