Java矩阵数学库的性能?

时间:2009-02-09 19:12:04

标签: java math matrix performance

我们正在计算运行时受矩阵运算约束的东西。 (如果感兴趣,请参阅下面的一些细节。)这次经历提出了以下问题:

民众对矩阵数学的Java库的性能有经验(例如,乘法,逆等)吗?例如:

我搜索过,一无所获。


我们的速度比较详情:

我们正在使用英特尔FORTRAN(ifort(IFORT)10.1 20070913)。我们使用Apache commons math 1.2矩阵运算在Java(1.6)中重新实现了它,并且它同意所有的精度数字。 (我们有理由在Java中想要它。)(Java双打,Fortran真* 8)。 Fortran:6分钟,Java 33分钟,同样的机器。 jvisualm profiling显示了在RealMatrixImpl中花费了大量时间。{getEntry,isValidCoordinate}(在未发布的Apache commons math 2.0中似乎已经消失了,但2.0并不快)。 Fortran正在使用Atlas BLAS例程(dpotrf等)。

显然这可能取决于我们在每种语言中的代码,但我们相信大部分时间都在等效的矩阵运算中。

在其他一些不涉及库的计算中,Java的速度并不慢,有时甚至更快。

19 个答案:

答案 0 :(得分:108)

我是Java Matrix Benchmark(JMatBench)的作者,我将就此讨论发表看法。

Java库之间存在显着差异,虽然在整个运营范围内没有明显的赢家,但在latest performance results(2013年10月)中可以看到一些明确的领导者。

如果您正在使用“大型”矩阵并且可以使用本机库,那么明确的赢家(大约快3.5倍)为MTJ system optimised netlib。如果您需要纯Java解决方案,那么MTJOjAlgoEJMLParallel Colt都是不错的选择。对于小矩阵,EJML是明显的赢家。

我没有提及的图书馆显示出重大的性能问题或缺少关键功能。

答案 1 :(得分:96)

加上我的2美分。我比较了其中一些库。我试图矩阵乘以3000乘3000矩阵的双精度。结果如下。

使用带有C / C ++,Octave,Python和R的多线程ATLAS,所花费的时间大约为4秒。

使用Jama和Java,花费的时间是50秒。

将Colt和Parallel Colt与Java一起使用,所需时间为150秒!

在JBLAS使用多线程ATLAS的情况下,将JBLAS与Java一起使用时间大约为4秒。

所以对我来说很明显,Java库的表现并不好。但是,如果有人必须使用Java编写代码,那么最好的选择是JBLAS。贾马,科尔特和平行柯尔特并不快。

答案 2 :(得分:48)

我是jblas的主要作者,并想指出我在2009年12月底发布了1.0版本。我在包装上做了很多工作,这意味着你现在可以用ATLAS下载一个“胖罐子”适用于Windows,Linux,Mac OS X,32位和64位的Windows和JNI库(Windows除外)。这样,只需将jar文件添加到类路径中,即可获得本机性能。请查看http://jblas.org

答案 3 :(得分:8)

Jeigen https://github.com/hughperkins/jeigen

  • 包装Eigen C ++库http://eigen.tuxfamily.org,这是最快的免费C ++库之一
  • 相对简洁的语法,例如'mmul','sub'
  • 处理密集和稀疏矩阵

快速测试,通过乘以两个密集矩阵,即:

import static jeigen.MatrixUtil。*;

int K = 100;
int N = 100000;
DenseMatrix A = rand(N, K);
DenseMatrix B = rand(K, N);
Timer timer = new Timer();
DenseMatrix C = B.mmul(A);
timer.printTimeCheckMilliseconds();

结果:

Jama: 4090 ms
Jblas: 1594 ms
Ojalgo: 2381 ms (using two threads)
Jeigen: 2514 ms
  • 与jama相比,一切都更快:-P
  • 与jblas相比,Jeigen不是那么快,但它处理稀疏矩阵。
  • 与ojalgo相比,Jeigen占用了相同的经过时间,但只使用了一个核心,因此Jeigen使用了总cpu的一半。 Jeigen有一个更简洁的语法,即'mmul'与'multiplyRight'

