Thursday, March 31, 2011

GraphLab on BlackLight?

I am very excited to report a recent meeting of Graphlab team with Joel Welling from Pittsburgh Supercomputing Center. We are in the process of porting GraphLab to BlackLight platform, a 4,096 cores supercomputer with 32TB of shared memory.

Currently, a preliminary mullticore version of GraphLab was ported to BlackLight by Joel Welling, for using the CoEM NLP algorithm. I applied for an account, and I can't wait to be approved and play with GraphLab on this machine. Not everyone gets an opportunity to run on a 2.8M$ machine..

The GraphLab team is planning to participate in PSC Data Analytics Symposium April 14,15 Pittsburgh. Anyone who is planning to be there and interested about GraphLab is welcome to meet us.

I plan to experiment with PMF matrix factorization algorithm and report the results here.

Monday, March 21, 2011

Large scale matrix factorization - Yahoo! KDD Cup

Recently I learned from Sean Owen about this year Yahoo! KDD Cup

This is a great opportunity to get large scale data, for testing matrix factorization algorithms. (Specifically I am using GraphLab Matrix factorization ).

In track1, the task is to predict user music recommendations. There are about 1M users, 600K music titles, and about 252M non-zero ratings in the training data. (To compare to Netflix, there where only 50K users, 500K movies and about 100M non-zero ratings). Unlike Netflix, the ratings are between 0-100 (and not 1-5). In matrix factorization context, need to think how to represent a rating of zero vs. non existing rating.

For a start, I have tested GraphLab matrix factorization data with the track1 dataset. On an 8 core machine (2x4 cores Intel Xeon 2.67 Ghz) each alternating least squares iteration takes around 150 seconds. After 10 iterations I get training RMSE of 21.7 and validation RMSE of 22.5.

For reader's requests, I have posted some more detailed instructions on how to run GraphLab on KDD Cup data here

Here is the output of the GraphLab program:

<40|0>bickson@bigbro6:~/newgraphlab/graphlabapi/release/demoapps/pmf$ ./pmf kddcup 0 --ncpus=8 --float=true --zero=true --scheduler="round_robin(max_iterations=10)" --lambda=2 --D=25
Setting run mode ALS_MATRIX
INFO   :pmf.cpp(main:1236): PMF starting

loading data file kddcup
Loading kddcup TRAINING
Matrix size is: 1000990 624961 1
Creating 252800275 edges...
.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................loading data file kddcupe
Loading kddcupe VALIDATION
Matrix size is: 1000990 624961 1
Creating 4003960 edges...
.....................loading data file kddcupt
Loading kddcupt TEST
Matrix size is: 1000990 624961 6649
Creating 6005940 edges...
...............................setting regularization weight to 2
PTF_ALS for matrix (1000990, 624961, 6649):252800275.  D=25
pU=2, pV=2, pT=1, muT=1, D=25
nuAlpha=1, Walpha=1, mu=0, muT=1, nu=25, beta=1, W=1, WT=1 BURN_IN=10
complete. Obj=4.85306e+11, TRAIN RMSE=61.9632 TEST RMSE=75.7155.
INFO   :asynchronous_engine.hpp(run:79): Worker 0 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 1 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 2 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 3 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 4 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 5 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 6 started.

INFO   :asynchronous_engine.hpp(run:79): Worker 7 started.

