上溢和下溢(Overflow and Underflow)
由于计算机中我们使用有限个数的位模式(bit)来表示无限个的实数,总会存在一些近似误差。因此如果理论上可行的算法并没有被设计为可以最小化舍入误差的累积,实践中就可能会出现问题。总之,在计算机中需要避免产生极小和极大值,否则它们因为舍入误差被近似为0或者∞,导致算法运算的错误。
下溢:当接近零的数被四舍五入为零时发生下溢。许多函数在其参数为零而不是一个很小的正数时才会表现出质的不同,因此通常要避免被零除(一些软件环境将在这种情况下抛出异常,有些会返回一个非数字 (not-a-number) 的占位符)或避免取零的对数(这通常被视为 −∞,进一步的算术运算会使其变成非数字)。
上溢:
当大量级的数被近似为 ∞ 或 −∞ 时发生上溢。进一步的运算通常导致这些无限值变为非数字。
以softmax函数为例,它必须对上溢和下溢进行数值稳定(避免上溢和下溢的情况)。softmax函数经常用来预测与multinoulli分布相关的概率(multimoulli分布有n个状态,softmax输出值表示能取到每个状态的概率为多少):
理论上,当所有都取一个常数c时,它们的输出应该均为
。实际中,若c是一个很小的负数,那么分母就会趋于0,产生下溢;若c是一个很大的正数,
的上溢就会导致整个表达式未定义。解决办法是令
,转而求
。这样分母中至少有一项为1,可以解决下溢问题;同时exp的参数最大为0,解决了上溢问题。重要的是,softmax函数不会因输入的向量减去一个标量而改变输出。
对于函数log(softmax),softmax分子上的下溢会导致softmax输出为0,如果先计算softmax输出,再传递给log,则会得到。因此要对log(softmax)也进行数值稳定,即让softmax不会因为下溢而输出0。
病态条件数(Poor Conditioning)
条件数表明函数相对于输入的微小变化而变化的快慢程度(类似导数?)。输入被轻微扰动而迅速改变的函数对于科学计算来说是可能是有问题的,因为输入中的舍入误差可能导致输出的巨大变化,这就是病态条件数。
对于函数,当
有特征值分解时,其条件数为
,也就是最大特征值和最小特征值的模之比,当该值很大时,矩阵求逆对输入的误差特别敏感。这种敏感性是矩阵本身的固有特性,而不是矩阵求逆期间舍入误差的结果。即使我们乘以完全正确的矩阵逆,病态条件数的矩阵也会放大预先存在的误差。在实践中,该错误将与求逆过程本身的数值误差进一步复合。
至于条件数与特征值的关系,其实没有很懂。不过特征值可以理解为运动的速度,其实就是变化的速度。关于特征值到底是什么,可以参考文章:https://www.matongxue.com/madocs/228.html。最大特征值就是其对应的特征向量方向上的速度,最小特征值同理,这样就是两个方向上最大变化速度与最小变化速度的比值,如果这个比值很大,说明输入有轻微扰动时,某个方向的变化速度很快,而某个方向变化速度很慢,这种变化的不一致确实和条件数的概念有符合部分。
基于梯度的优化方法(Gradient-Based Optimization)
大多数深度学习算法涉及某种形式的优化。优化指的是改变 x 以最小化或最大化某个函数 f(x) 的任务。我们通常以最小化 f(x) 指代大多数最优化问题。最大化可经由最小化算法最小化 −f(x) 来实现。我们把要最大化或最小化的函数称为目标函数(objective function)或准则(criterion)。当我们对其进行最小化时,我们也把它称为代价函数 (cost function)、损失函数 (loss function) 或误差函数 (error function)。通常用上标*表示最大化或最小化函数的x值:。
导数可以理解为:当函数的输入x有了微小的变化时,在之前的输出上如何缩放
能获得相应的变化,公式可以表示为:
。这个式子可以理解为:若是想让
有一个微小的变化,也就是相当于
是已知的,求得该点x的导数
后就可以得到x的变化
,将
作用在x上就会令
产生想要的微小变化。也就是说可以通过导数求得自变量的变化方向/趋势使得函数的输出向我们期望的方向变化。例如,我们知道对于足够小的 ϵ 来说,f(x − ϵsign(f′(x))) 是比 f(x) 小的。因此我们可以将 x 往导数的反方向移动一小步来减小 f(x)。这种技术被称为梯度下降 (gradient descent)。
当 ,导数无法提供往哪个方向移动的信息。