Softmax是深度学习和机器学习中非常核心的一个激活函数,用于多分类过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。
简单来说,Softmax 的作用是:将一组任意的实数,转换成一个合法的概率分布。
1. 数学公式
假设我们有一个包含KKK个实数的向量z=[z1,z2,…,zK]z = [z_1, z_2, \dots, z_K]z=[z1,z2,…,zK](在神经网络中,这通常是最后一层全连接层的原始输出,称为Logits),那么 Softmax 函数针对其中第iii个元素的计算公式为:
Softmax(zi)=ezi∑j=1Kezj \text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}}Softmax(zi)=∑j=1Kezjezi
- 分子:对当前元素ziz_izi求指数(ezie^{z_i}ezi)。
- 分母:对所有元素的指数求和。
- 结果:输出一个与输入维度相同的向量p=[p1,p2,…,pK]p = [p_1, p_2, \dots, p_K]p=[p1,p2,…,pK]。
2. 核心特性
通过上述公式,Softmax 输出的向量ppp具有以下三个极其重要的特性:
- 非负性:因为自然对数底数e≈2.718e \approx 2.718e≈2.718是一个正数,正数的任何次幂都是正数,所以pi>0p_i > 0pi>0。
- 总和为 1:因为分母是所有分子之和,所以∑i=1Kpi=1\sum_{i=1}^{K} p_i = 1∑i=1Kpi=1。
- 放大差异(保持相对大小):由于指数函数是单调递增的凸函数,它会把最大的值“放大”得更多,把较小的值“压缩”得更小。这使得最终的概率分布更加“自信”(即胜出者的概率特别高,其他人的概率特别低)。
举个直观的例子:
假设输入向量z=[2,1,0.1]z = [2, 1, 0.1]z=[2,1,0.1]
- 计算指数:e2≈7.389e^2 \approx 7.389e2≈7.389,e1≈2.718e^1 \approx 2.718e1≈2.718,e0.1≈1.105e^{0.1} \approx 1.105e0.1≈1.105
- 求和:7.389+2.718+1.105=11.2127.389 + 2.718 + 1.105 = 11.2127.389+2.718+1.105=11.212
- 计算 Softmax:
- p1=7.389/11.212≈0.659p_1 = 7.389 / 11.212 \approx 0.659p1=7.389/11.212≈0.659(65.9%)
- p2=2.718/11.212≈0.242p_2 = 2.718 / 11.212 \approx 0.242p2=2.718/11.212≈0.242(24.2%)
- p3=1.105/11.212≈0.099p_3 = 1.105 / 11.212 \approx 0.099p3=1.105/11.212≈0.099(9.9%)
可以看到,原本只是 2:1:0.1 的差距,经过 Softmax 后变成了 65.9% : 24.2% : 9.9% 的概率分布,最大值的优势被放大了。
3. 为什么需要 Softmax?(应用场景)
在多分类任务中(例如:识别一张图片是猫、狗还是老虎),神经网络的最后一层会输出 3 个分数。但这 3 个分数可能是负数,也可能加起来不等于 1,我们无法直接把它们当作“概率”来解释。
加入 Softmax 层后,这 3 个分数就被转化成了“模型认为这张图是猫的概率是 90%,是狗的概率是 8%,是老虎的概率是 2%”。这样我们就可以取概率最大的类别作为最终的预测结果(这叫Argmax操作)。
4. Softmax 与 Sigmoid 的区别
很多人会混淆 Softmax 和 Sigmoid,因为两者都可将输出压缩到 (0,1) 区间,但设计目的、使用场景和数学定义完全不同:
5. 实际工程中的“隐藏陷阱”:数值稳定性
在写代码实现 Softmax 时,绝对不能直接套用上面的基础公式。
原因:如果输入的ziz_izi值很大(比如 1000),e1000e^{1000}e1000会直接导致计算机浮点数溢出,变成inf(无穷大),导致程序崩溃。
解决方案(数值稳定版 Softmax):
因为对分子分母同时乘以一个常数不改变分数的值,我们通常会减去输入向量中的最大值:
Softmax(zi)=ezi−max(z)∑j=1Kezj−max(z) \text{Softmax}(z_i) = \frac{e^{z_i - \max(z)}}{\sum_{j=1}^{K} e^{z_j - \max(z)}}Softmax(zi)=∑j=1Kezj−max(z)ezi−max(z)
减去最大值后,最大的ezi−max(z)e^{z_i - \max(z)}ezi−max(z)会被控制在e0=1e^0 = 1e0=1以内,其他的都会变成e负数e^{\text{负数}}e负数,从而完美避免了数值溢出的问题。在 PyTorch (F.softmax) 和 TensorFlow (tf.nn.softmax) 中,底层都是用这种稳定方式实现的。
6. 最佳搭档:交叉熵损失函数
在训练神经网络时,Softmax 几乎从不单独使用,它总是和交叉熵损失组成“黄金搭档”:
- Softmax负责:把网络输出的生硬数字变成概率分布。
- 交叉熵负责:计算这个预测概率分布与真实标签的 One-Hot 分布之间的差异(损失),并指导网络反向传播更新权重。
在 PyTorch 中,甚至有一个专门把这两步合并在一起的函数叫CrossEntropyLoss(它内部自动包含了 Softmax 操作,所以使用它时,网络的最后一层不需要再加 Softmax)。
扩展问题:之前我们已经介绍了sigmoid、tanh、Relu等常见的激活函数,在实际应用中,神经网络一般怎样选择这些激活函数?
(图中笔记中提到回归任务选择线性激活,防止有人不理解什么是线性激活,这里解释一下:线性激活就是什么都不做,输入是什么,输出就是什么,公式是 f(x)=x))