Softmax 函数

1,413 阅读2分钟

在识别手写数字的流程中,我们提到,Softmax 层将神经网络的输出变成了一个概率分布。这里面主要用到的就是 Softmax 函数。

首先我们要回答一个问题,为什么要把一串数字变成概率分布?

我们可以从一个选择的问题说起。假设我们要从 3 个个体里随机选择一个个体,但它们分别具有权重为 1、4、13,我们希望权重高的个体更容易被选中。也就是说,被选中的概率与个体在总体中所占比例成正比

熟悉遗传算法的同学可能马上能想到,在遗传算法的个体选择里用到的 轮盘赌选择算法 就可以用在这个场景里。它的描述如下:

实际上很简单,将所有个体加和,然后计算各个个体在总数中的比例。这些比例之和为 1,那么就可以根据区间进行随机选择了。

以上述例子举例,三个个体总数为 1 + 4 + 13 = 18,所以比例分别为:

个体 比例 累计比例
1 1 / 18 = 0.06 0.06
4 4 / 18 = 0.22 0.06 + 0.22 = 0.28
13 13 / 18 = 0.72 0.28 + 0.72 = 1

这时随机生成一个 0 到 1 的数,如果落在 [0, 0.06) 中,则第一个个体被选中;如果落在 [0.06, 0.28) 中,则第二个个体被选中;如果落在 [0.28, 1) 中,则第三个个体被选中。

很容易理解,在轮盘赌算法里面,个体的值不能是负数,这就需要我们提前对个体值进行处理。假设我们原始值里面包含负数,那么在进行轮盘赌之前需要转化为正数。

将轮盘赌算法写成更易于理解的形式则为:

我们的原始值 x 可以包含正数和负数,但经过函数 f 的处理,可以都映射到正数上。你可能已经想到了,这里的 f 正是:

f(x) = e^x

综合一下,就得到了我们的 Softmax 函数:

假设我们的原始值为 -1、0、3、5,那么经由 Softmax 处理可得:

\sum_{j=1}^N f(x_j) = e^{-1} + e^0 + e^3 + e^5= 169.87

x 分子 e^x 比例
-1 0.368 0.002
0 1 0.006
3 20.09 0.118
5 148.41 0.874

在 Python 中,使用 Numpy 非常容易实现:

import numpy as np

def softmax(xs):
    return np.exp(xs) / sum(np.exp(xs))

xs = np.array([-1, 0, 3, 5])
print(softmax(xs)) # [0.0021657, 0.00588697, 0.11824302, 0.87370431]

当然,实际上我们把 Softmax 函数用在神经网络里并不是为了选择,而重点在于 表示概率,如果说我们的神经网络在像猫还是像狗的问题上分别输出为 -1 和 2,那么我们可以说,有 95.3% 像狗。这就是 Softmax 函数的功劳。

x e^x 概率
-1 0.368 0.047
2 7.39 0.953

参考