答案 4 :(得分:8)

我刚刚将Apache Commons Math与jlapack进行了比较。

测试:随机1024x1024矩阵的奇异值分解。

机器:Intel(R)Core(TM)2 Duo CPU E6750 @ 2.66GHz,linux x64

八度代码:A = rand(1024);抽动; [U,S,V] = SVD(A); TOC

results                                execution time
---------------------------------------------------------
Octave                                 36.34 sec

JDK 1.7u2 64bit
    jlapack dgesvd                     37.78 sec
    apache commons math SVD            42.24 sec


JDK 1.6u30 64bit
    jlapack dgesvd                     48.68 sec
    apache commons math SVD            50.59 sec

Native routines
Lapack* invoked from C:                37.64 sec
Intel MKL                               6.89 sec(!)

我的结论是从JDK 1.7调用的jlapack非常接近本机 lapack的二进制性能。我使用了Linux发行版附带的lapack二进制库,并调用了dgesvd例程来获取U,S和VT矩阵。所有测试都是在每次运行的完全相同的矩阵上使用双精度完成的(Octave除外)。

免责声明 - 我不是线性代数方面的专家,不属于上述任何一个库,这不是一个严格的基准。 这是一个“自制”测试,因为我有兴趣比较JDK 1.7到1.6的性能提升以及公共数学SVD到jlapack。

答案 5 :(得分:7)

我不能真正评论特定的库,但原则上这些操作在Java中没有什么理由变慢。 Hotspot通常会执行您希望编译器执行的操作:它将Java变量的基本数学运算编译为相应的机器指令(它使用SSE指令,但每个操作只有一个);对数组元素的访问被编译为使用“原始”MOV指令,如您所期望的那样;它可以决定如何在变量寄存器中分配变量;它重新命令指令以利用处理器架构......可能的例外是,正如我所提到的,Hotspot每个SSE指令只执行一次操作;原则上你可以有一个奇妙优化的矩阵库,每个指令执行多个操作,虽然我不知道你的特定FORTRAN库是否这样做,或者是否存在这样的库。如果确实如此,那么Java(或者至少是Hotspot)目前无法与之竞争(尽管您当然可以编写自己的本机库,并使用这些优化来从Java调用)。

那么这一切意味着什么呢?良好:

  • 原则上,值得寻找性能更好的图书馆,不幸的是我不能推荐一个
  • 如果性能对您来说真的很重要,我会考虑编写您自己的矩阵操作,因为您可能会执行某些库通常无法进行的优化,或者您使用的特定库没有(如果你有一个多处理器机器,找出该库是否真的是多线程的)

矩阵运算的障碍通常是当您需要逐行和逐列遍历时出现的数据位置问题,例如:在矩阵乘法中,因为您必须按照优化其中一个的顺序存储数据。但是如果你手写代码,你有时可以组合操作以优化数据局部性(例如,如果你将矩阵乘以其变换,你可以将列遍历转换为行遍历,如果你编写专用函数而不是组合两个库函数)。像往常一样,图书馆会给你非最佳表现以换取更快的发展;你需要决定性能对你有多重要。

答案 6 :(得分:6)

在java中有各种矩阵包的基准测试 http://code.google.com/p/java-matrix-benchmark/用于几种不同的硬件配置。但它不能代替你自己的基准。

性能将随着您所拥有的硬件类型(CPU,内核,内存,L1-3缓存,总线速度),矩阵的大小以及您打算使用的算法而变化。不同的库对不同的算法有不同的并发性,所以没有单一的答案。您可能还会发现,转换为本机库所期望的表单的开销会削弱您的用例的性能优势(某些Java库具有更灵活的矩阵存储选项,可用于进一步的性能优化)。 / p>

一般来说,JAMA,Jampack和COLT正在变老,并不代表Java中线性代数的当前性能状态。更现代的库可以更有效地使用多个内核和cpu缓存。 JAMA是一个参考实现,几乎实现了教科书算法,而不考虑性能。 COLT和IBM Ninja是第一个展示java可能性能的Java库,即使它们落后于本机库的50%。

答案 7 :(得分:4)

