J'essaie de calculer quelques (5-500) vecteurs propres correspondant aux plus petites valeurs propres de grandes matrices creuses symétriques carrées (jusqu'à 30000x30000) avec moins de 0,1% des valeurs étant non nulles.
J'utilise actuellement scipy.sparse.linalg.eigsh en mode inversion de décalage (sigma = 0.0), ce que j'ai compris à travers divers articles sur le sujet est la solution préférée. Cependant, il faut jusqu'à 1h pour résoudre le problème dans la plupart des cas. D'un autre côté, la fonction est très rapide, si je demande les valeurs propres les plus élevées (sous-secondes sur mon système), ce qui était attendu de la documentation.
Comme je suis plus familier avec Matlab du travail, j'ai essayé de résoudre le problème dans Octave, ce qui m'a donné le même résultat en utilisant eigs (sigma = 0) en quelques secondes (moins de 10s). Étant donné que je veux faire un balayage des paramètres de l'algorithme, y compris le calcul du vecteur propre, ce type de gain de temps serait également formidable en python.
J'ai d'abord changé les paramètres (en particulier la tolérance), mais cela n'a pas beaucoup changé dans les délais.
J'utilise Anaconda sur Windows, mais j'ai essayé de changer le LAPACK / BLAS utilisé par scipy (ce qui était une énorme douleur) de mkl (Anaconda par défaut) à OpenBlas (utilisé par Octave selon la documentation), mais je n'ai pas pu voir de changement dans performance.
Je n'ai pas pu déterminer s'il y avait quelque chose à changer dans l'ARPACK utilisé (et comment)?
J'ai téléchargé un testcase pour le code ci-dessous dans le dossier déroulant suivant: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0
En Python
import numpy as np
from scipy.sparse import csr_matrix, csc_matrix, linalg, load_npz
M = load_npz('M.npz')
evals, evecs = linalg.eigsh(M,k=6,sigma=0.0)
En octave:
M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);
Toute aide est appréciée!
Quelques options supplémentaires que j'ai essayées sur la base des commentaires et suggestions:
Octave:
eigs(M,6,0)
et eigs(M,6,'sm')
donnez-moi le même résultat:
[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]
tout eigs(M,6,'sa',struct('tol',2))
converge vers
[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933]
beaucoup plus rapide, mais uniquement si les valeurs de tolérance sont supérieures à 2, sinon elles ne convergent pas du tout et les valeurs sont fortement différentes.
Python:
eigsh(M,k=6,which='SA')
et les eigsh(M,k=6,which='SM')
deux ne convergent pas (erreur ARPACK sur aucune convergence atteinte). eigsh(M,k=6,sigma=0.0)
Donne seulement quelques valeurs propres (après presque une heure), qui sont différentes de l'octave pour les plus petites (même 1 petite valeur supplémentaire est trouvée):
[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]
Si la tolérance est suffisamment élevée, j'obtiens également des résultats eigsh(M,k=6,which='SA',tol='1')
qui se rapprochent des autres valeurs obtenues
[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]
encore une fois avec un nombre différent de petites valeurs propres. Le temps de calcul est encore proche de 30min. Alors que les différentes valeurs très petites peuvent être compréhensibles, car elles peuvent représenter des multiples de 0, la multiplicité différente me déconcerte.
De plus, il semble y avoir des différences fondamentales dans SciPy et Octave, que je ne peux pas encore comprendre.
la source
Réponses:
Une conjecture et quelques commentaires, puisque je n'ai pas Matlab / Octave:
Pour trouver de petites valeurs propres de matrices symétriques avec des valeurs propres> = 0, comme la vôtre, ce qui suit est waaay plus rapide que shift-invert:
eigsh( Aflip )
pour les grandes paires propres, c'est plus rapide que shift-invert pour les petits, parce queA * x
c'est plus rapide quesolve()
ce shift-invert doit faire. Matlab / Octave pourrait éventuellement le faireAflip
automatiquement, après un test rapide de positif-défini avec Cholesky.Pouvez-vous exécuter
eigsh( Aflip )
dans Matlab / Octave?Autres facteurs pouvant affecter la précision / vitesse:
La valeur par défaut d'Arpack pour le vecteur de départ
v0
est un vecteur aléatoire. J'utilisev0 = np.ones(n)
, ce qui peut être terrible pour certainsA
mais est reproductible :)Cette
A
matrice est presque exactement sigulaire,A * ones
~ 0.Multicore: scipy-arpack avec openblas / Lapack utilise environ 3,9 des 4 cœurs de mon iMac; Matlab / Octave utilise-t-il tous les cœurs?
Voici les valeurs propres de scipy-Arpack pour plusieurs
k
ettol
, récupérées à partir des fichiers journaux sous gist.github :Matlab / Octave sont-ils à peu près les mêmes? Sinon, tous les paris sont désactivés - vérifiez d'abord l'exactitude, puis la vitesse.
Pourquoi les valeurs propres vacillent-elles autant? Un petit <0 pour une matrice supposée non négative-définie est un signe d' erreur d'arrondi , mais l'astuce habituelle d'un minuscule décalage
A += n * eps * sparse.eye(n)
, n'aide pas.D'où cela
A
vient-il, quel problème? Pouvez-vous générer desA
images similaires , plus petites ou plus rares?J'espère que cela t'aides.
la source
tol
désordonné pour les petites valeurs propres - posez une nouvelle question à ce sujet si vous le souhaitez, faites le moi savoir.Je sais que c'est vieux maintenant, mais j'ai eu le même problème. Avez-vous révisé ici ( https://docs.scipy.org/doc/scipy/reference/tutorial/arpack.html )?
Il semble que lorsque vous définissez sigma sur un nombre faible (0), vous devez définir which = 'LM', même si vous souhaitez des valeurs faibles. En effet, la définition de sigma transforme les valeurs que vous souhaitez (faibles dans ce cas) en apparence élevées et vous pouvez donc toujours profiter des méthodes `` LM '', qui sont beaucoup plus rapides pour obtenir ce que vous voulez (les valeurs propres faibles ).
la source
Je veux d'abord dire que je ne sais pas pourquoi les résultats que vous et @Bill avez rapportés sont tels qu'ils sont. Je me demande simplement si
eigs(M,6,0)
dans Octave correspond àk=6 & sigma=0
, ou peut-être que c'est autre chose?Avec scipy, si je ne fournis pas de sigma, je peux obtenir un résultat en un temps décent de cette façon.
Je ne suis absolument pas sûr que cela ait du sens cependant.
Le seul moyen que j'ai trouvé d'utiliser sigma et d'obtenir un résultat dans un temps décent est de fournir M comme opérateur linéaire. Je ne suis pas trop familier avec cette chose, mais d'après ce que j'ai compris, mon implémentation représente une matrice d'identité, qui est ce que M devrait être s'il n'est pas spécifié dans l'appel. La raison en est qu'au lieu d'effectuer une résolution directe (décomposition LU), scipy utilisera un solveur itératif, qui est potentiellement mieux adapté. À titre de comparaison, si vous fournissez
M = np.identity(a.shape[0])
ce qui devrait être exactement le même, eigsh prend une éternité pour produire un résultat. Notez que cette approche ne fonctionne pas si ellesigma=0
est fournie. Mais je ne sais pas sisigma=0
est-ce vraiment utile?Encore une fois, aucune idée si elle est correcte mais définitivement différente d'avant. Ce serait formidable d'avoir la contribution de quelqu'un de scipy.
la source