Hiệu suất của các thư viện toán học ma trận Java? [đóng cửa]


151

Chúng tôi đang tính toán một cái gì đó mà thời gian chạy bị ràng buộc bởi các hoạt động ma trận. (Một số chi tiết bên dưới nếu quan tâm.) Kinh nghiệm này đã đưa ra câu hỏi sau:

Dân gian có kinh nghiệm về hiệu năng của các thư viện Java cho toán học ma trận (ví dụ: nhân, nghịch đảo, v.v.) không? Ví dụ:

Tôi tìm kiếm và không tìm thấy gì.


Chi tiết so sánh tốc độ của chúng tôi:

Chúng tôi đang sử dụng Intel FORTRAN (ifort (IFORT) 10.1 20070913). Chúng tôi đã thực hiện lại nó trong Java (1.6) bằng cách sử dụng ops ma trận 1.2 commons toán học của Apache và nó đồng ý với tất cả các chữ số chính xác của nó. (Chúng tôi có lý do để muốn nó trong Java.) (Java nhân đôi, Fortran real * 8). Fortran: 6 phút, Java 33 phút, cùng một máy. jvisualm profiling cho thấy nhiều thời gian dành cho RealMatrixImpl. {getEntry, isValidCoordine} (dường như đã biến mất trong Apache commons math 2.0, nhưng 2.0 không nhanh hơn). Fortran đang sử dụng các thói quen của Atlas BLAS (dpotrf, v.v.).

Rõ ràng điều này có thể phụ thuộc vào mã của chúng tôi trong từng ngôn ngữ, nhưng chúng tôi tin rằng hầu hết thời gian là trong các hoạt động ma trận tương đương.

Trong một số tính toán khác không liên quan đến các thư viện, Java đã không chậm hơn nhiều và đôi khi nhanh hơn nhiều.


Các toán học ma trận phức tạp ít nhất là O (n ^ 3) ... tệ hơn đến tồi tệ hơn, tôi cho rằng bạn có thể có thời gian và kiểm tra ...
Calyth

2
Tại sao bạn cần nghịch đảo? Đối với hầu hết tất cả các ứng dụng, bạn không cần nghịch đảo thực tế. Tính toán nghịch đảo là một ý tưởng tồi vì vấn đề ổn định.
Ying Xiao

1
@Calyth: Vâng, chúng tôi có thể thời gian. Tôi đã tự hỏi nếu những người khác đã có. @Ying Xiao: Vâng, cần tránh nghịch đảo. Tuy nhiên, tính toán này có vẻ đơn giản nhất khi sử dụng nó. Xem en.wikipedia.org/wiki/ .
dfrankow

2
@Calyth Điều đó là sai, có nhiều phương pháp hiệu quả hơn O (n ^ 3) bằng cách sử dụng phương pháp phân chia và chinh phục.
starblue

1
Hiệu suất bản địa nhanh nhất là từ JCublas. Nếu bạn cần đại số tuyến tính nhanh, bạn cần GPU. JOCL với clMath cũng có thể hoạt động và có thể di động tới CPU (và thậm chí cả biên dịch lại đa nền tảng), nhưng tôi chưa thử nghiệm nó.
Alexanderr Dubinsky

Câu trả lời:


98

Chỉ cần thêm 2 xu của tôi. Tôi đã so sánh một số các thư viện này. Tôi đã cố gắng nhân ma trận 3000 với 3000 ma trận nhân đôi với chính nó. Kết quả như sau.

Sử dụng ATLAS đa luồng với C / C ++, Octave, Python và R, thời gian thực hiện là khoảng 4 giây.

Sử dụng Jama với Java, thời gian thực hiện là 50 giây.

Sử dụng Colt và Parallel Colt với Java, thời gian thực hiện là 150 giây!

Sử dụng JBLAS với Java, thời gian thực hiện lại khoảng 4 giây vì JBLAS sử dụng ATLAS đa luồng.

Vì vậy, đối với tôi rõ ràng là các thư viện Java đã không hoạt động quá tốt. Tuy nhiên, nếu ai đó phải viết mã bằng Java, thì tùy chọn tốt nhất là JBLAS. Jama, Colt và Parallel Colt không nhanh.


