1.2.1 分段线性曲线
线性模型也许过于简单, 和 之间可能存在比较复杂的关系,如图1.7 所示.对于的线性模型,和 的关系就是一条斜率为正的直线,随着 越来越大,也应该越来越大.设定不同的 可以改变这条直线的斜率,设定不同的 则可以改变这条直线和 轴的交点.但无论如何改变 和 ,它永远都是一条直线,永远都是 越大,就越大:某一天的观看次数越多,次日的观看次数就越多.但在现实中,也许当 大于某个数值的时候,次日的观看次数反而会变少. 和 之间可能存在一种比较复杂的、像红色线一样的关系.但不管如何设置 和 ,我们永远无法用简单的线性模型构造红色线.显然,线性模型有很大的限制,这种来自模型的限制称为模型的偏差,无法模拟真实情况.
图1.7 线性模型的局限性
所以,我们需要写一个更复杂、更有灵活性、有更多未知参数的函数. 图1.8 中,红色线可以看作一个常数项 再加上一些 hard sigmoid 函数(hard sigmoid 函数的特性是当输入的值介于两个阈值间的时候,图像呈现出一个斜坡,其余位置都是水平的).常数项被设成红色线和轴的交点一样大.第1个蓝色函数斜坡的起点,设在红色函数的起始地方. 第2个斜坡的终点设在第一个转角处,第1个蓝色函数的斜坡和红色函数的第1段斜坡斜率相同,这时候求+❶, 就可以得到红色线左侧的线段.接下来,叠加第2个蓝色函数,所以第2个蓝色函数的斜坡就在红色函数的第1个转折点和第2个转折点之间,第2个蓝色函数的斜坡和红色函数的第2段斜坡斜率相同. 这时候求+❶+❷,就可以得到红色函数左侧和中间的线段.对于第2个转折点之后的部分,再叠加第3个蓝色函数,第3个蓝色函数的斜坡的起点设在红色函数的第2个转折点,蓝色函数的斜坡和红色函数的第3段斜坡斜率相同. 最后,求 +❶+❷+❸,就得到了完整的红色线.
图1.8 构建红色线
所以红色线[即分段线性曲线(piecewise linear curve)]可以看作一个常数和一些蓝色函数的叠加.分段线性曲线越复杂,转折的点越多,所需的蓝色函数就越多.
也许要考虑的 和 的关系不是分段线性曲线 ,而是图1.9 所示的曲线. 可以在这样的曲线上先取一些点,再把这些点连起来,变成一条分段线性曲线.而这条分段线性曲线跟原来的曲线非常接近,如果点取得够多或位置适当,分段线性曲线就可以逼近连续曲线,甚至可以逼近有角度和弧度的连续曲线. 我们可以用分段线性曲线来逼近任何连续曲线,只要有足够的蓝色函数.
图1.9 分段线性曲线可以逼近任何连续曲线
和 的关系非常复杂也没关系,可以想办法写一个带有未知数的函数.直接写 hard sigmoid 函数不是很容易,但可以用 sigmoid 函数来逼近 hard sigmoid 函数,如图1.10 所示.sigmoid函数的表达式为
其中,输入是 ,输出是 ,为常数.
图1.10 使用 sigmoid 函数逼近 hard sigmoid 函数
当 的值趋近于正无穷的时候,这一项就会几乎消失,就会收敛于常数 ;当 的值趋近于负无穷的时候,分母就会非常大,就会收敛于 0.
所以可以用这样的一个函数逼近蓝色函数.为了简洁,蓝色函数的表达式记为
(1.15)
其中
(1.16)
调整式(1.15)中的 、和 , 就可以构造各种不同形状的 sigmoid函数,从而用各种不同形状的 sigmoid函数逼近 hard sigmoid 函数.如图1.11 所示,如果调整 ,就会改变斜坡的坡度;如果调整,就可以左右移动sigmoid函数曲线;如果调整 ,就可以改变曲线的高度.所以,只要叠加拥有不同的 、 不同的 和不同的 的sigmoid函数,就可以逼近各种不同的分段线性函数(如图1.12 所示):
(1.17)
图1.11 调整参数,构造不同的 sigmoid 函数
图1.12 使用 hard sigmoid 函数来合成红色线
此外,我们可以不只用一个特征 ,而是用多个特征代入不同的 、、,构建出各种不同的sigmoid函数,从而得到更有灵活性(flexibility)的分段线性函数,如图1.13 所示. 可以用 来代表特征的编号. 如果要考虑 28 天的数据,就可以取 1 ~ 28.
图1.13 构建更有灵活性的函数
举个只考虑3个特征(即只考虑前3天~前1天)的例子. 此时可以取 1、2、3,每一个 就代表一个蓝色函数. 每一个蓝色函数都用一个 sigmoid函数来近似,一共需要3个 sigmoid函数:
(1.18)
代表在第 个 sigmoid 函数中乘给第 个特征的权重.设图1.13 的蓝色虚线框中有
(1.19)
我们可以用矩阵和向量相乘的方法,得到如下比较简洁的写法.
(1.20)
也可以改成线性代数比较常用的表示方式,如下所示.
(1.21)
对应的是 、、.有了、、, 分别通过 sigmoid函数得到 、、,即
(1.22)
因此,如图1.14 所示,蓝色虚线框里面做的事情,就是从 、、得到 、、.
图1.14 比较有灵活性函数的计算过程
上面这个比较有灵活性的函数可以用线性代数来表示,即
(1.23)
接下来,如图1.15 所示,是特征,绿色的是向量,灰色的是数值.、、、是未知参数.把矩阵展平,与其他项“拼合”,就可以得到一个很长的向量. 把 的每一行或每一列拿出来,拿行或拿列都可以. 先把 的每一列或每一行“拼”成一个长向量,再把 、、“拼”进来,这个长向量可以直接用 来表示. 我们将所有未知参数一律统称 .
图1.15 将未知参数“拼”成一个向量
Q: 优化是找一个可以让损失最小的参数,是否可以穷举所有可能的未知参数的值?
A:在只有 和 两个参数的前提下,可以穷举所有可能的 和 的值. 所以在参数很少的情况下,甚至可能不用梯度下降,也不需要优化技巧. 但是当参数非常多的时候,就不能使用穷举的方法,而应使用梯度下降的方法找出可以让损失最小的参数.
Q:刚才的例子里面有 3 个 sigmoid函数,为什么是 3 个,能不能是 4 个或更多个?
A:sigmoid 函数的数量由我们自己决定,sigmoid 函数的数量越多,可以产生的分段线性函数就越复杂.sigmoid 函数的数量也是一个超参数.
接下来定义损失. 此前的损失函数记作 ,现在未知参数太多了,所以直接用 来统设所有的参数,损失函数记作 . 损失函数能够判断 的好坏,计算方法跟只有两个参数的情况是一样的:先给定的值,即某一组 、、、的值,再把特征 加进去,得到估测出来的 ,最后计算一下跟真实标签之间的误差. 把所有的误差通通加起来,就得到了损失.
下一步就是优化,即优化
(1.24)
要找到一组 , 让损失越小越好,可以让损失最小的一组 称为 .一开始,要随机选一个初始的数值 . 接下来计算每一个未知参数对 的微分,得到向量 为
(1.25)
(1.26)
假设有 1000 个参数,向量的长度就是 1000,这个向量也称为梯度向量. 代表梯度; 是指计算梯度的位置,也就是 等于 的地方.计算出以后,接下来更新参数. 代表起始值,它是一个随机选的起始值,代表 更新过一次的结果. 用减掉微分结果和 的积,得到,以此类推,就可以把 1000 个参数都更新了(见图1.16):
(1.27)
(1.28)
图1.16 使用梯度下降更新参数
参数有 1000 个,就是 1000 个数值,是1000 维的向量,也是 1000 维的向量.整个操作就是这样,由 开始计算梯度,根据梯度把 更新成 ;再算一次梯度,再根据梯度把 更新成 ;以此类推,直到不想做,或者梯度为零,导致无法再更新参数为止. 不过在实践中,几乎不太可能梯度为零,通常停下来就是因为我们不想做了.
实现上,有个细节上的区别,如图1.17 所示,实际使用梯度下降时,会把 笔数据随机分成一个个的批量(batch),每个批量里面有 笔数据.本来是把所有的数据拿出来计算损失,现在只拿一个批量里面的数据出来计算损失,记为 .假设 够大,也许 和 会很接近.所以在实现上,每次会先选一个批量,用该批量来算 ,根据 来算梯度,再用梯度来更新参数;接下来再选下一个批量,算出 ,根据 算出梯度,再更新参数;最后再取下一个批量,算出 ,根据 算出梯度,再用 算出来的梯度更新参数.
图1.17 分批量进行梯度下降
把所有的批量都看过一遍的过程称为一个回合(epoch),每更新一次参数称为一次更新. 更新和回合是两个不同的概念.
举个例子,假设有 10 000 笔数据,即 等于 10 000;批量大小(batch size)设为 10,即 等于10.10 000 个样本(example)形成了 1000 个批量,所以在一个回合里面更新了参数 1000 次,所以一个回合不只更新参数一次.
再举个例子,假设有 1000 个数据,批量大小设为 100,批量大小和sigmoid 函数的个数都是超参数.1000 个 样本,批量大小 设为 100,1个回合总共更新10次参数.一个回合的训练其实不知道更新了几次参数,有可能 1000 次,也有可能 10 次,取决于批量有多大.