如何在Python中实现Softmax函数

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

enter image description here

其中S(y_i)y_i的软最大函数,e是指数函数,j是no。输入向量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)

它会产生输出与第一个实现相同,尽管第一个实现显式地取每列与最大值的差值,然后除以和。

有人能用数学方法解释一下吗?一个是对的,另一个是错的?

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

357417 次浏览

他们都是正确的,但从数值稳定性的角度来看,你的更合适。

你从

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

我想说,虽然从数学上讲,这两种方法都是正确的,但就实现而言,第一个方法更好。在计算softmax时,中间值可能会变得很大。两个大数的除法在数值上是不稳定的。这些笔记(来自斯坦福)提到了一个归一化技巧,这基本上就是你正在做的事情。

你可以找到为什么他们使用- max

从这里开始:

“当你在实际中编写计算Softmax函数的代码时,由于指数的存在,中间项可能非常大。大数除法在数值上可能不稳定,所以使用标准化技巧很重要。”

(好吧…这里有很多困惑,在问题和答案中…)

首先,这两个解决方案(即你的和建议的)是等效的;它们发生仅对1-D分数数组的特殊情况等效。如果你也尝试过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

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

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。和文档:

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

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

撇开axis问题不提,你的实现(即你选择先减去最大值)实际上比建议的解决方案要更好的 !事实上,这是实现softmax函数的推荐方式-请参阅在这里以了解理由(数值稳定性,也在这里的一些其他答案中指出)。

更简明的说法是:

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

所以,这实际上是对desertnaut的回答的一个评论,但由于我的声誉,我还不能评论它。正如他所指出的,只有当输入包含单个样本时,你的版本才是正确的。如果您的输入包含多个样本,则是错误的。问题是,一旦他接受了一个一维的输入,然后他接受了一个二维的输入。让我给你们看看这个。

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那样。数组([1,2,3,6])。

现在让我们使用3个样本,因为这就是为什么我们使用二维输入的原因。下面的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)

为了保持数值的稳定性,应减去max(x)。下面是softmax函数的代码;

def softmax (x):

if len(x.shape) > 1:
tmp = np.max(x, axis = 1)
x -= tmp.reshape((x.shape[0], 1))
x = np.exp(x)
tmp = np.sum(x, axis = 1)
x /= tmp.reshape((x.shape[0], 1))
else:
tmp = np.max(x)
x -= tmp
x = np.exp(x)
tmp = np.sum(x)
x /= tmp




return x

从数学的角度看,两边是相等的。

这很容易证明。让我们m=max(x)。现在你的函数softmax返回一个向量,它的第i个坐标等于

enter image description here

注意,这适用于任何m,因为对于所有(甚至是复杂的)数字e^m != 0

  • 从计算复杂度的角度来看,它们也是等效的,并且都在O(n)时间内运行,其中n是一个向量的大小。

  • 数值稳定性的角度来看,第一个解决方案是首选的,因为e^x增长非常快,即使x的值非常小,它也会溢出。减去最大值可以消除此溢出。为了实际体验我正在谈论的东西,尝试将x = np.array([1000, 5])输入到你的两个函数中。一个将返回正确的概率,第二个将溢出nan

  • 你的解决方案只适用于向量(Udacity测试也希望你计算矩阵)。为了修复它,你需要使用sum(axis=0)

编辑。从1.2.0版本开始,scipy包含了softmax作为一个特殊函数:

https://scipy.github.io/devdocs/generated/scipy.special.softmax.html

我写了一个在任意轴上应用softmax的函数:

def softmax(X, theta = 1.0, axis = None):
"""
Compute the softmax of each element along an axis of X.


Parameters
----------
X: ND-Array. Probably should be floats.
theta (optional): float parameter, used as a multiplier
prior to exponentiation. Default = 1.0
axis (optional): axis to compute values along. Default is the
first non-singleton axis.


Returns an array the same size as X. The result will sum to 1
along the specified axis.
"""


# make X at least 2d
y = np.atleast_2d(X)


# find axis
if axis is None:
axis = next(j[0] for j in enumerate(y.shape) if j[1] > 1)


# multiply y against the theta parameter,
y = y * float(theta)


