Python:如何编写可以在GPU上运行的代码?

7

我一直在尝试将我的代码实现在GPU上运行,但是收效甚微。希望有人能帮助实现。

关于问题,我有一个包含N个节点的图G和每个节点x上的分布mx。我想计算所有边缘上的每一对节点之间分布的距离。对于给定的一对节点(x, y),我使用python POT软件包中的ot.sinkhorn(mx, my, dNxNy)代码来计算距离。这里,mx、my是大小为Nx和Ny的向量,在节点x和y上,并且dNxNy是一个Nx x Ny的距离矩阵。

现在,我发现有一个GPU实现的代码ot.gpu.sinkhorn(mx, my, dNxNy)。但是这并不够好,因为每次迭代都需要上传mx、my和dNxNy到GPU,这是一个巨大的开销。所以,思路就是在GPU上并行化处理所有边缘。

代码的核心如下所示。mx_all是所有分布的集合。

for i,e in enumerate(G.edges):
    W[i] = W_comp(mx_all,dist,e)

def W_comp(mx_all, dist,  e):
    i = e[0]
    j = e[1]

    Nx = np.array(mx_all[i][1]).flatten()
    Ny = np.array(mx_all[j][1]).flatten()
    mx = np.array(mx_all[i][0]).flatten()
    my = np.array(mx_all[j][0]).flatten()

    dNxNy = dist[Nx,:][:,Ny].copy(order='C')

    W = ot.sinkhorn2(mx, my, dNxNy, 1)

以下是一个最小化工作示例。请忽略除虚线 === 之间的部分以外的所有内容。
import ot
import numpy as np
import scipy as sc


def main():
    import networkx as nx

    #some example graph
    G = nx.planted_partition_graph(4, 20, 0.6, 0.3, seed=2)
    L = nx.normalized_laplacian_matrix(G)

    #this just computes all distributions (IGNORE)
    mx_all = []
    for i in G.nodes:
        mx_all.append(mx_comp(L,1,1,i))  

    #some random distance matrix (IGNORE)
    dist = np.random.randint(5,size=(nx.number_of_nodes(G),nx.number_of_nodes(G)))          

# ============================================================================= 
#this is what needs to be parallelised on GPU
    W = np.zeros(nx.Graph.size(G))
    for i,e in enumerate(G.edges):
        print(i)
        W[i] = W_comp(mx_all,dist,e)

    return W

def W_comp(mx_all, dist,  e):
    i = e[0]
    j = e[1]

    Nx = np.array(mx_all[i][1]).flatten()
    Ny = np.array(mx_all[j][1]).flatten()
    mx = np.array(mx_all[i][0]).flatten()
    my = np.array(mx_all[j][0]).flatten()

    dNxNy = dist[Nx,:][:,Ny].copy(order='C')

    return ot.sinkhorn2(mx, my, dNxNy,1)

# =============================================================================

#some other functions (IGNORE)
def delta(i, n):

    p0 = np.zeros(n)
    p0[i] = 1.

    return p0

# all neighbourhood densities
def mx_comp(L, t, cutoff, i):
    N = np.shape(L)[0]

    mx_all = sc.sparse.linalg.expm_multiply(-t*L, delta(i, N))
    Nx_all = np.argwhere(mx_all > (1-cutoff)*np.max(mx_all))

    return mx_all, Nx_all  

if __name__ == "__main__":
    main()  

谢谢!


仅供澄清:您只想让它在GPU上运行吗?还是必须更快?此外,为什么要标记numba,您尝试使用numba进行操作还是希望得到使用numba的答案?另外,“并行”具体指什么意思,仅仅是一次将数组传输到GPU上,还是应该采用多线程/进程的方式实现并行? - MSeifert
@MSeifert 还有,为什么要打上numba标签,你是尝试使用numba吗?还是期望得到一个使用numba的答案?-- 我不期望得到numba的答案,但我发现它是一个潜在有用的包。另外,“并行”具体指什么意思?只是一次将数组传输到GPU,还是应该采用多线程/进程的方式进行并行处理?-- 理想情况下,对于ot.gpu.sinkhorn(mx,my,dNxNy)函数的多个实例(尽可能多,如果更容易的话可以预先定义数量),数组mx、my、dNxNy被传输到GPU并同时执行。 - Adam Gosztolai
你只是想让它在GPU上运行吗?还是必须更快?--理想情况下两者都要。函数ot.gpu.sinkhorn(mx,my,dNxNy)已经在GPU上运行了。问题在于它在循环中执行,因此在每次迭代中,mx和my都会上传到GPU,这是瓶颈所在。相反,应该并行运行多个ot.gpu.sinkhorn实例。 - Adam Gosztolai
1个回答

3

有一些包可以让您在GPU上运行代码。

您可以使用以下其中一个包:

  1. pyCuda
  2. numba(Pro)
  3. Theano
当您想使用numba时,建议使用Python Anaconda发行版。此外,需要Anaconda Accelerate。您可以使用conda install accelerate进行安装。在此示例中,您可以看到如何实现GPU的使用https://gist.githubusercontent.com/aweeraman/ae6e40f54a924f1f5832081be9521d92/raw/d6775c421aa4fa4c0d582e6c58873499d28b913a/gpu.py。通过将target ='cuda'添加到@vectorize装饰器来完成。请注意导入from numba import vectorize。vectorize装饰器以要加速的函数的签名作为输入。祝你好运!

来源:

https://weeraman.com/put-that-gpu-to-good-use-with-python-e5a437168c01 https://www.researchgate.net/post/How_do_I_run_a_python_code_in_the_GPU


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接