Java矩阵数学库的性能? [关闭]
Posted
技术标签:
【中文标题】Java矩阵数学库的性能? [关闭]【英文标题】:Performance of Java matrix math libraries? [closed] 【发布时间】:2010-10-06 11:30:39 【问题描述】:我们正在计算一些运行时间受矩阵运算约束的东西。 (如果有兴趣,下面的一些细节。)这次经历引发了以下问题:
人们是否对用于矩阵数学(例如乘法、逆运算等)的 Java 库的性能有经验?例如:
JAMA COLT Apache commons math我搜索了一下,一无所获。
我们的速度对比详情:
我们使用的是英特尔 FORTRAN(ifort (IFORT) 10.1 20070913)。我们使用 Apache commons math 1.2 矩阵运算在 Java (1.6) 中重新实现了它,并且它同意其所有数字的准确性。 (我们有理由在 Java 中使用它。)(Java doubles,Fortran real*8)。 Fortran:6 分钟,Java 33 分钟,同一台机器。 jvisualm 分析显示在 RealMatrixImpl.getEntry,isValidCoordinate 中花费了很多时间(这似乎在未发布的 Apache commons math 2.0 中消失了,但 2.0 并没有更快)。 Fortran 正在使用 Atlas BLAS 例程(dpotrf 等)。
显然,这可能取决于我们在每种语言中的代码,但我们相信大部分时间都是在等效矩阵运算中。
在其他几个不涉及库的计算中,Java 并没有慢很多,有时甚至快得多。
【问题讨论】:
棘手的矩阵数学运算至少是 O(n^3)... 更糟的是,我想您可以花时间测试... 为什么需要倒数?对于几乎所有应用程序,您不需要实际的逆。由于稳定性问题,计算逆是个坏主意。 @Calyth:是的,我们可以安排时间。我想知道其他人是否已经有了。 @Ying Xiao:是的,要避免倒数。然而,这种计算似乎使用它最直接。见en.wikipedia.org/wiki/…。 @Calyth 错了,使用分而治之的方法有比 O(n^3) 更有效的方法。 最快的原生性能来自 JCublas。如果您需要快速线性代数,则需要 GPU。带有 clMath 的 JOCL 也可以工作并且可以移植到 CPU(甚至是多平台,无需重新编译),但我还没有测试过。 【参考方案1】:我是 Java Matrix Benchmark (JMatBench) 的作者,我将就此讨论发表我的看法。
Java 库之间存在显着差异,虽然在整个操作范围内没有明显的赢家,但在 latest performance results(2013 年 10 月)中可以看到一些明显的领导者。
如果您正在使用“大型”矩阵并且可以使用本机库,那么明显的赢家(大约快 3.5 倍)是 MTJ 和 system optimised netlib。如果您需要纯 Java 解决方案,那么 MTJ、OjAlgo、EJML 和 Parallel Colt 是不错的选择。对于小型矩阵,EJML 无疑是赢家。
我没有提到的库显示出严重的性能问题或缺少关键功能。
【讨论】:
只是想我会提到你的基准测试真的很方便!感谢您花时间参与其中。 JBLAS 似乎支持 SVD,截至 2013 年 9 月:mikiobraun.github.io/jblas/javadoc/org/jblas/… 精彩的作品,非常感谢。 是否有您评估但未发布结果的库的列表,以及每个库的原因? MTJ 似乎已被废弃:存储库已存档,最后一次提交是在 2016 年。【参考方案2】:只是添加我的 2 美分。我比较了其中一些库。我试图将一个 3000 x 3000 的双精度矩阵与自身矩阵相乘。结果如下。
将多线程 ATLAS 与 C/C++、Octave、Python 和 R 结合使用,所用时间约为 4 秒。
将 Jama 与 Java 结合使用,耗时 50 秒。
在 Java 中使用 Colt 和 Parallel Colt,耗时 150 秒!
将 JBLAS 与 Java 结合使用,由于 JBLAS 使用多线程 ATLAS,所用时间再次约为 4 秒。
所以对我来说,很明显 Java 库的性能不太好。但是,如果有人必须用 Java 编写代码,那么最好的选择是 JBLAS。 Jama、Colt 和 Parallel Colt 并不快。
【讨论】:
我猜你使用的是多核机器,所以这些结果受到库是否使用多核的强烈影响?出于某些目的,例如当使用 mpi 或 hadoop 等进行并行化时,重要的时间实际上是 singlecore 时间,因为 mpi/hadoop 实现负责并行化事情。 (至少,对我来说,jblas 比 jama 快 2.5 倍,而不是你得到的 jama 快 10 倍。) 我刚刚发布了 v1.0 of netlib-java... 性能与 Fortran 代码相当(有时甚至超过),它可以使用机器优化的原生代码,而无需对用户代码进行任何更改.在寻找低级线性代数库时请考虑这一点。我还维护MTJ,它使用了netlib-java。在 Scala 中,使用 Breeze(也由netlib-java
提供支持)
使用 ND4j 和 java - 我相对较旧的笔记本电脑在 219 毫秒内完成了建议的乘法。而 python + numpy 在 349 毫秒内完成它
补充一下我关于使用 nd4j 的最后评论,我使用 native-platform 作为其后端,如果我使用 cuda-platform 大约需要 1 毫秒
您是否在某处发布了用于基准测试的代码?【参考方案3】:
我是 jblas 的主要作者,我想指出我在 2009 年 12 月下旬发布了 1.0 版。我在包装上做了很多工作,这意味着您现在可以使用 ATLAS 下载一个“胖 jar”和适用于 Windows、Linux、Mac OS X、32 位和 64 位(Windows 除外)的 JNI 库。这样,您只需将 jar 文件添加到类路径即可获得本机性能。查看http://jblas.org!
【讨论】:
受您的工作启发,我在netlib-java 中做了类似的事情;-) 哈哈,我也是,jeigen :-) JogAmp 也是如此,参见 jogamp-fat.jar。好主意:)【参考方案4】:我刚刚将 Apache Commons Math 与 jlapack 进行了比较。
测试:随机 1024x1024 矩阵的奇异值分解。
机器:Intel(R) Core(TM)2 Duo CPU E6750 @ 2.66GHz,linux x64
八度码:A=rand(1024); tic;[U,S,V]=svd(A);toc
结果执行时间 -------------------------------------------------- -------- 八度音阶 36.34 秒 JDK 1.7u2 64位 jlapack dgesvd 37.78 秒 apache commons 数学 SVD 42.24 秒 JDK 1.6u30 64位 jlapack dgesvd 48.68 秒 apache commons 数学 SVD 50.59 秒 本机例程 从 C 调用的 Lapack*:37.64 秒 英特尔 MKL 6.89 秒(!)我的结论是从 JDK 1.7 调用的 jlapack 非常接近原生 lapack 的二进制性能。我使用了 linux 发行版附带的 lapack 二进制库,并调用了 dgesvd 例程来获取 U、S 和 VT 矩阵。所有测试都是在每次运行时使用完全相同的矩阵(Octave 除外)使用双精度完成的。
免责声明 - 我不是线性代数方面的专家,不隶属于上述任何库,这不是一个严格的基准。 这是一个“自制”测试,因为我有兴趣比较 JDK 1.7 到 1.6 的性能提升以及 commons math SVD 到 jlapack。
【讨论】:
【参考方案5】:我不能真正评论特定的库,但原则上没有理由让这些操作在 Java 中变慢。 Hotspot 通常会做你期望编译器做的事情:它将 Java 变量的基本数学运算编译为相应的机器指令(它使用 SSE 指令,但每个操作只有一个);如您所料,对数组元素的访问被编译为使用“原始” MOV 指令;它决定如何在可能的情况下将变量分配给寄存器;它重新排序指令以利用处理器架构......一个可能的例外是,正如我所提到的,Hotspot 将只执行每个 SSE 指令的一个操作;原则上,您可以拥有一个经过优化的矩阵库,每条指令执行多个操作,尽管我不知道您的特定 FORTRAN 库是否这样做,或者是否存在这样的库。如果是这样,Java(或者至少是 Hotspot)目前没有办法与之竞争(尽管您当然可以编写自己的本机库并使用这些优化从 Java 调用)。
那么这一切意味着什么?嗯:
原则上,值得四处寻找性能更好的库,但遗憾的是我无法推荐一个 如果性能对您来说真的很重要,我会考虑只编写您自己的矩阵运算,因为这样您就可以执行某些库通常无法执行的优化,或者您使用的特定库不能执行的某些优化(如果你有一台多处理器机器,看看这个库是否真的是多线程的)矩阵运算的障碍通常是当您需要逐行和逐列遍历时出现的数据局部性问题,例如在矩阵乘法中,因为您必须以优化一个或另一个的顺序存储数据。但是,如果您手动编写代码,您有时可以组合操作以优化数据局部性(例如,如果您将矩阵与其变换相乘,您可以将列遍历转换为行遍历,如果您编写一个专用函数而不是组合两个库函数)。像往常一样,库会给你非最佳性能以换取更快的开发;您需要确定性能对您的重要性。
【讨论】:
【参考方案6】:洁根https://github.com/hughperkins/jeigen
封装了 Eigen C++ 库 http://eigen.tuxfamily.org,这是可用的最快的免费 C++ 库之一 相对简洁的语法,例如'mmul'、'sub' 处理密集和稀疏矩阵快速测试,通过将两个密集矩阵相乘,即:
导入静态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”
【讨论】:
杰根看起来棒极了!我最近使用 JNI 和 DLL 在 Java 中实现了 Eigen,以解决非常大的稀疏矩阵。对于我的测试(超过 8000x8000 矩阵),我的 DLL 版本比并行 colt 快 20 多倍。我希望我知道 Jeigen!【参考方案7】:Java 中提供了各种矩阵包的基准测试 http://code.google.com/p/java-matrix-benchmark/ 用于几种不同的硬件配置。但它不能替代您自己的基准测试。
性能会因您拥有的硬件类型(cpu、内核、内存、L1-3 缓存、总线速度)、矩阵大小和您打算使用的算法而异。不同的库对不同的算法有不同的并发处理,所以没有单一的答案。您可能还会发现,转换为本机库所期望的形式的开销抵消了您的用例的性能优势(一些 java 库在矩阵存储方面具有更灵活的选项,可用于进一步的性能优化)。
一般来说,JAMA、Jampack 和 COLT 已经过时,并不代表 Java 中线性代数的当前性能状态。更现代的库更有效地利用了多核和 cpu 缓存。 JAMA 是一个参考实现,几乎实现了教科书算法,很少考虑性能。 COLT 和 IBM Ninja 是第一个证明 java 性能是可能的 java 库,即使它们落后于本地库 50%。
【讨论】:
【参考方案8】:我是la4j(Java 的线性代数)库的作者,这是我的观点。我已经在 la4j 上工作了 3 年(最新版本是 0.4.0 [2013 年 6 月 1 日]),直到现在我才可以开始进行性能分析和优化,因为我刚刚介绍了所需的最低功能。所以,la4j 没有我想要的那么快,但我花了很多时间来改变它。
我目前正在将新版本的 la4j 移植到JMatBench 平台。我希望新版本能显示出比上一个更好的性能,因为我在 la4j 中做了一些改进,例如更快的内部矩阵格式、不安全的访问器和矩阵乘法的快速阻塞算法。
【讨论】:
不 - la4j 真的没有竞争力。见code.google.com/p/java-matrix-benchmark 变化很大。自从您回答以来,我已经发布了两个版本的库。当前版本是 0.4.0。它只是飞。【参考方案9】:你看过Intel Math Kernel Library吗?它声称甚至优于ATLAS。通过 JNI 包装器,MKL 可以是 used in Java。
【讨论】:
我们有。 a) 它的许可比 Atlas 更严格(所以我们不能使用所有的计算机); b) 它不是 Java(正如我所说,我们有理由想要使用 Java)。 也就是说,这不是我关于 Java 库的问题的答案(但我没有反对它的声誉)。 @dfrankow:我已经更新了我的答案,以解决您对在 Java 中使用它的担忧。 +1,如果你正在寻找速度,这似乎是要走的路 最后一个链接坏了。【参考方案10】:严重依赖 Pentium 和更高版本处理器的矢量计算功能(从 MMX 扩展开始,如 LAPACK 和现在的 Atlas BLAS)的 Linalg 代码并不是“经过出色优化”,而只是行业标准。要在 Java 中复制这种性能,您将需要本机库。我遇到了与您描述的相同的性能问题(主要是为了能够计算 Choleski 分解)并且没有发现任何真正有效的东西:Jama 是纯 Java,因为它应该只是实现者遵循的模板和参考工具包。 ..这从未发生过。你知道 Apache 数学公用... 至于 COLT,我仍然需要对其进行测试,但它似乎在很大程度上依赖于 Ninja 的改进,其中大部分是通过构建一个临时 Java 编译器来实现的,所以我怀疑它是否会有所帮助。 到那时,我认为我们“只是”需要共同努力来构建原生 Jama 实现......
【讨论】:
好点!带有用于 Atlas 的 JNI 包装器的 alpha 阶段项目:jblas.org。作者博文:mikiobraun.blogspot.com/2008/10/…【参考方案11】:基于 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/
【讨论】:
【参考方案12】:我们已经使用 COLT 进行了一些相当大的严肃财务计算,并且对它非常满意。在我们的大量配置代码中,我们几乎不需要用我们自己的实现替换 COLT 实现。
在他们自己的测试中(显然不是独立的),我认为他们声称是英特尔手动优化的汇编程序例程的 2 倍。使用它的诀窍是确保您了解他们的设计理念,并避免无关的对象分配。
【讨论】:
【参考方案13】:我发现,如果您要创建大量高维矩阵,如果将 Jama 更改为使用一维数组而不是二维数组,则可以使 Jama 快 20%。这是因为 Java 不能有效地支持多维数组。 IE。它创建一个数组数组。
Colt 已经这样做了,但我发现它比 Jama 更复杂、更强大,这可以解释为什么 Colt 的简单函数会更慢。
答案真的取决于你在做什么。贾马不支持柯尔特可以做的事情的一小部分,这些事情会产生更大的影响。
【讨论】:
【参考方案14】:您可能想查看jblas 项目。这是一个相对较新的 Java 库,它使用 BLAS、LAPACK 和 ATLAS 进行高性能矩阵运算。
开发者发布了一些benchmarks,其中 jblas 胜过 MTJ 和 Colt。
【讨论】:
【参考方案15】:对于 3d 图形应用程序,lwjgl.util 矢量实现的性能比上面提到的 jblas 高出大约 3 倍。
我已经完成了 vec4 与 4x4 矩阵的 100 万次矩阵乘法。
lwjgl 大约 18ms 完成,jblas 大约需要 60ms。
(我认为,JNI 方法不太适合快速连续应用相对较小的乘法。因为转换/映射可能比实际执行乘法花费更多的时间。)
【讨论】:
【参考方案16】:还有UJMP
【讨论】:
【参考方案17】:有许多不同的免费 Java 线性代数库。 http://www.ujmp.org/java-matrix/benchmark/ 不幸的是,该基准只为您提供有关矩阵乘法的信息(转置测试不允许不同的库利用它们各自的设计特性)。
您应该看看这些线性代数库在被要求计算各种矩阵分解时的表现。 http://ojalgo.org/matrix_compare.html
【讨论】:
【参考方案18】:Matrix Tookits Java (MTJ) 之前已经提到过,但对于其他偶然发现该主题的人来说,也许值得再次提及。对于那些感兴趣的人,似乎还有人谈论让 MTJ 替换 apache commons math 2.0 中的 linalg 库,尽管我不确定最近进展如何。
【讨论】:
【参考方案19】:您应该将 Apache Mahout 添加到您的购物清单中。
【讨论】:
以上是关于Java矩阵数学库的性能? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章