# subtract the max for numerical stability
y = y - np.expand_dims(np.max(y, axis = axis), axis)


# exponentiate y
y = np.exp(y)


# take the sum along the specified axis
ax_sum = np.expand_dims(np.sum(y, axis = axis), axis)


# finally: divide elementwise
p = y / ax_sum


# flatten if X was 1D
if len(X.shape) == 1: p = p.flatten()


return p

正如其他用户所描述的那样,减去最大值是很好的做法。我写了一篇关于它的详细文章。

我想补充一点对这个问题的理解。这里减去数组的最大值是正确的。但如果你运行另一篇文章中的代码,你会发现当数组是2D或更高维度时,它不会给你正确的答案。

在这里我给你一些建议:

  1. 为了得到max,试着沿着x轴做,你会得到一个1D数组。
  2. 重塑你的最大数组原始形状。
  3. np。Exp得到指数值。
  4. np。沿轴求和。
  5. 得到最终结果。

根据结果,你将通过做矢量化得到正确的答案。因为和大学作业有关,所以我不能把具体的代码贴在这里,如果你不明白我可以多给你一些建议。

Sklearn还提供了softmax的实现

from sklearn.utils.extmath import softmax
import numpy as np


x = np.array([[ 0.50839931,  0.49767588,  0.51260159]])
softmax(x)


# output
array([[ 0.3340521 ,  0.33048906,  0.33545884]])

在上面的回答中已经回答了很多细节。max被减去以避免溢出。我在这里添加了python3中的另一个实现。

import numpy as np
def softmax(x):
mx = np.amax(x,axis=1,keepdims = True)
x_exp = np.exp(x - mx)
x_sum = np.sum(x_exp, axis = 1, keepdims = True)
res = x_exp / x_sum
return res


x = np.array([[3,2,4],[4,5,6]])
print(softmax(x))

为了提供另一种解决方案,考虑这样的情况:你的参数值非常大,以至于exp(x)会溢出(在否定的情况下)或溢出(在肯定的情况下)。这里你希望尽可能长时间地保持在对数空间中,只在你可以相信结果是良好的地方取幂。

import scipy.special as sc
import numpy as np


def softmax(x: np.ndarray) -> np.ndarray:
return np.exp(x - sc.logsumexp(x))

