Mahout源码分析DistributedLanczosSolver(3)--Job2

来源:互联网 发布:添加网络打印机步骤 编辑:程序博客网 时间:2024/06/03 11:04

Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit。

1. 前奏:

本篇接着上篇继续分析,分析LanczosSolver中的:Vector nextVector = isSymmetric ? corpus.times(currentVector) : corpus.timesSquared(currentVector);之后。前篇说到这个是建立了一个job任务,并且按照一定的算法求得了一个nextVector,那么接下来是?

if (state.getScaleFactor() <= 0) {        state.setScaleFactor(calculateScaleFactor(nextVector));      }
这里首先判断getScaleFactor的值是否小于等于0,因为刚开始的时候初始化scaleFactor = 0;,所以这里要调用calculateScaleFactor(nextVector)函数:

protected double calculateScaleFactor(Vector nextVector) {    return nextVector.norm(2);  }
这个是如何计算的呢?else if (power == 2.0) { return Math.sqrt(dotSelf()); 这个就是norm函数中当参数是2的时候调用的代码了,所以这里返回的是先nextVector自点乘,然后开根号;(测试的时候这个值是:2029123.4011255247,excel计算的这个值是:2034667.82368468)接下来:

 nextVector.assign(new Scale(1.0 / state.getScaleFactor()));
nextVector 乘以1除以scaleFactor其实就是nextVector除以scaleFactor而已,数值太大了要变小点?经过这一步,nextVector变为:

{0:0.011875906226907599,1:0.0017759586067652153,2:0.0021729514771005837,3:0.014292365192727802,4:0.09660595016979406,5:0.002638859113021243,6:0.0026868791091140517,7:2.476888783392492E-4,8:0.001831833994868574,9:0.005012618192500366,10:8.604490527160895E-4,11:0.0029456317791350514,12:0.9951190694939772}
excel里面变为:

0.01187710.0017762260.0021732280.014294310.0966174390.002638990.00268705000.0050126000.99511791可见,由于误差,excel中的数据直接变为0了(比较小的数值);

接下来还是更新nextVector的:

 double alpha = currentVector.dot(nextVector);      nextVector.assign(currentVector, new PlusMult(-alpha));
首先是currentVector和nextVector的点积,然后用nextVector中的项减去currentVector中的项乘以alpha的值更新nextVector中的项;上面的测试结果,alpha的值为:0.315642761491587,excel计算的值是0.31564687543564,这里就很接近了;然后是nextVector的值:

{0:-0.07566764464132066,1:-0.08576759226146304,2:-0.08537059939112766,3:-0.07325118567550044,4:0.009062399301565813,5:-0.08490469175520701,6:-0.0848566717591142,7:-0.087295861989889,8:-0.08571171687335968,9:-0.08253093267572789,10:-0.08668310181551216,11:-0.0845979190890932,12:0.9075755186257489}
excel中的值是:

-0.075668-0.08576847-0.08537146-0.0732503820.009072747-0.0849057-0.0848576-0.1-0.1-0.082532-0.1-0.10.90757322接着是:

endTime(TimingSection.ITERATE);      startTime(TimingSection.ORTHOGANLIZE);      orthoganalizeAgainstAllButLast(nextVector, state);      endTime(TimingSection.ORTHOGANLIZE);
endTime和startTime应该只是和目录有关的设置吧,这里不管了,直接看orthoganalizeAgainstAllButLast函数:

protected void orthoganalizeAgainstAllButLast(Vector nextVector, LanczosState state) {    for (int i = 0; i < state.getIterationNumber(); i++) {      Vector basisVector = state.getBasisVector(i);      double alpha;      if (basisVector == null || (alpha = nextVector.dot(basisVector)) == 0.0) {        continue;      }      nextVector.assign(basisVector, new PlusMult(-alpha));    }  }
这个函数的操作就是使用bisis来更新nextVector,更新采用原始值减去basisVector对应值乘以(nextVector和basisVector的点积)来更新;第一次basisVector中只有一个值,是13个1初始根号13的向量,那么更新后的nextVector是:

{0:-0.07566764464132064,1:-0.08576759226146302,2:-0.08537059939112765,3:-0.07325118567550043,4:0.009062399301565828,5:-0.084904691755207,6:-0.08485667175911418,7:-0.08729586198988899,8:-0.08571171687335967,9:-0.08253093267572788,10:-0.08668310181551214,11:-0.08459791908909318,12:0.9075755186257489}
感觉和之前没有啥差别,因为nextVector和basisVector的点积很小的缘故;接下来是:

beta = nextVector.norm(2);
额,这个函数之前分析过:就是nextVector自己点积,然后开根号即可,得到的beta值是:0.9488780991876485,然后判断alpha和beta是否超过某个数,如下:

if (outOfRange(beta) || outOfRange(alpha)) {        log.warn("Lanczos parameters out of range: alpha = {}, beta = {}.  Bailing out early!",            alpha, beta);        break;      }
看到outOfRange函数:

private static boolean outOfRange(double d) {    return Double.isNaN(d) || d > SAFE_MAX || -d > SAFE_MAX;  }
由于SAFE_MAX=1.0E150,所以肯定是不会超过的;那么就继续往下分析了;

nextVector.assign(new Scale(1 / beta));      state.setBasisVector(i, nextVector);      previousVector = currentVector;      currentVector = nextVector;      // save the projections and norms!      triDiag.set(i - 1, i - 1, alpha);      if (i < desiredRank - 1) {        triDiag.set(i - 1, i, beta);        triDiag.set(i, i - 1, beta);      }      state.setIterationNumber(++i);
感觉和刚才一样了,nextVector先出示beta的值,然后设置basisVector的第1个值(所谓第1个值是因为这时i为1,计数从0开始),那么basisVector就有两个值了,第0个是13个1除以根号13,第1个是nextVector了;然后重新赋值,previousVector、currentVector,最后就是triDiag的设置了,这个是一个3乘以3的矩阵,这个3是前面设置的rank值;triDiag设置后的值是:

[[0.315642761491587, 0.9488780991876485, 0.0], [0.9488780991876485, 0.0, 0.0], [0.0, 0.0, 0.0]]

2. 循环,job2

接着开始第二次while循环,使用nextVector更新后的currentVector再针对输入数据跑一边job1的算法;感觉这里的rank值有点像是控制循环的次数的感觉;由于这里i初始就被设置为1了,而且rank设置为3,所以这里只循环两次;最后循环完成后,triDiag的值是:

[[0.315642761491587, 0.9488780991876485, 0.0], [0.9488780991876485, 2.855117440373572, 0.0], [0.0, 0.0, 0.0]]
因为接下来就是只对这个值进行操作,所以记录下这个值;

3.处理triDiag(3*3矩阵)

首先是初始化:

EigenDecomposition decomp = new EigenDecomposition(triDiag);
看着个初始化做的事情:首先去判断triDiag是否是对称的,是的话就执行if里面的操作:

public EigenDecomposition(Matrix x, boolean isSymmetric) {    n = x.columnSize();    d = new DenseVector(n);    e = new DenseVector(n);    v = new DenseMatrix(n, n);    if (isSymmetric) {      v.assign(x);      // Tridiagonalize.      tred2();      // Diagonalize.      tql2();    } else {      // Reduce to Hessenberg form.      // Reduce Hessenberg to real Schur form.      hqr2(orthes(x));    }  }
assign就是把x赋值给v,tred2和tql2是做什么的呢?

额,吓我一跳,because 太他X长了,果然java不适合做矩阵处理。。。


分享,成长,快乐

转载请注明blog地址:http://blog.csdn.net/fansy1990


原创粉丝点击