前言

如果遇到排版问题,请点击 阅读原文

这个课程是来自于 YouTube 上 NTU 李宏毅老师的视频课程,老师的课讲得非常有趣,通过引入 Pokémon 来生动的讲解机器学习中一些技术的应用,只要你有一定的高数、线代以及概率基础,看这个课程无压力。
我在学习的同时将其搬运并做简单的英文翻译,并加上自己的理解与更通俗的解释。加深自己印象的同时希望能对国内不能使用 YouTube 的读者们提供一个方便。

Regression 回归运算

回归运算其实就是用一个函数去拟合当前给出的数据,如下图:

20180210151826989117180.jpg

图中蓝色点代表数据,我们假设这组数据是 Linear Regression 线性回归的,那我们就需要用一条直线去拟合它们,也就是那条红色的线。

Regression 的使用范围也是很广的:

  • 股票预测:

    201802101518270933581.png

$$ \begin{eqnarray} f ( 以往多年股票的走势情况 ) = 明天的点数 \end{eqnarray} $$

当然真正的股市也不可能这么简单,你能预测你就发了?

  • 自动驾驶
    20180210151827101157873.png

$$ \begin{eqnarray} f ( 传感器得到的数据 ) = 方向盘与油门的控制 \end{eqnarray} $$

  • 推荐系统
    像淘宝、京东等的购物网站,会推送一些商品给你,这些商品肯定要是你喜欢的或者需要的,你才可能去购买。一个好的推荐系统可能会让这些网站的利润成倍提高。

    $$ \begin{eqnarray} \ f ( 用户 A,商品 B ) = 用户 A 购买商品 B 的可能性 \end{eqnarray} $$

    如果这个可能性很大的话,购物网站就会更倾向于向用户 A 推荐此商品

但今天,我们要做的是一件更加实际的事情。

用数据估测宝可梦的攻击力(CP值)

比如,下面是一只妙蛙种子,你给他吃一些糖果或者星辰,它就会进化成妙蛙草,进化以后,它的 CP 值就变了。

20180210151827184555492.png

如果我们有能力预测它进化后 CP 值的变化的话,我们就能够事先决定是否进化这只宝可梦。如果它 CP 值比较低的话,有可能你就把它拿去做糖果了? 就不进化它了,这就可以节省一些糖果用来进化更强的宝可梦。

那我们现在要做的就是,找到这么一个 function,我们输入这只宝可梦的相关数据,他就能返回给我们,进化过后,可能的 CP 值是多少。

$$ \begin{eqnarray} \ f ( 宝可梦的信息 ) = 进化后的 CP 值 \end{eqnarray} $$

这里,我们用 $x$ 代表这只宝可梦,则:

  • $ x_{cp} $ 代表其进化前的 CP 值,为 14
  • $ x_s $ 代表它所属的物种,为 妙蛙种子
  • $ x_{hp} $ 代表它进化前的生命值,为 10
  • $ x_w $ 代表它进化前的重量,为 11.62 kg
  • $ x_{hp} $ 代表它进化前的生命值,为 0.88 m
  • $y$ 则代表进化后的 CP 值

这里 $x$ 的下标表示:这些都是 $x$ 这个个体的某个属性(比如 $小明\_{体重}$、$小明\_{身高}$)。

那我们怎么来解这个问题呢,我们知道,ML 其实就是寻找一个 Model(模型),将我们的数据代进去,经过复杂的运算后就能得到我们想要的结果。

所以我们首先需要找到这个 Model

第一步:Model

一个 Model 其实就是一个 Function set(一组方法)。那我们要寻找的这个 Model,它应该长什么样子呢?

我们当然还是期望它能简单点,所以呢,我们就假设它是这么一个方程组:

$$ y = b + w \cdot x_{cp} $$

就是一个常数 $b$ 和一个数 $w$,它们组合起来,$x$ 与 $y$ 就构成一种线性关系。当然,我们现在的 $b$ 和 $w$ 都是不确定的,它可以是任何的数字,不过我们能从直觉上排除一些组合,比如 $w$ 和 $b$ 都为负数:

$$ f_1: y = -1 - 2 \cdot x $$

这样子 $y$ 就成了负数,我们知道,一个宝可梦的 CP 值是不可能为负数的,所以我们能够直接排除这类组合。

前面提到,我们假设的这个方程是一个线性的函数,所以我们这个 Model 就是一个 Linear Model(线性模型)

$$ \ Linear\ Model: y = b + \sum w_i x_i \\\ x_i:输入\ x\ 的某个属性(如 CP) \\\ b:bias(误差) \\\ w:weight(权重) $$

有了 Model 我们就需要考虑下一个问题:

第二步:Training Data

我们需要训练数据,因为 ML 就像人一样,本来就是通过一定量的基础练习,才能够学到这类数据的共通点。像下面这个图,左侧是杰尼龟,右侧则是杰尼龟进化后,变成的卡咪龟

20180210151827722460431.png

