153

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

人们对矩阵数学(例如,乘法、逆运算等)的 Java 库的性能有经验吗?例如:

我搜索并一无所获。


我们的速度比较的详细信息:

我们正在使用英特尔 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 并没有慢很多,有时甚至快得多。

4

19 回答 19

113

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

Java 库之间存在显着差异,虽然在整个操作范围内没有明显的赢家,但从最新的性能结果(2013 年 10 月)中可以看出,有一些明显的领先者。

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

我没有提到的库显示出严重的性能问题或缺少关键功能。

于 2011-12-09T04:13:09.620 回答
101

只是加我的 2 美分。我比较了其中一些库。我试图将一个 3000 x 3000 的双精度矩阵与自身矩阵相乘。结果如下。

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

使用 Jama 和 Java,所用时间为 50 秒。

在 Java 中使用 Colt 和 Parallel Colt,耗时 150 秒!

将 JBLAS 与 Java 结合使用,由于 JBLAS 使用多线程 ATLAS,所花费的时间再次约为 4 秒。

所以对我来说,很明显 Java 库的性能不太好。但是,如果有人必须用 Java 编写代码,那么最好的选择是 JBLAS。Jama、Colt 和 Parallel Colt 并不快。

于 2010-06-17T20:11:20.960 回答
53

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

于 2010-01-31T22:10:30.647 回答
9

我刚刚将 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。

于 2012-02-05T07:48:01.413 回答
8

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

那么,这意味着什么?好:

  • 原则上,值得四处寻找性能更好的库,但不幸的是我不能推荐一个
  • 如果性能对您来说真的很重要,我会考虑只编写您自己的矩阵运算,因为这样您就可以执行某些库通常无法执行的优化,或者您使用的特定库不能执行的优化(如果您有多处理器机器,看看这个库是否真的是多线程的)

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

于 2009-02-09T20:45:21.437 回答
8

杰根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”
于 2012-10-04T06:28:25.640 回答
6

对于一些不同的硬件配置, 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%。

于 2010-10-03T06:18:22.860 回答
5

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

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

于 2011-10-04T05:51:37.183 回答
4

您看过英特尔数学核心库吗?它声称甚至优于ATLAS。MKL 可以通过 JNI 包装器在 Java中使用。

于 2009-02-09T19:45:21.923 回答
3

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

于 2009-02-09T21:04:04.623 回答
3

以 Varkhan 的帖子为基础,奔腾特定的本机代码会做得更好:

于 2009-02-09T22:38:22.197 回答
3

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

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

于 2009-02-12T15:55:31.990 回答
2

我发现,如果您正在创建大量高维矩阵,如果将 Jama 更改为使用一维数组而不是二维数组,您可以让 Jama 快 20%。这是因为 Java 不能有效地支持多维数组。IE。它创建一个数组数组。

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

答案真的取决于你在做什么。Jama 不支持 Colt 可以做的事情的一小部分,这些事情会产生更大的影响。

于 2009-05-18T18:49:31.400 回答
2

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

开发人员已经发布了一些基准,其中 jblas 与 MTJ 和 Colt 相比有优势。

于 2009-07-20T05:32:28.797 回答
2

对于 3d 图形应用程序,lwjgl.util 矢量实现的性能优于上述 jblas 约 3 倍。

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

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

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

于 2012-02-24T02:43:59.983 回答
1

还有UJMP

于 2009-07-20T05:48:39.437 回答
0

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

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

于 2009-05-18T12:11:46.477 回答
0

Matrix Tookits Java (MTJ) 之前已经提到过,但对于其他偶然发现该线程的人来说,也许值得再次提及。对于那些感兴趣的人,似乎还有人谈论让 MTJ 替换apache commons math 2.0中的 linalg 库,尽管我不确定最近进展如何。

于 2009-07-08T15:30:38.567 回答
0

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

于 2010-04-24T22:43:37.487 回答