线性回归模型指南 - 理论部分

最近,重新刷起了吴恩达的机器学习课程,系统性复习了之前学过的知识,发现又有不少收获,打算仔细整理一番👍

要谈论什么是线性回归首先要对什么是机器学习有一个基本的认识,什么是机器学习?抽象来说机器学习就是学习一个函数 $$ f(input) = output $$ 其中 $f$ 指的就是具体的机器学习模型。机器学习就是自动拟合输入 - 输出之间的关系的一套方法论。有时候我们会发现一些问题很难定义出一个具体的算法来解决,这时就是机器学习发光发热的地方了,我们可以让它从数据中自己学习、总结一些模式,做出相关的预测。这也是它和传统的算法(二分、递归等)区别的地方。不得不承认,机器学习从定义上来说就很迷人,它似乎为所有难以解决的问题提供了一套可行的解决框架。恰恰现实生活中的一些问题就是很难用传统算法解决的

📒 为此,我总觉得每个程序员都应该懂点机器学习/深度学习,它也是我们解决问题的一大工具💪

线性回归就是经典的机器学习入门模型之一,可以说是机器学习界的 “Hello world”经典的比如波士顿房价预测项目(虽然说现在已经是烂大街的项目了)

前面的公式中,$input$ 为机器学习中所谓的特征(Feature),常用记号 $x$ 表示。而 $output$ 可以根据是预测值还是预测类别可以大致划分为回归问题(Regression problem)和分类问题(Classification problem)两大类

📒 如何理解特征?所谓特征就是,跟要预测的东西高度相关的东西还是用预测房价作为例子,房价显然跟占地面积、绿化条件等相关,这里的占地面积等就是特征。机器学习中可以对特征分析,看哪些跟输出的关联程度高,或者运用我们的领域知识(Domain knowledge),自己选择好的特征。但总的来说,机器学习还是要求我们花费大量精力在提取好的特征上,这也是机器学习被人诟病的地方,而这个缺点在深度学习中被大大缓解,当然那是后话了

📒 机器学习无法魔法般地理解你提供的各种格式的 $input$,比如图片、文本、视频等。在机器学习中,$input$ 常常被处理为数字,才能用各种机器学习方法学习。有些特征本身就是数字,比如预测房价,房子的占地面积这个特征本身就是一个数字。当输入不是数字的时候,就需要别的手段将输入转化为数字,比如用词嵌入向量模型表示文本等,这里不展开细讲。我们暂时假设已经将输入处理为了数字的形式

今天要提到的线性回归模型就属于监督学习分类下的回归模型,它足够简单,但是又可以阐述很多机器学习的思想,用来入门是再适合不过了。话不多说,让我们开始吧 :)

📒 本文假定你对基本的微积分和线性代数有所了解,比如你需要知道行向量乘列向量如何进行以及对应的记号表示,矩阵乘法的定义,函数如何求导等

线性回归的英文是 Linear regression。顾名思义,由两部分组成:

  • Linear 的含义就是它是线性的以二维平面为例,$y=kx+b$ 这种就是线性,画出来是一条直线,而 $y=x^2$ 这种就不是,因为它画出来为曲线
  • Regression 是因为它符合机器学习中对回归问题的定义——预测一个不限制范围的值

📒 为了形式的简洁下面的记号 $f(x)$ 其实省略了下标 $w,b$。$f(x)=f_{w,b}(x)$

📒 有时候会看到有的书或者博客用 $h_\theta$ 表示模型,我认为 $f(x)$ 比较简洁就用了这个记法

如果要进一步对线性回归模型进行细分,又可以分成如下几类

如果模型的输入特征只有一个,就叫做单变量线性回归(Univariate linear regression),此时达到了最简单的形式 $$ f(x)=wx+b $$ 在机器学习中,分别称 $w$ 和 $b$ 为权重(Weight)和偏置项(Bias)

📒 注意:$\theta$ 为一个向量,按道理应该用 $\vec \theta$ 表示,但是下面为了简洁,我都省略了箭头

📒 也可以用向量的形式写,用 $\theta=[b, w]$ 表示模型的参数,令 $\vec x=[1, x]^T$。那么根据向量乘法的知识我们可以知道 $\theta^T\vec x=wx+b$

