如何在Python中实现Softmax函数
How to implement the Softmax function in Python
从Udacity's deep learning class开始,y_i的softmax只是指数除以整个Y向量的指数之和:
其中S(y_i)
是y_i
的softmax函数,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))
哪个returns:
[ 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)
产生与第一个实现相同的输出,即使第一个实现明确取每列与最大值的差值,然后除以总和。
谁能从数学上说明原因?一个正确,一个错误吗?
实现在代码和时间复杂度上是否相似?哪个效率更高?
他们都是正确的,但从数值稳定性的角度来看,你的更受欢迎。
你开始于
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 时,中间值可能会变得非常大。将两个大数相除可能在数值上不稳定。 These notes(来自斯坦福大学)提到了一个归一化技巧,这实际上就是您正在做的事情。
Here 你可以找出他们为什么使用 - max
。
从那里开始:
"When you’re writing code for computing the Softmax function in practice, the intermediate terms may be very large due to the exponentials. Dividing large numbers can be numerically unstable, so it is important to use a normalization trick."
(嗯...这里有很多混乱,无论是在问题还是在答案中...)
首先,这两个解决方案(即您的和建议的)不等价;它们 碰巧 仅在一维分数数组的特殊情况下等效。如果您还尝试了 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 documentation:
The default, axis=None, will sum all of the elements of the input array
虽然在这里我们想要按行求和,因此 axis=0
。对于一维数组,(唯一)行的总和与所有元素的总和恰好相同,因此在这种情况下您的结果相同...
撇开 axis
问题不谈,您的实施(即您选择先减去最大值)实际上比建议的解决方案 更好 !事实上,这是实现 softmax 函数的推荐方法 - 参见 here 的理由(数值稳定性,这里的其他一些答案也指出了)。
更简洁的版本是:
def softmax(x):
return np.exp(x) / np.exp(x).sum(axis=0)
所以,这确实是对 desertnaut 的回答的评论,但由于我的声誉,我还不能评论它。正如他所指出的,只有当您的输入包含一个样本时,您的版本才是正确的。如果您的输入包含多个样本,那就错了。 但是desertnaut的解法也是错误的。问题是他一次取一个1维的输入,然后他取一个2维的输入。让我给你看一下。
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]])
你可以看到desernauts版本在这种情况下会失败。 (如果输入只是像 np.array([1, 2, 3, 6]) 这样的一维,则不会。
现在让我们使用 3 个样本,因为这就是我们使用二维输入的原因。下面的 x2 与 desernauts 示例中的 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
return 是一个向量,其第 i 个坐标等于
请注意,这适用于任何 m
,因为对于所有(甚至复杂的)数字 e^m != 0
从计算复杂度的角度来看,它们也是等价的,并且在 O(n)
时间内都是 运行,其中 n
是向量的大小。
从 numerical stability 的角度来看,第一个解决方案是首选,因为 e^x
增长非常快,即使 x
的值很小,它也会溢出.减去最大值可以消除这种溢出。要实际体验我正在谈论的内容,请尝试将 x = np.array([1000, 5])
输入到您的两个函数中。一个会 return 正确概率,第二个会溢出 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
如其他用户所述,减去最大值是一种很好的做法。我写了一个详细的post关于它here。
我想补充一点对问题的理解。这里减去数组的最大值是正确的。但是如果你 运行 另一个 post 中的代码,你会发现当数组是二维或更高维度时它没有给你正确的答案。
这里给大家一些建议:
- 要获得最大值,请尝试沿 x 轴进行,您将得到一个一维数组。
- 将您的最大数组重塑为原始形状。
- 做np.exp得到指数值。
- 沿轴做np.sum。
- 得到最终结果。
按照结果进行矢量化,您将得到正确答案。由于涉及到大学作业,这里不能post具体代码,不明白的可以多多指教
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)
会下溢(在否定情况下)或溢出(在肯定情况下)。在这里,您希望尽可能长时间地保留在 log space 中,仅在您可以相信结果将是 well-behaved.
的最后取幂
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-of-N 输出编码的神经网络(即,如果我们压缩端点,将更难区分 1 -of-N 输出 class 因为我们无法分辨哪个是“最大”或“最小”,因为它们被压扁了。);它还使总输出总和为 1,明显的赢家将更接近 1,而其他彼此接近的数字将总和为 1/p,其中 p 是具有相似值的输出神经元的数量。
从向量中减去最大值的目的是,当您执行 e^y 指数时,您可能会得到非常高的值,该值会将浮点数限制在最大值处,从而导致平局,但在本例中并非如此例子。如果你减去最大值得到一个负数,这将成为一个大问题,然后你有一个负指数迅速缩小改变比率的值,这是发帖人的问题中发生的事情并产生了错误的答案。
Udacity 提供的答案非常低效。我们需要做的第一件事是计算所有向量分量的 e^y_j,保留这些值,然后将它们相加并相除。 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
目标是使用 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)
每个人似乎都post他们的解决方案所以我post我的:
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 的密集层输出兼容的东西。
的解决方案在这种情况下不起作用,因为我有批量数据。因此,我提出了另一个适用于这两种情况的解决方案:
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)
结果:
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]]
这是使用 numpy 的广义解决方案以及与 tensorflow ans 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 ]]]
Softmax 使用 tensorflow:
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.]]
Softmax 使用 scipy:
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.]]
Softmax 使用 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 notes,请允许我总结一下:
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 函数输出一个表示结果列表的概率分布的向量。它也是深度学习class化任务中使用的核心元素。
当我们有多个 classes 时使用 Softmax 函数。
这对于找出最大的 class 很有用。概率。
Softmax 函数最适合用于输出层,我们实际上是在尝试获得定义每个输入的 class 的概率。
取值范围为 0 到 1。
Softmax函数将logits [2.0, 1.0, 0.1] 转化为概率[0.7, 0.2, 0.1],概率之和为1。Logits是神经网络最后一层输出的原始分数。在激活发生之前。要理解softmax函数,必须要看第(n-1)层的输出。
softmax 函数实际上是一个 arg max 函数。这意味着它不是 return 来自输入的最大值,而是最大值的位置。
例如:
在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.reshape。
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
正如某些人所说,您的版本在数值上更稳定 'for large numbers'。对于小数字可能是相反的。
我使用了这三个简单的行:
x_exp=np.exp(x)
x_sum=np.sum(x_exp, axis = 1, keepdims = True)
s=x_exp / x_sum
从Udacity's deep learning class开始,y_i的softmax只是指数除以整个Y向量的指数之和:
其中S(y_i)
是y_i
的softmax函数,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))
哪个returns:
[ 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)
产生与第一个实现相同的输出,即使第一个实现明确取每列与最大值的差值,然后除以总和。
谁能从数学上说明原因?一个正确,一个错误吗?
实现在代码和时间复杂度上是否相似?哪个效率更高?
他们都是正确的,但从数值稳定性的角度来看,你的更受欢迎。
你开始于
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 时,中间值可能会变得非常大。将两个大数相除可能在数值上不稳定。 These notes(来自斯坦福大学)提到了一个归一化技巧,这实际上就是您正在做的事情。
Here 你可以找出他们为什么使用 - max
。
从那里开始:
"When you’re writing code for computing the Softmax function in practice, the intermediate terms may be very large due to the exponentials. Dividing large numbers can be numerically unstable, so it is important to use a normalization trick."
(嗯...这里有很多混乱,无论是在问题还是在答案中...)
首先,这两个解决方案(即您的和建议的)不等价;它们 碰巧 仅在一维分数数组的特殊情况下等效。如果您还尝试了 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 documentation:
The default, axis=None, will sum all of the elements of the input array
虽然在这里我们想要按行求和,因此 axis=0
。对于一维数组,(唯一)行的总和与所有元素的总和恰好相同,因此在这种情况下您的结果相同...
撇开 axis
问题不谈,您的实施(即您选择先减去最大值)实际上比建议的解决方案 更好 !事实上,这是实现 softmax 函数的推荐方法 - 参见 here 的理由(数值稳定性,这里的其他一些答案也指出了)。
更简洁的版本是:
def softmax(x):
return np.exp(x) / np.exp(x).sum(axis=0)
所以,这确实是对 desertnaut 的回答的评论,但由于我的声誉,我还不能评论它。正如他所指出的,只有当您的输入包含一个样本时,您的版本才是正确的。如果您的输入包含多个样本,那就错了。 但是desertnaut的解法也是错误的。问题是他一次取一个1维的输入,然后他取一个2维的输入。让我给你看一下。
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]])
你可以看到desernauts版本在这种情况下会失败。 (如果输入只是像 np.array([1, 2, 3, 6]) 这样的一维,则不会。
现在让我们使用 3 个样本,因为这就是我们使用二维输入的原因。下面的 x2 与 desernauts 示例中的 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
return 是一个向量,其第 i 个坐标等于
请注意,这适用于任何 m
,因为对于所有(甚至复杂的)数字 e^m != 0
从计算复杂度的角度来看,它们也是等价的,并且在
O(n)
时间内都是 运行,其中n
是向量的大小。从 numerical stability 的角度来看,第一个解决方案是首选,因为
e^x
增长非常快,即使x
的值很小,它也会溢出.减去最大值可以消除这种溢出。要实际体验我正在谈论的内容,请尝试将x = np.array([1000, 5])
输入到您的两个函数中。一个会 return 正确概率,第二个会溢出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
如其他用户所述,减去最大值是一种很好的做法。我写了一个详细的post关于它here。
我想补充一点对问题的理解。这里减去数组的最大值是正确的。但是如果你 运行 另一个 post 中的代码,你会发现当数组是二维或更高维度时它没有给你正确的答案。
这里给大家一些建议:
- 要获得最大值,请尝试沿 x 轴进行,您将得到一个一维数组。
- 将您的最大数组重塑为原始形状。
- 做np.exp得到指数值。
- 沿轴做np.sum。
- 得到最终结果。
按照结果进行矢量化,您将得到正确答案。由于涉及到大学作业,这里不能post具体代码,不明白的可以多多指教
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)
会下溢(在否定情况下)或溢出(在肯定情况下)。在这里,您希望尽可能长时间地保留在 log space 中,仅在您可以相信结果将是 well-behaved.
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-of-N 输出编码的神经网络(即,如果我们压缩端点,将更难区分 1 -of-N 输出 class 因为我们无法分辨哪个是“最大”或“最小”,因为它们被压扁了。);它还使总输出总和为 1,明显的赢家将更接近 1,而其他彼此接近的数字将总和为 1/p,其中 p 是具有相似值的输出神经元的数量。
从向量中减去最大值的目的是,当您执行 e^y 指数时,您可能会得到非常高的值,该值会将浮点数限制在最大值处,从而导致平局,但在本例中并非如此例子。如果你减去最大值得到一个负数,这将成为一个大问题,然后你有一个负指数迅速缩小改变比率的值,这是发帖人的问题中发生的事情并产生了错误的答案。
Udacity 提供的答案非常低效。我们需要做的第一件事是计算所有向量分量的 e^y_j,保留这些值,然后将它们相加并相除。 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
目标是使用 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)
每个人似乎都post他们的解决方案所以我post我的:
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 的密集层输出兼容的东西。
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)
结果:
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]]
这是使用 numpy 的广义解决方案以及与 tensorflow ans 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 ]]]
Softmax 使用 tensorflow:
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.]]
Softmax 使用 scipy:
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.]]
Softmax 使用 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 notes,请允许我总结一下:
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 函数输出一个表示结果列表的概率分布的向量。它也是深度学习class化任务中使用的核心元素。
当我们有多个 classes 时使用 Softmax 函数。
这对于找出最大的 class 很有用。概率。
Softmax 函数最适合用于输出层,我们实际上是在尝试获得定义每个输入的 class 的概率。
取值范围为 0 到 1。
Softmax函数将logits [2.0, 1.0, 0.1] 转化为概率[0.7, 0.2, 0.1],概率之和为1。Logits是神经网络最后一层输出的原始分数。在激活发生之前。要理解softmax函数,必须要看第(n-1)层的输出。
softmax 函数实际上是一个 arg max 函数。这意味着它不是 return 来自输入的最大值,而是最大值的位置。
例如:
在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.reshape。
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
正如某些人所说,您的版本在数值上更稳定 'for large numbers'。对于小数字可能是相反的。
我使用了这三个简单的行:
x_exp=np.exp(x)
x_sum=np.sum(x_exp, axis = 1, keepdims = True)
s=x_exp / x_sum