Entering last iter with 1
161.488) Iter ALS 1  Obj=4.63853e+11, TRAIN RMSE=60.5707 TEST RMSE=26.6540.
Entering last iter with 2
301.86) Iter ALS 2  Obj=9.7782e+10, TRAIN RMSE=27.7971 TEST RMSE=26.0930.
Entering last iter with 3
445.925) Iter ALS 3  Obj=8.91077e+10, TRAIN RMSE=26.5305 TEST RMSE=24.1940.
Entering last iter with 4
585.759) Iter ALS 4  Obj=7.09672e+10, TRAIN RMSE=23.6696 TEST RMSE=23.0499.
Entering last iter with 5
727.565) Iter ALS 5  Obj=6.42765e+10, TRAIN RMSE=22.5229 TEST RMSE=22.6883.
Entering last iter with 6
870.943) Iter ALS 6  Obj=6.17103e+10, TRAIN RMSE=22.0672 TEST RMSE=22.5748.
Entering last iter with 7
1011.14) Iter ALS 7  Obj=6.06398e+10, TRAIN RMSE=21.8743 TEST RMSE=22.5319.
Entering last iter with 8
1153.29) Iter ALS 8  Obj=6.01234e+10, TRAIN RMSE=21.7807 TEST RMSE=22.5117.
Entering last iter with 9
1292.27) Iter ALS 9  Obj=5.98422e+10, TRAIN RMSE=21.7295 TEST RMSE=22.5004.
INFO   :asynchronous_engine.hpp(run:89): Worker 5 finished.

Entering last iter with 10
INFO   :asynchronous_engine.hpp(run:89): Worker 0 finished.

INFO   :asynchronous_engine.hpp(run:89): Worker 1 finished.

INFO   :asynchronous_engine.hpp(run:89): Worker 4 finished.

INFO   :asynchronous_engine.hpp(run:89): Worker 7 finished.

INFO   :asynchronous_engine.hpp(run:89): Worker 2 finished.

INFO   :asynchronous_engine.hpp(run:89): Worker 6 finished.

1430.98) Iter ALS 10  Obj=5.96712e+10, TRAIN RMSE=21.6983 TEST RMSE=22.4935.
INFO   :asynchronous_engine.hpp(run:89): Worker 3 finished.

Final result. Obj=5.96743e+10, TRAIN RMSE= 21.6989 TEST RMSE= 22.4935.
Exporting KDD cup test graph: kddcupt.kdd.out
**Completed successfully (mean prediction: 64.919045)**
Finished in 1437.142338 
Counters are: 0) EDGE_TRAVERSAL, 6038.63
Counters are: 1) BPTF_SAMPLE_STEP, 0
Counters are: 2) CALC_RMSE_Q, 0.044609
Counters are: 3) ALS_LEAST_SQUARES, 3258.77
Counters are: 4) NA, 0
Counters are: 5) BPTF_TIME_EDGES, 0
Counters are: 6) BPTF_LEAST_SQUARES, 0
Counters are: 7) CALC_OBJ, 3.51506
Counters are: 8) NA, 0
Counters are: 9) BPTF_MVN_RNDEX, 0
Counters are: 10) BPTF_LEAST_SQUARES2, 0

 === REPORT FOR core ===
[Numeric]
ncpus:          8
[Other]
affinities:     false
compile_flags:  -O3 -Wall -g -mfpmath=sse -msse2 -funroll-loops -fprefetch-loop-arrays -fopenmp
engine: async
scheduler:      round_robin
schedyield:     true
scope:  edge

 === REPORT FOR engine ===
[Numeric]
num_edges:              2.528e+08
num_syncs:              0
num_vertices:           1.62595e+06
updatecount:            1.62595e+07     (count: 8, min: 1.97158e+06, max: 2.11913e+06, avg: 2.03244e+06)
[Timings]
runtime:                1412.8 s
[Other]
termination_reason:     task depletion (natural)
[Numeric]
updatecount_vector:             1.62595e+07     (count: 8, min: 1.97158e+06, max: 2.11913e+06, avg: 2.03244e+06)
updatecount_vector.values:              1.99981e+06,2.01133e+06,1.97158e+06,2.08794e+06,2.00821e+06,2.11913e+06,2.02736e+06,2.03415e+06,


I wrote a simple Matlab script to parse the text input files into sparse Matlab matrix. Here it is:
%Written by Danny Bickson, CMU, March 211
%This script reads KDD cup track1 format and saves
%it into a sparse Matlab matrix
nUsers=1000990;
nItems=624961;
nRatings=262810175;
nTrainRatings=252800275;
nProbeRatings=4003960;
nTestRatings=6005940;


runmode=1; % 1 for training, 2 for probe, 3 for test