如果模型有多个输入的特征,就叫做多变量线性回归(Multiple linear regresseion) $$ f(x)=w_1x_1+w_1x_2+…w_nx_n+b $$ 其中 $x_i$ 是不同的特征,一共有 $n$ 个特征,为此我们需要每个特征学习一个权重 $w_i$

📒 同理,可以选择用向量的形式来写,令 $\theta=[b, w_1, w_2, …, w_n]$,$\vec x=[1, x_1, x_2, …, x_n]^T$,向量乘法之后也可以得到上面的形式。你会惊讶地发现,单变量线性回归和多变量线性回归有了统一的形式——$f(\vec x)=\theta^T\vec x$这在后面求解梯度的时候会带来很大的方便

定义了线性回归模型之后,我们需要衡量它的预测好坏,显然,我们希望预测的值跟实际上的值的“距离”越接近越好。在机器学习中,我们会规定一个损失函数(Cost function)衡量“距离”,损失自然是越低越好。当模型在验证集上的损失降到最低不再明显变化的时候,我们认为模型收敛了,此时得到了最好的模型

📒 在机器学习中,通常将数据划分为训练集/验证集/测试集,模型用训练集上的数据学习,在验证集上验证、调参,最后在测试集上进行泛化性验证(测试集包含没有见过的数据)。只用训练集/测试集这种划分方法,直接在测试集上调参是不正确的做法。测试集当且仅当最后你训练和调参结束,选出你认为的最好模型的的时候,在论文里面是报告结果的时候采用的

线性回归模型的损失函数最常用的是均平方误差,我更经常直接用英文的缩写 MSE(Mean square error)代指。其公式如下:

$$ MSE=\frac{1}{2m}\sum^m_{i=1}(\hat y^{(i)} - y^{(i)})^2 $$

其中

  • $m$ 表示样本个数
  • 上角标 ${(i)}$ 加了括号,和指数的记号进行区分,表示第 $i$ 个样本的预测/真实值
  • $\hat y$ 这个记号表示线性回归模型的预测,$y$ 表示本来的真实值

📒 我采用了符合机器学习惯例的记号,推荐记住~

📒 线性回归模型不是非要用 MSE,也可以用绝对值误差 MAE,MAE 适用于:当数据集中的异常值(Outlier)比较多的时候,降低对这种样本的敏感度

前面提到当模型在验证集上的损失降到最低而且不再变化的时候,我们得到最好的模型。但是要如何让模型不断改进预测,降低损失呢?🤔 梯度下降(Gradient descent)算法是一种通用的做法

不要被这个名字所迷惑,梯度下降算法其实没有那么神秘。先整理我们目前学到了什么:

  • 模型的预测 $\hat y$ 跟它参数,如果是单变量线性回归模型,就是和 $w$ 和 $b$ 有关
  • 损失函数跟模型的预测有关系,因为数据本身真实的值这个我们是无法改变的

所以损失函数实际上是一个关于模型参数的函数,在机器学习中,常用记号 $J$ 表示

先考虑简单的单变量线性回归,当它采用 MSE 作为损失函数的时候: $$ J(w, b) = \frac{1}{2m}\sum^m_{i=1}(f(x^{(i)})-y^{(i)})^2 = \frac{1}{2m}\sum^m_{i=1}(wx^{(i)} + b - y^{(i)})^2 $$

根据 $w$ 和 $b$ 的取值不同,$J(w,b)$ 也不同,因此改进线性回归模型其实就是一直在调整这两个参数让 $J(w,b)$ 的值更小。用数学的语言来说,求解最优模型其实就是求解函数 $J(w,b)$ 的最小点

📒 回忆 $m$ 为训练集的样本个数。更为严格来说,上面的梯度下降式子是批梯度下降(Batch gradient descent),即每个计算梯度的时候用的是整个训练集上的样本。当数据集很大的时候这个方法就无法很好 Scale,此时我们就需要使用随机梯度下降(Stochastic gradient descent)

📒 只要学过导数、最小值,我们不难求解出上面公式的最小值,但这是因为线性回归模型比较简单,当模型更加复杂的时候,用数学方法求解也会更加困难,因此在实践中采用的都是梯度下降算法(不考虑强化学习,因为强化学习优化的目标一般不是一个可微的函数)

