如何避免使用numpy.random.multinomial时出现值错误?

7 投票
4 回答
8181 浏览
提问于 2025-04-18 04:01

当我使用这个随机生成器:numpy.random.multinomial时,我总是遇到这个问题:

ValueError: sum(pvals[:-1]) > 1.0

我一直在传递这个softmax函数的输出:

def softmax(w, t = 1.0):
    e = numpy.exp(numpy.array(w) / t)
    dist = e / np.sum(e)
    return dist

不过现在我遇到这个错误后,我还为参数(pvals)添加了这个:

while numpy.sum(pvals) > 1:
    pvals /= (1+1e-5)

但这并没有解决问题。有什么正确的方法可以确保我避免这个错误呢?

补充:这里有一个包含这段代码的函数

def get_MDN_prediction(vec):
    coeffs = vec[::3]
    means = vec[1::3]
    stds = np.log(1+np.exp(vec[2::3]))
    stds = np.maximum(stds, min_std)
    coe = softmax(coeffs)
    while np.sum(coe) > 1-1e-9:
        coe /= (1+1e-5)
    coeff = unhot(np.random.multinomial(1, coe))
    return np.random.normal(means[coeff], stds[coeff])

4 个回答

1

我使用的 softmax 实现对于我用的数值来说不够稳定。因此,有时候输出的结果总和会大于 1(比如 1.0000024...)。

这个情况应该通过一个循环来处理。但是有时候输出会出现 NaN(不是一个数字),在这种情况下,循环根本不会被触发,错误就一直存在。

另外,numpy.random.multinomial 在遇到 NaN 时也不会报错。

现在我用的是下面这个:

def softmax(vec):
    vec -= min(A(vec))
    if max(vec) > 700:
        a = np.argsort(vec)
        aa = np.argsort(a)
        vec = vec[a]
        i = 0
        while max(vec) > 700:
            i += 1
            vec -= vec[i]
        vec = vec[aa]
    e = np.exp(vec)
    return e/np.sum(e)

def sample_multinomial(w):
    """
       Sample multinomial distribution with parameters given by softmax of w
       Returns an int    
    """
    p = softmax(w)
    x = np.random.uniform(0,1)
    for i,v in enumerate(np.cumsum(p)):
        if x < v: return i
    return len(p)-1 # shouldn't happen...
2

有一点很少有人注意到:我们可以通过去掉值中的logsumexp,轻松得到一个更稳健的softmax版本。

from scipy.misc import logsumexp

def log_softmax(vec):
    return vec - logsumexp(vec)

def softmax(vec):
    return np.exp(log_softmax(vec))

你可以自己检查一下:

print(softmax(np.array([1.0, 0.0, -1.0, 1.1])))

很简单,对吧?

5

我知道这个问题已经很久了,但因为我刚遇到同样的问题,所以我觉得这个问题还是很有意义的。这里是我找到的解决办法:

a = np.asarray(a).astype('float64')
a = a / np.sum(a)
b = np.random.multinomial(1, a, 1)

我把重要的部分加粗了。如果你忽略了那部分,你提到的问题就会时不时出现。但是如果你把数组的类型改成float64,就不会再出现这个问题了。

9

我在做语言模型工作时也遇到了这个问题。

这个问题的根源在于numpy自动转换数据类型的方式:我的sorfmax()输出的是float32类型,但numpy.random.multinomial()会自动把pval转换成float64类型。这种数据类型的转换有时会导致pval.sum()的值超过1.0,因为在计算时会出现数值四舍五入的问题。

这个问题已经被大家注意到,并在这里发布了相关信息。

撰写回答