如何在 Python 中实现 Softmax 函数

新手上路,请多包涵

Udacity 的深度学习类 中,y_i 的 softmax 就是简单的指数除以整个 Y 向量的指数之和:

在此处输入图像描述

其中 S(y_i) 是—的softmax函数, y_i e 是指数, j 输入向量 Y 中的列数。

我尝试了以下方法:

 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))

返回:

 [ 0.8360188   0.11314284  0.05083836]

但建议的解决方案是:

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

它产生 与第一个实现相同的输出,即使第一个实现显式地获取每列和最大值的差异,然后除以总和。

有人可以在数学上显示为什么吗?一个是对的,一个是错的吗?

实现在代码和时间复杂度方面是否相似?哪个更有效率?

原文由 alvas 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 755
2 个回答

它们都是正确的,但从数值稳定性的角度来看,您更喜欢您的。

你从

e ^ (x - max(x)) / sum(e^(x - max(x))

通过使用 a^(b - c) = (a^b)/(a^c) 的事实,我们有

= e ^ x / (e ^ max(x) * sum(e ^ x / e ^ max(x)))

= e ^ x / sum(e ^ x)

这是另一个答案所说的。您可以将 max(x) 替换为任何变量,它会取消。

原文由 Trevor Merrifield 发布,翻译遵循 CC BY-SA 3.0 许可协议

(好吧……这里的问题和答案都很混乱……)

首先,这两种解决方案(即您的和建议的) 并不 等同;它们 恰好 只在一维分数数组的特殊情况下是等价的。如果您还尝试了 Udacity 测验提供的示例中的二维分数数组,您就会发现它。

结果方面,两个解决方案之间唯一的实际区别是 axis=0 参数。为了解情况是否如此,让我们尝试您的解决方案 ( your_softmax ) 和唯一不同的是 axis 参数:

 import numpy as np

# your solution:
def your_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()

# correct solution:
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(axis=0) # only difference

正如我所说,对于一维分数数组,结果确实是相同的:

 scores = [3.0, 1.0, 0.2]
print(your_softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
print(softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
your_softmax(scores) == softmax(scores)
# array([ True,  True,  True], dtype=bool)

尽管如此,以下是 Udacity 测验中给出的二维分数数组的结果作为测试示例:

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

print(your_softmax(scores2D))
# [[  4.89907947e-04   1.33170787e-03   3.61995731e-03   7.27087861e-02]
#  [  1.33170787e-03   9.84006416e-03   2.67480676e-02   7.27087861e-02]
#  [  3.61995731e-03   5.37249300e-01   1.97642972e-01   7.27087861e-02]]

print(softmax(scores2D))
# [[ 0.09003057  0.00242826  0.01587624  0.33333333]
#  [ 0.24472847  0.01794253  0.11731043  0.33333333]
#  [ 0.66524096  0.97962921  0.86681333  0.33333333]]

结果不同——第二个确实与 Udacity 测验中预期的结果相同,其中所有列的总和确实为 1,而第一个(错误)结果并非如此。

所以,所有的大惊小怪实际上都是为了实现细节—— axis 论点。根据 numpy.sum 文档

默认情况下,axis=None,将对输入数组的所有元素求和

而在这里我们想按行求和,因此 axis=0 。对于一维数组,(唯一)行的总和与所有元素的总和恰好相同,因此在这种情况下您的结果相同……

axis 问题放在一边,您的实施(即您选择先减去最大值)实际上比建议的解决方案 更好!事实上,这是实现 softmax 函数的推荐方法 - 参见 此处 的理由(数字稳定性,也被其他一些答案指出)。

原文由 desertnaut 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题