3
Tôi đoán bạn đang sử dụng máy đa lõi, vì vậy những kết quả này bị ảnh hưởng mạnh mẽ bởi liệu thư viện có sử dụng đa lõi hay không? Đối với một số mục đích, ví dụ như khi ai parallelizing sử dụng MPI hoặc hadoop vv, thời gian quan trọng thực sự là singlecore thời gian, kể từ khi thực mpi / hadoop sẽ chăm sóc của parallelizing thứ. (Ít nhất, đối với tôi jblas nhanh hơn khoảng 2,5 lần so với jama, không nhanh hơn 10 lần so với jama như bạn có.)
Hugh Perkins

17
Tôi vừa phát hành v1.0 của netlib-java ... hiệu suất ngang bằng (và đôi khi vượt qua) mã Fortran và nó có thể sử dụng các bản địa được tối ưu hóa của máy mà không có bất kỳ thay đổi nào đối với mã người dùng. Vui lòng xem xét điều này khi tìm kiếm các thư viện đại số tuyến tính cấp thấp. Tôi cũng duy trì MTJ , sử dụng netlib-java. Trong Scala, sử dụng Breeze (cũng được cung cấp bởi netlib-java)
fommil

4
Sử dụng ND4j và java - máy tính xách tay tương đối cũ của tôi hoàn thành phép nhân được đề xuất trong vòng 219 mili giây. Trong khi python + numpy hoàn thành nó trong vòng 349 millis
bennyl

2
Và chỉ để thêm vào nhận xét cuối cùng của tôi về việc sử dụng nd4j, tôi đã sử dụng nền tảng gốc làm phụ trợ của nó, nếu tôi sử dụng nền tảng
cuda

Bạn đã xuất bản mã của bạn cho điểm chuẩn ở đâu đó?
bruziuz

108

Tôi là tác giả của Điểm chuẩn Ma trận Java ( JMatBench ) và tôi sẽ đưa ra suy nghĩ của mình về cuộc thảo luận này.

Có sự khác biệt đáng kể giữa các thư viện Java và mặc dù không có người chiến thắng rõ ràng trong toàn bộ phạm vi hoạt động, có một vài nhà lãnh đạo rõ ràng có thể thấy trong kết quả hoạt động mới nhất (tháng 10 năm 2013).

Nếu bạn đang làm việc với ma trận "lớn" và có thể sử dụng các thư viện gốc, thì người chiến thắng rõ ràng (nhanh hơn khoảng 3,5 lần) là MTJ với netlib được tối ưu hóa hệ thống . Nếu bạn cần một giải pháp Java thuần túy thì MTJ , OjAlgo , EJMLParallel Colt là những lựa chọn tốt. Đối với ma trận nhỏ EJML là người chiến thắng rõ ràng.

Các thư viện tôi không đề cập cho thấy các vấn đề hiệu suất quan trọng hoặc thiếu các tính năng chính.


6
Chỉ cần nghĩ rằng tôi đề cập rằng điểm chuẩn của bạn là thực sự tiện dụng! Cảm ơn đã đặt thời gian của bạn vào nó.
hohonuuli

1
JBLAS dường như hỗ trợ SVD kể từ ngày 13 tháng 9: mikiobraun.github.io/jblas/javadoc/org/jblas/ phỏng
Leopd

công việc tuyệt vời, thx rất nhiều.
webpat

Có một danh sách ở đâu đó của các thư viện bạn đã đánh giá nhưng không công bố kết quả và lý do cho mỗi thư viện không?
Kevin Krumwiede

1
MTJ dường như bị bỏ rơi: kho lưu trữ được lưu trữ và lần cam kết cuối cùng là vào năm 2016.
Danila Piatov

51

Tôi là tác giả chính của jblas và muốn chỉ ra rằng tôi đã phát hành Phiên bản 1.0 vào cuối tháng 12 năm 2009. Tôi đã làm việc rất nhiều trên bao bì, có nghĩa là bây giờ bạn có thể tải xuống một "lọ mỡ" với các thư viện ATLAS và JNI cho Windows, Linux, Mac OS X, 32 và 64 bit (trừ Windows). Bằng cách này, bạn sẽ có được hiệu năng riêng chỉ bằng cách thêm tệp jar vào đường dẫn lớp của bạn. Kiểm tra nó tại http://jblas.org !


