首先在这里使用Numba。我读到nopython模式应该产生更快的代码但是:
@jit(float64[:](int64[:], int64, float64), nopython=True)
def epsilon_bound(l, k, delta):
return l/k+np.sqrt(np.log(1/delta))*np.sqrt(1/(2*k))
@jit(float64(float64, int64, float64), nopython=False)
def sim_bin(epsilon, sims, delta):
k=10000
s = np.random.binomial(k, epsilon, size=(sims,))
print(nb.typeof(s))
bound = epsilon_bound(s, k, delta)
violations = np.greater(epsilon, bound)
return np.sum(violations)/float(sims)
%%time
a = sim_bin(0.1, 1_000_000, 0.1)
运行得更快:
array(int64, 1d, C)
CPU times: user 66.7 ms, sys: 0 ns, total: 66.7 ms
Wall time: 65.7 ms
比这个:
@jit(float64[:](int64[:], int64, float64), nopython=True)
def epsilon_bound(l, k, delta):
return l/k+np.sqrt(np.log(1/delta))*np.sqrt(1/(2*k))
@jit(float64(float64, int64, float64), nopython=True)
def sim_bin(epsilon, sims, delta):
k=10000
s = np.random.binomial(k, epsilon, size=(sims,))
#print(nb.typeof(s))
bound = epsilon_bound(s, k, delta)
violations = np.greater(epsilon, bound)
return np.sum(violations)/float(sims)
CPU times: user 4.94 s, sys: 8.02 ms, total: 4.95 s
Wall time: 4.93 s
运行sim_bin.inspect_types()显示第一个选项正在使用所有pyobject,而第二个选项正确地推断所有类型。根据文档(http://numba.pydata.org/numba-doc/0.31.0/glossary.html#term-nopython-mode),nopython模式应该生成更快的代码。 有谁知道发生了什么?必须有一个很好的理由,但我是使用Numba的新手。是因为我主要使用矢量化的numpy函数吗?
谢谢!
答案 0 :(得分:3)
该函数的一个主要瓶颈(至少使用numba 0.31,windows 10)似乎是np.random.binomial
- 调用。当我测试它时:
@jit(nopython=True)
def nbbinom():
return np.random.binomial(10000, 0.1, size=(1000000,))
nbbinom() # warmup
%timeit nbbinom()
# 1 loop, best of 3: 2.45 s per loop
%timeit np.random.binomial(10000, 0.1, size=(1000000,))
# 10 loops, best of 3: 23.1 ms per loop
然而,这可能取决于numba版本。 Numba(不幸地)经常遭遇性能回归(幸运的是)快速修复。可能它只需要在他们的bug跟踪器上出现问题(如果它还没有修复)。
但即使这样你的代码也包含很多矢量化操作。如果你使用矢量化操作,你将无法通过numba获得更多的速度提升。根据经验:如果你已经可以使用numpy而不使用python循环你不需要numba (也有例外。例如:我发现numba对于小的来说肯定更快numpy-ufuncs有很大开销的数组。)
另一件事是创建随机数组比实际操作需要更长的时间(numpy和numba):
import numpy as np
from numba import njit
@njit
def epsilon_bound1(l, k, delta):
return l/k+np.sqrt(np.log(1/delta))*np.sqrt(1/(2*k))
def epsilon_bound2(l, k, delta):
return l/k+np.sqrt(np.log(1/delta))*np.sqrt(1/(2*k))
def sim_bin(s, k, epsilon, sims, delta, func):
bound = func(s, k, delta)
violations = np.greater(epsilon, bound)
return np.sum(violations)/float(sims)
epsilon = 0.1
sims = 1000000
delta = 0.1
k=10000
s = np.random.binomial(k, epsilon, size=(sims,))
%timeit np.random.binomial(k, epsilon, size=(sims,))
# 1 loop, best of 3: 232 ms per loop
sim_bin(s, k, 0.1, 1000000, 0.1, epsilon_bound1) # warmup
%timeit sim_bin(s, k, 0.1, 1000000, 0.1, epsilon_bound1)
# 10 loops, best of 3: 28.5 ms per loop
%timeit sim_bin(s, k, 0.1, 1000000, 0.1, epsilon_bound2)
# 10 loops, best of 3: 37.6 ms per loop
因此,当您对sim_bin
进行基准测试时,实际上只会将调用基准调整为np.random.binomial
,无论是相对快速的numpy还是(当前)非常慢的numba实现。