softmax函数的目的是保留向量的比例,而不是在值饱和时用sigmoid压扁端点(即趋于+/- 1 (tanh)或从0到1(后勤))。这是因为它保留了更多关于端点变化率的信息,因此更适用于具有1 / n输出编码的神经网络(即,如果我们压缩端点,将更难区分1 / n输出类,因为我们无法分辨哪一个是“最大”。或“;smallest"因为他们被压扁了。)此外,它使总输出和为1,并且明显的获胜者将更接近1,而其他相互接近的数字将和为1/p,其中p是具有相似值的输出神经元的数量。

从向量中减去最大值的目的是,当你计算e^y指数时,你可能会得到非常高的值,将浮点数夹在最大值处,导致平局,但在这个例子中不是这样。如果你减去最大值得到一个负数,那么就会出现一个大问题,然后你就会得到一个负指数,它会迅速缩小数值,改变比率,这就是在海报上的问题中发生的情况,并得到错误的答案。

Udacity提供的答案效率低得可怕。我们需要做的第一件事是计算所有向量分量的e^y_j, KEEP这些值,然后求和,然后除。Udacity搞砸的地方是他们计算了两次e^y_j !!正确答案如下:

def softmax(y):
e_to_the_y_j = np.exp(y)
return e_to_the_y_j / np.sum(e_to_the_y_j, axis=0)

我的建议是:

def softmax(z):
z_norm=np.exp(z-np.max(z,axis=0,keepdims=True))
return(np.divide(z_norm,np.sum(z_norm,axis=0,keepdims=True)))

它既适用于随机也适用于批量 欲了解更多详情,请参阅: https://medium.com/@ravish1729/analysis-of-softmax-function-ad058d6a564d < / p >

目标是使用Numpy和Tensorflow实现类似的结果。与原始答案的唯一变化是np.sum api的axis参数。

最初的方法: axis=0——然而,当维数为N时,这并不能提供预期的结果。

修改方法: axis=len(e_x.shape)-1 -总是在最后一个维度上求和。这提供了与tensorflow的softmax函数类似的结果。

def softmax_fn(input_array):
"""
| **@author**: Prathyush SP
|
| Calculate Softmax for a given array
:param input_array: Input Array
:return: Softmax Score
"""
e_x = np.exp(input_array - np.max(input_array))
return e_x / e_x.sum(axis=len(e_x.shape)-1)

似乎每个人都发布了他们的解决方案,所以我将发布我的:

def softmax(x):
e_x = np.exp(x.T - np.max(x, axis = -1))
return (e_x / e_x.sum(axis=0)).T

我得到了与从sklearn导入的完全相同的结果:

from sklearn.utils.extmath import softmax

我需要一些与Tensorflow的密集层输出兼容的东西。

来自@desertnaut的解决方案在这种情况下不工作,因为我有批量的数据。因此,我提出了另一个解决方案,应该在这两种情况下工作:

def softmax(x, axis=-1):
e_x = np.exp(x - np.max(x)) # same code
return e_x / e_x.sum(axis=axis, keepdims=True)
< p >结果:

logits = np.asarray([
[-0.0052024,  -0.00770216,  0.01360943, -0.008921], # 1
[-0.0052024,  -0.00770216,  0.01360943, -0.008921]  # 2
])


print(softmax(logits))


#[[0.2492037  0.24858153 0.25393605 0.24827873]
# [0.2492037  0.24858153 0.25393605 0.24827873]]

裁判:Tensorflow softmax

下面是使用numpy的广义解,以及与tensorflow和scipy的正确性比较:

数据准备:

import numpy as np


np.random.seed(2019)


batch_size = 1
n_items = 3
n_classes = 2
logits_np = np.random.rand(batch_size,n_items,n_classes).astype(np.float32)
print('logits_np.shape', logits_np.shape)
print('logits_np:')
print(logits_np)

输出:

logits_np.shape (1, 3, 2)
logits_np:
[[[0.9034822  0.3930805 ]
[0.62397    0.6378774 ]
[0.88049906 0.299172  ]]]

使用tensorflow的Softmax:

import tensorflow as tf


logits_tf = tf.convert_to_tensor(logits_np, np.float32)
scores_tf = tf.nn.softmax(logits_np, axis=-1)


print('logits_tf.shape', logits_tf.shape)
print('scores_tf.shape', scores_tf.shape)


with tf.Session() as sess:
scores_np = sess.run(scores_tf)


print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)


print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np,axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

输出:

logits_tf.shape (1, 3, 2)
scores_tf.shape (1, 3, 2)
scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
[0.4965232  0.5034768 ]
[0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

使用scipy的Softmax:

from scipy.special import softmax


scores_np = softmax(logits_np, axis=-1)


print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)


print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

输出:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
[0.4965232  0.5034768 ]
[0.6413727  0.35862732]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

使用numpy (https://nolanbconaway.github.io/blog/2017/softmax-numpy):

def softmax(X, theta = 1.0, axis = None):
"""
Compute the softmax of each element along an axis of X.


Parameters
----------
X: ND-Array. Probably should be floats.
theta (optional): float parameter, used as a multiplier
prior to exponentiation. Default = 1.0
axis (optional): axis to compute values along. Default is the
first non-singleton axis.


Returns an array the same size as X. The result will sum to 1
along the specified axis.
"""


# make X at least 2d
y = np.atleast_2d(X)


# find axis
if axis is None:
axis = next(j[0] for j in enumerate(y.shape) if j[1] > 1)


# multiply y against the theta parameter,
y = y * float(theta)


# subtract the max for numerical stability
y = y - np.expand_dims(np.max(y, axis = axis), axis)


# exponentiate y
y = np.exp(y)


# take the sum along the specified axis
ax_sum = np.expand_dims(np.sum(y, axis = axis), axis)


# finally: divide elementwise
p = y / ax_sum


# flatten if X was 1D
if len(X.shape) == 1: p = p.flatten()


return p




scores_np = softmax(logits_np, axis=-1)


print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)


print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

输出:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
[0.49652317 0.5034768 ]
[0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]
import tensorflow as tf
import numpy as np