2
lấy cảm hứng từ công việc của bạn, tôi đã làm một điều tương tự trong netlib-java ;-)
fommil

2
Haha, tôi cũng vậy, vì jeigen :-)
Hugh Perkins

JogAmp cũng làm như vậy, xem phần chạy bộ-fat.jar. Ý kiến ​​hay :)
gouliej

8

Tôi thực sự không thể nhận xét về các thư viện cụ thể, nhưng về nguyên tắc, có rất ít lý do để các hoạt động như vậy chậm hơn trong Java. Hotspot thường thực hiện các loại công việc mà bạn mong muốn trình biên dịch thực hiện: nó biên dịch các phép toán cơ bản trên các biến Java thành các lệnh máy tương ứng (nó sử dụng các lệnh SSE, nhưng chỉ một lệnh cho mỗi thao tác); truy cập vào các phần tử của một mảng được biên dịch để sử dụng các lệnh MOV "thô" như bạn mong đợi; nó đưa ra quyết định về cách phân bổ biến cho các thanh ghi khi có thể; nó yêu cầu lại các hướng dẫn để tận dụng kiến ​​trúc bộ xử lý ... Một ngoại lệ có thể xảy ra là như tôi đã đề cập, Hotspot sẽ chỉ thực hiện một thao tác cho mỗi lệnh SSE; về nguyên tắc bạn có thể có một thư viện ma trận được tối ưu hóa tuyệt vời, thực hiện nhiều thao tác trên mỗi lệnh, mặc dù tôi không ' Tôi biết nếu, giả sử, thư viện FORTRAN cụ thể của bạn làm như vậy hoặc nếu một thư viện như vậy thậm chí tồn tại. Nếu đúng như vậy, hiện tại không có cách nào để Java (hoặc ít nhất là Hotspot) cạnh tranh với điều đó (mặc dù bạn có thể viết thư viện riêng của mình với những tối ưu hóa đó để gọi từ Java).

Vậy, tất cả điều này có ý nghĩa gì? Tốt:

  • về nguyên tắc, đáng để săn lùng một thư viện hoạt động tốt hơn, mặc dù không may là tôi không thể giới thiệu một thư viện
  • nếu hiệu suất thực sự quan trọng đối với bạn, tôi sẽ xem xét chỉ mã hóa các hoạt động ma trận của riêng bạn, bởi vì sau đó bạn có thể thực hiện một số tối ưu nhất định mà thư viện thường không thể hoặc thư viện cụ thể mà bạn sử dụng không (nếu bạn có máy đa bộ xử lý, tìm hiểu xem thư viện có thực sự đa luồng không)

Một trở ngại cho các hoạt động ma trận thường là các vấn đề cục bộ dữ liệu phát sinh khi bạn cần duyệt qua từng hàng và từng cột, ví dụ như trong phép nhân ma trận, vì bạn phải lưu trữ dữ liệu theo thứ tự tối ưu hóa cái này hay cái khác. Nhưng nếu bạn viết tay mã, đôi khi bạn có thể kết hợp các hoạt động để tối ưu hóa địa phương dữ liệu (ví dụ: nếu bạn nhân một ma trận bằng phép biến đổi của nó, bạn có thể biến một cột ngang thành một hàng ngang nếu bạn viết một hàm chuyên dụng thay vì kết hợp hai chức năng thư viện). Như thường lệ trong cuộc sống, một thư viện sẽ cung cấp cho bạn hiệu suất không tối ưu để đổi lấy sự phát triển nhanh hơn; bạn cần phải quyết định hiệu suất của bạn quan trọng như thế nào.


8

Tôi chỉ so sánh Apache Commons Math với jlapack.

Kiểm tra: phân rã giá trị số ít của ma trận 1024x1024 ngẫu nhiên.

Máy: CPU Intel (R) Core (TM) 2 Duo E6750 @ 2.66GHz, linux x64

