在 Python 中,使用 numpy 按列计算数组的 softmax
In Python, calculate the softmax of an array column-wise using numpy
在 https://classroom.udacity.com/courses/ud730/lessons/6370362152/concepts/63815621490923 之后,我正在尝试编写一个 "softmax" 函数,当给定一个二维数组作为输入时,它会计算每一列的 softmax。我写了下面的脚本来测试它:
import numpy as np
#scores=np.array([1.0,2.0,3.0])
scores=np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]])
def softmax(x):
if x.ndim==1:
S=np.sum(np.exp(x))
return np.exp(x)/S
elif x.ndim==2:
result=np.zeros_like(x)
M,N=x.shape
for n in range(N):
S=np.sum(np.exp(x[:,n]))
result[:,n]=np.exp(x[:,n])/S
return result
else:
print("The input array is not 1- or 2-dimensional.")
s=softmax(scores)
print(s)
然而,结果 "s" 结果是一个零数组:
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
如果我删除 for 循环中的“/S”,'un-normalized' 结果如我所料;不知何故,“/S”除法似乎使所有元素都为零,而不是像我期望的那样将每个元素除以 S。代码有什么问题?
"zeros"的原因在于输入的数据类型,它是"int"类型。将输入转换为 "float" 解决了问题:
import numpy as np
#scores=np.array([1.0,2.0,3.0])
scores=np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]])
def softmax(x):
x=x.astype(float)
if x.ndim==1:
S=np.sum(np.exp(x))
return np.exp(x)/S
elif x.ndim==2:
result=np.zeros_like(x)
M,N=x.shape
for n in range(N):
S=np.sum(np.exp(x[:,n]))
result[:,n]=np.exp(x[:,n])/S
return result
else:
print("The input array is not 1- or 2-dimensional.")
s=softmax(scores)
print(s)
请注意,我已将 "x=x.astype(float)" 添加到函数定义的第一行。这会产生预期的输出:
[[ 0.09003057 0.00242826 0.01587624 0.33333333]
[ 0.24472847 0.01794253 0.11731043 0.33333333]
[ 0.66524096 0.97962921 0.86681333 0.33333333]]
您的代码中的问题在于您如何实例化您将要计算的结果的占位符,即
result=np.zeros_like(x)
因为如果 x
是一个整数数组,那么 result
也是一个整数数组,当你给它赋值时,
result[:,n]=np.exp(x[:,n])/S
强制转换为整数。当您标准化除以 S
时,所有转换为整数的数字都在区间 (0, 1]
中,转换完成后截断为零,因此您有一个零数组。
你说过,如果你不归一化,result
不同于零...那是因为在这种情况下你将数字转换为大于 1 的整数。
一种可能的解决方案,您可以在您的代码中使用原样,包括实例化一个浮点数组,而不考虑 x
[=25 的类型=]
result=np.zeros(x.shape)
但我不得不说,您的代码计算了两次指数并使用了可以使用矢量化运算的循环。
这是一个不同的实现,(a)避免了循环,(b)避免了不必要的指数计算,
def sm(a):
s = np.exp(a)
if a.ndim == 1:
return s/s.sum()
elif a.ndim == 2:
return s/s.sum(0)
else:
return
小测试,
In [32]: sm(np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]]))
Out[32]:
array([[ 0.09003057, 0.00242826, 0.01587624, 0.33333333],
[ 0.24472847, 0.01794253, 0.11731043, 0.33333333],
[ 0.66524096, 0.97962921, 0.86681333, 0.33333333]])
In [33]:
请注意,它也可以完美地使用整数数组作为输入。
附录
跟随 from n13函数可以重写为
def sm(a):
s = np.exp(a)
if a.ndim <3: return s/s.sum(0)
谢谢n13。
PS 当我写附录时,我没有意识到 n13 已经发布了 自己...
Numpy 有一些漂亮的矩阵运算,使这个问题更容易解决。
计算指数适用于任何维度的矩阵
sum() 方法接受一个参数 axis,它允许我们将总和限制在给定的轴上——列映射到轴在我们的例子中是 0。
def softmax(x):
exp = np.exp(x) # exp just calculates exp for all elements in the matrix
return exp / exp.sum(0) # sum axis = 0 argument sums over axis representing columns
在 https://classroom.udacity.com/courses/ud730/lessons/6370362152/concepts/63815621490923 之后,我正在尝试编写一个 "softmax" 函数,当给定一个二维数组作为输入时,它会计算每一列的 softmax。我写了下面的脚本来测试它:
import numpy as np
#scores=np.array([1.0,2.0,3.0])
scores=np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]])
def softmax(x):
if x.ndim==1:
S=np.sum(np.exp(x))
return np.exp(x)/S
elif x.ndim==2:
result=np.zeros_like(x)
M,N=x.shape
for n in range(N):
S=np.sum(np.exp(x[:,n]))
result[:,n]=np.exp(x[:,n])/S
return result
else:
print("The input array is not 1- or 2-dimensional.")
s=softmax(scores)
print(s)
然而,结果 "s" 结果是一个零数组:
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]]
如果我删除 for 循环中的“/S”,'un-normalized' 结果如我所料;不知何故,“/S”除法似乎使所有元素都为零,而不是像我期望的那样将每个元素除以 S。代码有什么问题?
"zeros"的原因在于输入的数据类型,它是"int"类型。将输入转换为 "float" 解决了问题:
import numpy as np
#scores=np.array([1.0,2.0,3.0])
scores=np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]])
def softmax(x):
x=x.astype(float)
if x.ndim==1:
S=np.sum(np.exp(x))
return np.exp(x)/S
elif x.ndim==2:
result=np.zeros_like(x)
M,N=x.shape
for n in range(N):
S=np.sum(np.exp(x[:,n]))
result[:,n]=np.exp(x[:,n])/S
return result
else:
print("The input array is not 1- or 2-dimensional.")
s=softmax(scores)
print(s)
请注意,我已将 "x=x.astype(float)" 添加到函数定义的第一行。这会产生预期的输出:
[[ 0.09003057 0.00242826 0.01587624 0.33333333]
[ 0.24472847 0.01794253 0.11731043 0.33333333]
[ 0.66524096 0.97962921 0.86681333 0.33333333]]
您的代码中的问题在于您如何实例化您将要计算的结果的占位符,即
result=np.zeros_like(x)
因为如果 x
是一个整数数组,那么 result
也是一个整数数组,当你给它赋值时,
result[:,n]=np.exp(x[:,n])/S
强制转换为整数。当您标准化除以 S
时,所有转换为整数的数字都在区间 (0, 1]
中,转换完成后截断为零,因此您有一个零数组。
你说过,如果你不归一化,result
不同于零...那是因为在这种情况下你将数字转换为大于 1 的整数。
一种可能的解决方案,您可以在您的代码中使用原样,包括实例化一个浮点数组,而不考虑 x
[=25 的类型=]
result=np.zeros(x.shape)
但我不得不说,您的代码计算了两次指数并使用了可以使用矢量化运算的循环。
这是一个不同的实现,(a)避免了循环,(b)避免了不必要的指数计算,
def sm(a):
s = np.exp(a)
if a.ndim == 1:
return s/s.sum()
elif a.ndim == 2:
return s/s.sum(0)
else:
return
小测试,
In [32]: sm(np.array([[1,2,3,6],
[2,4,5,6],
[3,8,7,6]]))
Out[32]:
array([[ 0.09003057, 0.00242826, 0.01587624, 0.33333333],
[ 0.24472847, 0.01794253, 0.11731043, 0.33333333],
[ 0.66524096, 0.97962921, 0.86681333, 0.33333333]])
In [33]:
请注意,它也可以完美地使用整数数组作为输入。
附录
跟随
def sm(a):
s = np.exp(a)
if a.ndim <3: return s/s.sum(0)
谢谢n13。
PS 当我写附录时,我没有意识到 n13 已经发布了
Numpy 有一些漂亮的矩阵运算,使这个问题更容易解决。
计算指数适用于任何维度的矩阵
sum() 方法接受一个参数 axis,它允许我们将总和限制在给定的轴上——列映射到轴在我们的例子中是 0。
def softmax(x):
exp = np.exp(x) # exp just calculates exp for all elements in the matrix
return exp / exp.sum(0) # sum axis = 0 argument sums over axis representing columns