8
votes

Calculer "v ^ t a v" pour une matrice de vecteurs v

J'ai un k * n matrix x et un k * k matrice A. Pour chaque colonne de x , je tiens à calculer le scalaire xxx

(ou, mathématiquement, xi '* a * xi ).

actuellement, j'ai un pour boucle: xxx

mais depuis n est grand, je voudrais le faire plus vite si possible (c'est-à-dire en utilisant certains Fonctions numpées au lieu d'une boucle).


0 commentaires

3 Réponses :


0
votes

Vous ne pouvez pas le faire plus vite sauf si vous parallélisez le tout: un fil par colonne. Vous utiliserez toujours des boucles - vous ne pouvez pas vous échapper de cela.

La carte Réduire est une bonne façon de regarder ce problème: Map Matit Multiples, réduire les sommets.


1 commentaires

Bien sûr, je ne peux pas aller plus vite à partir d'un point de vue de la complexité, mais éviter les boucles Python (en faveur de constructions numpées) fournit généralement une vitesse simplement en évitant le code Python plus lent.



4
votes

Vous pouvez utiliser le numpy.einsum : xxx

Cela obtiendra le même résultat. Voyons si c'est beaucoup plus rapide:

 Entrez la description de l'image ici

ressemble à dot est toujours l'option la plus rapide, en particulier parce qu'il utilise des blas filetés, par opposition à einsum qui fonctionne sur un noyau. xxx


14 commentaires

Ceci est considérablement plus lent pour une grande dimension sur les processeurs modernes en raison de sa capacité à utiliser une blas filetée.


@Ophion bon point, mais je crois que ce sera toujours plus rapide que le python pour boucle ... quelque chose qui vaut la peine d'être vérifié


Python pour boucle CYTHON / NUMPLY pour La boucle n'a pas d'importance. Le temps n'est vraiment pas dans la boucle.


Je n'ai pas de blas enfilé (bien que je devrais évidemment l'obtenir à un moment donné). Pour N = 10000 , cela surperformez mon code d'origine (76,2ms contre 1,48ms).


@nneonneo Je termine un test ici, le mien est Blas avec 4 cœurs ... Voyons les résultats ...


@Ophion ... vous avez raison ... J'ai mis à jour la réponse avec certaines comparaisons contre une blas optimisée et pour High N , le numpy.einsum est beaucoup plus lent.


Vous devez créer les tableaux en dehors de la fonction pour éviter l'impact de aléatoire .


@nneonneo mais cela ne changerait pas de manière significative les résultats


Juste pour confirmer certains résultats, j'utilise MKL et il est certainement plus lent sur ma machine.


HM, vous avez peut-être raison. Merci pour le lien einsum ; C'est bien de savoir ce qu'il peut faire. Dommage que ce ne soit pas la solution la plus rapide. (Très surprenant qu'il soit plus rapide que la solution de @ ianh pour n = 10000, k = 10 sur un noyau, cependant)


@nneNneo Vérifiez cette question où il est montré de nombreux cas où Einsum surperforms ... il peut être très utile et plus rapide dans certains cas


@nneonneo apporte un bon point. Lorsque tout est dit et fait, quelle version est plus rapide dépendra probablement de la taille des matrices et de la configuration du système à utiliser.


@LANH Je pense que nous pouvons dire que lorsque l'Atlas échoue à plus d'un noyau, votre solution sera plus rapide, sinon le einsum peut être plus rapide ...


@nneonneo np.dot (x, x) échelle à environ n ^ 2.8 pendant np.einsum ("ij, jk", x, x) est naïf et des échelles à n ^ 3 . np.dot sera toujours plus rapide par noyau pour les grandes tableaux.



7
votes

Cela semble le faire bien: (x.t.dot (a) * x.t) .sum (axe = 1)

Edit: Ceci est un peu plus rapide. np.einsum ('... I, ... I -> ...', x.t.dot (a), x.t) . Les deux fonctionnent mieux si x et a sont contigus de force contiguë.


1 commentaires

Apparaît Handly battre mon code d'origine: pour n = 10000, k = 10 , mon code est 76,2ms, le nouveau code est 1.64ms . Agréable!