def softmax(x):
return (np.exp(x).T / np.exp(x).sum(axis=-1)).T


logits = np.array([[1, 2, 3], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])


sess = tf.Session()
print(softmax(logits))
print(sess.run(tf.nn.softmax(logits)))
sess.close()

根据所有的回答和CS231n笔记,请允许我总结:

def softmax(x, axis):
x -= np.max(x, axis=axis, keepdims=True)
return np.exp(x) / np.exp(x).sum(axis=axis, keepdims=True)

用法:

x = np.array([[1, 0, 2,-1],
[2, 4, 6, 8],
[3, 2, 1, 0]])
softmax(x, axis=1).round(2)

输出:

array([[0.24, 0.09, 0.64, 0.03],
[0.  , 0.02, 0.12, 0.86],
[0.64, 0.24, 0.09, 0.03]])

softmax函数是一种激活函数,它将数字转换为和为1的概率。softmax函数输出一个向量,表示结果列表的概率分布。它也是深度学习分类任务中使用的核心元素。

当我们有多个类时,使用Softmax函数。

它对于找出有最大值的类很有用。概率。

Softmax函数理想地用于输出层,在那里我们实际上试图获得定义每个输入类的概率。

取值范围是0 ~ 1。

Softmax函数将对数[2.0,1.0,0.1]转换为概率[0.7,0.2,0.1],概率和为1。Logits是神经网络最后一层输出的原始分数。在激活发生之前。为了理解softmax函数,我们必须看看第(n-1)层的输出。

softmax函数实际上是一个arg max函数。这意味着它不会返回输入中的最大值,而是返回最大值的位置。

例如:

softmax之前

X = [13, 31, 5]

softmax后

array([1.52299795e-08, 9.99999985e-01, 5.10908895e-12]

代码:

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

这也适用于np. remodeling。

   def softmax( scores):
"""
Compute softmax scores given the raw output from the model


:param scores: raw scores from the model (N, num_classes)
:return:
prob: softmax probabilities (N, num_classes)
"""
prob = None


exponential = np.exp(
scores - np.max(scores, axis=1).reshape(-1, 1)
)  # subract the largest number https://jamesmccaffrey.wordpress.com/2016/03/04/the-max-trick-when-computing-softmax/
prob = exponential / exponential.sum(axis=1).reshape(-1, 1)


        



return prob

这将泛化并假设您正在规范化尾随维度。

def softmax(x: np.ndarray) -> np.ndarray:
e_x = np.exp(x - np.max(x, axis=-1)[..., None])
e_y = e_x.sum(axis=-1)[..., None]
return e_x / e_y

我很好奇它们之间的性能差异

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)


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


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


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






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

使用

print("----- softmax")
%timeit  a=softmax(x)
print("----- softmaxv2")
%timeit  a=softmaxv2(x)
print("----- softmaxv3")
%timeit  a=softmaxv2(x)
print("----- softmaxv4")
%timeit  a=softmaxv2(x)

增加x内部的值(+100 +200 +500…)我使用原始numpy版本得到的结果始终更好(这里只是一个测试)

----- softmax
The slowest run took 8.07 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 17.8 µs per loop
----- softmaxv2
The slowest run took 4.30 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 23 µs per loop
----- softmaxv3
The slowest run took 4.06 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 23 µs per loop
----- softmaxv4
10000 loops, best of 3: 23 µs per loop

直到……x内的值达到~800,则得到

----- softmax
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:4: RuntimeWarning: overflow encountered in exp
after removing the cwd from sys.path.
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:4: RuntimeWarning: invalid value encountered in true_divide
after removing the cwd from sys.path.
The slowest run took 18.41 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 23.6 µs per loop
----- softmaxv2
The slowest run took 4.18 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 22.8 µs per loop
----- softmaxv3
The slowest run took 19.44 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 23.6 µs per loop
----- softmaxv4
The slowest run took 16.82 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 22.7 µs per loop

就像一些人说的,你的版本在“大数字”上更稳定。对于小数字来说,情况可能正好相反。

我用了这三句简单的话:

x_exp=np.exp(x)
x_sum=np.sum(x_exp, axis = 1, keepdims = True)
s=x_exp / x_sum