Javamatrixmath库的性能?

我们正在计算一些运行时受matrix运算约束的东西。 (如果感兴趣,下面有些细节。)这个经验提示下面的问题:

民间有经验的matrixmath(例如,乘法,逆等)Java库的性能? 例如:

  • JAMA
  • 小马
  • 阿帕奇公用math

我search,什么也没找


我们的速度比较的细节:

我们正在使用英特尔FORTRAN(ifort(IFORT)10.1 20070913)。 我们已经用Java(1.6)重新实现了它,使用了Apache commons math 1.2matrix操作,并且它同意所有的数字的准确性。 (我们有理由希望在Java中。)(Java双打,Fortran真正* 8)。 Fortran:6分钟,Java 33分钟,同一台机器。 jvisualm分析显示在RealMatrixImpl中花了很多时间{getEntry,isValidCoordinate}(似乎已经在未发行的Apache commons math 2.0中消失了,但是2.0不会更快)。 Fortran正在使用Atlas BLAS例程(dpotrf等)。

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

在其他一些不涉及库的计算中,Java的速度并不是很慢,有时候要快得多。

只要加我2分钱。 我比较了一些这些库。 我试图matrix乘以一个3000×3000的双打matrix。 结果如下。

使用C / C ++,Octave,Python和R的multithreadingATLAS,花费的时间约为4秒。

使用Java与Java,所花费的时间是50秒。

和Java一起使用Colt和Parallel Colt,花费的时间是150秒!

使用JBLAS和Java,JBLAS使用multithreadingATLAS的时间又是4秒左右。

所以对我来说,很显然,Java库的performance并不好。 但是,如果有人需要使用Java进行编码,那么最好的select是JBLAS。 贾马,柯尔特和平行柯尔特并不快。

我是Javamatrix基准(Java Matrix Benchmark, JMatBench )的作者,我将就这个讨论给出我的想法。

Java库存在显着的差异,虽然在整个运营范围内没有明显的优势,但从最新的业绩结果 (2013年10月)中可以看到一些明确的领导者。

如果您正在使用“大型”matrix,并且可以使用本地库,那么明确的获胜者(大约3.5倍)就是使用系统优化的netlib的 MTJ 。 如果您需要一个纯粹的Java解决scheme,那么MTJ , OjAlgo , EJML和Parallel Colt都是不错的select。 对于小型matrix,EJML是明显的赢家。

我没有提到的图书馆显示了重大的性能问题或缺less关键function。

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

http://code.google.com/p/java-matrix-benchmark/上提供了各种可用于Java的matrix软件包的基准testing,并提供了几种不同的硬件configuration。; 但是这不能替代你自己的基准。

性能会随着硬件types(CPU,内核,内存,L1-3caching,总线速度),matrix大小以及您打算使用的algorithm而变化。 不同的库对不同的algorithm需要不同的并发性,所以没有单一的答案。 你也可能发现翻译成本地库所期望的forms的开销会否定你的用例的性能优势(一些java库有更多关于matrix存储的灵活选项,可用于进一步的性能优化)。

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

我只是比较了Apache Commons Math和jlapack。

testing:对一个随机的1024x1024matrix进行奇异值分解。

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

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

结果执行时间
 -------------------------------------------------- -------
倍频36.34秒

 JDK 1.7u2 64bit
     jlapack dgesvd 37.78秒
     apache的常见问题mathSVD 42.24秒


 JDK 1.6u30 64bit
     jlapack dgesvd 48.68秒
     apache的常见问题mathSVD 50.59秒

原生例程
 Lapack *从C引用:37.64秒
英特尔MKL 6.89秒(!)

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

免责声明 – 我不是线性代数的专家,不隶属于任何上述图书馆,这不是一个严格的基准。 这是一个“自制”的testing,因为我有兴趣比较JDK 1.7的性能提高到1.6以及常见的mathSVD到jlapack。

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

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

一个快速的testing,通过乘以两个密集matrix,即:

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不是那么快,但是处理稀疏matrix。
  • 与Ojalgo相比,Jeigen花费大约相同的时间,但只使用一个核心,所以Jeigen使用总CPU的一半。 Jeigen有一个很好的语法,比如'mmul'和'multiplyRight'

我不能真正评论特定的库,但原则上这样的操作在Java中速度较慢的原因很less。 热点一般是你希望编译器做的事情:它将Javavariables的基本math运算编译为相应的机器指令(它使用SSE指令,但每个操作只有一个); 访问数组的元素被编译为使用“原始”MOV指令,如你所期望的; 它可以决定如何分配variables到寄存器; 它重新命令指令来利用处理器体系结构…一个可能的例外是,正如我所提到的,Hotspot只会对每个SSE指令执行一个操作; 原则上你可以有一个非常优化的matrix库,每个指令执行多个操作,但是我不知道你的特定的FORTRAN库是否这样做,或者如果这样的库甚至存在。 如果是这样的话,Java(或者至lessHotspot)目前还没有办法与之竞争(尽pipe你当然可以编写自己的本地库和这些优化来从Java调用)。