那现在,整个 Model 的 输入就是这只杰尼龟,我们用 $x^1$ 来表示,那这只 卡咪龟 我们就用 $\widehat{y}^1$ 来表示。这里 $x$ 和 $\widehat{y}$ 的上标表示:这是一个完整的个体,1 只是它的编号(比如 $学生^1$ 、$学生^2$),至于 hat(就是 $\widehat{y}$ 头上的那个尖尖符号),它代表这是一个准确的值(因为这是真实的数据,为了和后面预测出来的数据 $y$ 做区分)。

只有一只肯定不够呀,我们需要很多的数据,就要抓足够多的宝可梦,比如这只 伊布,它进化过后就是 雷精灵

20180210151827811541481.png

那我们同样就能够得到$x^2$ 和 $\widehat{y}^2$,就像这样:

20180210151827831581456.png

嗯,我们搜集了十只宝可梦?????????? ,数据可以从这里找到。

我们就有了 10Training Data(训练数据)

$$ (x^1,\widehat{y}^1) \\\ (x^2,\widehat{y}^2) \\\ \vdots \\\ (x^{10},\widehat{y}^10) $$

我们将其进化前的 CP 值和进化后的 CP 值画在一个二维坐标图上(横轴为进化前的 CP 值),那每个蓝色的点都代表一只宝可梦:

2018021115182792145885.png

现在我们有了 ModelTraining Data,但是我们还需要一个函数来将它们连接起来,这个函数就是接下来要讲的:

第三步:Loss Function

2018021115182800497363.png

中间蓝色的块就是 Loss Function(误差函数)。为什么需要这个函数呢,因为我们现在需要根据这 10 只已知宝可梦数据,代入 Model 推测出它们进化后的 CP 值,然后再与实际的 CP 值进行比较,来慢慢调整 Model 中的 weightbias。所以,我们需要有一个函数来评判这次推测的误差度,这就是 Loss Function

$$ \begin{cases} L(f) = L(w,b) = \sum\_{n=1}^{10} (\widehat{y}^n - y^n)^2 \\\ y^n = b + w\cdot x\_{cp}^n \end{cases} \\\ \Downarrow \\\ L(f) = \sum\_{n=1}^{10} (\widehat{y}^n - (b + w\cdot x\_{cp}^n))^2 $$

上面的方程其实就是将 $\widehat{y}$ 准确值减去$y$估测值,然后将其平方,再将 10 只宝可梦都这样计算并加起来。

我们要做的就是从我们的 Model 中挑选出一个 function $f$,它能够让 Loss Function $L(f)$ 的计算结果最小,这个 function 我们就将它命名为 $f^*$:

$$ f^* = arg \min_f L(f) $$

或者从另一个角度考虑,我们的 function 其实就只由 weight $w$ 和 bias $b$ 来确定的,那上面的公式还可以写成如下:

$$ w^\*, b^* = arg \min\_{w,b} L(w,b) $$

我们需要做的就是 穷举所有的 ? 和 ?,直到找到最佳的那一对,让 Loss Function $L$ 最小。

第四步:Gradient Descent

上面说的穷举真不是一个好办法(基本没法实现),那我们能不能找一个更好、更有效率的办法解决这个问题呢?有!

  1. 用线性代数的办法:求解非齐次线性方程组(由于这里的方程并不是同解,所以这个办法还是会有些折腾)
  2. 用高等数学的办法:L 可微分,求梯度即可

如下曲线,我们随机选择一个起点 $w^0$,然后在这个点上对 $L$ 求 $w$ 的微分 $\frac{dL}{dw}|\_{w=w^0}$:

20180211151828415490517.jpg

如果你还搞不太懂微分是啥,那就假想这个曲线是一个山坡,你站在 $w^0$ 上,向左迈一步($w$ 减小)或者向右迈一步 ($w$ 增大),然后看往哪边走 $L$ 会变小就往那个方向走一步,得到一个新的位置 $w^1$,然后这样不断重复,就有机会走到最低点。

$$ w^1 \gets w^0 - \eta \frac{dL}{dw}|\_{w=w^0} $$

20180211151828471476871.jpg

那新问题出现了,我们步子该迈多大呢?Gradient Descent 中,这个步子的大小为:

$$ \- {\color{red}\eta} \frac{dL}{dw}|\_{w=w^0} $$

其中,$\frac{dL}{dw}|\_{w=w^0}$ 为 $w^0$ 处的梯度,${\color{red}\eta}$ 是一个常数项,我们把它叫做 Learning Rate(学习速率),它是一个事先定好的数值,越大,每踏出一步的距离就越大,这意味着学习得就越快。负号则是因为,我们所求的梯度如果是负值说明我们往这个方向前进,$L$ 就会变小,我们就需要增大 $w$,所以,梯度的符号和我们前进的方向是相反的关系。

到了 $w^1$ 后重新计算梯度,很明显这里的梯度比 $w^0$ 小了很多,所以迈的下一步也会随之变小。经过很多次的调整行走后,我们终于走到了 $w^T$,在这个地方,微分趋近于 0,算法就认为这里是最好的点了(让 $L$ 最小的点)。

