Python: как написать этот код для запуска на GPU? - PullRequest
7 голосов
/ 25 мая 2019

Я довольно долго пытался реализовать свой код для работы на GPU, но без особого успеха.Буду очень признателен за помощь в реализации.

Позвольте мне сказать несколько слов о проблеме.У меня есть граф G с N узлами и распределением mx на каждом узле х.Я хотел бы вычислить расстояние между распределениями для каждой пары узлов для всех ребер.Для данной пары (x, y) я использую код ot.sinkhorn(mx, my, dNxNy) из пакета python POT для вычисления расстояния.Опять же, 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()  

Спасибо !!

1 Ответ

3 голосов
/ 06 июня 2019

Есть несколько пакетов, которые позволяют запускать код на вашем графическом процессоре.

Вы можете использовать один из следующих пакетов:

  1. PyCuda
  2. Numba (Pro)
  3. Theano

Если вы хотите использовать numba, для этого рекомендуется дистрибутив Python Anaconda. Также нужна Anaconda Accelerate. Вы можете установить его, используя conda install accelerate. В этом примере вы можете увидеть, как достигается использование графического процессора https://gist.githubusercontent.com/aweeraman/ae6e40f54a924f1f5832081be9521d92/raw/d6775c421aa4fa4c0d582e6c58873499d28b913a/gpu.py. Это делается путем добавления target='cuda' к декоратору @vectorize. Обратите внимание на импорт from numba import 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

...