有没有办法对其进行矢量化或加速?我已经使用numba进行了测试,但它仍然是一个主要的瓶颈。使用numba在1-d numpy数组上运行我的函数会导致代码快几个数量级,但在下面的2-d数组上使用numba时,基本上可以忽略不计。分解是一个numpy矩阵,表示相关矩阵的cholesky分解,x和n是常量,nrand是numpy.random
@jit
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = np.empty((2*x, n))
for i in range(x):
# Generate the random uncorrelated walks
wv = nrand.normal(loc=0, scale=1, size=n)
ws = nrand.normal(loc=0, scale=1, size=n)
uncorrelated_walks[2*i] = wv
uncorrelated_walks[(2*i) + 1] = ws
# Create a matrix out of these walks
uncorrelated_walks = np.matrix(uncorrelated_walks)
m, n = uncorrelated_walks.shape
correlated_walks = np.empty((m, n))
# Go through column and correlate the walk values
for i in range(n):
correlated_timestep = np.transpose(uncorrelated_walks[:, i]) * decomposition
correlated_walks[:, i] = correlated_timestep
return correlated_walks
编辑:我已经做了建议的更改,现在我的代码如下,但不幸的是仍然是一个主要的瓶颈。有什么想法吗?
@jit
def generate_random_correlated_walks(self, decomposition, x, n):
rows = 2*x
uncorrelated_walks = np.random.normal(loc=0, scale=1, size=(rows, n))
correlated_walks = np.empty((rows, n))
for i in range(n):
correlated_timestep = np.dot(np.transpose(uncorrelated_walks[:, i]), decomposition)
correlated_walks[:, i] = correlated_timestep
return correlated_walks
答案 0 :(得分:3)
您可以改进的第一件事是删除for
循环。如果您认为它确实生成随机数,则使用相同的输入参数多次调用np.random.normal
没有任何优势。
不使用np.matrix
,而是使用np.array
。当您考虑使用上一项可以将函数的整个第一部分缩短为一步时,这将使您的生活更轻松。
您当然可以通过简单的矩阵乘法完全删除最终循环:uncorrelated_walks.T @ decomposition
将为您提供当前correlated_walks
的转置。您可以通过更改参数的顺序来避免transposes之一。
你最终得到的结论是:
def generate_random_correlated_walks(decomposition, x, n):
uncorrelated_walks = nrand.normal(loc=0, scale=1, size=(2*x, n))
correlated_walks = np.dot(decomposition.T, uncorrelated_walks)
return correlated_walks
不确定这对你有多大帮助,但删除Python级循环应该是一种提升,因为它会减少多个numpy调用的开销。
你可以牺牲易读性来将整个事物变成一个单行:
def generate_random_correlated_walks(decomposition, x, n):
return np.dot(decomposition.T, nrand.normal(loc=0, scale=1, size=(2*x, n)))