• mahout源码分析之DistributedLanczosSolver(五)Job over


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

    1. Job 篇

    接上篇,分析到EigenVerificationJob的run方法:

    public int run(Path corpusInput,
                     Path eigenInput,
                     Path output,
                     Path tempOut,
                     double maxError,
                     double minEigenValue,
                     boolean inMemory,
                     Configuration conf) throws IOException {
        this.outPath = output;
        this.tmpOut = tempOut;
        this.maxError = maxError;
        this.minEigenValue = minEigenValue;
    
        if (eigenInput != null && eigensToVerify == null) {
          prepareEigens(conf, eigenInput, inMemory);
        }
        DistributedRowMatrix c = new DistributedRowMatrix(corpusInput, tempOut, 1, 1);
        c.setConf(conf);
        corpus = c;
    
        // set up eigenverifier and orthoverifier TODO: allow multithreaded execution
    
        eigenVerifier = new SimpleEigenVerifier();
    
        // we don't currently verify orthonormality here.
        // VectorIterable pairwiseInnerProducts = computePairwiseInnerProducts();
    
        Map<MatrixSlice, EigenStatus> eigenMetaData = verifyEigens();
    
        List<Map.Entry<MatrixSlice, EigenStatus>> prunedEigenMeta = pruneEigens(eigenMetaData);
    
        saveCleanEigens(new Configuration(), prunedEigenMeta);
        return 0;
      }

    这里先明确几个输入参数,inputPath、outputPath、tempPath就不用多说了, eigenPath就是上篇最后生成的 rawEigenvectors文件;inMemory是false、maxError是0.05,minEigenValue是0.0;顺便说一下,如果直接运行这个类是不行的,比如像下面这样调用:

    package mahout.fansy.svd;
    
    import java.io.IOException;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.mahout.math.hadoop.decomposer.EigenVerificationJob;
    
    public class RunEigenVerificationJob {
    
    	/**
    	 * 调用EigenVerificationJob 
    	 */
    	private static Path prefix=new Path("hdfs://ubuntu:9000");
    	public static void main(String[] args) throws IOException {
    		Path inputPath=new Path(prefix,"/svd/input/wine");
    		Path rawEigenVectorPath=new Path(prefix,"/svd/output1/rawEigenvectors");
    		Path outputPath=new Path(prefix,"/svd/output1/cleanEigenvectors");
    		Path outputTmpPath=new Path(prefix,"/svd/temp");
    		double maxError=0.5;
    		
    		double minEigenvalue=0.0;
    		boolean inMemory=false;
    		Configuration conf=new Configuration();
    		conf.set("mapred.job.tracker", "ubuntu:9001");
    		int result=new EigenVerificationJob().run(inputPath,
                    rawEigenVectorPath,
                    outputPath,
                    outputTmpPath,
                    maxError,
                    minEigenvalue,
                    inMemory,
                    conf);
    		System.out.println("result success?"+(result==0?true:false));
    	}
    
    }
    

    这样调用会出现Runtime Error和file not found的错误,Runtime就不是很明白了,file not found 是因为在temp中的文件是按照时间生成的,然后如果没有和前面的任务在一个总的文件中调用,那么找到的文件目录是找不到的,所以会出现这样的错误。

    接下来,首先会进入prepareEigens方法:

    private void prepareEigens(Configuration conf, Path eigenInput, boolean inMemory) {
        DistributedRowMatrix eigens = new DistributedRowMatrix(eigenInput, tmpOut, 1, 1);
        eigens.setConf(conf);
        if (inMemory) {
          List<Vector> eigenVectors = Lists.newArrayList();
          for (MatrixSlice slice : eigens) {
            eigenVectors.add(slice.vector());
          }
          eigensToVerify = new SparseRowMatrix(eigenVectors.size(), eigenVectors.get(0).size(),
                                               eigenVectors.toArray(new Vector[eigenVectors.size()]),
                                               true,
                                               true);
    
        } else {
          eigensToVerify = eigens;
        }
      }

    首先初始化DistributedRowMatrix变量,由于inMemory是false,所以直接把 eigens变量赋值给了eigensToVerify变量;

    然后就是两个赋值语句,分别初始化corpus、eigenVerifier;然后还是初始化变量eigenMetaData,不过这个是调用了一个函数:verifyEigens来进行的;

    private Map<MatrixSlice, EigenStatus> verifyEigens() {
        Map<MatrixSlice, EigenStatus> eigenMetaData = Maps.newHashMap();
    
        for (MatrixSlice slice : eigensToVerify) {
          EigenStatus status = eigenVerifier.verify(corpus, slice.vector());
          eigenMetaData.put(slice, status);
        }
        return eigenMetaData;
      }

    eigensToVerify遍历的是rawEigenvector里面的那三个eigenVectors;然后就调用verify方法,其中corpus是所有的输入数据(5行13列的数据),slice.vector()是eigenVectors中的一个,看verify的操作:

    public EigenStatus verify(VectorIterable corpus, Vector vector) {
        Vector resultantVector = corpus.timesSquared(vector);
        double newNorm = resultantVector.norm(2);
        double oldNorm = vector.norm(2);
        double eigenValue;
        double cosAngle;
        if (newNorm > 0 && oldNorm > 0) {
          eigenValue = newNorm / oldNorm;
          cosAngle = resultantVector.dot(vector) / newNorm * oldNorm;
        } else {
          eigenValue = 1.0;
          cosAngle = 0.0;
        }
        return new EigenStatus(eigenValue, cosAngle, false);
      }

    corpus.timesSquared(vector)就是前面的Job1,回顾下job1做的事情:就是把corpus矩阵中的每一个行向量乘以slice.vector()的转置得到的值d,然后使用原来的这个行向量中的项值乘以d在加上原值,得到更新后的行向量,在corpus中所有的行向量加起来得到最后的行向量,即是resultantVector,比如针对vector=[0.01671441233225078, 0.0935655369363106, 0.09132650234523473, -0.0680324702834075, -0.9461123439509093, 0.10210271255992123, 0.10042714365337412, 0.11137954332150339, 0.10331974823993555, 0.10621406378767596, 0.10586960137353602, 0.09262650242313884, 0.09059904726143547];原始数据还是wine,那么得到的resultantVector就是:

    {0:-285.43017035605783,1:-61.30237570857193,2:-68.94124551381431,3:-520.2302762811703,4:-3232.201254912267,5:-32.31785150049481,6:-37.63572264009423,7:-12.025276244275622,8:-28.58260635344015,9:-6.8801603142200065,10:-28.491567864130573,11:-68.13521243410383,12:4382.173720122737}

    excel中得到的结果是:

    -217.2301704 -50.91237571 -56.33124551 -437.0302763 -2673.201255 -17.4178515 -22.39572264 -10.55527624 -18.20260635 20.93983969 -23.47156786 -51.26521243 9897.17372

    看到和java计算的结果还是有点误差的,这个等下在后面补充下(主要是验证写个job1的仿制代码);

    newNorm就是resultantVector自己点乘然后开根号,值为:5479.061620543984,excel中的是:10263.9596402234。汗,这个值就很不一样了,看来的确是要验证下了;oldNorm就是vector的自乘然后开根号;然后就返回了。

    这里就新建了rank个Job了,所以一共有5个Job,这样job都完了。

    2.验证篇:

    前面说怎么后面计算的误差值那么大?按理说也只是小数点后面的误差而已,通过前面编写的TimesSquareMapperFollow来进行debug(注意这里的设置的路径,在运行RunSVD的时候需要修改DistributedRowMatrix的276、277行,把其注释掉,这样就不会删除那个临时文件了),然后就可以进行测试了,首先来看第一条输出向量的d值:


    额,感觉和前面的后面8位小数点后才不一样而已;然后是计算的是第一个值:


    这里就是和excel不一样,咋回事呢?回去看源代码,才发现原来不需要再加上原始值的,如下:


    这样就对了。




    分享,成长,快乐

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


  • 相关阅读:
    javascript之DOMReady
    JQuery之proxy实现绑定代理
    javascript之数据推送
    javascript之高级函数应用思想
    函数的四种调用方式
    javascript多线程简介
    数组之迭代应用
    Git快速上手 : Tortoise工具使用
    Git 服务器搭建
    Git 安装与使用(二)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3400470.html
Copyright © 2020-2023  润新知