ML01 - Regression 案例学习 (上)
前言
这个课程是来自于 YouTube 上 NTU 李宏毅老师的视频课程,老师的课讲得非常有趣,通过引入 Pokémon 来生动的讲解机器学习中一些技术的应用,只要你有一定的高数、线代以及概率基础,看这个课程无压力。
我在学习的同时将其搬运并做简单的英文翻译,并加上自己的理解与更通俗的解释。加深自己印象的同时希望能对国内不能使用 YouTube 的读者们提供一个方便。
Regression 回归运算
回归运算其实就是用一个函数去拟合当前给出的数据,如下图:
图中蓝色点代表数据,我们假设这组数据是 Linear Regression 线性回归的,那我们就需要用一条直线去拟合它们,也就是那条红色的线。
Regression 的使用范围也是很广的:
- 股票预测:
$$
\begin{eqnarray}
f ( 以往多年股票的走势情况 ) = 明天的点数
\end{eqnarray}
$$
当然真正的股市也不可能这么简单,你能预测你就发了😂 - 自动驾驶
$$
\begin{eqnarray}
f ( 传感器得到的数据 ) = 方向盘与油门的控制
\end{eqnarray}
$$ - 推荐系统
像淘宝、京东等的购物网站,会推送一些商品给你,这些商品肯定要是你喜欢的或者需要的,你才可能去购买。一个好的推荐系统可能会让这些网站的利润成倍提高。
$$
\begin{eqnarray}
\ f ( 用户 A,商品 B ) = 用户 A 购买商品 B 的可能性
\end{eqnarray}
$$
如果这个可能性很大的话,购物网站就会更倾向于向用户 A 推荐此商品
但今天,我们要做的是一件更加实际的事情。
用数据估测宝可梦的攻击力(CP值)
比如,下面是一只妙蛙种子,你给他吃一些糖果或者星辰,它就会进化成妙蛙草,进化以后,它的 CP 值就变了。
如果我们有能力预测它进化后 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
就像人一样,本来就是通过一定量的基础练习,才能够学到这类数据的共通点。像下面这个图,左侧是杰尼龟
,右侧则是杰尼龟
进化后,变成的卡咪龟
:
那现在,整个 Model
的 输入就是这只杰尼龟
,我们用 \(x^1\) 来表示,那这只 卡咪龟
我们就用 \(\widehat{y}^1\) 来表示。这里 \(x\) 和 \(\widehat{y}\) 的上标表示:这是一个完整的个体,1 只是它的编号(比如 \(学生^1\) 、\(学生^2\)),至于 hat(就是 \(\widehat{y}\) 头上的那个尖尖符号),它代表这是一个准确的值(因为这是真实的数据,为了和后面预测出来的数据 \(y\) 做区分)。
只有一只肯定不够呀,我们需要很多的数据,就要抓足够多的宝可梦,比如这只 伊布
,它进化过后就是 雷精灵
:
那我们同样就能够得到\(x^2\) 和 \(\widehat{y}^2\),就像这样:
嗯,我们搜集了十只宝可梦🐶🐱🐢🐹🦄🦊🐻🐼🐨🐯 ,数据可以从这里找到。
我们就有了 10
组 Training Data(训练数据)
:
$$
(x^1,\widehat{y}^1) \\
(x^2,\widehat{y}^2) \\
\vdots \\
(x^{10},\widehat{y}^10)
$$
我们将其进化前的 CP 值和进化后的 CP 值画在一个二维坐标图上(横轴为进化前的 CP 值),那每个蓝色的点都代表一只宝可梦:
现在我们有了 Model
和 Training Data
,但是我们还需要一个函数来将它们连接起来,这个函数就是接下来要讲的:
第三步:Loss Function
中间蓝色的块就是 Loss Function(误差函数)
。为什么需要这个函数呢,因为我们现在需要根据这 10 只已知宝可梦数据,代入 Model
推测出它们进化后的 CP 值,然后再与实际的 CP 值进行比较,来慢慢调整 Model
中的 weight
和 bias
。所以,我们需要有一个函数来评判这次推测的误差度,这就是 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
上面说的穷举真不是一个好办法(基本没法实现),那我们能不能找一个更好、更有效率的办法解决这个问题呢?有!
- 用线性代数的办法:求解非齐次线性方程组(由于这里的方程并不是同解,所以这个办法还是会有些折腾)
- 用高等数学的办法:L 可微分,求梯度即可
如下曲线,我们随机选择一个起点 \(w^0\),然后在这个点上对 \(L\) 求 \(w\) 的微分 \(\frac{dL}{dw}|_{w=w^0}\):
如果你还搞不太懂微分是啥,那就假想这个曲线是一个山坡,你站在 \(w^0\) 上,向左迈一步(\(w\) 减小)或者向右迈一步 (\(w\) 增大),然后看往哪边走 \(L\) 会变小就往那个方向走一步,得到一个新的位置 \(w^1\),然后这样不断重复,就有机会走到最低点。
$$
w^1 \gets w^0 - \eta \frac{dL}{dw}|_{w=w^0}
$$
那新问题出现了,我们步子该迈多大呢?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\) 最小的点)。
但很明显我们能看到,这只是一个 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
的原理:
Gradient Descent
其实就相当于每次计算所处位置圆弧的法线方向,这个方向是数值变化最明显的方向,所以照着这个方向能最快的走到最低点。
但是,遇到这种图怎么办?
不用担心(至少现在),因为 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}
$$
本文总结
- 我们讲了
Regression(线性回归)
的一些作用与高大上的一些应用场景,不过这些都是很复杂的应用; - 然后我们就提出了一个用
Regression
来解决宝可梦升级 CP 值预测
的系统; - 通过将宝可梦的属性代数化:\(x\) 代表某个宝可梦个体、\(x_{cp}\) 代表它的 CP 值、\(x_h\) 代表它的高度等等,让我们能够通过代数的方法解决这个预测 CP 的问题;
- 在最开始,我们需要建立一个
Model(模型)
,Model
其实就是一堆Function(计算方法)
的集合,我们将一些数据输入进去,他就能输出我们想要的结果:比如我们输入一只宝可梦的数据,他就能输出这只宝可梦进化后的 CP 值; - 在第二步,我们需要
Training Data(训练数据)
。我们需要有大量的训练数据,才能够教会我们的模型正确预测可能的 CP 值变化; - 有了
Model
和Training Data
,我们还需要有Loss Function(误差函数)
来评价我们当前模型的好坏,其实它的实现很简单,就是一个普通的函数,然后将Model
预测的 CP 值,和实际已知进化后的 CP 值做比较,他们差距越大,Loss Funciton
输出的 \(L\) 也就越大,越小说明预测得越准确; - 最后我们讲了如何训练这个
Model
,用Gradient Descent(梯度下降)
算法来调节模型,梯度下降算法其实就是通过高等数学中的微分运算,找到一个能让 \(L\) 变得更小的方向(并且这个方向是能让 \(L\)减小得最快的),根据这个方向来决定是增大参数的大小还是减小参数的大小,总之,我们能够通过不断地训练调节,得到一个能比较合理的、误差尽可能小的模型。
今天就先写到这里,小步快跑,下次更新见…
[ML01 - Regression 案例学习 (下)][1]
[1]: https://aiellochan.github.io/2018/02/11/Regression-案例学习-(下)