Mã Octave: A = rand (1024); tic; [U, S, V] = svd (A); toc

kết quả thời gian thực hiện
-------------------------------------------------- -------
Octave 36,34 giây

JDK 1.7u2 64 bit
    jlapack dgesvd 37,78 giây
    apache commons toán SVD 42,24 giây


JDK 1.6u30 64 bit
    jlapack dgesvd 48,68 giây
    apache commons toán SVD 50,59 giây

Thói quen bản địa
Lapack * được gọi từ C: 37,64 giây
Intel MKL 6.89 giây (!)

Kết luận của tôi là jlapack được gọi từ JDK 1.7 rất gần với hiệu suất nhị phân nguyên gốc của lapack. Tôi đã sử dụng thư viện nhị phân lapack đi kèm với distro linux và gọi thường trình dgesvd để lấy ma trận U, S và VT. Tất cả các thử nghiệm đã được thực hiện bằng cách sử dụng độ chính xác kép trên chính xác cùng một ma trận mỗi lần chạy (trừ Octave).

Tuyên bố miễn trừ trách nhiệm - Tôi không phải là chuyên gia về đại số tuyến tính, không liên kết với bất kỳ thư viện nào ở trên và đây không phải là điểm chuẩn khắt khe. Đây là một thử nghiệm 'sản xuất tại nhà', vì tôi rất thích so sánh mức tăng hiệu năng của JDK 1.7 đến 1.6 cũng như giao tiếp toán học SVD với jlapack.


8

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

  • kết thúc thư viện Eigen C ++ http: // eigen.tuxf Family.org , đây là một trong những thư viện C ++ miễn phí nhanh nhất hiện có
  • cú pháp tương đối ngắn gọn, ví dụ 'mmul', 'sub'
  • xử lý cả ma trận dày đặc và thưa thớt

Một bài kiểm tra nhanh, bằng cách nhân hai ma trận dày đặc, nghĩa là:

nhập jeigen tĩnh.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();

Các kết quả:

Jama: 4090 ms
Jblas: 1594 ms
Ojalgo: 2381 ms (using two threads)
Jeigen: 2514 ms
  • So với jama, mọi thứ nhanh hơn :-P
  • So với jblas, Jeigen không hoàn toàn nhanh như vậy, nhưng nó xử lý các ma trận thưa thớt.
  • So với ojalgo, Jeigen mất khoảng thời gian như nhau, nhưng chỉ sử dụng một lõi, vì vậy Jeigen sử dụng một nửa tổng số cpu. Jeigen có cú pháp chặt chẽ hơn, tức là 'mmul' so với 'MultiplyRight'

Jeigen trông thật tuyệt! Gần đây tôi đã triển khai Eigen trong Java bằng cách sử dụng JNI và một DLL để giải các ma trận thưa thớt rất lớn. Phiên bản của tôi với DLL nhanh hơn 20 lần so với colt song song cho các thử nghiệm của tôi (hơn 8000x8000 ma trận). Tôi ước tôi đã biết về Jeigen!
Z boson

6

Có một điểm chuẩn của các gói ma trận khác nhau có sẵn trong java trên http://code.google.com.vn/p/java-matrix-benchmark/ cho một vài cấu hình phần cứng khác nhau. Nhưng nó không thay thế cho việc làm điểm chuẩn của riêng bạn.

Hiệu suất sẽ thay đổi theo loại phần cứng bạn có (cpu, lõi, bộ nhớ, bộ đệm L1-3, tốc độ bus), kích thước của ma trận và các thuật toán bạn định sử dụng. Các thư viện khác nhau có sự đồng thời khác nhau đối với các thuật toán khác nhau, vì vậy không có câu trả lời duy nhất. Bạn cũng có thể thấy rằng chi phí dịch thuật sang biểu mẫu mà thư viện gốc mong đợi sẽ phủ nhận lợi thế về hiệu suất cho trường hợp sử dụng của bạn (một số thư viện java có các tùy chọn linh hoạt hơn về lưu trữ ma trận, có thể được sử dụng để tối ưu hóa hiệu suất hơn nữa).

