3

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”,则“未标准化”结果与我预期的一样;不知何故,“/S”除法似乎使所有元素都为零,而不是像我期望的那样将每个元素除以 S。代码有什么问题?

4

3 回答 3

6

“零”的原因在于输入的数据类型,即“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]]
于 2016-04-20T09:10:38.970 回答
3

代码中的问题是如何为要计算的结果实例化占位符,即

    result=np.zeros_like(x)

因为 ifx是一个整数数组,也是result一个整数数组,当你分配给它时,

        result[:,n]=np.exp(x[:,n])/S

强制转换为整数。当您标准化除以S所有转换为整数的数字时,在区间内(0, 1],转换完成截断为零,因此您有一个零数组。

您说过,如果您不进行标准化,result则与零不同……那是因为在这种情况下,您将转换为大于 1 的整数。

一个可能的解决方案,你可以在你的代码使用,包括实例化一个浮点数组,与类型无关x

    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]: 

请注意,它也可以完美地使用整数数组作为输入。

附录

根据n13的建议,该函数可以重写为

def sm(a):
    s = np.exp(a)
    if a.ndim <3: return s/s.sum(0) 

谢谢n13

PS当我写附录时,我没有意识到n13已经自己发布了答案......

于 2016-04-20T09:33:36.703 回答
1

Numpy 有一些漂亮的矩阵运算,使这个问题更容易解决。

计算指数适用于任何维度的矩阵

sum()方法接受一个参数,它允许我们将总和限制在给定的轴上——在我们的例子中,列映射到轴 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
于 2017-11-15T03:39:51.597 回答