Datawhile
一、基本知识
1.什么是机器学习
机器学习,顾名思义,机器具备有学习的能力。机器学习就是让机器具备找一个函数的能力。机器具备找函数的能力以后,它可以做很多事。比如语音识别,机器听一段声音,产生这段声音对应的文字。我们需要的是一个函数,该函数的输入是声音信号,输出是这段声音信号的内容。这个函数显然非常复杂,人类难以把它写出来,因此想通过机器的力量把这个函数自动找出来。还有好多的任务需要找一个很复杂的函数,以图像识别为例,图像识别函数的输入是一张图片,输出是这个图片里面的内容。AlphaGo 也可以看作是一个函数,机器下围棋需要的就是一个函数,该函数的输入是棋盘上黑子跟白子的位置,输出是机器下一步应该落子的位置。
2.机器学习类别
随着要找的函数不同,机器学习有不同的类别:机器学习分为回归、分类和结构化学习。
回归
定义:根据已知的数据,找到一个函数,该函数的输出是一个数值,一个标量(scalar),这种机器学习的任务称为回归。
举例:假设机器要预测未来某一个时间的 PM2.5 的数值。机器要找一个函数 f,其输入是可能是种种跟预测 PM2.5 有关的指数,包括今天的 PM2.5 的数值、平均温度、平均的臭氧浓度等等,输出是明天中午的 PM2.5的数值,找这个函数的任务称为回归(regression)。
分类
定义:分类任务要让机器做选择题。人类先准备好一些选项,这些选项称为类别(class),现在要找的函数的输出就是从设定好的选项里面选择一个当作输出,该任务称为分类。
举例:每个人都有邮箱账户,邮箱账户里面有一个函数,该函数可以检测一封邮件是否为垃圾邮件。分类不一定只有两个选项,也可以有多个选项。AlphaGo 也是一个分类的问题,如果让机器下围棋,做一个 AlphaGo,给出的选项与棋盘的位置有关。棋盘上有 19 × 19 个位置,机器下围棋其实是一个有 19 × 19 个选项的选择题。机器找一个函数,该函数的输入是棋盘上黑子跟白子的位置,输出就是从 19×19 个选项里面,选出一个正确的选项,从 19 × 19 个可以落子的位置里面,选出下一步应该要落子的位置。
结构化学习
定义:机器不只是要做选择题或输出一个数字,而是产生一个有结构的物体,叫机器产生有结构的东西的问题称为结构化学习
举例:比如让机器画一张图,写一篇文章。
二、案例学习
以一个发布在平台的视频点击次数预测为例介绍下机器学习的运作过程。我们的已知条件是与视频播放相关的很多信息,比如:每天点赞的人数、订阅人数、观看次数。根据一个频道过往所有的信息可以预测明天的观看次数。要求是找一个函数,该函数的输入是后台的信息,输出是隔天这个频道会有的总观看的次数。
机器学习解决该问题分为三个步骤:1.建立函数模型。2.定义损失函数。3.最优化求解。
1.建立函数模型
第一个步骤是写出一个带有未知参数的函数f,其能预测未来观看次数。简单的,我们将函数写成
$$
y=b+\omega x_1 \tag{1}
$$
x_1为今天观看该视频的总人次,y为要预测的明天观看该视频的总人次,b跟\omega是未知的参数,是我们需要通过数据去找出来的。
这个函数及参数的设定是一个猜测,猜测往往来自于对这个问题本质上的了解,即领域知识。机器学习就需要一些领域知识。也许今天的观看次数,总是会跟昨天的观看次数有点关联,所以把昨天的观看次数,乘上一个数值,但是总是不会一模一样,所以再加上一个b做修正,当作是对于明天观看总人次的预测,这是一个猜测,它不一定是对的,我们后面还会再来修正这个猜测。
总之,带有未知的参数(parameter)的函数称为模型(model)。模型在机器学习里面,就是一个带有未知的参数的函数,特征(feature)x_1是这个函数里面已知的,它是来自于后台的信息,今天点击的总次数是已知的,而 \omega跟b是未知的参数。\omega称为权重(weight),b称为偏置(bias)。
2.定义损失函数
因为我们建立的函数模型中有两个未知参数,为了寻求最优的参数组来达到最佳的预测效果,我们需要定义一个损失(loss)函数。损失函数的参数是函数模型中的未知参数b和\omega,即为L(b,\omega).
例如我们取b=500,\omega=1,则预测函数为y=500+x_1.
举个例子,假设我们已知周一到周六的观看总人次分别为{4800,5200,5400,6200,6900,6800},我们来预测周日的观看总人次。
我们把周一观看总人次代入到y=500+x_1中,得到预测的周二的观看总人次为5300,而实际上有5200人次观看,真实的值称为标签(label),我们取的参数预测周二的结果高估了这个视频可能的点击次数,可以计算一下估测的值\hat{y}跟真实值y的差距e。直观的,我们取差距的绝对值:
$$
e_1=|y-\hat{y}|=100 \tag{2}
$$
我们不能只用周一的值预测周二的,要用每一天的值预测后一天的,得到差距来看预测的效果如何,类似得到
$$
e_2=|y-\hat{y}|=300 \tag{3}
$$
$$
e_3=|y-\hat{y}|=300 \tag{4}
$$
$$
e_4=|y-\hat{y}|=200 \tag{5}
$$
$$
e_5=|y-\hat{y}|=600 \tag{6}
$$
接下来把每一天的预测误差累加取均值,得到损失L
$$
L=\frac{1}{N} \displaystyle\sum_{i=n}e_n=300 \tag{7}
$$
其中,N代表训练数据的个数,即周一到周六的训练数据,L是每一笔训练数据的误差e相加以后的结果.L越大,代表现在这一组参数{b,\omega}越不好,L越小,代表现在这一组参数越好。估测的值跟实际的值之间的差距,有不同的计算方法,计算y与\hat{y}之间绝对值的差距,如式(8)所示,称为平均绝对误差.
$$
e=|y-\hat{y}| \tag{8}
$$
如果算y与\hat{y}之间平方的差距,如式(9)所示,则称为均方误差.
$$
e=(y-\hat{y})^2 \tag{9}
$$
有一些任务中y和\hat{y}都是概率分布,这个时候可能会选择交叉熵。
以下的数字是真实的例子,是这个视频真实的后台的数据所计算出来的结果。可以调整不同的\omega和不同的b,求取各种\omega和各种b,组合起来以后,我们可以为不同的\omega跟b的组合,都去计算它的损失,就可以画出图1.2所示的等高线图。在这个等高线图上面,越偏红色系,代表计算出来的损失越大,就代表这一组\omega跟b越差。如果越偏蓝色系,就代表损失越小,就代表这一组omega跟b越好,拿这一组\omega跟b,放到函数里面,预测会越精准。假设w=−0.25, b=−500,这代表这个频道每天看的人越来越少,而且损失这么大,跟真实的情况不太合。如果w=0.75, b=500,估测会比较精准。如果\omega代一个很接近1的值,b带一个小小的值,比如说100多,这个时候估测是最精准的,这跟大家的预期可能是比较接近的,就是拿前一天的点击的总次数,去预测隔天的点击的总次数,可能前一天跟隔天的点击的总次数是差不多的,因此\omega 设1,b设一个小一点的数值,也许估测就会蛮精准的。如图1.2所示的等高线图,就是试了不同的参数,计算它的损失,画出来的等高线图称为误差表面(error surface).
3.最优化求解
接下来进入机器学习的第3步:解一个最优化的问题。找一个\omega跟b,把未知的参数找一个数值出来,看代哪一个数值进去可以让损失L的值最小,就是要找的\omega跟b,让损失最小的参数称为\omega^*跟b^*代表它们是最好的一组\omega跟b,可以让损失的值最小。
这里我们使用梯度下降方法。为了简化起见,先假设只有一个未知的参数\omega,b是已知的.\omega代不同的数值的时候,就会得到不同的损失,这一条曲线就是误差表面,只是刚才在前一个例子里面,误差表面是2维的,这边只有一个参数,所以这个误差表面是1维的。
怎么样找一个\omega让损失的值最小呢? 如图1.3所示,首先要随机选取一个初始的点 。接下来计算\frac{\partial L}{\partial \omega}|_ {\omega=\omega_0},在\omega等于 \omega_0的时候,参数\omega对损失的微分。计算在这一个点,在\omega_0这个位置的误差表面的切线斜率,也就是蓝色的虚线的斜率,如果这一条虚线的斜率是负的,代表说左边比较高,右边比较低。在这个位置附近,左边比较高,右边比较低。如果左边比较高右边比较低的话,就把\omega的值变大,就可以让损失变小。如果算出来的斜率是正的,就代表左边比较低右边比较高。左边比较低右边比较高,如果左边比较低右边比较高的话,就代表把\omega变小了,\omega往左边移,可以让损失的值变小。这个时候就应该把\omega的值变小。我们可以想像说有一个人站在这个地方,他左右环视一下,算微分就是左右环视,它会知道左边比较高还是右边比较高,看哪边比较低,它就往比较低的地方跨出一步。这一步的步伐的大小取决于两件事情:
-
第一件事情是这个地方的斜率,斜率大步伐就跨大一点,斜率小步伐就跨小一点。
-
另外,学习率(learning rate)\eta也会影响步伐大小。学习率是自己设定的,如果\eta设大一点,每次参数更新就会量大,学习可能就比较快。如果\eta设小一点,参数更新就很慢,每次只会改变一点点参数的数值。这种在做机器学习,需要自己设定,不是机器自己找出来的,称为超参数(hyperparameter)。
Q: 为什么损失可以是负的? A: 损失函数是自己定义的,在刚才定义里面,损失就是估测的值跟正确的值的绝对值。如果根据刚才损失的定义,它不可能是负的。但是损失函数是自己决定的,比如设置一个损失函数为绝对值再减 100,其可能就有负的。这个曲线并不是一个真实的损失,并不是一个真实任务的误差表面。因此这个损失的曲线可以是任何形状。
把\omega_0往右移一步,新的位置为\omega_1,这一步的步伐是\eta乘上微分的结果:
$$
\omega_1 \leftarrow \omega_0-\eta\frac{\partial L}{\partial \omega}|_ {\omega=\omega_0} \tag{10}
$$
接下来反复进行刚才的操作,计算一下\omega_1微分的结果,再决定现在要把\omega_1移动多少,再移动到\omega_2,再继续反复做同样的操作,不断地移动\omega的位置,最后会停下来。往往因为两种情况会停下来:
-
第一种情况是一开始会设定说,在调整参数的时候,在计算微分的时候,最多计算几次。上限可能会设为100 万次,参数更新100万次后,就不再更新了,更新次数也是一个超参数。
-
还有另外一种理想上的,停下来的可能是,当不断调整参数,调整到一个地方,它的微分的值就是这一项,算出来正好是0的时候,如果这一项正好算出来是0,0乘上学习率\eta还是0,所以参数就不会再移动位置。假设是这个理想的情况,把\omega_0更新到\omega_1,再更新到\omega2,最后更新到\omega_T有点卡,\omega_T卡住了,也就是算出来这个微分的值是0了,参数的位置就不会再更新。
梯度下降有个问题在于按上述的逻辑,可能会没有找到让损失最小的\omega。在图1.4所示的例子里面,把\omega设定在最右侧红点附近这个地方可以让损失最小。但如果在梯度下降中,\omega_0是随机初始的位置,也很有可能走到\omega_T这里,训练就停住了,无法再移动\omega_T的位置。右侧红点这个位置是真的可以让损失最小的地方,称为全局最小值(global minima),而\omega_T这个地方称为局部最小值(local minima),其左右两边都比这个地方的损失还要高一点,但是它不是整个误差表面上面的最低点。
所以常常可能会听到有人讲到梯度下降不是个好方法,这个方法会有局部最小值的问题,无法真的找到全局最小值。事实上局部最小值是一个假问题,在做梯度下降的时候,真正面对的难题不是局部最小值。 近年来,研究者们发现在高维空间中,损失函数的局部最小值点可能并不是主要问题,更常见的是鞍点问题。鞍点是指在某些方向上是凸的,而在其他方向上是凹的点。 解决局部最小值问题的一些常见方法包括:
-
多次随机初始化:通过多次随机初始化模型参数,增加找到全局最小值的机会。
-
使用随机梯度下降(SGD):SGD每次只使用一个样本来更新模型参数,这有助于算法跳出局部最小值。
-
带动量的梯度下降:动量可以帮助梯度下降法加速收敛,并避免陷入局部最小值。
-
自适应学习率的梯度下降:自适应学习率算法可以根据梯度的大小自动调整学习率,避免陷入局部最小值。
-
正则化技术:正则化可以减少过拟合的风险,间接帮助避免局部最小值。 有两个参数的情况下使用梯度下降,其实跟刚才一个参数没有什么不同。如果一个参数没有问题的话,可以很快的推广到两个参数。假设有两个参数,随机初始值为\omega_0,b_0。要计算\omega,b跟损失的微分,计算在\omega=\omega_0,b=b_0的位置,要计算\omega和b对L的微分.
$$
\frac{\partial L}{\partial b}|_ {\omega=\omega_0,b=b_0} \tag{11}
$$
$$
\frac{\partial L}{\partial \omega}|_ {\omega=\omega_0,b=b_0} \tag{12}
$$
计算完后更新\omega和b,把\omega_0减掉学习率乘上微分的结果得到\omega_1,把b_0减掉学习率乘上微分的结果得到b_1.
$$
\omega_1 \leftarrow \omega_0-\eta\frac{\partial L}{\partial \omega}|_ {\omega=\omega_0,b=b_0} \tag{13}
$$
$$
b_1 \leftarrow b_0-\eta\frac{\partial L}{\partial b}|_ {\omega=\omega_0,b=b_0} \tag{14}
$$
在深度学习框架里面,比如PyTorch里面,算微分都是程序自动帮计算的。就是反复同样的步骤,就不断的更新\omega和b,期待最后,可以找到一个最好的\omega^*和b^*. 如图1.5所示,随便选一个初始的值,先计算一下\omega和b对L的微分,接下来更新\omega和b。把\omega和b更新的方向结合起来,就是一个向量,就是红色的箭头,再计算一次微分,再决定要走什么样的方向,把这个微分的值乘上学习率,再乘上负号,我们就知道红色的箭头要指向那里,就知道如何移动\omega和b的位置,一直移动,期待最后可以找出一组不错的\omega和b。用梯度下降进行一番计算以后,实际算出来的最好的\omega^∗= 0.97,b^∗ = 100,跟猜测蛮接近的。因为x_1的值可能跟y很接近,所以这个\omega就设一个接近1的值,b就设一个比较偏小的值。损失L(\omega^∗, b^∗) 算一下是480.