首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >版本1.16.6处的numpy.random.multinomial比后期版本快10倍

版本1.16.6处的numpy.random.multinomial比后期版本快10倍
EN

Stack Overflow用户
提问于 2021-12-20 22:17:40
回答 2查看 205关注 0票数 11

以下是代码和结果:

代码语言:javascript
复制
python -c "import numpy as np; from timeit import timeit; print('numpy version {}: {:.1f} seconds'.format(np.__version__, timeit('np.random.multinomial(1, [0.1, 0.2, 0.3, 0.4])', number=1000000, globals=globals())))"
代码语言:javascript
复制
numpy version 1.16.6:  1.5 seconds # 10x faster
numpy version 1.18.1: 15.5 seconds
numpy version 1.19.0: 17.4 seconds
numpy version 1.21.4: 15.1 seconds

需要注意的是,在固定随机种子的情况下,不同的numpy版本的输出是相同的。

代码语言:javascript
复制
python -c "import numpy as np; np.random.seed(0); print(np.__version__); print(np.random.multinomial(1, [0.1, 0.2, 0.3, 0.4], size=10000))" /tmp/tt

对于1.16.6之后的numpy版本为什么慢10倍有什么建议吗?

我们已经将熊猫升级到最新版本1.3.4,在1.16.6之后需要numpy版本。

EN

回答 2

Stack Overflow用户

发布于 2021-12-21 04:48:45

TL;DR: --这是由numpy.random.multinomial函数中的附加检查的开销引起的一个局部性能回归。由于所需检查的相对执行时间,非常小的数组受到强烈影响。

在引擎盖下面

Numpy码的Git提交进行的二进制搜索表明,性能回归在2019年4月中旬首次出现。它可以在提交dd77ce3cb中复制,但不能在7e8e19f9a中复制。提交中间存在一些构建问题,但是通过一些快速修复,我们可以显示提交0f3dd0650是导致问题的第一个原因。提交人说:

扩展多项式以允许广播 修正NumPy中遗漏的zipf更改 启用0作为超几何的有效输入

此承诺的深入分析表明,它修改了Cython mtrand.pyx中定义的multinomial函数,以执行以下两个额外的检查:

代码语言:javascript
复制
def multinomial(self, np.npy_intp n, object pvals, size=None):
    cdef np.npy_intp d, i, sz, offset
    cdef np.ndarray parr, mnarr
    cdef double *pix
    cdef int64_t *mnix
    cdef int64_t ni

    d = len(pvals)
    parr = <np.ndarray>np.PyArray_FROM_OTF(pvals, np.NPY_DOUBLE, np.NPY_ALIGNED)
    pix = <double*>np.PyArray_DATA(parr)
    check_array_constraint(parr, 'pvals', CONS_BOUNDED_0_1)   # <==========[HERE]
    if kahan_sum(pix, d-1) > (1.0 + 1e-12):
        raise ValueError("sum(pvals[:-1]) > 1.0")

    if size is None:
        shape = (d,)
    else:
        try:
            shape = (operator.index(size), d)
        except:
            shape = tuple(size) + (d,)

    multin = np.zeros(shape, dtype=np.int64)
    mnarr = <np.ndarray>multin
    mnix = <int64_t*>np.PyArray_DATA(mnarr)
    sz = np.PyArray_SIZE(mnarr)
    ni = n
    check_constraint(ni, 'n', CONS_NON_NEGATIVE)              # <==========[HERE]
    offset = 0
    with self.lock, nogil:
        for i in range(sz // d):
            random_multinomial(self._brng, ni, &mnix[offset], pix, d, self._binomial)
            offset += d

    return multin

如果代码是健壮的,那么这两个检查是必需的。然而,考虑到它们的用途,它们目前相当昂贵。

事实上,在我的机器上,第一次检查要支付大约75%的开销,第二次要支付20%的费用。检查只需几微秒,但由于输入非常小,与计算时间相比,开销很大。

解决此问题的一个方法是为此编写一个特定的Numba函数,因为您的输入数组非常小。在我的机器上,np.random.multinomial在一个微不足道的Numba函数中获得了良好的性能。

票数 3
EN

Stack Overflow用户

发布于 2021-12-20 23:36:32

我检查了一些引擎盖下的发电机,发现时间没有多大变化。

我猜想差异可能是由于某些开销造成的,因为您只对单个值进行采样。这似乎是个很好的假设。当我将所生成的随机样本的大小增加到1000时,1.16.6和1.19.2 (我现在的Numpy版本)之间的差距减小到了20%。

代码语言:javascript
复制
python -c "import numpy as np; from timeit import timeit; print('numpy version {}: {:.1f} seconds'.format(np.__version__, timeit('np.random.
multinomial(1, [0.1, 0.2, 0.3, 0.4], size=1000)', number=10000, globals=globals())))"
代码语言:javascript
复制
numpy version 1.16.6: 1.1 seconds
numpy version 1.19.2: 1.3 seconds

请注意,的两个版本都有这种开销,只是较新的版本具有更大的开销。在这两个版本中,一次采样1000值要比样本1值1000次要快得多。

它们的代码在1.16.6和1.17.0之间发生了很大变化,例如此承诺,很难进行分析。对不起,这不能更好地帮助你--我提议在Numpy's github上提出一个问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70428623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档