Python中实现Softmax函数的方法及分析

Python中实现Softmax函数的方法及分析

技术背景

在机器学习,特别是深度学习的分类任务中,Softmax函数是一个常用的激活函数。它能将一组实数转换为概率分布,使得所有输出值的和为1,这样可以方便地表示每个类别对应的概率。Softmax函数的数学定义为:对于输入向量 $Y$,其第 $i$ 个元素的Softmax值 $S(y_i)$ 为 $\frac{e^{y_i}}{\sum_{j}e^{y_j}}$,其中 $e$ 是自然常数,$j$ 是输入向量 $Y$ 的列数。

实现步骤

两种常见实现方法

方法一

1
2
3
4
5
6
7
8
9
import numpy as np

def softmax(x):
"""Compute softmax values for each sets of scores in x."""
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()

scores = [3.0, 1.0, 0.2]
print(softmax(scores))

方法二

1
2
3
4
5
6
7
8
import numpy as np

def softmax(x):
"""Compute softmax values for each sets of scores in x."""
return np.exp(x) / np.sum(np.exp(x), axis=0)

scores = [3.0, 1.0, 0.2]
print(softmax(scores))

代码解释

  • 方法一:先对输入向量 $x$ 中的每个元素减去向量中的最大值,然后计算指数,最后将每个元素的指数值除以所有元素指数值的和。这样做的目的是为了避免指数运算时出现数值溢出的问题,提高数值稳定性。
  • 方法二:直接对输入向量 $x$ 中的每个元素计算指数,然后将每个元素的指数值除以所有元素指数值的和。这种方法在输入值较小时可以正常工作,但当输入值较大时,可能会出现数值溢出的问题。

两种方法的数学等价性证明

方法一的表达式为 $\frac{e^{x - \max(x)}}{\sum_{j}e^{x_j - \max(x)}}$,根据指数运算法则 $a^{b - c} = \frac{a^b}{a^c}$,可以将其变形为:
[
\begin{align*}
\frac{e^{x - \max(x)}}{\sum_{j}e^{x_j - \max(x)}}&=\frac{\frac{e^x}{e^{\max(x)}}}{\sum_{j}\frac{e^{x_j}}{e^{\max(x)}}}\
&=\frac{e^x}{e^{\max(x)}\sum_{j}\frac{e^{x_j}}{e^{\max(x)}}}\
&=\frac{e^x}{\sum_{j}e^{x_j}}
\end{align*}
]
这与方法二的表达式是等价的。

核心代码

以下是一个综合的代码示例,展示了不同输入情况下两种方法的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np

# 方法一
def softmax_1(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()

# 方法二
def softmax_2(x):
return np.exp(x) / np.sum(np.exp(x), axis=0)

# 一维输入
scores_1d = [3.0, 1.0, 0.2]
print("一维输入 - 方法一:", softmax_1(scores_1d))
print("一维输入 - 方法二:", softmax_2(scores_1d))

# 二维输入
scores_2d = np.array([[1, 2, 3, 6],
[2, 4, 5, 6],
[3, 8, 7, 6]])
print("二维输入 - 方法一:", softmax_1(scores_2d))
print("二维输入 - 方法二:", softmax_2(scores_2d))

最佳实践

  • 数值稳定性:在实际应用中,建议使用方法一,即先减去最大值再计算指数,以避免数值溢出的问题。
  • 多维输入处理:当输入为多维数组时,需要注意 axis 参数的使用。如果要对每一行进行Softmax计算,需要将 axis 参数设置为1。

以下是一个处理多维输入的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

def softmax(x):
if len(x.shape) > 1:
s = np.max(x, axis=1)
s = s[:, np.newaxis]
e_x = np.exp(x - s)
div = np.sum(e_x, axis=1)
div = div[:, np.newaxis]
return e_x / div
else:
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()

scores_2d = np.array([[1, 2, 3, 6],
[2, 4, 5, 6],
[3, 8, 7, 6]])
print(softmax(scores_2d))

常见问题

数值溢出问题

当输入值较大时,直接计算指数可能会导致数值溢出。使用先减去最大值再计算指数的方法可以有效避免这个问题。

多维输入处理错误

在处理多维输入时,如果没有正确设置 axis 参数,可能会得到错误的结果。需要根据具体需求设置 axis 参数,以确保对正确的维度进行求和。

性能问题

不同的实现方法在性能上可能会有所差异。可以使用 timeit 模块对不同的实现方法进行性能测试,选择性能最优的方法。以下是一个性能测试的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
import timeit

def softmax_1(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()

def softmax_2(x):
return np.exp(x) / np.sum(np.exp(x), axis=0)

x = [10, 10, 18, 9, 15, 3, 1, 2, 1, 10, 10, 10, 8, 15]

print("方法一性能:", timeit.timeit(lambda: softmax_1(x), number=10000))
print("方法二性能:", timeit.timeit(lambda: softmax_2(x), number=10000))

Python中实现Softmax函数的方法及分析
https://119291.xyz/posts/2025-04-22.implementation-and-analysis-of-softmax-function-in-python/
作者
ww
发布于
2025年4月22日
许可协议