switch runmode
    case 1
        filename='/path/to/trainIdx1.txt';
        ratings=nTrainRatings;
        outfile='/path/to/train1.mat';
    case 2
        filename='/path/to/validationIdx1.txt';
        ratings=nProbeRatings;
        outfile='/path/to/probe1.mat';
    case 3
        filename='/path/to/testIdx1.txt';
        ratings=nTestRatings;
        outfile='/path/to/test1.mat';
end
rows=zeros(ratings,1);
cols=rows;
vals=rows;
try

ff=fopen(filename,'r');
cnt=1;
for j=1:nUsers
  % read user id and number of ratings
  [a,num]=fscanf(ff,'%d|%d',2);
  assert(num==2);

  user=a(1);  
  numofratings=a(2);
  if (mod(j,1000)==0)
      disp(['user: ', num2str(user),' ratings: ', num2str(numofratings)]);
  end
  if (runmode==3)
      assert(numofratings==6); % 6 ratings per each user in test file
  else if (runmode == 2)
      assert(numofratings==4); % 4 ratings per user in probe file
  end


  for i=1:numofratings % for each ratings
    b=-100;
    if (runmode<=2)
        [b,num]=fscanf(ff,'%d %d %d %d:%d:%d',6);
        assert(num==6);
    else
        [b,num]=fscanf(ff,'%d %d %d:%d:%d',5);
        assert(num==5);
    end
    rows(cnt)=user+1;  % user
    assert(rows(cnt)>=1 && rows(cnt)<=nUsers);
    cols(cnt)=b(1)+1; % item
    assert(cols(cnt)>=1 && cols(cnt)<=nItems);

    if (runmode<=2)
        vals(cnt)=b(2); % rating
        assert(vals(cnt)>=0 && vals(cnt)<=100);
    else
        vals(cnt)=1; % placeholder for missing rating
    end
    cnt=cnt+1;
  end
end

assert(cnt==ratings+1);

catch ex
    disp(['exception on ', num2str(i), ' ', num2str(j)]);
    ex
end

% construct and save a sparse Matlab matrix
A=sparse(double(rows), double(cols), double(vals));
save(outfile,'-v7.3','A');

Friday, March 4, 2011

Tuning Hadoop configuration for high performance - Mahut on Amazon EC2

In this post I will share some of the insights I got when tuning Hadoop/Mahout on Amazon EC regular and high performance nodes. I was using two algorithms.
1) Mahout's Alternating least squares application (See MAHOUT-542) with Netflix data. (Sparse matrix with 100,000,000 non zeros). Test was done with up to 64 HPC nodes (512 cores).
2) CoEM algorithm - NLP algorithm (R. Jones, 2005) with data graph of around 200,000,000 edges.

Below are running time results for running one iteration of alternating least squares (implemented by Sebastian Schelter) on Netflix data. Runtime is in seconds.
X-axis are the participating machines - from 4 to 64 machines.











My conclusion from this experiment, is that 16 HPC nodes (256 cores) are enough for computing matrix factorization/CoEM of this scale. Beyond 16 nodes there is no benefit in further parallism.

Below I explain how I fine-tuned performance.
Preliminaries: I assume you followed the instruction on  part 1 of this tutorial to setup Hadoop on EC2.


1) The hdfs-site.xml file
dfs.replication
- I set dfs replication to 1. Replication determines the number of copies the hdfs data is saved on. When working with a relative low number of nodes (several) higher replication delays performance.

hadoop.tmp.dir
hadoop.data.dir
dfs.name.dir
You should set all those directories to point to DIFFERENT paths which have ENOUGH DISK SPACE.
Default hadoop configuration points to either /tmp or /usr/local/hadoop-0.20.2/ and in Amazon
EC2 there is a 10Gb disk space limit for the root partition. To increase available storage,
on regular nodes I set the above fields to /mnt/tmp1, /mnt/tmp2/ and /mnt/tmp3
On HPC nodes, I first mounted /dev/sdb using the command:
mkdir -p /home/data
mount -t ext3 /dev/sdb/ /home/data/
And then created /home/data/tmp1 /home/data/tmp2 /home/data/tmp3 and pointed the above fields to there.