让我们暂时不考虑 $b$ 只考虑 $w$,那么此时 $J$ 是一个关于 $w$ 的函数,我们可以以 $w$ 为横轴,$J(w)$ 为纵轴画出如下的图:

📒 注意,上面的图并不严格遵循 $J(w)$ 的定义,为了方便我这里直接画了 $y=\frac{1}{2}x^2$。但是形状应该差不多,可以用来理解梯度下降算法

从图中不难看出,当 $w=0$ 的时候 $J(w)$ 取到了最小值。假设模型当前的参数 $w=5$,计算得到损失 $J(5)=12.5$,我们要如何更新 $w$ 让模型更好呢?答案是让 $w$ 沿着梯度的反方向更新(图中红色的线为在 $w=5$ 这个点的切线),不难求出这一点的梯度(导数)是 $5$,$w$ 应该减小,因此应该是减去这个梯度(所以说是反方向),同时引入学习率 $\alpha$ 控制更新的幅度,得到更新式子 $w \leftarrow w - \alpha \cdot 5$

📒 想象你自己站在 $w=5$ 这个点要前进到 $w=0$ 这个最小值在的点,如果学习率 $\alpha$ 太大,你新得到的 $w$ 可能会小于 $0$,一下子越过了 $w=0$ 这个点。虽然你可以通过梯度下降再次尝试更新,但此时往往你会发现你的模型的损失一直在变化无法收敛。学习率和梯度共同控制了每次参数更新的幅度

📒 我们在只考虑 $w$ 的时候得出了该如何更新的结论——沿着梯度的反方向,考虑更多的参数的时候这个结论仍然适用,不过那就要涉及到求解偏导数乃至向量求导的知识,而且此时的 $J$ 的可视化也更为困难,所以这里不细讲。只需要记住模型的更新总是沿着梯度的反方向前进,从直觉上进行把握👻

在单变量线性回归中,梯度更新的式子如下: $$ w \leftarrow w - \alpha \cdot \frac{\partial}{\partial w}J(w,b) $$

别忘了还有 $b$,它也要更新 $$ b \leftarrow b - \alpha \cdot \frac{\partial}{\partial b}J(w,b) $$

我们来对其中的梯度计算进行推导 $$ \begin{aligned} \frac{\partial}{\partial w}J(w,b)&=\frac{\partial}{\partial w}\frac{1}{2m}\sum_{i=1}^m(f(x^{(i)})-y^{(i)})^2 \\\ &= \frac{\partial}{\partial w}\frac{1}{2m}(wx^{(i)}+b-y^{(i)})^2 \\\ &= \frac{\partial}{\partial w}\frac{1}{m}\sum_{i=1}^m(f(x^{(i)})-y^{(i)})x^{(i)} \end{aligned} $$ $$ \begin{aligned} \frac{\partial}{\partial b}J(w,b)&=\frac{\partial}{\partial w}\frac{1}{2m}\sum_{i=1}^m(f(x^{(i)})-y^{(i)})^2 \\\ &= \frac{\partial}{\partial b}\frac{1}{2m}(wx^{(i)}+b-y^{(i)})^2 \\\ &= \frac{\partial}{\partial b}\frac{1}{m}\sum_{i=1}^m(f(x^{(i)})-y^{(i)}) \end{aligned} $$

如果是多变量线性回归,我们要求解每个 $\frac{\partial }{w_i}J(w_1,w_2, …,b)$ 显然很不方便,此时用向量形式推导梯度是最好的

在向量的形式下,损失函数 MSE 写作:

$$ J(\theta) = \frac{1}{2m}(X\theta - \vec{y})^T(X\theta - \vec{y}) $$