我是la4j(线性代数for Java)库的作者,这是我的观点。我已经在la4j工作了3年(最新版本是0.4.0 [2013年6月1日])并且现在我才开始进行性能分析和优化,因为我刚刚介绍了所需的最小功能。所以,la4j没有我想要的那么快,但我花了很多时间来改变它。

我目前正在将新版本的la4j移植到JMatBench平台。我希望新版本会比之前的版本表现出更好的性能,因为我在la4j中做了一些改进,例如更快的内部矩阵格式,不安全的访问器和用于矩阵乘法的快速阻塞算法。

答案 8 :(得分:3)

我们已经使用COLT进行了一些非常大的严谨的财务计算,并对此非常满意。在我们的大量配置代码中,我们几乎从未用我们自己的代码替换COLT实现。

在他们自己的测试中(显然不是独立的)我认为他们声称在英特尔手动优化的汇编程序例程中只有2倍。使用它的诀窍是确保你理解他们的设计理念,并避免无关的对象分配。

答案 9 :(得分:3)

你看过Intel Math Kernel Library了吗?它声称甚至超越了ATLAS。 MKL可以通过JNI包装器used in Java

答案 10 :(得分:2)

您可能想查看jblas项目。它是一个相对较新的Java库,它使用BLAS,LAPACK和ATLAS进行高性能矩阵操作。

开发者发布了一些benchmarks,其中jblas对MTJ和Colt有利。

答案 11 :(得分:2)

基于Varkhan的帖子,Pentium特定的本机代码会做得更好:

答案 12 :(得分:2)

Linalg代码严重依赖于Pentiums和后来的处理器的矢量计算功能(从MMX扩展开始,如LAPACK和现在的Atlas BLAS)不是“奇妙优化”,而只是行业标准。要在Java中复制该性能,您将需要本机库。我遇到了与你描述的相同的性能问题(主要是为了能够计算Choleski分解)并且没有发现任何真正有效的东西:Jama是纯Java,因为它应该只是实现者遵循的模板和参考工具包。 ......从未发生过。你知道Apache数学公共......至于COLT,我还是要测试它,但它似乎很大程度上依赖于Ninja的改进,其中大部分是通过构建一个特殊的Java编译器来实现的,所以我怀疑它会有所帮助。 那时,我认为我们“只是”需要集体努力来建立一个本地的Jama实施......

答案 13 :(得分:2)

对于3d图形应用程序,lwjgl.util向量实现在上面提到的jblas上执行了大约3倍。

我已经完成了vec4与4x4矩阵的100万次矩阵乘法。

lwjgl在大约18ms完成,jblas需要大约60ms。

(我假设,JNI方法不适合快速连续应用相对较小的乘法。因为转换/映射可能比实际执行乘法花费更多时间。)

答案 14 :(得分:1)

还有UJMP

答案 15 :(得分:0)

我发现如果你创建了很多高维矩阵,如果你改变它使用单维数组而不是二维数组,你可以使Jama快20%。这是因为Java不能有效地支持多维数组。即。它创建了一个数组数组。

Colt已经这样做了,但我发现它比Jama更复杂,更强大,这可以解释为什么Colt的简单功能会变慢。

答案实际上取决于你正在做的事情。贾马特并不支持柯尔特可以做的事情的一小部分,这使得更多的不同。

答案 16 :(得分:0)

Matrix Tookits Java(MTJ)之前已经提到过,但也许值得一提的是其他任何人都绊倒在这个线程上。对于那些感兴趣的人来说,似乎还有关于MTJ替换apache commons math 2.0中的linalg库的讨论,尽管我不确定最近这是如何进展的。

答案 17 :(得分:0)

有许多不同的免费java线性代数库。 http://www.ujmp.org/java-matrix/benchmark/ 遗憾的是,该基准测试仅为您提供有关矩阵乘法的信息(通过转置测试不允许不同的库利用其各自的设计特征)。

您应该看到的是这些线性代数库在被要求计算各种矩阵分解时的表现。 http://ojalgo.org/matrix_compare.html

答案 18 :(得分:0)

您应该将Apache Mahout添加到您的购物清单。