7
votes

Sommes non triviales de produits extérieurs sans temporaire dans NUMPY

Le problème réel que je souhaite résoudre est, étant donné qu'un ensemble de vecteurs d'unité n em> et un autre ensemble de vecteurs m em> calculez pour chacun des vecteurs de l'unité la moyenne du Valeur absolue du produit DOT de celui-ci avec chacun des vecteurs m em>. Essentiellement cela consiste à calculer le produit extérieur des deux matrices et en résumant et en moyenne avec une valeur absolue bloquée entre les deux.

pour n em> et m em> pas trop grand ceci est Pas difficile et il existe de nombreuses façons de procéder (voir ci-dessous). Le problème est quand n em> et m em> sont importants, les temporaires créés sont énormes et offrent une limitation pratique pour l'approche fournie. Ce calcul peut-il être fait sans créer des temporaires? La principale difficulté que j'ai est due à la présence de la valeur absolue. Existe-t-il des techniques générales pour "threading" de tels calculs? P>

à titre d'exemple, considérez le code suivant P>

T = np.einsum('ik,jk,j', nhat, m, np.ones(M)) / M


3 Réponses :


0
votes

Ceci est un peu plus lent, mais ne crée pas la grande matrice intermédiaire.

m2 = np.average(m,0)
vals = np.zeros(N)
for i in xrange(N):
    u=nhat[i]
    if u[0] >= 0 and u[1] >= 0 and u[2] >= 0:
        vals[i] = abs(np.dot(u,m2))
    else:
        for j in xrange(M):
            vals[i]+=abs(np.dot(u,m[j]))
        vals[i]/=M


3 commentaires

Cela fonctionne, bien sûr, mais pour toutes les grandes valeurs de n ou m cela sera douloureusement lent. Il peut être fait plus rapidement en utilisant une seule boucle et diffuser uniquement un de n ou m (semblable au code que j'ai fourni dans la question mais appliqué à un seul Nhat ou m ). Mais même cela est douloureusement lent pour les deux n et m grand.


Vous pouvez utiliser Cython pour améliorer encore la vitesse de la ou des boucles. Il peut également améliorer l'indexation des valeurs uniques telles que les vals [i] (pas des tranches).


Cela semble invraisemblable qu'il y aurait une différence de performance significative lorsqu'elle ne fait qu'une des boucles de Python, tant que au moins, au moins le plus grand de N et M est vectorisé. Si N ou M est vraiment si gros, la surcharge en boucle ne doit pas dominer par rapport aux calculs engendrés. Avez-vous enfoncé cela? Si vous décidez que vous avez besoin d'une boucle C, jetez un coup d'œil à Numba. Pas tout aussi mature que Cyron, mais pour ce type de fonctionnalité, cela fonctionne parfaitement.



1
votes

Je ne pense pas qu'il y ait un moyen facile (en dehors de Cyron et similaire) pour accélérer votre opération exacte. Mais vous voudrez peut-être déterminer si vous avez vraiment besoin de calculer ce que vous calculez. Car si au lieu de la moyenne des valeurs absolues, vous pouvez utiliser le carré moyen racine , vous seriez toujours Soyez en quelque sorte à la moyenne des grossitudes de produits intérieurs, mais vous pouvez l'obtenir en un seul coup comme étant:

rms_2 = np.sqrt(np.average(np.einsum('ij,kj->ik', nhat, m)**2, axis=-1))


0 commentaires

3
votes

Sur la base de certains des commentaires, il semble que l'utilisation de Cyron soit la meilleure façon d'y aller. Je n'ai bêtement jamais regardé à l'aide de Cyron. Il s'avère être relativement facile à produire du code de travail.

Après la recherche, je mets ensemble le code Cython suivant. Ceci est pas le code le plus général, probablement pas le meilleur moyen de l'écrire et peut probablement être rendu plus efficace. Malgré tout, il ne s'agit que d'environ 25% plus lentement que le code einsum () dans la question originale de sorte que ce n'est pas trop mauvais! Il a été écrit pour travailler explicitement avec des tableaux créés comme dans la question initiale (d'où les modes supposés des tableaux d'entrée).
Malgré les mises en garde, il fournit une solution raisonnablement efficace au problème initial et peut servir de point de départ dans des situations similaires. xxx


0 commentaires