2016-10-13 4 views
1

J'essaye de tester l'efficacité de l'utilisation du @vectorize decorator du module Python Numba pour accélérer un extrait de code pertinent pour mon code actuel. J'utilise un extrait de code fourni dans CUDAcast # 10 disponible here et ci-dessous:Gain de vitesse négatif en utilisant Numba Vectorize target = 'cuda'

import numpy as np 
from timeit import default_timer as timer 
from numba import vectorize 


@vectorize(["float32(float32, float32)"], target='cpu') 
def VectorAdd(a,b): 
     return a + b 

def main(): 
     N = 32000000 

     A = np.ones(N, dtype=np.float32) 
     B = np.ones(N, dtype=np.float32) 
     C = np.zeros(N, dtype=np.float32) 


     start = timer() 
     C = VectorAdd(A, B) 
     vectoradd_time = timer() - start 

     print("C[:5] = " + str(C[:5])) 
     print("C[-5:] = " + str(C[-5:])) 

     print("VectorAdd took %f seconds" % vectoradd_time) 

if __name__ == '__main__': 
     main() 

Dans la démo dans le CUDAcast, le démonstrateur obtient un gain de vitesse 100x en envoyant la grande équation de tableau à la gpu via le @ vectoriser le décorateur. Cependant, quand je mets la cible de @vectorize au gpu:

@vectorize(["float32(float32, float32)"], target='cuda') 

... le résultat est 3-4 fois plus lent. Avec target = 'cpu' mon temps d'exécution est 0.048 secondes; avec target = 'cuda' mon temps d'exécution est 0.22 secondes. J'utilise un ordinateur portable DELL Precision avec processeur Intel Core i7-4710MQ et GPU NVIDIA Quadro K2100M. La sortie de nvprof en cours d'exécution (outil de profil NVIDIA) indique que la majorité du temps est consacrée à la gestion de la mémoire (attendue), mais même l'évaluation de la fonction prend plus de temps sur le GPU que sur l'UC. Évidemment, ce n'est pas le résultat que j'espérais, mais est-ce dû à une erreur de ma part ou est-ce raisonnable en fonction de mon matériel et de mon code?

Répondre

0

Cette question est aussi intéressante pour moi. J'ai essayé votre code et obtenu des résultats similaires. Pour étudier cette question en quelque sorte, je l'ai écrit le noyau CUDA en utilisant cuda.jit et ajoutez dans votre code:

import numpy as np 
from timeit import default_timer as timer 
from numba import vectorize, cuda 

N = 16*50000 #32000000 
blockdim = 16, 1 
griddim = int(N/blockdim[0]), 1 

@cuda.jit("void(float32[:], float32[:])") 
def VectorAdd_GPU(a, b): 
    i = cuda.grid(1) 
    if i < N: 
     a[i] += b[i] 

@vectorize("float32(float32, float32)", target='cpu') 
def VectorAdd(a,b): 
    return a + b 


A = np.ones(N, dtype=np.float32) 
B = np.ones(N, dtype=np.float32) 
C = np.zeros(N, dtype=np.float32) 

start = timer() 
C = VectorAdd(A, B) 
vectoradd_time = timer() - start 
print("VectorAdd took %f seconds" % vectoradd_time) 

start = timer() 
d_A = cuda.to_device(A) 
d_B = cuda.to_device(B) 
VectorAdd_GPU[griddim,blockdim](d_A, d_B) 
C = d_A.copy_to_host() 
vectoradd_time = timer() - start 
print("VectorAdd_GPU took %f seconds" % vectoradd_time) 

print("C[:5] = " + str(C[:5])) 
print("C[-5:] = " + str(C[-5:])) 

Dans cette « référence » Je prends aussi en compte le temps pour la copie de tableaux d'hôte périphérique et du périphérique à l'hôte. Dans ce cas, la fonction GPU est lente par rapport à la CPU.

Pour le cas ci-dessus:

CPU - 0.0033; 
GPU - 0.0096; 
Vectorize (target='cuda') - 0.15 (for my PC). 

Si le temps de copie ne sont pas comptabilisés:

GPU - 0.000245 

Alors, ce que j'ai appris, (1) La copie de l'hôte à l'appareil et du dispositif héberger prend du temps. C'est évident et bien connu. (2) Je ne connais pas la raison mais @vectorize peut considérablement ralentir les calculs sur GPU. (3) Il est préférable d'utiliser des noyaux auto-écrits (et bien sûr de minimiser la copie de la mémoire). Par ailleurs, j'ai également testé le @ cuda.jit en résolvant l'équation de conduction thermique par un système de différences finies explicite et trouvé que le temps d'exécution du programme python est comparable à celui du programme C et accélère environ 100 fois. C'est parce que, heureusement dans ce cas vous pouvez faire de nombreuses itérations sans échange de données entre l'hôte et l'appareil.

UPD. Logiciel utilisé & Matériel: Win7 64bit, Processeur: Intel Core2 Quad 3GHz, GPU: NVIDIA GeForce GTX 580.

+0

Roman, merci pour le 'bilan de santé'. J'apprécie aussi votre code @ cuda.jit. Je suis nouveau à Numba et CUDA, donc ce sera un bon prochain chemin pour moi d'explorer! Pouvez-vous ajouter à votre message quel matériel vous utilisez (processeur, GPU, etc.)? – blrmkrAE