Skip to content

PCA and SVD for low-rank matrices, LOBPCG for positive-defined generalized eigenvalue problem#29488

Closed
pearu wants to merge 41 commits intopytorch:masterfrom
Quansight:pearu/lowrank-linalg
Closed

PCA and SVD for low-rank matrices, LOBPCG for positive-defined generalized eigenvalue problem#29488
pearu wants to merge 41 commits intopytorch:masterfrom
Quansight:pearu/lowrank-linalg

Conversation

@pearu
Copy link
Collaborator

@pearu pearu commented Nov 8, 2019

This PR implements the following linear algebra algorithms for low-rank matrices:

  • Approximate A as Q Q^H A - using Algorithm 4.4 from Halko et al, 2009.
    • exposed as torch.lowrank.get_approximate_basis(A, q, niter=2, M=None) -> Q
    • dense matrices
    • batches of dense matrices
    • sparse matrices
    • documentation
  • SVD - using Algorithm 5.1 from Halko et al, 2009.
    • uses torch.lowrank.get_approximate_basis
    • exposed as torch.svd_lowrank(A, q=6, niter=2, M=None) -> (U, S, V)
    • dense matrices
    • batches of dense matrices
    • sparse matrices
    • documentation
  • PCA - using torch.svd_lowrank
    • uses torch.svd_lowrank
    • exposed as torch.pca_lowrank(A, center=True, q=None, niter=2) -> (U, S, V)
    • dense matrices
    • batches of dense matrices
    • sparse matrices, uses non-centered sparse matrix algorithm
    • documentation
  • generalized eigenvalue solver using the original LOBPCG algorithm Knyazev, 2001
    • exposed as torch.lobpcg(A, B=None, k=1, method="basic", ...)
    • dense matrices
    • batches of dense matrices
    • sparse matrices
    • documentation
  • generalized eigenvalue solver using robust LOBPCG with orthogonal basis selection Stathopoulos, 2002
    • exposed as torch.lobpcg(A, B=None, k=1, method="ortho", ...)
    • dense matrices
    • batches of dense matrices
    • sparse matrices
    • documentation
  • generalized eigenvalue solver using the robust and efficient LOBPCG Algorithm 8 from Duersch et al, 2018 that switches to orthogonal basis selection automatically
    • the "ortho" method improves iterations so rapidly that in the current test cases it does not make sense to use the basic iterations at all. If users will have matrices for which basic iterations could improve convergence then the tracker argument allows breaking the iteration process at user choice so that the user can switch to the orthogonal basis selection if needed. In conclusion, there is no need to implement Algorithm 8 at this point.
  • benchmarks
    • torch.svd vs torch.svd_lowrank, see notebook Low-rank SVD. In conclusion, the low-rank SVD is going to be useful only for large sparse matrices where the full-rank SVD will fail due to memory limitations.
    • torch.lobpcg vs scipy.sparse.linalg.lobpcg, see notebook LOBPCG - pytorch vs scipy. In conculsion, both implementations give the same results (up to numerical errors from different methods), scipy lobpcg implementation is generally faster.
    • On very small tolerance cases, torch.lobpcg is more robust than scipy.sparse.linalg.lobpcg (see test_lobpcg_scipy results)

Resolves #8049.

@pearu pearu self-assigned this Nov 8, 2019
@pearu pearu changed the title PCA and SVD for low-rank matrices [WIP] PCA and SVD for low-rank matrices, LOBPCG for positive-defined generalized eigenvalue problem [WIP] Nov 20, 2019
@lobpcg
Copy link

lobpcg commented Nov 21, 2019

LOBPCG Algorithm 1 from Duersch et al, 2018 appears to simply be the original Algorithm 5.1 from A. V. Knyazev, Toward the Optimal Preconditioned Eigensolver: Locally Optimal Block Preconditioned Conjugate Gradient Method. SIAM Journal on Scientific Computing 23 (2001), no. 2, pp. 517-541. http://dx.doi.org/10.1137/S1064827500366124 It is probably appropriate the cite the original paper...

