2017-08-07 77 views
1

我发现我的模拟瓶颈之一是从泊松分布产生的随机数。我原来的代码是这样的Numba和随机数从泊松分布

import numpy as np 
#Generating some data. In the actual code this comes from the previous 
#steps in the simulation. But this gives an example of the type of data 
n = 5000000 
pop_n = np.array([range(500000)]) 

pop_n[:] = np.random.poisson(lam=n*pop_n/np.sum(pop_n)) 

现在,我读到numba可以非常简单地提高速度。我定义了功能

from numba import jit 

@jit() 
def poisson(n, pop_n, np=np): 
    return np.random.poisson(lam=n*pop_n/np.sum(pop_n)) 

这个确实运行得比原来快。不过,我尝试走得更远:)当我写

@jit(nopython=True) 
def poisson(n, pop_n, np=np): 
    return np.random.poisson(lam=n*pop_n/np.sum(pop_n)) 

Failed at nopython (nopython frontend) 
Invalid usage of Function(np.random.poisson) with parameters  (array(float64, 1d, C)) 
Known signatures: 
* (float64,) -> int64 
*() -> int64 
* parameterized 

一些问题:为什么是这样的错误发生,如何解决它。

有更好的优化吗?

+0

看起来Numba还不支持从任何np.random函数返回数组。您应该首先设置一个指定其项目类型的空数组,然后才能添加值。看看这里的例子https://github.com/numba/numba/issues/1596 –

+2

我没有看到任何实际的原因,为什么这个功能应该更快。 'np.random.poisson'已经在C中实现了。在另一个编译函数中包装它最多会被编译器优化,最坏的情况是会导致开销。 – kazemakase

+0

@kazemakase pop_n上的操作怎么样?它的数组除以它的总和? –

回答

2

Numba不支持数组作为lam参数np.random.poisson,所以你要自己做循环:

import numba as nb 
import numpy as np 

@nb.njit 
def poisson(n, pop_n): 
    res = np.empty_like(pop_n) 
    pop_n_sum = np.sum(pop_n) 
    for idx, item in enumerate(range(pop_n.shape[0])): 
     res[idx] = np.random.poisson(n*pop_n[idx]/pop_n_sum) 
    return res 

n = 5000000 
pop_n = np.array(list(range(1, 500000)), dtype=float) 
poisson(n, pop_n) 

但根据我的计时,这是一样快,使用纯NumPy的:

%timeit poisson(n, pop_n) 
# 203 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 
%timeit np.random.poisson(lam=n*pop_n/np.sum(pop_n)) 
# 203 ms ± 3.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

这是因为,即使Numba支持np.random.poisson和喜欢np.sum这些功能仅支持为方便其实并不以加快代码(多)。它可能可以避免函数调用的开销,但它只会在纯Python中调用np.random.poisson一次,并不多(并且与创建50万个随机数相比,完全可以忽略不计)。如果你想加快循环,你不能用纯NumPy的做,但你不应该指望numba(或其他东西)可以以相当于NumPy的功能提供了重要的加速

Numba是极快的。如果很容易让它们变得更快 - 那么NumPy的开发者也会更快。 :)

+1

作为其他人试图加快随机数生成的额外我刚刚发现random_intel,它似乎运行得比基地numpy快得多 –

+0

@DiogoSantos你的意思是什么'random_intel'?我找不到有关该功能的任何文档。你有链接吗?这可能是非常有用的:) – MSeifert

+0

这是一个非常模糊的评论。我在谈论python-intel。随机数字生成的基准可以在[这里]找到(https://software.intel.com/zh-cn/blogs/2016/06/15/faster-random-number-generation-in-intel-distribution-for -蟒蛇) –