dfs.block.size
The default is 64MB. For CoEM set it to 4MB, so there will be enough mappers for all cores. For Netflix data I set it to 16MB. When the block size is too small, there are too manny mappers, resulting in loading the system, having many task failures, and some of the job trackers gets black-listed. Having too few mappers does not exploit well parallism. Unfortunately it seems that block size should be tuned separately for each algorithm.

2) The file core-site.xml should be configured as explained in the first part of this post.

3) The file mapred-site.xml
mapred.map.task
empirically setting them to the number of  cores -1 seemed to work the best. (On HPC nodes, 15 cores). Note that this number is per machine.
mapred.reduce.task
Common practice says to set it to 0.95 * number of machines * (number of cores-1).
For me that did not work well, especially with 64 machines - reduce phase becomes terribly slow with very slow copying phase (in Kb instead of MB). Finally I set it to 64 for all experiments.

mapred.tasktracker.map.tasks.maximum, mapred.tasktracker.reduce.tasks.maximum
set them to the values above. Note that it seems that reduce tasks maximum is a global maximum and not a limit per single machines. So in this case 64 was a global limit of 64 reduce tasks.

mapred.task.timeout, mapred.tasktracker.expiry.interval
default is 600000 milliseconds which was too low for ALS. If the interval is too low, task will be killed prematurely. I set it to 7200000
mapred.task.tracker.expiry.interval
don't ask me what is the difference to previous field - probably a bug. Anyway I set it as well.

mapred.compress.map.output, mapred.output.compress
again I set those fields to true. It reduced
significantly the disk writes to about 1/3 the size.

mapred.child.java.opts
set it to -Xmx2500Mb , the default is 500, which results in out of memory errors, java heap errors and GC errors.


4) The file hadoop-env.sh
On HPC nodes, set
JAVA_HOME=/usr/lib/jvm/jre-openjdk
On regular nodes, set
JAVA_HOME=/usr/lib/jvm/java-6-openjdk
Heap size parameter controls the heap size. When it is too small you get
out of memory error and out of heap size erros.
HADOOP_HEAPSIZE=4000

5) Avoiding string parsing as much as possible
Java string parsing is rather slow. Avoid reading string input files as possible and write the data in binary format whenever possible. For the CoEM algorithm, avoiding string parsing resulted in x4 faster code, since the inputs files where read on each iteration.

Some tips I got from Julio Lopez, OpenCloud project @ CMU:
Block size and controlling the number of mappers. I believe someone already commented on this. In general, you want to have the block sizes relatively large in order to induce your job to perform sequential instead of random I/O. You can use the "InputFormat" to control how the work is split and how many tasks are created.

I've found that the first instincts users have is to match the number of mappers or reducers per node to the number of cores. For many Hadoop applications, this does not work. Properly setting these parameters is application dependent (module the available resources). In Hadoop these are framework-wide parameters. In my experience, how memory is allocated to tasks has a much larger impact on application performance. However, it is not clear how these memory parameters should be set, and there are all sorts of complex interactions among tasks.

For reference, in the cloud cluster, there are 8 cores per node, we allow 10 simultaneous tasks to execute per node and in general we see better throughput that way. As I mentioned earlier, most jobs experience contention for memory.

Interesting related projects/ papers: 
1) http://www.cs.duke.edu/~shivnath/amr.html
2) Kai Ren, Julio López and Garth Gibson. Otus: Resource Attribution in Data-Intensive Clusters. MapReduce: The Second International Workshop on MapReduce and its Applications. San Jose, CA, June 2011. (bib, pdf)


Other useful tips:

When stopping and starting Hadoop you should be very careful since Hadoop generates a zillion of temp file, that if found on the next run makes a mess.

1) I always run from script
echo Y | hadoop namenode -format
Since if the file system was formatted the script will get stuck without getting the "Y" input.