Also, this implementation may become unstable for various reasons.
More stable, but still simple, versions are described at
I. Lashuk, M. E. Argentati, E. Ovchinnikov and A. V. Knyazev, Preconditioned Eigensolver LOBPCG in hypre and PETSc. In Lecture Notes in Computational Science and Engineering, v. 55 (Proceedings of the 16th International Conference on Domain Decomposition Methods. 2005). Editors: O.~B. Widlund and D.~E. Keyes, pages 635-642. Springer, Berlin, 2007. ISBN: 3-540-34468-3. (http://math.ucdenver.edu/~aknyazev/research/papers/DD16/knyazev_contrib_revised/dd16.pdf)
or simply follow the latest code
https://github.com/scipy/scipy/blob/master/scipy/sparse/linalg/eigen/lobpcg/lobpcg.py

@pearu
Copy link
Collaborator Author

pearu commented Nov 21, 2019

@lobpcg Thanks for your comment!
Yes, I am aware of the possible instability issues with the basic version of LOBPCG algorithm.
I implemented it for reference and plan to implement also the more robust versions of the LOBPCG.
IIUC, the stability of lobpcg in SciPy is achieved by "soft-locking" the eigenpairs that have converged.
Using soft-locking for batches of eigenproblems is problematic as different batches may have different convergences scenarios and so the soft-locking feature might be made available only for dense and sparse matrix cases.

With the current sparse test matrices, the basic lobpcg works ok. While there are several (large) sparse matrices available for which the basic lobpcg might have problems, using these in pytorch test-site might be unfeasible due to their size. So, I wonder if you could provide any hints for how to generate relatively small sparse matrices where the basic lobpcg is guaranteed to fail?

@lobpcg
Copy link

lobpcg commented Nov 21, 2019

It is not a matter of being sparse or dense, or even large/small. The instability mostly appears when the vectors in the RR become linearly dependent for any reason, unless one runs expensive explicit full orthogonalization prior to RR.

Easy ways to break RR:

  1. run long enough with unreasonably small tolerance, especially in single precision
  2. choose the block size large enough, e.g., n/6, where n is the matrix size
  3. run in a loop with random initial guesses - some will fail
  4. run with random initial guesses, but using a poor random number generator with a short cycle, relative to n, which thus creates a special block structure in the initial guess

And there are few trickier ones, with special choices of the initial guesses.

It is difficult, but still possible to break the latest code
https://github.com/scipy/scipy/blob/master/scipy/sparse/linalg/eigen/lobpcg/lobpcg.py
so you can use it as a base for comparison when your code fails.

@pearu
Copy link
Collaborator Author

pearu commented Dec 8, 2019

@pytorchbot rebase this please

@kostmo
Copy link
Member

kostmo commented Dec 28, 2019

💊 CircleCI build failures summary and remediations

As of commit 76c3cfb (more details on the Dr. CI page):


Commit 76c3cfb was recently pushed. Waiting for builds...


This comment was automatically generated by Dr. CI (expand for details).Follow this link to opt-out of these comments for your Pull Requests.

Please report bugs/suggestions on the GitHub issue tracker.

This comment has been revised 81 times.

@pearu pearu force-pushed the pearu/lowrank-linalg branch 3 times, most recently from 65abdb7 to 0717e11 Compare January 4, 2020 11:30
@pearu pearu changed the title PCA and SVD for low-rank matrices, LOBPCG for positive-defined generalized eigenvalue problem [WIP] PCA and SVD for low-rank matrices, LOBPCG for positive-defined generalized eigenvalue problem Jan 4, 2020
@pearu pearu requested a review from ezyang January 4, 2020 11:42
@pearu
Copy link
Collaborator Author

pearu commented Jan 4, 2020

The PR is ready for review.

@lobpcg
Copy link

lobpcg commented Jan 6, 2020

This PR implementations of LOBPCG do not follow
https://github.com/scipy/scipy/blob/master/scipy/sparse/linalg/eigen/lobpcg/lobpcg.py
which is stable, while still avoiding any expensive QR-based orthogonalization.

Not a blocker, but may want to keep this in mind if there would be a need in the future to improve performance for large block sizes.

Thanks for your implementations!

@ezyang
Copy link
Contributor

ezyang commented Jan 8, 2020

I'm working on finding some good reviewers for this PR.

@ezyang ezyang requested a review from vincentqb January 8, 2020 22:00
@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2020

@vincentqb has graciously accepted to review this PR. @nikitaved, if you also want to bill Quansight time to help review this PR, that would also be fine by me.

@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2020

@lobpcg How does this diff look to you? Happy to assign you as a reviewer too.

@lobpcg
Copy link

lobpcg commented Jan 9, 2020

@ezyang I support this PR, but unfamiliar with pytorch. And this PR code is rather long, so I am unable to formally review, but thanks for asking.

I've looked briefly at a couple of core functions, and not noticed anything troubling, just had a comment #29488 (comment)

@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2020

@pearu it may also help reviewers quite a bit if we split this PR into one per piece of functionality, if this is easily possible (I haven't read it yet so I don't know if there's some dependence)

@pearu
Copy link
Collaborator Author

pearu commented Jan 9, 2020

Indeed, this PR implements two new features, low-rank SVD and LOBPCG, which are independent methods. However, the expected expertise of reviewers is the same and both features depend on some new utility methods needed for testing (see tests/common_utils.py), and some minor fixes in torch/_six.py and torch/serialization.py.

@zou3519 zou3519 added the triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module label Jan 9, 2020
@ezyang
Copy link
Contributor

ezyang commented Jan 9, 2020

That's cool. In that case the utility of splitting would mostly be being able to land one part earlier than the rest, but if we're not in a rush let's just keep it together.

@pearu pearu requested a review from nikitaved January 14, 2020 19:41
Copy link
Contributor

@vincentqb vincentqb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I've done a first pass on SVD/PCA.

@pearu pearu force-pushed the pearu/lowrank-linalg branch from b7c3b41 to e36ccec Compare January 18, 2020 20:51
@pearu
Copy link
Collaborator Author

pearu commented Jan 19, 2020

Thanks @vincentqb for the review of the SVD/PCA part. I have addressed all your questions and concerns. There is an open question of whether we should keep the complex input support or not because the pytorch complex support is incomplete currently.

@pearu pearu force-pushed the pearu/lowrank-linalg branch from 55a362f to f5385d7 Compare March 13, 2020 15:59
@vincentqb
Copy link
Contributor

@vincentqb Update from a JIT developer: apparently we're NOT supposed to put torch.jit.script annotations in core library #33418 (comment)

So if deleting that annotation suffices, that looks good too.

Let's remove the annotation for now. We can open a separate pull request to make this jitable, and discuss why decorating doesn't work.

@pearu
Copy link
Collaborator Author

pearu commented Mar 13, 2020

@vincentqb I believe my last commit fixes the issue: the decorator is removed and lobpcg is torchscript jit'able.

Copy link
Contributor

@vincentqb vincentqb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vincentqb
Copy link
Contributor

vincentqb commented Mar 13, 2020

Phabricator is refusing to update the original internal diff. We'll need to open a new PR to land the change. I'll close this one in the meanwhile.

@pearu -- can you push the change to a new PR, and link to this one? I'll approve it and merge it from there.

@pearu
Copy link
Collaborator Author

pearu commented Mar 13, 2020

@vincentqb done creating a new PR.
Thanks!

vincentqb added a commit to vincentqb/pytorch that referenced this pull request Mar 16, 2020
facebook-github-bot pushed a commit that referenced this pull request Mar 16, 2020
…lized eigenvalue problem - copy (#34721)

Summary:
This is a copy of PR #29488 to help the merging process.
Pull Request resolved: #34721

Differential Revision: D20444270

Pulled By: vincentqb

fbshipit-source-id: 042c56c8c0dae37834f52b4aee2deae7dd6fa659
@pearu pearu deleted the pearu/lowrank-linalg branch March 17, 2020 14:02
@dvirginz
Copy link

@pearu - Amazing work, thanks a lot!
Used it for LBO decompositions, and compared it to Reuter's 2009.
Thank you!

@vincentqb
Copy link
Contributor

@pearu, @ezyang, @vincentqb What do you think about some advertisement for this method? I could write, for example, a tutorial on Spectral Clustering with different Graph-Laplacians for MNIST/Fashion-MNIST and use LOBPCG/SVD/whatever for it. Could be useful for benchamarking as well...

@nikitaved @lobpcg -- Are you interested in writing about this? :)

@nikitaved
Copy link
Collaborator

@vincentqb , absolutely!

@vincentqb
Copy link
Contributor

Great! I'm adding @wookim3 to the loop.

@jspisak
Copy link
Contributor

jspisak commented May 1, 2020

this is really cool, thanks for working on this!!

@lobpcg
Copy link

lobpcg commented May 1, 2020

I do not think I can write it, never running pytorch myself, but I would be glad to review/edit. Please feel free to ping me.

@wookim3
Copy link

wookim3 commented May 5, 2020

@nikitaved - Thank you! To get started, can you share your email address? We can create a Google doc and collaborate together on there.

cc @vincentqb

@nikitaved
Copy link
Collaborator

nikitaved commented May 5, 2020

@wookim3, sure, [email protected] it is. Thank you! But just so it is clear, it is a tutorial we are talking about, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

open source triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature request] [pytorch] Truncated SVD