1.1 案例学习
本节以视频的观看次数预测为例介绍机器学习的运作过程.假设有人想要通过视频平台赚钱,他会在意频道有没有流量,这样他才会知道自己能不能获利.假设从后台可以看到很多相关的信息,比如每天点赞的人数、订阅人数、观看次数.根据一个频道过往所有的信息,可以预测明天的观看次数. 我们想寻找一个函数,该函数的输入是后台的信息,输出是次日这个频道的预计观看次数.
机器学习的过程分为3个步骤.第1个步骤是写出一个带有未知参数的函数 ,它能预测未来观看次数. 比如将函数写成
(1.1)
其中,是要预测的值,假设这里要预测的是2月26日这个频道总的观看次数.是这个频道前一天(2月25日)的观看次数. 和是数值;和是未知的参数,我们只能隐约地猜测它们的值. 猜测往往来自对这个问题本质上的了解,即领域知识(domain knowledge).机器学习需要一些领域知识,比如一天的观看次数总是会跟前一天的观看次数有点关联,所以不妨把前一天的观看次数乘以一个数值,再加上一个 做修正,当作对2月26日观看次数的预测. 这只是一个猜测,不一定是对的,稍后我们再来修正这个猜测.
带有未知参数(parameter)的函数称为模型(model). 模型在机器学习里面,就是一个带有未知参数的函数,特征(feature) 是这个函数里面已知的来自后台的信息——2月25日的观看次数是已知的. 称为权重(weight),称为偏置(bias).
第2个步骤是定义损失(loss),损失也是一个函数,记为.损失函数输出的值意味着,当把模型参数设定为某个数值时,这个数值好还是不好.举一个具体的例子,如果我们猜测,,则函数就变成了 .对于从训练数据中计算损失这个问题,训练数据是这个频道过去的观看次数.如果我们已经掌握2017年1月1日~ 2020年12月31日的观看次数(如图1.1 所示)接下来就可以计算损失了.
图1.1 2017年1月1日~ 2020年12月31日的观看次数(此处的观看次数是随机生成的)
把2017年1月1日的观看次数代入函数,得到
(1.2)
根据我们的猜测,预测次日的观看次数为 ,但真实的观看次数为4900,我们高估了这个频道的观看次数. 可以评估一下估测值跟真实值间的差距.评估差距其实有多种方式,比如取二者差的绝对值:
(1.3)
真实值称为标签(label).
我们不仅可以用2017年1月1日的值来预测2017年1月2日的值,也可以用2017年1月2日的值来预测2017年1月3日的值.根据2017年1月2日的观看次数4900,我们预测2017年1月3日的观看次数是5400.接下来计算 5400跟标签(7500)之间的差距:
(1.4)
以此类推,把接下来每一天的差距通通加起并取平均,得到损失 :
(1.5)
其中,代表训练数据数,即4年来所有的训练数据. 是每一笔训练数据的误差平均以后的结果.越大,代表我们猜测的这组参数越差;越小,代表这组参数越好.
估测值跟真实值之间的差距,其实有不同的评估方法,比如计算二者差的绝对值,如式(1.6) 所示,这个评估方式所计算的值称为平均绝对误差(Mean Absolute Error,MAE).
(1.6)
也可以计算 二者差的平方,如式(1.7) 所示,称为这个评估方式所计算的值均方误差(Mean Squared Error,MSE).
(1.7)
在有些任务中, 和都是概率分布,这时候可能会选择计算交叉熵(cross entropy).}刚才举的那些数字不是真实的例子,以下数字才是真实的例子,是用一个频道真实的后台数据计算出来的结果.我们可以调整不同的和不同的 ,计算损失,并画出图1.2 所示的等高线图.在这个等高线图中,色相越红,代表计算出来的损失越大,也就代表这一对越差;色相越蓝,就代表损失越小,也就代表这一对越好. 将损失小的放到函数里面,预测会更精准. 从图1.2 中我们得知,如果为代入一个接近1的值,并为代入一个较小的正值(比如100),则预测较精准,这跟大家的预期可能比较接近:相邻两天观看次数总是差不多的.
在图1.2 中,我们尝试了不同的参数,并且计算了损失. 这样画出来的等高线图称为误差表面(error surface).
图1.2 误差表面
机器学习的第3个步骤是解一个优化问题,即找到最好的一对,使损失的值最小. 我们用符号,代表最好的一对.
对于这个问题,梯度下降(gradient descent)是最常用的优化方法.为了简化起见,先假设只有参数是未知的,而是已知的.当为代入不同的数值时,就会得到不同的损失,从而绘制出误差表面,只是刚才在前一个例子里面,误差表面是二维的,而这里只有一个参数,所以误差表面是一维的.怎么才能找到一个让损失值最小呢?如图1.3 所示,首先要随机选取一个初始的点.接下来计算,也就是时,损失对参数的微分,得到处误差表面的切线(即蓝色虚线)的斜率. 如果斜率是负的,就代表左边比较高、右边比较低,此时把的值变大,就可以让损失变小. 相反,如果斜率是正的,就代表把变小可以让损失变小.我们可以想象有一个人站在这个地方左右环视,看看左边比较高还是右边比较高,并往比较低的地方跨出一步.步伐的大小取决于以下两件事情.
图1.3 优化过程
● 这个地方的斜率,斜率大,步伐就跨大一点;斜率小,步伐就跨小一点.
● 学习率(learning rate).学习率可以自行设定,如果设大一点,每次参数更新就会量大,学习可能就比较快;如果设小一点,参数更新就很慢,每次只改变一点点参数的值. 这种需要自己设定,而不是由机器找出来的参数称为超参数(hyperparameter).
Q: 为什么损失可以是负的?
A: 根据刚才损失的定义,损失是估测值和真实值的差的绝对值,不可能是负的.但如何定义损失函数是我们自己决定的,比如设置一个损失函数为差的绝对值再减100,它就可以为负了.损失曲线并不反映真实的损失,也不是真实任务的误差表面.因此,损失曲线可以是任何形状.
把往右移一步,新的位置为,这一步的步伐是乘上微分的结果,即
(1.8)
接下来反复执行刚才的操作,计算一下的微分结果,再决定要把移动多少,得到,继续执行同样的操作,不断地移动的位置,最后我们会停下来.这往往对应两种情况.
● 第一种情况是在一开始就设定,在调整参数的时候,微分最多计算几次,如100万次,参数更新100万次后,就不再更新了,我们就会停下来. 更新次数也是一个超参数.
● 另一种情况是在不断调整参数的过程中,我们遇到了微分的值是0的情况,此时哪怕继续迭代,参数的位置也不再更新,我们因此而停下来.
梯度下降有一个很大的问题,就是有可能既没有找到真正最好的解,也没有找到可以让损失最小的.在图1.4 所示的例子中,把设定在最右侧红点附近可以让损失最小.但如果在梯度下降过程中,是随机初始的位置,则也很有可能走到时,训练就停住了,我们无法再移动的位置.右侧红点这个位置是真的可以让损失最小的地方,称为全局最小值(globalminimum);而这个地方称为局部最小值(local minimum),其左右两边都比这个地方的损失还要高一点,但它不是整个误差表面上的最低点.所以我们常常可能会听到有人讲梯度下降法不是什么好方法,无法真正找到全局最小值.
图1.4 局部最小值
在有两个参数的情况下使用梯度下降法,跟只有一个参数的情景没有什么不同.
假设有两个参数和,它们的随机初始值分别为 和. 在、的位置,分别计算对的微分以及对的微分:
(1.9)
计算完毕后,更新和. 把减掉学习率和微分结果的积,得到;把减掉学习率和微分结果的积,得到.
(1.10)
在深度学习框架(如 PyTorch)中,微分都是由程序自动计算的.程序会不断地更新和,试图找到一对最好的. 可以将这个计算过程绘制成一系列点,如图1.5 所示,随便选一个初始值,计算一下和,就可以决定更新的方向. 这是一个向量,见图1.5 中红色的箭头.沿箭头方向不断移动,应该就可以找出一组不错的和.实际上,在真正用梯度下降进行一番计算以后,有.计算损失,结果是480. 也就是说,在2017年~ 2020年的数据上,如果使用这个函数,为代入0.97,为代入100,则平均误差是480.
图1.5 梯度下降优化的过程