上周调研并介绍了一些高级矩阵操作,本周的内容就是来实现其中的LU分解,目前已经几近完成。实现的思路上参照了尚未正式release的Spark 1.1中分布式SVD奇异值分解的内容,所以先来介绍Spark 1.1中分布式SVD
目前已经release的1.0.x版本的Spark中,计算一个分布式矩阵的SVD,需要将其转换成本地breeze的DenseMatrix,然后调用SVD的API,这样无疑受限制于单节点的内存,无法计算大规模矩阵。在今年7月23日, 原AMPLab的博士生,现Databricks公司的创始人之一辛湜在微博上发文,表示其公司已经实现了开源的分布式SVD。
这部分内容,也就是我们下面要介绍的尚未release的Spark 1.1版本中计算SVD的方法
Spark 1.1版本的SVD分解主要是Databricks的实习生Li Pu完成的,其提交的issue地址在此,其主要思路是将SVD分解任务并行化,在特征向量分解部分,一台机器(例如提交该application的master节点)运行ARPACK,而其他节点分布式地并行计算Sparsematrix和向量的乘法。作者原本希望调用最新版本的breeze来实现,但是考虑到实际的依赖关系,目前直接使用netlib-java调用ARPACK,跨过breeze这一层来实现调用,预计Spark 1.1正式发布后,会将此部分代码修改成调用breeze。该版本代码的实验效果在其官方博客中已经展示出来,top-5的效果很不错。
参照上面所提及的思路,我们在实现时,也是当矩阵规模较小时,调用本地的breeze代码实现。当矩阵规模较大时,分布式计算。
但是在实际操作时,当遇到大型矩阵时,由于LU分解的算法本身是按照行主行串行迭代计算的,这一步目前的算法无法并行化,所以根据矩阵规模,会导致需要上千上万数量级的迭代次数,对于Spark而言亦是相当糟糕的性能开销,这里需要进一步优化。
还有个实际的问题是,目前Spark 1.0.x版本中,当迭代次数比较大时(例如一千次),Spark计算的依赖关系很长时,容易出现StackOverflowError,这个issue目前在Spark上已经有人提出并解决,不过需要等到Spark 1.1版本才会更新,目前的做法是迭代几百次之后checkpoint一下,清空掉之前的依赖。
将尚未正式release的分布式SVD算法引入我们的包中,测试验证一下其性能,并且尝试解决之前尚未解决的调用底层ARPACK的问题。
优化目前实现的LU分解的算法,降低每一轮迭代的开销。