使多维张量的 numpy einsum 更快
Making numpy einsum faster for multidimensional tensors
我有一些使用以下代码的代码 einsum
:
y = np.einsum('wxyijk,ijkd->wxyd', x, f)
其中(例如)x 的形状是 (64, 26, 26, 3, 3, 3),f 的形状是 (3, 3, 3, 1),两者都有 dtype=float
%timeit np.einsum('wxyijk,ijkd->wxyd', x, f)
# 2.01 ms ± 55.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
这对我的应用程序来说太慢了,它对时间很关键。无论是使用 GPU(通过 CuPy)还是路径加速(通过 opt-einsum)似乎都没有使它变得更快。有没有什么方法可以让它在 NumPy 中变得更快,或者这是否和它即将达到的一样快?
在这种情况下,您可以使用 optimize 关键字,自己实现,或使用 tensordot。不过,第一个版本实际上应该做同样的事情(重塑-> 点 -> 重塑)。
您的实施
x=np.random.rand(64, 26, 26, 3, 3, 3)
f=np.random.rand(3, 3, 3, 1)
%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f)
#886 µs ± 3.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
配合优化="optimal"
%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f,optimize="optimal")
#275 µs ± 23.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
重塑和 BLAS 调用
这通常会导致与 optimize="optimal"
相当的性能,也许在这种情况下,不必要的数组复制会导致速度下降。
def contract(x,f):
s1=x.shape
x_=x.reshape(s1[0]*s1[1]*s1[2],s1[3]*s1[4]*s1[5])
s2=f.shape
f_=f.reshape(s2[0]*s2[1]*s2[2],s2[3])
return np.dot(x_,f_).reshape(s1[0],s1[1],s1[2],s2[3])
%timeit contract(x,f)
#144 µs ± 3.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Tensordot
%timeit np.tensordot(x,f,axes=3)
#176 µs ± 4.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
我有一些使用以下代码的代码 einsum
:
y = np.einsum('wxyijk,ijkd->wxyd', x, f)
其中(例如)x 的形状是 (64, 26, 26, 3, 3, 3),f 的形状是 (3, 3, 3, 1),两者都有 dtype=float
%timeit np.einsum('wxyijk,ijkd->wxyd', x, f)
# 2.01 ms ± 55.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
这对我的应用程序来说太慢了,它对时间很关键。无论是使用 GPU(通过 CuPy)还是路径加速(通过 opt-einsum)似乎都没有使它变得更快。有没有什么方法可以让它在 NumPy 中变得更快,或者这是否和它即将达到的一样快?
在这种情况下,您可以使用 optimize 关键字,自己实现,或使用 tensordot。不过,第一个版本实际上应该做同样的事情(重塑-> 点 -> 重塑)。
您的实施
x=np.random.rand(64, 26, 26, 3, 3, 3)
f=np.random.rand(3, 3, 3, 1)
%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f)
#886 µs ± 3.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
配合优化="optimal"
%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f,optimize="optimal")
#275 µs ± 23.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
重塑和 BLAS 调用
这通常会导致与 optimize="optimal"
相当的性能,也许在这种情况下,不必要的数组复制会导致速度下降。
def contract(x,f):
s1=x.shape
x_=x.reshape(s1[0]*s1[1]*s1[2],s1[3]*s1[4]*s1[5])
s2=f.shape
f_=f.reshape(s2[0]*s2[1]*s2[2],s2[3])
return np.dot(x_,f_).reshape(s1[0],s1[1],s1[2],s2[3])
%timeit contract(x,f)
#144 µs ± 3.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Tensordot
%timeit np.tensordot(x,f,axes=3)
#176 µs ± 4.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)