20180211151828585017243.jpg

但很明显我们能看到,这只是一个 Local Minimum(局部最小),全局最小的点并不在这里,当然 Linear Model 不太会存在这种走到 Local Minimum 的情况,至于为什么,后面会给予说明。

我们总的过程用公式表达就是这样的:

$$ 随机选择一个初始的 w^0 和 b^0 \\\ \Downarrow \\\ 分别对 w^0 和 b^0 做微分并计算下一个点 w^1 和 b^1: \begin{cases} w^1 \gets w^0 - {\color{red}\eta} \frac{dL}{dw}|\_{w=w^0,b=b^0} \\\ b^1 \gets b^0 - {\color{red}\eta} \frac{dL}{db}|\_{w=w^0,b=b^0} \end{cases} \\\ \Downarrow \\\ 分别对 w^1 和 b^1 做微分并计算下一个点 w^2 和 b^2: \begin{cases} w^2 \gets w^1 - {\color{red}\eta} \frac{dL}{dw}|\_{w=w^1,b=b^1} \\\ b^2 \gets b^1 - {\color{red}\eta} \frac{dL}{db}|\_{w=w^1,b=b^1} \end{cases} \\\ \vdots \\\ 最终得到一组让 L 最小的 w^T 和 b^T $$

Gradient Descent 到底是什么呢?其实就是将 $L$ 分别对 $w$ 和 $b$ 做偏微分,最后组成一个向量:

$$ \nabla L = \begin{bmatrix} \frac{\partial L}{\partial w} \\\ \frac{\partial L}{\partial b} \end{bmatrix} _{gradient} $$

当然如果你还是有点点糊涂的话,下面这张图就能更好地向你说明,Gradient Descent 的原理:

20180211151828747733608.png

Gradient Descent 其实就相当于每次计算所处位置圆弧的法线方向,这个方向是数值变化最明显的方向,所以照着这个方向能最快的走到最低点。

但是,遇到这种图怎么办?

2018021115182877412672.jpg

不用担心(至少现在),因为 Linear Model 的图形其实不会像上面的图那样,而是像上面第二张图那样的,一圈一圈很规整的凹面图形,几乎不存在 Local Minimum 的问题。

最后,我们看一下 $\frac {\partial L} {\partial w} $ 和 $\frac {\partial L} {\partial b} $ 都怎么计算的(如果你不会的话,可要恶补一下高等数学了)

$$ L(f) = \sum\_{n=1}^{10} (\widehat{y}^n - (b + w\cdot x\_{cp}^n))^2 \\\ \Downarrow \\\ \begin{cases} \frac {\partial L} {\partial w} = \sum\_{n=1}^{10} 2\cdot (\widehat{y}^n - (b + w\cdot x\_{cp}^n))(\-x\_{cp}^n) \\\ \frac {\partial L} {\partial b} = \sum\_{n=1}^{10} 2\cdot (\widehat{y}^n - (b + w\cdot x\_{cp}^n)){\-1} \end{cases} $$

本文总结

  1. 我们讲了 Regression(线性回归) 的一些作用与高大上的一些应用场景,不过这些都是很复杂的应用;
  2. 然后我们就提出了一个用 Regression 来解决宝可梦升级 CP 值预测的系统;
  3. 通过将宝可梦的属性代数化:$x$ 代表某个宝可梦个体、$x_{cp}$ 代表它的 CP 值、$x_h$ 代表它的高度等等,让我们能够通过代数的方法解决这个预测 CP 的问题;
  4. 在最开始,我们需要建立一个 Model(模型)Model 其实就是一堆 Function(计算方法)的集合,我们将一些数据输入进去,他就能输出我们想要的结果:比如我们输入一只宝可梦的数据,他就能输出这只宝可梦进化后的 CP 值;
  5. 在第二步,我们需要 Training Data(训练数据)。我们需要有大量的训练数据,才能够教会我们的模型正确预测可能的 CP 值变化;
  6. 有了 ModelTraining Data,我们还需要有 Loss Function(误差函数)来评价我们当前模型的好坏,其实它的实现很简单,就是一个普通的函数,然后将 Model 预测的 CP 值,和实际已知进化后的 CP 值做比较,他们差距越大,Loss Funciton 输出的 $L$ 也就越大,越小说明预测得越准确;
  7. 最后我们讲了如何训练这个 Model,用 Gradient Descent(梯度下降)算法来调节模型,梯度下降算法其实就是通过高等数学中的微分运算,找到一个能让 $L$ 变得更小的方向(并且这个方向是能让 $L$减小得最快的),根据这个方向来决定是增大参数的大小还是减小参数的大小,总之,我们能够通过不断地训练调节,得到一个能比较合理的、误差尽可能小的模型。

今天就先写到这里,小步快跑,下次更新见...

ML01 - Regression 案例学习 (下)


Aiello_Chan
860 声望20 粉丝