Not long ago, I have released GraphLab SVD version 2. This is an experimental and improved version of the SVD in version 1. I am already getting a lot of feedback and early users who want to try it out. Here is a quick tutorial on how to try it out.
Installation
Checkout GraphLab using the instructions in our
download page.
After your pull from mercurial do:
hg pull
hg update v2
./configure
cd release
make -j4
Preparing the matrix
There are two possible inputs for the SVD solver.
a)
Matrix market format as explained
here. This format is slower but more readable and recommended for beginners.
NOTE: For using this format, you will need to verify that the macro USE_GRAPH2 is defined
at the file toolkits/matrix_factorization/gklanczos.cpp. (This will be soon changed to a command line argument).
b)
Binary format. This is much faster format. For converting to this format, you will need to have your matrix in
sparse matrix market format. Then you can use the application
matmat2bin (matrix market to binary) for converting your data into binary format.
Example conversion. Assume we have a matrix A2 given by:
<235|0>bickson@bigbro6:~/ygraphlab/graphlabapi/debug/toolkits/parsers$ cat A2
%%MatrixMarket matrix coordinate real general
3 4 12
1 1 0.8147236863931789
1 2 0.9133758561390194
1 3 0.2784982188670484
1 4 0.9648885351992765
2 1 0.9057919370756192
2 2 0.6323592462254095
2 3 0.5468815192049838
2 4 0.1576130816775483
3 1 0.1269868162935061
3 2 0.09754040499940952
3 3 0.9575068354342976
3 4 0.9705927817606157
We can convert it to binary format using the command:
<234|1>bickson@bigbro6:~/ygraphlab/graphlabapi/debug/toolkits/parsers$ ./matmat2bin A2 --outdir=./
WARNING: matmat2bin.cpp(main:66): Eigen detected. (This is actually good news!)
INFO: matmat2bin.cpp(main:68): GraphLab V2 matrix factorization library code by Danny Bickson, CMU
Send comments and bug reports to danny.bickson@gmail.com
Currently implemented algorithms are: Lanczos
WARNING: graph2.hpp(set_use_vcolor:148): Graph vertex color is disabled.
Load matrix A2
INFO: io.hpp(load_matrixmarket_graph:324): Reading matrix market file: A2
Rows: 3
Cols: 4
Nonzeros: 12
Constructing all vertices.
Adding edges.
Graph size: 12
INFO: graph2.hpp(finalize:193): Graph finalized in 0.000921 secs
Writing result to file: ./A2.nodes
Writing result to file: ./A2-r.nodes
Writing result to file: ./A2.weights
Writing result to file: ./A2-r.weights
Writing result to file: ./A2.edges
Writing result to file: ./A2-r.edges
The output is composed of 6 files. Two of them (.nodes and .edges) represent CSR structure, Two of them (-r.nodes and -r.edges) have CSC structure, and the remaining .weights and -r.weights store the edge weights.
NOTE: matmat2bin supports matrices of up to 1 billion non-zeros. For larger matrices contact me for more efficient conversion methods.
Running SVD
Here is an example run for the same matrix A2:
./gklanczos A2 --ncpus=4 --nsv=4 --nv=4 --max_iter=2
WARNING: gklanczos.cpp(main:347): Eigen detected. (This is actually good news!)
INFO: gklanczos.cpp(main:349): GraphLab V2 matrix factorization library code by Danny Bickson, CMU
Send comments and bug reports to danny.bickson@gmail.com
Currently implemented algorithms are: Lanczos
Load matrix A2
INFO: io.hpp(load_matrixmarket_graph:324): Reading matrix market file: A2
Rows: 3
Cols: 4
Nonzeros: 12
Constructing all vertices.
INFO: graph3.hpp(load_directed:651): A2 Read 7 nodes
INFO: graph3.hpp(load_directed:656): A2 Read 12 edges
INFO: graph3.hpp(load_directed:662): A2 Read: 12 weights
INFO: graph3.hpp(load_directed:665): A2 Read: 12 reverse weights
INFO: gklanczos.cpp(lanczos:138): Starting iteration: 1 at time: 0.000109
INFO: gklanczos.cpp(lanczos:154): Starting step: 1 at time: 0.000227
INFO: gklanczos.cpp(lanczos:154): Starting step: 2 at time: 0.000652
INFO: gklanczos.cpp(lanczos:154): Starting step: 3 at time: 0.001225
Singular value 0 2.16097 Error estimate: 1.08256e-15
Singular value 1 0.97902 Error estimate: 1.8651e-15
Singular value 2 0.554159 Error estimate: 8.61711e-16
Singular value 3 5.39089e-65 Error estimate: 3.15243e-16
Lanczos finished in 0.003244
INFO: io.hpp(write_output_vector:768): Going to write output to file: A2.singular_values (vector of size: 4)
Command line arguments
--data= //input file name. Note that even for the binary format, the header of the matrix market file (first 2-3 lines) should be present, at the same folder where the .nodes, .edges, and .weights files are found.
--nv= //number of inner steps of each iterations. Typically the number should be greater than the number of singular values you look for.
--nsv= //number of singular values computed
--max_iter= //number of restarts. 2 = no restart.
--ncpus= //number of used cores
--ortho_repeats= //number of repeats on the orthogonalization step. Default is 1 (no repeats). Increase this number for higher accuracy but slower execution. Maximal allowed values is 3.
--debug= //extended debugging information
--tol = //convergence threshold. For large matrices set this number set this number higher (for example 1e-1, while for small matrices you can set it to 1e-16). As smaller the convergence threshold execution is slower.
--initial_vector= //matrix market file where the initial guess vector is stored. Optional.
--save_vectors= //true to save vectors U and V to file.
Reading the output
The output of the program is a matrix market vector with the computed singular value. File location is printed in the program log. For example:
INFO: io.hpp(write_output_vector:768): Going to write output to file: A2.singular_values (vector of size: 4)
And here is the output file in our A2 example:
%%MatrixMarket matrix array real general
%%GraphLab SVD Solver library. This file contains the singular values.
4 1 4
2.160971179601
0.97902007969
0.5541592971957
5.390893684725e-65
Optionally, you can also store the computed eigenvectors U and V using the flag --save_vectors=true. In that case a separate file will be created for each vector U_i and V_i.
Understanding the error measure
Following Slepc, the error measure is computed by a combination of:
sqrt( ||Av_i - sigma(i) u_i ||_2^2 + ||A^Tu_i - sigma(i) V_i ||_2^2 ) / sigma(i)
Namely, the deviation of the approximation sigma(i) u_i from Av_i , and vice versa.
Scalability
Currently the code was tested with up to 1.2 billion non-zeros on a 24 core machine. Each Lanczos iteration takes 10s of seconds. I am soon going to test it with a 3.5 billion non-zero matrix.
Difference to Mahout
Mahout SVD solver is implemented using the same Lanczos algorithm. However, there are several differences
1) In Mahout there are no restarts, so quality of the solution deteriorates very rapidly, after 5-10 iterations the solution is no longer accurate. Running without restarts can be done using our solution with the --max_iter=2 flag.
2) In Mahout there is a single orthonornalization step in each iteration while in our implementation there are two (after computation of u_i and after v_i ).
3) In Mahout there is no error estimation while we provide for each singular value the approximated error.
4) Our solution is typically x100 times faster than Mahout.