Cupy 比 numpy 慢
Cupy is slower than numpy
我试图用 cupy 而不是 numpy 来加速我的 python 代码。这里的问题是,使用 cupy,我的代码变得非常慢。也许我在这个问题上有点天真了。
也许任何人都可以在我的代码中找到瓶颈:
import cupy as np
import time as ti
def f(y, t):
y_ = np.zeros(2 * N_1*N_2) # n: e-6, c: e-5
for i in range(0, N_1*N_2):
y_[i] = y[i + N_1*N_2] # n: e-7, c: e-5 or e-6
for i in range(N_1*N_2):
sum = -4*y[i] # n: e-7, c: e-7 after some statements e-5
if (i + 1 in indexes) and (not (i in indi)):
sum += y[i+1] # n: e-7, c: e-7 after some statements e-5
if (i - 1) in indexes and (i % N_1 != 0):
sum += y[i-1] # n: e-7, c: e-7 after some statements e-5
if i + N_1 in indexes:
sum += y[i+N_1] # n: e-7, c: e-7 after some statements e-5
if i - N_1 in indexes:
sum += y[i-N_1] # n: e-7, c: e-7 after some statements e-5
y_[i + N_1*N_2] = sum
return y_
def k_1(y, t, h):
return np.asarray(f(y, t)) * h
def k_2(y, t, h):
return np.asarray(f(np.add(np.asarray(y) , np.multiply(1/2 , k_1(y, t, h))), t + 1/2 * h)) * h
# k_2, k_4 look just like k_2, may be with an 1/2 here or there
# some init stuff is happening here
while t < T_end:
# also some magic happening here which is just data saving
y = np.asarray(y) + 1/6*(k_1(y, t, m) + 2*k_2(y, t, m) + 2*k_3(y, t, m) + k_4(y, t, m))
t += m
编辑
我尝试对我的代码进行基准测试,这里有一些结果,它们可以被视为代码中的注释。每个数字保留一行。单位是秒。 n: Numpy, c:CuPy, 我多半是粗略估计一下顺序。
另外我测试了
np.multiply # n: e-6, c: e-5
和
np.add # n: e-5 or e-6, c: 0.005 or e-5
您的代码示例不起作用,因为您没有在任何地方定义 N_1
、N_2
、indexes
和 indi
。此外,您在代码中的评论似乎无法帮助其他人理解发生了什么。
您的代码可能不会从 numba/cupy 中获益,因为您尚未对代码中的操作进行矢量化。就您目前的代码工作方式而言,列表可能与 numpy 数组一样快。
如果你摆脱 for 循环并改变
y_ = np.zeros(2 * N_1*N_2)
for i in range(0, N_1*N_2):
y_[i] = y[i + N_1*N_2]
到
n = N1*N2
y_ = np.zeros(2*n)
y_[:n] = y[n:2*n]
依此类推,您的代码将大大加快。
你的代码并不慢,因为 numpy 很慢,而是因为你调用了许多 (python) 函数,并且调用函数(以及迭代和访问对象,基本上 python 中的所有内容)很慢python。因此 cupy 不会帮助你(但可能会损害性能,因为它必须做更多的设置,例如将数据复制到 gpu)。如果您可以制定您的算法以使用更少的 python 函数(如另一个答案中的矢量化),这将极大地加速您的代码(您可能不需要 cupy)。
您还可以查看 numba,它使用本机代码中的 llvm 编译您的代码。如果你这样做,一定要阅读一些文档并使用 nopython=True
,否则你只会用慢速 numba 代码切换慢速 cupy 代码。
我试图用 cupy 而不是 numpy 来加速我的 python 代码。这里的问题是,使用 cupy,我的代码变得非常慢。也许我在这个问题上有点天真了。
也许任何人都可以在我的代码中找到瓶颈:
import cupy as np
import time as ti
def f(y, t):
y_ = np.zeros(2 * N_1*N_2) # n: e-6, c: e-5
for i in range(0, N_1*N_2):
y_[i] = y[i + N_1*N_2] # n: e-7, c: e-5 or e-6
for i in range(N_1*N_2):
sum = -4*y[i] # n: e-7, c: e-7 after some statements e-5
if (i + 1 in indexes) and (not (i in indi)):
sum += y[i+1] # n: e-7, c: e-7 after some statements e-5
if (i - 1) in indexes and (i % N_1 != 0):
sum += y[i-1] # n: e-7, c: e-7 after some statements e-5
if i + N_1 in indexes:
sum += y[i+N_1] # n: e-7, c: e-7 after some statements e-5
if i - N_1 in indexes:
sum += y[i-N_1] # n: e-7, c: e-7 after some statements e-5
y_[i + N_1*N_2] = sum
return y_
def k_1(y, t, h):
return np.asarray(f(y, t)) * h
def k_2(y, t, h):
return np.asarray(f(np.add(np.asarray(y) , np.multiply(1/2 , k_1(y, t, h))), t + 1/2 * h)) * h
# k_2, k_4 look just like k_2, may be with an 1/2 here or there
# some init stuff is happening here
while t < T_end:
# also some magic happening here which is just data saving
y = np.asarray(y) + 1/6*(k_1(y, t, m) + 2*k_2(y, t, m) + 2*k_3(y, t, m) + k_4(y, t, m))
t += m
编辑 我尝试对我的代码进行基准测试,这里有一些结果,它们可以被视为代码中的注释。每个数字保留一行。单位是秒。 n: Numpy, c:CuPy, 我多半是粗略估计一下顺序。 另外我测试了
np.multiply # n: e-6, c: e-5
和
np.add # n: e-5 or e-6, c: 0.005 or e-5
您的代码示例不起作用,因为您没有在任何地方定义 N_1
、N_2
、indexes
和 indi
。此外,您在代码中的评论似乎无法帮助其他人理解发生了什么。
您的代码可能不会从 numba/cupy 中获益,因为您尚未对代码中的操作进行矢量化。就您目前的代码工作方式而言,列表可能与 numpy 数组一样快。
如果你摆脱 for 循环并改变
y_ = np.zeros(2 * N_1*N_2)
for i in range(0, N_1*N_2):
y_[i] = y[i + N_1*N_2]
到
n = N1*N2
y_ = np.zeros(2*n)
y_[:n] = y[n:2*n]
依此类推,您的代码将大大加快。
你的代码并不慢,因为 numpy 很慢,而是因为你调用了许多 (python) 函数,并且调用函数(以及迭代和访问对象,基本上 python 中的所有内容)很慢python。因此 cupy 不会帮助你(但可能会损害性能,因为它必须做更多的设置,例如将数据复制到 gpu)。如果您可以制定您的算法以使用更少的 python 函数(如另一个答案中的矢量化),这将极大地加速您的代码(您可能不需要 cupy)。
您还可以查看 numba,它使用本机代码中的 llvm 编译您的代码。如果你这样做,一定要阅读一些文档并使用 nopython=True
,否则你只会用慢速 numba 代码切换慢速 cupy 代码。