2) Remove all /tmp/*.pid files, or else Hadoop will think some old processes are running.

3) Remove all files in the directories hadoop.tmp.dir, hadoop.data.dir, dfs.name.dir
especially VERSION files. Old VERSION files lead to namespaceID collisions.

4) Delete old logs from /usr/local/hadoop-0.20.2/logs/

Monday, February 28, 2011

The GraphLab large scale machine learning framework - installation on MAC OSX 10.6

GraphLab is an open source large scale parallel machine learning framework.

I was asked by Dan, an avid reader of this blog, to supply installation instructions for MAC OSX Snow Leopard 10.6. Installation is quite simple.

1) Install cmake using the following link: cmake 2.8.4

2) Download graphlab code and install GraphLab where XXX is the latest version you can find in here
wget http://graphlab.org/release/graphlabapi_v1_XXXX.tar.gz
tar xvzf graphlabapi_v1_XXXX.tar.gz
cd graphlabapi
./configure --bootstrap 
cd debug #or equivalently cd release
make -j 4
cd tests
./runtests.sh

Anyone who tries it out - update me if it went smoothly!

NOTE: We now support Eigen linear algebra package. It can be installed using the command:
./configure --bootstrap --eigen
However, on MAC OS, gcc45 is required. See explanation here.

NOTE2: The current GraphLab MAC setup default to gcc-4.2. If you like to use your default compiler, you can comment the first few lines of the file CMakeLists.txt in the root graphlab folder, namely the lines:
if(APPLE)
  set(CMAKE_C_COMPILER "gcc-4.2")
  set(CMAKE_CXX_COMPILER "c++-4.2")
endif(APPLE)

Friday, February 25, 2011

Mahout on Amazon EC2 - part 5 - installing Hadoop/Mahout on high performance instance (CentOS/RedHat)

This post explains how to install Mahout ML framework on top of Amazon EC2 (CentOS/RedHat based machine).
The notes are based on older Mahout notes: https://cwiki.apache.org/MAHOUT/mahout-on-amazon-ec2.html which are unfortunately outdated.

Note: part 1 of this post, explains how to install the same installation on top of Ubuntu based machine.

Full procedure should take around 2-3  hours.. :-(

1) Start high performance instance from amazon aws console
Cent OS AMI ID ami-7ea24a17 (x86_64)  Edit AMI
Name:  Basic Cluster Instances HVM CentOS 5.4   
Description:  Minimal CentOS 5.4, 64-bit architecture, and HVM-based virtualization for use with Amazon EC2 Cluster Instances.

2) Login into the instance (right mouse click on running instance from AWS console)

3) Install some required stuff
sudo yum update
sudo yum upgrade
sudo apt-get install python-setuptools  
sudo easy_install "simplejson"

4) Install boto (unfortunately I was not able to install it using easy_install directly)
wget http://boto.googlecode.com/files/boto-1.8d.tar.gz
tar xvzf boto-1.8d.tar.gz
cd boto=1.8d
sudo easy_install .

5) Install maven2 (unfortunately I was not able to install it using yum)
wget http://www.trieuvan.com/apache/maven/binaries/apache-maven-2.2.1-bin.tar.gz
tar xvzf apache-maven-2.2.1-bin.tar.gz
cp -R apache-maven-2.2.1 /usr/local/
ln -s /usr/local/apache-maven-2.2.1/bin/mvn /usr/local/bin/

6) Download and install Hadoop
wget http://apache.cyberuse.com//hadoop/core/hadoop-0.20.2/hadoop-0.20.2.tar.gz   
tar vxzf hadoop-0.20.2.tar.gz  
sudo  mv hadoop-0.20.2 /usr/local/

add the following to $HADOOP_HOME/conf/hadoop-env.sh
export JAVA_HOME=/usr/lib/jvm/jre-openjdk/  
# The maximum amount of heap to use, in MB. Default is 1000  
export HADOOP_HEAPSIZE=2000  

add the following to $HADOOP_HOME/conf/core-site.xml and also $HADOOP_HOME/conf/mapred-site.xml

<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>   <property>
<name>mapred.job.tracker</name>  
<value>localhost:9001</value>
</property>
 <property>  
<name>dfs.replication</name>  
 <value>1</value>      
  </property>
</configuration>


Edit the file hdfs-site.xml

<configuration>
 <property>
  <name>hadoop.tmp.dir</name>
  <value>/home/data/tmp/</value>
 </property>
<property>
 <name>dfs.data.dir</name>
 <value>/home/data/tmp2/</value>
</property>
<property>
 <name>dfs.name.dir</name>
 <value>/home/data/tmp3/</value>
</property>
</configuration>

Note: directory /home/data does not exist, and you will have to create it
when starting the instance using the commands:
# mkdir -p /home/data  
# mount -t ext3 /dev/sdb/ /home/data/ 
The reason for this setup is that the root dir has only 10GB, while /dev/sdb/
has 800GB.

set up authorized keys for localhost login w/o passwords and format your name node
# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

  • Checkout and build Mahout from trunk. Alternatively, you can upload a Mahout release tarball and install it as we did with the Hadoop tarball (Don't forget to update your .profile accordingly).

    # svn co http://svn.apache.org/repos/asf/mahout/trunk mahout
    # cd mahout
    # mvn clean install
    # cd ..
    # sudo mv mahout /usr/local/mahout-0.4
    


    4)Add the following to your .profile
    export JAVA_HOME=/usr/lib/jvm/java-6-openjdk
    export HADOOP_HOME=/usr/local/hadoop-0.20.2
    export HADOOP_CONF_DIR=/usr/local/hadoop-0.20.2/conf
    export MAHOUT_HOME=/usr/local/mahout-0.4/
    export MAHOUT_VERSION=0.4-SNAPSHOT
    export MAVEN_OPTS=-Xmx1024m
    

    Verify that the paths on .profile point to the exact version you downloaded

    6) Run Hadoop, just to prove you can, and test Mahout by building the Reuters dataset on it. Finally, delete the files and shut it down.

    # $HADOOP_HOME/bin/hadoop namenode -format
    $HADOOP_HOME/bin/start-all.sh
    jps     // you should see all 5 Hadoop processes (NameNode, SecondaryNameNode, DataNode, JobTracker, TaskTracker)
    cd $MAHOUT_HOME
    ./examples/bin/build-reuters.sh
    $HADOOP_HOME/bin/stop-all.sh
    rm -rf /tmp/*   // delete the Hadoop files


  • Remove the single-host stuff you added to $HADOOP_HOME/conf/core-site.xml and $HADOOP_HOME/conf/mapred-site.xml in step #6b and verify you are happy with the other conf file settings. The Hadoop startup scripts will not make any changes to them. In particular, upping the Java heap size is required for many of the Mahout jobs.
    // edit $HADOOP_HOME/conf/mapred-site.xml to include the following:
    <property>
       <name>mapred.child.java.opts</name>
       <value>-Xmx2000m</value>
    </property>

    7) Allow for Hadoop to run even if you will work on a different EC2 machine:
    echo "NoHostAuthenticationForLocalhost yes" >>~/.ssh/config
    

    8) Now bundle the image.
    Using Amazon AWS console - select running instance, right mouse click and then bundle EBS image. Enter image name and description. Now the machine will reboot and the image will be created.
  • Thursday, February 24, 2011

    Some thoughts about accuracy of Mahout's SVD

    I was testing Mahout's SVD code and I encountered some subtleties.
    I wonder if I am missing anything or is there a bug in the code?

    1) The ordering of eigenvalues was the opposite than eigenvectors. But this was hopefully fixed by now in patch-369.
    2) When requesting a rank of 4, we get 3 eigenvalues... So it seems that the rank is always lower by one.
    3) There are two transformations which makes comparison of results with matlab (or pen & paper) harder:

    a) The scaleFactor. Defined in: ./math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosState.java
    I quote a documentation remark in: ./math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java:48
    " /** To avoid floating point overflow problems which arise in power-methods like Lanczos, an initial pass is made
     * through the input matrix to
    generate a good starting seed vector by summing all the rows of the input matrix, and
    compute the trace(inputMatrixt*matrix)
    This latter value, being the sum of all of the singular values, is used to rescale the entire matrix, effectively forcing the largest singular value to be strictly less than one, and transforming floating point overflow
    problems into floating point underflow (ie, very small singular values will become invisible, as they  will appear to be zero and the algorithm will terminate).*/
    

    b) The second transformation is orthonogolization of the resulting vector. This step is optional (IMHO).
    see: ./math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java:118
    The function call is: orthoganalizeAgainstAllButLast(nextVector, state);
    Again I quote from documentation:
    /** 

    This implementation uses {@link org.apache.mahout.math.matrix.linalg.EigenvalueDecomposition} to do the * eigenvalue extraction from the small (desiredRank x desiredRank) tridiagonal matrix. Numerical stability is * achieved via brute-force: re-orthogonalization against all previous eigenvectors is computed after every pass. * This can be made smarter if (when!) this proves to be a major bottleneck. Of course, this step can be parallelized * as well. *


    If anyone wants to reproduce my test, Can can add the function testLanczosSolver2() to TestLanczosSolver.java (code below).
    1) To run it, you need first to comment the line:
    //nextVector.assign(new Scale(1 / scaleFactor));
    in LanczosSolver.java, so it is easier to compare the results to Matlab, without the scaling.
    2) You need to also comment the line:
    //orthoganalizeAgainstAllButLast(nextVector, basis);
    in LanczosSolver.java

    The factorized matrix is:
    >> A
    
    3.1200 -3.1212 -3.0000
    -3.1110 1.5000 2.1212
    -7.0000 -8.0000 -4.0000
    
    The eigenvalues are;
    >> [a,b]=eig(A'*A)
    
    a =
    
    0.2132 -0.8010 -0.5593
    -0.5785 0.3578 -0.7330
    0.7873 0.4799 -0.3871
    
    b =
    
    0.0314 0 0
    0 42.6176 0
    0 0 131.2553
    

    Now I run the unit test testLanczosSolver2 and I get:
    INFO: Lanczos iteration complete - now to diagonalize the tri-diagonal auxiliary matrix.
    Feb 9, 2011 1:25:36 PM org.slf4j.impl.JCLLoggerAdapter info
    INFO: Eigenvector 0 found with eigenvalue 131.25526355941963
    Feb 9, 2011 1:25:36 PM org.slf4j.impl.JCLLoggerAdapter info
    INFO: Eigenvector 1 found with eigenvalue 42.61761063477249
    Feb 9, 2011 1:25:36 PM org.slf4j.impl.JCLLoggerAdapter info
    INFO: Eigenvector 2 found with eigenvalue 0.03137295830779152
    Feb 9, 2011 1:25:36 PM org.slf4j.impl.JCLLoggerAdapter info
    INFO: LanczosSolver finished.
    

    As you can see the eigenvalues are correct.

    @Test
    public void testLanczosSolver2() throws Exception {
    int numRows = 3; int numCols = 3;
    int numColumns = 3;
    SparseRowMatrix m = new SparseRowMatrix(new int[]{numRows, numCols});
    /**
    
        * 3.1200 -3.1212 -3.0000
          -3.1110 1.5000 2.1212
          -7.0000 -8.0000 -4.0000
    
    */
    m.set(0,0,3.12);
    m.set(0,1,-3.12121);
    m.set(0,2,-3);
    m.set(1,0,-3.111);
    m.set(1,1,1.5);
    m.set(1,2,2.12122);
    m.set(2,0,-7);
    m.set(2,1,-8);
    m.set(2,2,-4);
    
    int rank = 4;
    Matrix eigens = new DenseMatrix(rank, numColumns);
    long time = timeLanczos(m, eigens, rank, false);
    assertTrue("Lanczos taking too long! Are you in the debugger? ", time < 10000);
    }
    
    Update: June 1st, 2011: Now GraphLab has also an efficient SVD Lanczos solver. Some performance benchmarks are found here:

    The GraphLab machine learning framework on Amazon EC2 - part 2 - testing

    This page has moved.

    For linear solver example applications see: http://graphlab.org/gabp.html

    For matrix factorization example applications see http://graphlab.org/pmf.html

    For clustering example applications see http://graphlab.org/clustering.html