softmax上溢和下溢问题

在计算机里面数据都是以二进制的形式存储的,如果数据超过了计算机所能存储的最大范围,就会发生溢出。

softmax公式:

                                                                    f(x)=\frac{exp^{(x)}}{\sum_{i=1}^{k}exp^{(x)}_i}

softmax公式里面因为存在指数函数,所以有可能会出现上溢或下溢的问题。如下面的例子所示: 

import math
import numpy as np

def softmax(inp):
    
    length = len(inp)
    exps = []
    res = 0
    ind = 0
    for item in inp:
        exp = math.exp(item)
        res = res + exp
        exps.append(exp)
        ind+=1
    exps = np.array(exps)   
    return exps/res

    
inp = [1000,500,500]
inp1 = [-1000,-1000,-1000]
print("上溢:",softmax(inp))
print("下溢:",softmax(inp1))

当指数函数里面传入的值很大时,就会出现上溢,爆出OverflowError.

softmax上溢和下溢问题_第1张图片

当指数函数里面传入的值是很小的负数时,就会出现下溢,输出结果就是0, 这样就有可能导致分母的值为0。比如,inp=[-1000,-1000,-1000]。

解决这个问题的方法就是利用softmax的冗余性。我们可以看到对于任意一个数a, x-a和x在softmax中的结果都是一样的。

                                                       \frac{exp^{(x-a)}}{\sum_{i=1}^{k}exp^{(x-a)}_i}=\frac{exp^{(x)}exp^{(-a)}}{exp^{(-a)}\sum_{i=1}^{k}exp^{(x)}_i}=\frac{exp^{(x)}}{\sum_{i=1}^{k}exp^{(x)}_i}

所以,对于一组输入x = [x_1,x_2,...,x_n],我们可以让a=max(x). 这样就可以保证x-a的最大值等于0,也就不会产生上溢的问题。同时,因为一定有x-a=0,exp^{(0)}=1, 所以分母\sum_{i=1}^{k}exp^{(x-a)}_i的值就不可能为0,也就解决了下溢的问题。大家可以去改改上面的代码看看。

在用梯度下降法最小化交叉熵损失函数的时候,对参数求导需要计算log(softmax)。用这个方法同样可以保证不会出现log(0)的情况,因为softmax的分母至少有一项为1,就不会等于0了。

                                log(\frac{exp^{(x-a)}}{\sum_{i=1}^{k}exp^{(x-a)}_i}) =log(e^{(x-a)})-log(\sum_{i=1}^{k}exp^{(x-a)}_i)=(x-a)-log(\sum_{i=1}^{k}exp^{(x-a)}_i)

 

你可能感兴趣的:(机器学习)