1. 数值上溢与下溢
计算机导致数值溢出的根本原因在于,使用有限的位数去表示连续的实数。这就导致了误差的出现,我们称之为舍入误差。舍入误差会导致很多后果,其中下溢(underflow)和上溢(overflow)是其中较为典型的代表。
下溢: 接近0的数字因为舍入误差导致该数在计算机中表示为0;
上溢: 数量级特别大的数的被近似为无穷。
上溢和下溢是深度学习中常见的数值溢出问题(尽管很多框架都对这些问题做了优化,但是并不代表数值溢出问题肯定不会出现),特别是涉及到指数函数时,该问题尤为突出,下面我将举两个在深度学习中常见的带有指数函数的激活函数的例子。
2. Sigmoid激活函数
函数表达式:
f
(
x
)
=
e
x
e
x
+
1
f(x)=\frac{e^{x}}{e^{x}+1}
f(x)=ex+1ex
我们可以看到,sigmoid函数中存在e的指数次幂,当x为很大的正数时,该指数就可能会发生数值上溢,从而导致出现无穷大除以无穷大的情况,数值不稳定。这时,我们就可以考虑sigmoid的另一个形式:
f
(
x
)
=
1
1
+
e
−
x
f(x)=\frac{1}{1+e^{-x}}
f(x)=1+e−x1
此时,虽然分母中出现下溢,但是整体上
f
(
x
)
f(x)
f(x)保证了数值稳定性。
在pytorch的sigmoid实现中,对输入x做了clip操作,使x维持在[-20, 20],从而防止数值溢出。
3. Softmax
softmax函数是必须要进行数值稳定的。其函数表达式:
f
(
x
i
)
=
e
x
i
∑
j
=
0
N
e
x
j
f(x_{i})=\frac{e^{x_{i}}}{\sum_{j=0}^{N}e^{x_{j}}}
f(xi)=∑j=0Nexjexi
当所有的
x
i
x_{i}
xi都是一个很小的负数时,发生数值下溢,导致函数中分母为0,数值不稳定;当有一个
x
i
x_{i}
xi特别大时,发生数值上溢,导致出现无穷除以无穷的情况,数值不稳定。由此可见,softmax无论是数值上溢还是数值下溢,都会导致softmax的数值不稳定,因此必须对其进行数值稳定。
采用的方法很简单,在进行计算之前,先对进行
z
i
=
x
i
−
m
a
x
(
x
)
z_{i}=x_{i}-max(x)
zi=xi−max(x),然后再使用
z
i
z_{i}
zi进行计算。此时,自变量的取值范围小于等于0,且必定有一个
z
i
z_{i}
zi等于0。所以数值上溢直接不存在,当出现数值下溢时,由于有一个
z
i
z_{i}
zi必定等于0,所以分母必定不会为0,数值下溢问题也相应的解决了。
为什么softmax可以这样变换而sigmoid却不可以呢?因为softmax函数的输出值不会因为其输入值的整体平移(整体加上同一个标量)而发生改变,所以我们可以进行这样的变换,但是sigmoid就不可以。
深度学习中还有许多应对数值不稳定的方法,欢迎大家在评论区交流。
如果有任何问题,欢迎在评论区指正,我会及时修改。