Я пытаюсь вычислить несколько (5-500) собственных векторов, соответствующих наименьшим собственным значениям больших симметричных квадратных разреженных матриц (до 30000x30000) с ненулевыми значениями менее 0,1%.
В настоящее время я использую scipy.sparse.linalg.eigsh в режиме shift-invert (sigma = 0.0), который, как я выяснил, в различных сообщениях на эту тему является предпочтительным решением. Однако для решения проблемы в большинстве случаев требуется до 1 часа. С другой стороны, функция очень быстрая, если я запрашиваю самые большие собственные значения (в секундах в моей системе), что ожидалось из документации.
Поскольку я больше знаком с Matlab с работы, я попытался решить проблему в Octave, которая дала мне тот же результат, используя eigs (sigma = 0) всего за несколько секунд (sub 10s). Поскольку я хочу выполнить поиск параметров алгоритма, включая вычисление собственных векторов, такой выигрыш во времени был бы также полезен в python.
Сначала я изменил параметры (особенно допуск), но это не сильно изменилось в сроки.
Я использую Anaconda в Windows, но попытался переключить LAPACK / BLAS, используемый scipy (что было очень трудно), с mkl (по умолчанию Anaconda) на OpenBlas (используемый Octave в соответствии с документацией), но не увидел изменений в представление.
Я не смог выяснить, было ли что-то изменить в используемом ARPACK (и как)?
Я загрузил тестовый пример для кода ниже в следующую папку dropbox: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0
В питоне
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)
В октаве:
M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);
Любая помощь ценится!
Некоторые дополнительные опции, которые я опробовал на основе комментариев и предложений:
Октава:
eigs(M,6,0)
и eigs(M,6,'sm')
дай мне тот же результат:
[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]
пока eigs(M,6,'sa',struct('tol',2))
сходится к
[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933]
намного быстрее, но только если значения допуска выше 2, иначе оно не сходится вообще и значения сильно отличаются.
Python:
eigsh(M,k=6,which='SA')
и eigsh(M,k=6,which='SM')
оба не сходятся (ошибка ARPACK при отсутствии достигнутой конвергенции). Только eigsh(M,k=6,sigma=0.0)
дает некоторые собственные значения (после почти часа), которые отличаются от октавы для самых маленьких (найдено даже 1 дополнительное небольшое значение):
[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]
Если допуск достаточно высок, я также получаю результаты eigsh(M,k=6,which='SA',tol='1')
, которые приближаются к другим полученным значениям
[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]
снова с другим количеством маленьких собственных значений. Время вычислений все еще почти 30 минут. В то время как различные очень маленькие значения могут быть понятны, так как они могут представлять кратные 0, различная множественность сбивает с толку меня.
Кроме того, в SciPy и Octave, похоже, есть некоторые принципиальные различия, которые я пока не могу понять.
источник
Ответы:
Гипотеза и некоторые комментарии, так как у меня нет Matlab / Octave:
Чтобы найти малые собственные значения симметричных матриц с собственными значениями> = 0, как и у вас, следующее быстрее, чем инверсия сдвига:
eigsh( Aflip )
для больших собственных пар быстрее, чем инвертирование сдвига, для маленьких, потому чтоA * x
это быстрее, чемsolve()
должно делать инвертирование сдвига. Matlab / Octave, возможно, могли бы сделать этоAflip
автоматически, после быстрой проверки на положительную определенность с помощью Cholesky.Можете ли вы бегать
eigsh( Aflip )
в Matlab / Octave?Другие факторы, которые могут повлиять на точность / скорость:
Arpack по умолчанию для начального вектора
v0
является случайным вектором. Я используюv0 = np.ones(n)
, что может быть ужасно для некоторых,A
но воспроизводимо :)Эта
A
матрица почти точно сигулярная,A * ones
~ 0.Multicore: scipy-arpack с openblas / Lapack использует ~ 3,9 из 4 ядер на моем iMac; Matlab / Octave используют все ядра?
Вот собственные значения scipy-Arpack для нескольких
k
иtol
извлеченные из лог- файлов в gist.github :Matlab / Octave примерно одинаковы? Если нет, все ставки выключены - сначала проверьте правильность, затем скорость.
Почему собственные значения так сильно колеблются? Крошечные <0 для предположительно неотрицательно определенной матрицы являются признаком ошибки округления , но обычный трюк с небольшим сдвигом
A += n * eps * sparse.eye(n)
не помогает.Откуда это
A
взялось, из какой проблемной области? Можете ли вы генерировать аналогичныеA
, меньшие или редкие?Надеюсь это поможет.
источник
tol
это грязно для небольших собственных значений - задайте новый вопрос, если хотите, дайте мне знать.Я знаю, что сейчас это старо, но у меня была та же проблема. Вы просматривали здесь ( https://docs.scipy.org/doc/scipy/reference/tutorial/arpack.html )?
Кажется, что когда вы устанавливаете сигма на низкое число (0), вы должны установить, который = 'LM', даже если вы хотите низкие значения. Это связано с тем, что настройка sigma преобразует значения, которые вы хотите (в данном случае, низкими), в высокие, и поэтому вы все еще можете использовать методы LM, которые намного быстрее получают то, что вы хотите (низкие собственные значения) ).
источник
Сначала я хочу сказать, что понятия не имею, почему результаты, о которых вы и @Bill сообщили, такие, какие они есть. Мне просто интересно, соответствует ли
eigs(M,6,0)
Октаваk=6 & sigma=0
, или, может быть, это что-то еще?С помощью scipy, если я не предоставлю сигму, я смогу получить результат за приемлемое время.
Я совершенно не уверен, имеет ли это смысл.
Единственный способ найти сигма и получить результат за приемлемое время - это предоставить M в качестве линейного оператора. Я не слишком знаком с этой вещью, но из того, что я понял, моя реализация представляет собой матрицу идентичности, которая должна быть M, если она не указана в вызове. Причина этого в том, что вместо выполнения прямого решения (декомпозиции LU), scipy будет использовать итерационный решатель, который потенциально лучше подходит. Для сравнения, если вы предоставите
M = np.identity(a.shape[0])
, что должно быть точно так же, то eigsh всегда будет приносить результат. Обратите внимание, что этот подход не работает, еслиsigma=0
он предусмотрен. Но я не уверен,sigma=0
действительно ли это полезно?Опять же, не знаю, если это правильно, но определенно отличается от ранее. Было бы замечательно, если бы кто-то из Сципи сделал свой вклад.
источник