Nói chung, mặc dù, JAMA, Jampack và COLT đang già đi và không đại diện cho trạng thái của hiệu suất hiện tại có sẵn trong Java cho đại số tuyến tính. Các thư viện hiện đại hơn giúp sử dụng hiệu quả hơn nhiều lõi và bộ nhớ cpu. JAMA là một triển khai tham chiếu và thực hiện khá nhiều thuật toán trong sách giáo khoa mà ít quan tâm đến hiệu suất. COLT và IBM Ninja là các thư viện java đầu tiên cho thấy hiệu năng có thể có trong java, ngay cả khi chúng bị tụt lại 50% so với các thư viện gốc.


4

Tôi là tác giả của thư viện la4j (Đại số tuyến tính cho Java) và đây là quan điểm của tôi. Tôi đã làm việc trên la4j được 3 năm (phiên bản mới nhất là 0.4.0 [01 tháng 6 năm 2013]) và chỉ bây giờ tôi mới có thể bắt đầu thực hiện phân tích và tối ưu hóa hiệu suất vì tôi chỉ đảm bảo chức năng tối thiểu cần thiết. Vì vậy, la4j không nhanh như tôi muốn nhưng tôi đang dành nhiều thời gian để thay đổi nó.

Tôi hiện đang ở giữa phiên bản mới của nền tảng la4j sang nền tảng JMatBench . Tôi hy vọng phiên bản mới sẽ hiển thị hiệu suất tốt hơn phiên bản trước vì có một số cải tiến tôi đã thực hiện trong la4j như định dạng ma trận nội bộ nhanh hơn nhiều, bộ truy cập không an toàn và thuật toán chặn nhanh để nhân ma trận.


1
Không - la4j thực sự không cạnh tranh. Xem code.google.com/p/java-matrix-benchmark
Christopher Manning

Nó đã thay đổi rất nhiều. Tôi đã phát hành hai phiên bản của thư viện kể từ câu trả lời của bạn. Bản phát hành hiện tại là 0.4.0. Và nó chỉ bay.
Vladimir Kostyukov

3

Mã Linalg phụ thuộc nhiều vào Pentium và khả năng tính toán véc tơ của bộ xử lý sau này (bắt đầu với các phần mở rộng MMX, như LAPACK và bây giờ là Atlas BLAS) không phải là "tối ưu hóa tuyệt vời", mà đơn giản là tiêu chuẩn công nghiệp. Để tái tạo sự hoàn hảo đó trong Java, bạn sẽ cần các thư viện nguyên gốc. Tôi đã có vấn đề về hiệu năng giống như bạn mô tả (chủ yếu là để có thể tính toán phân tách Choleski) và không tìm thấy gì thực sự hiệu quả: Jama là Java thuần túy, vì nó được cho là chỉ là một bộ công cụ mẫu và tham chiếu để người thực hiện tuân theo. .. điều đó không bao giờ xảy ra. Bạn biết commons toán học Apache ... Đối với COLT, tôi vẫn phải kiểm tra nó nhưng dường như nó phụ thuộc rất nhiều vào các cải tiến Ninja, hầu hết đều đạt được bằng cách xây dựng một trình biên dịch Java đặc biệt, vì vậy tôi nghi ngờ nó sẽ giúp ích. Tại thời điểm đó, tôi nghĩ rằng chúng ta "


Điểm tốt! Một dự án giai đoạn alpha với các trình bao bọc JNI cho Atlas: jblas.org . Bài đăng trên blog của tác giả: mikiobraun.blogspot.com/2008/10/ từ
dfrankow

3

Chúng tôi đã sử dụng COLT cho một số tính toán tài chính nghiêm trọng khá lớn và đã rất hài lòng với nó. Trong mã được lược tả kỹ lưỡng của chúng tôi, chúng tôi gần như không bao giờ phải thay thế một triển khai COLT bằng một mã của chúng tôi.

Trong thử nghiệm của riêng họ (rõ ràng là không độc lập) tôi nghĩ rằng họ yêu cầu trong phạm vi 2 trong số các thói quen lắp ráp được tối ưu hóa bằng tay của Intel. Mẹo để sử dụng nó tốt là đảm bảo rằng bạn hiểu triết lý thiết kế của họ và tránh phân bổ đối tượng bên ngoài.