那么这是什么意思? 好:

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

对matrix运算的障碍往往是数据局部性的问题,当你需要遍历行和列时,例如在matrix乘法中,因为你必须按优化顺序存储数据。 但是如果你手动编写代码,有时你可以结合操作来优化数据的局部性 (例如,如果你将一个matrix乘以它的变换,你可以把列遍历成一个行遍历,如果你写一个专用函数而不是合并两个库函数)。 像往常一样,图书馆会给你提供非最佳的performance,以换取更快的发展; 你需要决定performance对你有多重要。

我们用COLT进行了一些相当大的严肃的财务计算,并对此非常满意。 在我们强大的代码中,我们几乎从来不需要用我们自己的代码replaceCOLT实现。

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

严重依赖Pentium和后来处理器的vector计算能力的Linalg代码(从MMX扩展开始,如LAPACK和现在的Atlas BLAS)并不是“非常优化的”,而是简单的行业标准。 要在Java中复制这种性能,您将需要本地库。 我已经遇到了与您描述的相同的性能问题(主要是为了能够计算Choleski分解),并且没有发现任何真正的高效性:Jama是纯Java,因为它应该只是实现者需要遵循的模板和参考工具包。 ..从来没有发生过。 你知道Apachemathcommons …至于COLT,我仍然要testing它,但它似乎严重依赖于忍者的改进,其中大部分是通过build立一个临时的Java编译器达到,所以我怀疑这将有助于。 那时候,我认为我们“只是”需要集体努力来build立一个本土的贾马执行机构……

在Varkhan的文章的基础上,奔腾特定的本地代码将会更好:

  • jBLAS:一个为Atlas提供JNI封装的alpha阶段项目: http ://www.jblas.org。

    • 作者的博客文章: http : //mikiobraun.blogspot.com/2008/10/matrices-jni-directbuffers-and-number.html 。
  • MTJ:另一个这样的项目: http : //code.google.com/p/matrix-toolkits-java/

你可能想看看jblas项目。 这是一个相对较新的Java库,使用BLAS,LAPACK和ATLAS进行高性能matrix运算。

开发者已经发布了一些基准 ,jblas从MTJ和Colt中脱颖而出。

我是la4j (Linear Algebra for Java)库的作者,这里是我的观点。 我一直在la4j工作3年(最新版本是0.4.0 [2013年6月1日]),直到现在我才能开始做性能分析和优化,因为我刚刚介绍了最小的必需function。 所以,la4j没有我想要的那么快,但我花费我的时间来改变它。

我目前正在将新版本的la4j移植到JMatBench平台中。 我希望新版本会显示更好的性能,因为在la4j中有一些改进,比如更快的内部matrix格式,不安全的访问器和matrix乘法的快速阻塞algorithm。

你有没有看过英特尔math核心库 ? 它声称甚至ATLAS跑赢。 MKL可以通过JNI包装器在Java中使用 。

还有UJMP

对于三维graphics应用程序,lwjgl.utilvector实现超出上述提到的jblas约3倍。

我已经完成了一个vec4与4x4matrix的1百万个matrix乘法。

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

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

我发现如果你正在创build大量的高维matrix,如果你把它改成使用单维数组而不是二维数组,你可以使得贾马的速度提高20%左右。 这是因为Java不能有效地支持multidimensional array。 即。 它创build一个数组的数组。

柯尔特已经这样做了,但我发现它比贾马更复杂,更强大,这可以解释为什么简单的function比柯尔特慢。

答案真的取决于你在做什么。 贾马尔不支持柯尔特可以做的事情的一小部分,使更多的差异。

Matrix Tookits Java(MTJ)之前已经提到,但也许值得一提的是任何人都在这个线程中磕磕绊绊。 对于那些感兴趣的人来说,似乎也有人谈论让MTJreplaceapache commons math 2.0中的linalg库,尽pipe我不确定最近进展如何。

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

你不是在Java版本中颠簸吗? 事实上,你花大部分时间在getEntry()是一个线索,这是发生。

与Commons-Math可以看到的另一个问题是matrix是作为一个二维数组来pipe理的。 虽然我不认为所需的double-dereference是减速的原因,但这确实意味着单个行(假设[rowIdx] [colIdx])实际上是单独的对象,将由GC单独处理。 你在GC上花了很多时间吗?