在识别手写数字的流程中,我们提到,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 正是:
综合一下,就得到了我们的 Softmax 函数:
假设我们的原始值为 -1、0、3、5,那么经由 Softmax 处理可得:
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 | 概率 | |
---|---|---|
-1 | 0.368 | 0.047 |
2 | 7.39 | 0.953 |