我有以下优化问题。给定两个np.arrays X
,Y
和一个函数K
我想尽可能快地计算矩阵入射gram_matrix,其中(i,j)-th
元素计算为{{ 1}}。
这里有一个使用嵌套for循环的实现,它被认为是解决这类问题最慢的。
K(X[i],Y[j])
真的很感激任何帮助。
答案 0 :(得分:1)
你肯定至少可以对内循环进行矢量化:
def proxy_kernel_vect(X, Y, K):
K_vect = np.vectorize(K)
gram_matrix = np.zeros((X.shape[0], Y.shape[0]))
for i, x in enumerate(X):
gram_matrix[i] = K_vect(x, Y)
return gram_matrix
对于相对较长的数组,这会带来很好的改进:
In [15]: a = np.array(range(1000))
...: b = np.array(range(1000))
...:
In [16]: %timeit proxy_kernel(a, b, k)
1 loops, best of 3: 665 ms per loop
In [17]: %timeit proxy_kernel_vect(a, b, k)
1 loops, best of 3: 266 ms per loop
其中k
只是lambda x, y: x+y
。
答案 1 :(得分:1)
np.vectorize
确实在速度方面做了一些改进 - 大约2倍(这里我使用math.atan2
作为带有2个标量参数的黑盒函数)。
In [486]: X=np.linspace(0,1,100)
In [487]: K_vect=np.vectorize(math.atan2)
In [488]: timeit proxy_kernel(X,X,math.atan2)
100 loops, best of 3: 7.84 ms per loop
In [489]: timeit K_vect(X[:,None],X)
100 loops, best of 3: 3.49 ms per loop
In [502]: timeit np.arctan2(X[:,None],X) # numpy compiled loop
1000 loops, best of 3: 871 µs per loop
,其中
def proxy_kernel(X,Y,K):
gram_matrix = np.zeros((X.shape[0], Y.shape[0]))
for i, x in enumerate(X):
for j, y in enumerate(Y):
gram_matrix[i, j] = K(x, y)
return gram_matrix
只要K
是黑匣子,就会受到K
次X.shape[0]*Y.shape[0]
次调用所需时间的限制。您可以尝试最小化迭代时间,但仍然受到所有这些函数调用的限制。
https://stackoverflow.com/a/29733040/901925利用axis
函数的np.linalg.norm
参数,加速了Gausian内核的计算。
答案 2 :(得分:0)
您还可以尝试numba模块中的vectorize
装饰器。
使用vectorize
和numpy broadcasting:
from numba import vectorize
@vectorize(['float64(float64, float64)'])
def K(x,y):
return x + y
a = np.arange(1000)
b = np.arange(1000)
gram_array = K(a[None,:], b[:, None])