当前位置: 首页 > 知识库问答 >
问题:

如何在Python中实现Softmax函数

辛麻雀
2023-03-14

从Udacity的深度学习类来看,y_i的软最大值只是指数除以整个Y向量的指数之和:

其中< code>S(y_i)是< code>y_i的softmax函数,而< code>e是指数,而< code>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)

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

有人能用数学说明为什么吗?一个正确,另一个错误吗?

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

共有3个答案

束雅达
2023-03-14

所以,这确实是对逃兵答案的评论,但由于我的声誉,我还不能对此发表评论。正如他所指出的,只有输入包含单个样本时,您的版本才是正确的。如果您的输入包含多个样本,则是错误的。然而,逃兵的解决方案也是错误的。问题是,一旦他接受了一维输入,然后又接受了二维输入。让我给你看看这个。

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

# desertnaut solution (copied from his answer): 
def desertnaut_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

# my (correct) solution:
def softmax(z):
    assert len(z.shape) == 2
    s = np.max(z, axis=1)
    s = s[:, np.newaxis] # necessary step to do broadcasting
    e_x = np.exp(z - s)
    div = np.sum(e_x, axis=1)
    div = div[:, np.newaxis] # dito
    return e_x / div

让我们以沙漠为例:

x1 = np.array([[1, 2, 3, 6]]) # notice that we put the data into 2 dimensions(!)

这是输出:

your_softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

desertnaut_softmax(x1)
array([[ 1.,  1.,  1.,  1.]])

softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

您可以看到,在这种情况下,说明版本将失败。(如果输入只是像np.array([1, 2, 3, 6])那样的一维,则不会)。

现在让我们使用 3 个样本,因为这是我们使用 2 维输入的原因。以下 x2 与来自德纳特示例的 x2 不同。

x2 = np.array([[1, 2, 3, 6],  # sample 1
               [2, 4, 5, 6],  # sample 2
               [1, 2, 3, 6]]) # sample 1 again(!)

此输入由一个包含 3 个样本的批次组成。但样本一和样本三本质上是相同的。我们现在期望有 3 行 softmax 激活,其中第一行应该与第三行相同,也与 x1 的激活相同!

your_softmax(x2)
array([[ 0.00183535,  0.00498899,  0.01356148,  0.27238963],
       [ 0.00498899,  0.03686393,  0.10020655,  0.27238963],
       [ 0.00183535,  0.00498899,  0.01356148,  0.27238963]])


desertnaut_softmax(x2)
array([[ 0.21194156,  0.10650698,  0.10650698,  0.33333333],
       [ 0.57611688,  0.78698604,  0.78698604,  0.33333333],
       [ 0.21194156,  0.10650698,  0.10650698,  0.33333333]])

softmax(x2)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047],
       [ 0.01203764,  0.08894682,  0.24178252,  0.65723302],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

我希望你能看到我的解决方案只是这样。

softmax(x1) == softmax(x2)[0]
array([[ True,  True,  True,  True]], dtype=bool)

softmax(x1) == softmax(x2)[2]
array([[ True,  True,  True,  True]], dtype=bool)

此外,以下是TensorFlows softmax实施的结果:

import tensorflow as tf
import numpy as np
batch = np.asarray([[1,2,3,6],[2,4,5,6],[1,2,3,6]])
x = tf.placeholder(tf.float32, shape=[None, 4])
y = tf.nn.softmax(x)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(y, feed_dict={x: batch})

结果是:

array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037045],
       [ 0.01203764,  0.08894681,  0.24178252,  0.657233  ],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037045]], dtype=float32)
宋飞文
2023-03-14

(嗯……这里有很多困惑,无论是问题还是答案……)

首先,这两种解决方案(即你的和建议的解决方案)是不等价的;它们碰巧只在一维分数数组的特殊情况下是等价的。如果你也尝试过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,而第一个(错误)结果并非如此。

因此,所有的麻烦实际上都是为了实现细节——参数。根据numpy的说法。总和文档:

默认值 axis = None 将对输入数组的所有元素求和

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

撇开问题不谈,您的实现(即您选择先减去max)实际上比建议的解决方案要好!事实上,这是实现softmax函数的推荐方法——请看这里的理由(数字稳定性,这里的一些其他答案也指出了这一点)。

姬乐
2023-03-14

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

你从开始

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),它会抵消掉。

 类似资料:
  • 问题内容: 当实现具有多个属性的类时(例如下面的玩具示例),处理哈希的最佳方法是什么? 我认为和应该是一致的,但是如何实现能够处理所有属性的适当的哈希函数呢? 问题答案: 对于相等的对象应返回相同的值。它也不应在对象的整个生命周期内发生变化。通常,您只为不可变的对象实现它。 一个简单的实现就是公正。这始终是正确的,但效果很差。 您的解决方案,返回一个属性元组的哈希,是很好的。但是请注意,您无需列出

  • 我正在学习神经网络,并在python中实现它。我首先定义了一个 softmax 函数,我遵循这个问题给出的解决方案 Softmax 函数 - python。以下是我的代码: 我得到了一个测试代码,看看函数是否正确。是测试数据,

  • 问题内容: 我以前的编程中,代码段仅用于调试目的(记录命令等)。通过使用预处理程序指令,可以完全禁用这些语句以进行生产,如下所示: 做类似的事情的最好方法是什么? 问题答案: 如果只想禁用日志记录方法,请使用该模块。如果日志级别设置为排除调试语句,那么它将非常接近无操作(它仅检查日志级别并返回而不插入日志字符串)。 如果要在特定条件下以字节码编译时实际删除代码块,则唯一的选择是相当神秘的全局变量。

  • 问题内容: 如何实现与C#代码等效的Python? 这是一个好主意吗??请在您的答案中举例说明。 问题答案: 正如其他人在这里提到的: 在Python中不需要接口。这是因为Python具有适当的多重继承,还具有鸭式输入法,这意味着 必须 在Java中具有接口的地方,而不必在Python中具有接口。 也就是说,接口还有多种用途。其中一些被Python 2.6中引入的Pythons抽象基类覆盖。如果您

  • 问题内容: 我想知道Python 3中的新super是如何实现的。 我做了一个小例子之后,这个问题就浮现在脑海中,我得到了一个奇怪的错误。我正在使用Pyutilib组件体系结构(PCA),并且已经制作了自定义元类来驱动另一个类的创建: 我收到以下错误: 我wonderign究竟超(一样),它引发的错误,而所有的,并存在。另外的“老方法”-正在工作。 问题答案: 如何执行?这是python3.3的代

  • 问题内容: 我已经实现了 算法 对于GMM使用这个 后[GMMs]与最大似然优化 努比](https://towardsdatascience.com/how-to-code-gaussian-mixture-models- from-scratch-in-python-9e7975df5252)未成功,如下所示: when I run the algorithm on a 1-D time-se