3

Bạn đã xem Thư viện hạt nhân toán học Intel chưa? Nó tuyên bố sẽ vượt trội hơn cả ATLAS . MKL có thể được sử dụng trong Java thông qua các hàm bao JNI.


2
Chúng tôi có điều đó. a) Cấp phép của nó hạn chế hơn Atlas (vì vậy chúng tôi không thể sử dụng tất cả các máy tính của mình); b) đó không phải là Java (và như tôi đã nói, chúng tôi có lý do để muốn ở trong Java).
dfrankow

tức là, đây không phải là câu trả lời cho câu hỏi của tôi về các thư viện Java (nhưng tôi không có tiếng tăm gì để đánh giá thấp nó).
dfrankow

@dfrankow: Tôi đã cập nhật câu trả lời của mình để giải quyết mối quan tâm của bạn về việc sử dụng nó trong Java.
Zach Scrivena

1
+1, Nếu đó là tốc độ mà bạn đang tìm kiếm, đây dường như là con đường để đi
Gab Royer

2
Liên kết cuối cùng bị hỏng.
gouliej


2

Bạn có thể muốn kiểm tra dự án jblas . Đây là một thư viện Java tương đối mới sử dụng BLAS, LAPACK và ATLAS cho các hoạt động ma trận hiệu năng cao.

Nhà phát triển đã đăng một số điểm chuẩn trong đó jblas xuất hiện thuận lợi chống lại MTJ và Colt.


2

Đối với các ứng dụng đồ họa 3d, việc triển khai vectơ lwjgl.util được thực hiện ở trên các jblas đã đề cập ở mức 3.

Tôi đã thực hiện 1 triệu phép nhân ma trận của một vec4 với ma trận 4 x 4.

lwjgl hoàn thành trong khoảng 18ms, jblas cần khoảng 60ms.

(Tôi giả sử rằng cách tiếp cận JNI không phù hợp lắm cho việc áp dụng nhanh chóng các phép nhân tương đối nhỏ. Vì việc dịch / ánh xạ có thể mất nhiều thời gian hơn so với thực hiện phép nhân.)


1

Tôi đã thấy rằng nếu bạn đang tạo ra nhiều Ma trận chiều cao, bạn có thể tạo Jama nhanh hơn khoảng 20% ​​nếu bạn thay đổi nó để sử dụng một mảng một chiều thay vì một mảng hai chiều. Điều này là do Java không hỗ trợ các mảng đa chiều một cách hiệu quả. I E. nó tạo ra một mảng các mảng

Colt đã làm điều này rồi, nhưng tôi đã thấy nó phức tạp và mạnh mẽ hơn Jama có thể giải thích tại sao các chức năng đơn giản lại chậm hơn với Colt.

Câu trả lời thực sự phụ thuộc vào việc bạn đang làm. Jama không hỗ trợ một phần nhỏ những gì Colt có thể làm để tạo ra sự khác biệt.



0

Có rất nhiều thư viện đại số tuyến tính java có sẵn miễn phí khác nhau. http://www.ujmp.org/java-matrix/benchmark/ Thật không may, điểm chuẩn đó chỉ cung cấp cho bạn thông tin về phép nhân ma trận (với việc chuyển đổi bài kiểm tra không cho phép các thư viện khác nhau khai thác các tính năng thiết kế tương ứng của họ).

Những gì bạn nên xem là cách các thư viện đại số tuyến tính này thực hiện khi được yêu cầu tính toán các phân tách ma trận khác nhau. http://ojalgo.org/matrix_compare.html


0

Matrix Tookits Java (MTJ) đã được đề cập trước đó, nhưng có lẽ nó đáng được nhắc lại một lần nữa cho bất kỳ ai khác vấp phải chủ đề này. Đối với những người quan tâm, có vẻ như cũng có nói về việc MTJ thay thế thư viện linalg trong apache commons math 2.0 , mặc dù tôi không chắc điều đó tiến triển gần đây như thế nào.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.