其中

  • $X$ 为输入的矩阵,常用大写字母表示矩阵,它的每一行为一个样本的特征值 $(x^{(i)})^T$,大小为 $(m, n+1)$
    • 前面提到我们有 $n$ 个特征,这里为 $n+1$ 维是因为在第一个位置插入了一个 $1$,这样相乘的时候 $1$ 会和 $b$ 做计算
    • $x^{(i)}$ 需要转置因为本来它本是列向量
    • 对于单个样本是 $\theta^T\vec x$,对于 $m$ 个样本的计算就要用矩阵乘法 $X\theta$
  • $\theta$ 正如我们前面说的是 $[b, w_1, w_2, …, w_n]$,长为 $n + 1$
  • 因此 $X\theta$ 就是模型的预测值,根据矩阵乘法的知识,我们会得到长为 $m$ 的向量,表示对每个样本的预测
  • $X\theta - \vec y$ 就是每个预测的误差
  • 顺带一提,假设 $\vec a$ 为列向量,$\vec a^T\vec a$ 得到的总是一个标量,为每个元素的平方和。如果让 $\vec a=X\theta -\vec y$ 就得到了上面右边的部分,这也解释了为什么会是这个形式

🤔️ 更新:在 维度分析 这篇博客中,我展示了如何用维度分析技巧快速推导出这个公式的解,感兴趣的话可以看下

下面我们开始尝试推导这个公式的梯度,这需要你有一定的向量/矩阵求导知识,可以选择跳过🔮不过我建议还是看看,因为机器学习里面还挺多公式推导的

$$ \begin{aligned} \frac{\partial}{\partial \theta}\ J(w,b) &= \frac{\partial}{\partial \theta}\ \frac{1}{2m}(X\theta - \vec{y})^T(X\theta - \vec{y}) \\\ &= \frac{1}{2m}\frac{\partial}{\partial \theta}\ (\theta^TX^T - \vec{y}^T)(X\theta - \vec{y}) \\\ &= \frac{1}{2m}\frac{\partial}{\partial \theta}\ (\theta^TX^TX\theta - \theta^TX^T\vec y - \vec y^TX\theta + \vec y^T\vec y) \\\ &= \frac{1}{2m}\frac{\partial}{\partial \theta}\ (\theta^TX^TX\theta - \theta^T(X^T\vec y) - (X^T\vec y)^T\theta + \vec y^T\vec y) \\\ &= \frac{1}{2m}\frac{\partial}{\partial \theta}\ (\theta^TX^TX\theta - 2\theta^T(X^T\vec y) + \vec y^T\vec y) \\\ &= \frac{1}{2m}(\frac{\partial}{\partial \theta}\ (\theta^TX^TX\theta) - 2\frac{\partial}{\partial \theta}(\theta^TX^T\vec y))) \\\ &= \frac{1}{2m}(2X^TX\theta - 2X^T\vec y)) \\\ &= \frac{1}{m}(X^TX\theta - X^T\vec y)) \\\ &= \frac{1}{m}X^T(X\theta-\vec y) \end{aligned} $$

几个解释:

  • $X^T$ 的大小是 $(n+1, m)$,$\vec y$ 是 $(m, 1)$,因此 $X^T\vec y$ 其实是一个维度为 $(n+1, 1)$ 的列向量,注意在线性代数中,当 $\vec a$ 和 $\vec b$ 都为列向量的时候,有 $\vec a^T\vec b=\vec b^T\vec a$ 成立。所以 $\theta^T(X^T\vec y) = (X^T\vec y)^T\theta$
  • 其他几个地方的推导我推荐直接代向量/矩阵求导公式,可以参考这个 Cheatsheet。当然如果对这方面很感兴趣更推荐直接去看原理证明
    • 比如上面的 $\frac{\partial}{\partial \theta}(\theta^TX^T\vec y))$,其实就是换元法,令 $\vec b=X^T\vec y$,刚好对应 Cheatsheet 里面的 $\frac{\partial }{\partial \theta}\theta^T\vec b=\vec b$

📒 向量形式在实现代码的时候也带来了很大方便,我们可以利用成熟的 Numpy 高效进行计算,而不是自己写一个 for 循环一个个样本计算

线性回归模型的理论部分就是以上的内容,本文介绍了单变量线性回归,多变量线性回归,前者可以看成是后者的一个特例。最后我们将其都用向量的形式统一了写法,并给出了向量形式下采用 MSE 作为损失函数的时候的梯度计算公式

本来还想放一下代码在这里,结果写着写着发现这一篇博客已经很长了,看来只好将线性回归模型的算法放在另一篇了🙌