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

7

当我使用这个随机生成器: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])

1
你检查过所有的值都是有限数了吗? - joeln
当您将pvals.sum()传递给np.random.multinomial时,它的值是多少? - askewchan
你没有展示一些重要的信息,比如函数A是什么以及完整的回溯信息(包括实际代码,sum(pvals[:-1]) > 1.0这段代码并未呈现)。 - Davidmh
A是numpy.array,我已经替换了它。 - capybaralet
如果您使用np.random.choice而不是np.random.multinomial,则不会出现错误并获得相同的结果。 - greentec
4个回答

9

在进行语言建模工作时,我也遇到了这个问题。

这个问题的根源来自于numpy的隐式数据转换:我的softmax()的输出是float32类型,然而,numpy.random.multinomial()会将pval隐式地转换成float64类型。由于数值舍入,这种数据类型的转换有时会导致pval.sum()超过1.0。

已经在这里识别并发布了此问题。


4

我知道这个问题很久远了,但由于我刚刚遇到了相同的问题,所以我认为它仍然有效。以下是我找到的解决方案:

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

我已经将重要部分加粗。如果你省略那一部分,你提到的问题就会时不时发生。但是,如果你将数组类型更改为float64,它将永远不会发生。


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

简单,不是吗?

1
我使用softmax(np.array([1/20.]*20)).sum()计算得到的总和为1.0000000000000002。 - Brad Solomon

1
我使用的softmax实现对我使用的值不够稳定。因此,有时输出的总和大于1(例如,1.0000024...)。
这种情况应该由while循环处理。但有时输出包含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...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接