我们正在计算运行时受矩阵运算约束的东西 . (如果感兴趣,请参阅下面的一些细节 . )这次经历提出了以下问题
民众对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 回答
Jeigen https://github.com/hughperkins/jeigen
包装Eigen C库http://eigen.tuxfamily.org,这是最快的免费C库之一
相对简洁的语法,例如'mmul','sub'
处理密集和稀疏矩阵
快速测试,通过乘以两个密集矩阵,即:
import static jeigen.MatrixUtil . *;
结果:
与jama相比,一切都更快:-P
_999_与jblas相比,Jeigen不是那么快,但它处理稀疏矩阵 .
与ojalgo相比,Jeigen占用了大约相同的经过时间,但只使用了一个核心,因此Jeigen占用了总CPU的一半 . Jeigen有一个更简洁的语法,即'mmul'与'multiplyRight'
我不能真正评论特定的库,但原则上这些操作在Java中没有什么理由变慢 . Hotspot通常会执行您希望编译器执行的操作:它将Java变量的基本数学运算编译为相应的机器指令(它使用SSE指令,但每个操作只有一个);访问数组的元素是编译为按照您的预期使用“原始”MOV指令;它决定如何在可能的情况下将变量分配给寄存器;它重新命令指令以利用处理器架构...一个可能的例外是,正如我所提到的,Hotspot每个SSE指令只执行一次操作;原则上你可以有一个奇妙优化的矩阵库,每个指令执行多个操作,虽然我不知道你的特定FORTRAN库是否这样做,或者是否存在这样的库 . 如果确实如此,那么Java(或者至少是Hotspot)目前还没有办法与之竞争(尽管你可以编写自己的本机库,并使用这些优化来从Java调用) .
那么,这意味着什么?好:
原则上,值得寻找性能更好的图书馆,但不幸的是我不能推荐一个
如果性能对你来说真的很重要,我会考虑编写你自己的矩阵运算,因为你可以执行某些优化,库通常可以't, or that a particular library your using doesn' t(如果你有一个多处理器机器,找出该库是否真的多线程)
矩阵操作的障碍通常是当您需要逐行和逐列遍历时出现的数据局部性问题,例如:在矩阵乘法中,因为您必须按照优化其中一个的顺序存储数据 . 但是如果你手写代码,你有时可以 combine operations to optimise data locality (例如,如果你将矩阵乘以它的变换,如果你编写一个专用函数而不是组合两个库函数,你可以将列遍历转换成行遍历) . 像往常一样,图书馆会给你非最佳表现以换取更快的发展;你需要决定性能对你有多重要 .
只是为了加我2美分 . 我比较了其中一些库 . 我试图矩阵乘以3000乘3000矩阵的双精度 . 结果如下 .
使用带有C / C,Octave,Python和R的多线程ATLAS,所花费的时间大约为4秒 .
使用Jama和Java,花费的时间是50秒 .
使用Colt和Parallel Colt与Java,所用时间为150秒!
使用JBLAS和Java,由于JBLAS使用多线程ATLAS,所以花费的时间大约为4秒 .
所以对我来说很明显,Java库的表现并不好 . 但是,如果有人必须使用Java编写代码,那么最好的选择是JBLAS . 贾马,科尔特和平行柯尔特并不快 .
我是Java Matrix Benchmark(JMatBench)的作者,我将对此讨论提出自己的想法 .
Java库之间存在显着差异,虽然在整个运营范围内没有明显的赢家,但在latest performance results(2013年10月)中可以看到一些明显的领导者 .
如果您正在使用"large"矩阵并且可以使用本机库,那么明确的赢家(大约快3.5倍)是MTJ,带有system optimised netlib . 如果您需要纯Java解决方案,那么MTJ,OjAlgo,EJML和Parallel Colt是不错的选择 . 对于小型矩阵,EJML是明显的赢家 .
我没有提到的库显示出重大的性能问题或缺少关键功能 .
我已经在2009年12月底发布了1.0版本 . 我在包装上做了很多工作,这意味着您现在可以下载带有ATLAS和JNI库的"fat jar",用于Windows,Linux,Mac OS X,32位和64位(Windows除外) ) . 这样,只需将jar文件添加到类路径中,即可获得本机性能 . 请查看http://jblas.org!
我刚刚将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
我的结论是从JDK 1.7调用的jlapack非常接近lapack的原生二进制性能 . 我使用了Linux发行版附带的lapack二进制库,并调用了dgesvd例程来获取U,S和VT矩阵 . 所有测试均在每次运行完全相同的矩阵上使用双精度完成(Octave除外) .
免责声明 - 我不是线性代数方面的专家,不属于上述任何一个库,这不是一个严格的基准 . 这是一个“自制”测试,因为我有兴趣比较JDK 1.7到1.6的性能提升以及公共数学SVD到jlapack .
对于一些不同的硬件配置,在http://code.google.com/p/java-matrix-benchmark/上的java中提供了各种矩阵包的基准测试 . 但它不能替代做自己的基准测试 .
性能将随着您所拥有的硬件类型(CPU,内核,内存,L1-3缓存,总线速度),矩阵的大小以及您打算使用的算法而变化 . 不同的库对不同的算法有不同的并发性,所以没有单一的答案 . 您可能还会发现,转换为本机库所期望的表单的开销会削弱您的用例的性能优势(某些Java库具有更灵活的矩阵存储选项,可用于进一步的性能优化) .
一般来说,JAMA,Jampack和COLT正在变老,并不代表Java中线性代数的当前性能状态 . 更现代的库可以更有效地使用多个内核和cpu缓存 . JAMA是一个参考实现,几乎实现了教科书算法,而不考虑性能 . COLT和IBM Ninja是第一个展示java可能性能的Java库,即使它们落后于本机库的50% .
我们已经使用COLT进行了一些非常大的严谨的财务计算,并对此非常满意 . 在我们的大量配置代码中,我们几乎从未用我们自己的代码替换COLT实现 .
在他们自己的测试中(显然不是独立的)我认为他们声称在英特尔手动优化的汇编程序中只有2倍 . 使用它的诀窍是确保您了解他们的设计理念,并避免无关的对象分配 .
我是la4j(线性代数for Java)库的作者,这是我的观点 . 我刚刚完成了所需的最低功能 . 所以,la4j并没有花费我的时间来改变它 .
我目前正在将新版本的la4j移植到JMatBench平台 . 我希望新版本会比之前的版本表现出更好的性能,因为我在la4j中做了一些改进,例如更快的内部矩阵格式,不安全的访问器和用于矩阵乘法的快速阻塞算法 .
你看过Intel Math Kernel Library了吗?它声称甚至超越了ATLAS . MKL可以通过JNI包装器used in Java .
Linalg代码严重依赖于Pentiums和后来的处理器的矢量计算功能(从MMX扩展开始,如LAPACK和现在的Atlas BLAS)不是“奇妙优化”,而只是行业标准 . 要在Java中复制该性能,您将需要本机库 . 我遇到了与你描述的相同的性能问题(主要是为了能够计算Choleski分解)并且没有发现任何真正有效的东西:Jama是纯Java,因为它应该只是实现者遵循的模板和参考工具包 . ......从未发生过 . 你知道Apache数学公共......至于COLT,我仍然要测试它,但它似乎很大程度上依赖于Ninja的改进,大多数通过构建一个特殊的Java编译器来实现这一点,所以我怀疑它会有所帮助 . 那时,我认为我们“只是”需要集体努力来 Build 本土的Jama实施......
在Varkhan的帖子的基础上,Pentium特定的本机代码会做得更好:
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进行高性能矩阵操作 .
开发商发布了一些benchmarks,其中jblas对MTJ和Colt有利 .
对于3d图形应用程序,lwjgl.util向量实现超出上面提到的jblas约3倍 .
我已经完成了一个带有4x4矩阵的vec4的100万次矩阵乘法 .
lwjgl在大约18ms完成,jblas需要大约60ms .
(我假设,JNI方法不适合快速连续应用相对较小的乘法 . 因为转换/映射可能比实际执行乘法花费更多时间 . )
还有UJMP
有许多不同的免费java线性代数库 . http://www.ujmp.org/java-matrix/benchmark/遗憾的是,该基准测试仅为您提供有关矩阵乘法的信息(通过转置测试不允许不同的库利用其各自的设计特征) .
你应该看看这些线性代数库在被要求计算各种矩阵分解时的表现 . http://ojalgo.org/matrix_compare.html
我发现如果你创建了很多高维矩阵,如果你改变它使用单维数组而不是二维数组,你可以使Jama快20% . 这是因为Java不能有效地支持多维数组 . 即 . 它创建了一个数组数组 .
Colt已经做到了这一点,但我发现它比Jama更复杂,更强大,这可以解释为什么Colt的简单功能会变慢 .
答案真的取决于你正在做的事情 . 贾马不支持柯尔特可以做的事情的一小部分,这使得更多的差异 .
Matrix Tookits Java(MTJ)之前已经提到过,但也许's worth mentioning again for anyone else stumbling onto this thread. For those interested, it seems like there'也谈到让MTJ取代apache commons math 2.0中的linalg库,尽管我最近在进步 .
您应该将Apache Mahout添加到您的购物清单中 .