在 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