2017-05-08 58 views
3

我試圖從331x23152和23152x23152矩陣中獲取點積。R中的慢點積

在Python和Octave中這是一個簡單的操作,但是在R中這似乎非常慢。

N <- 331 
M <- 23152 

mat_1 = matrix(rnorm(N*M,mean=0,sd=1), N, M) 
mat_2 = matrix(rnorm(N*M,mean=0,sd=1), M, M) 
tm3 <- system.time({ 
    mat_3 = mat_1%*%mat_2 
}) 
print(tm3) 

輸出是

user system elapsed 
101.95 0.04 101.99 

換句話說,這點積需要超過100秒來執行。

我正在運行64位R-3.4.0,在帶有16 GB RAM的i7-4790上運行RStudio v1.0.143。因此,我不希望這項行動花費這麼長時間。

我可以俯視嗎?我已經開始研究包bigmemory和bigalgebra,但我不禁想到有一個解決方案,而不必訴諸包。


編輯

爲了讓您有時間差的想法,以下是八度的腳本:

n = 331; 
m = 23152; 

mat_1 = rand(n,m); 
mat_2 = rand(m,m); 
tic 
mat_3 = mat_1*mat_2; 
toc 

輸出是

Elapsed time is 3.81038 seconds. 

而且在Python:

import numpy as np 
import time 

n = 331 
m = 23152 

mat_1 = np.random.random((n,m)) 
mat_2 = np.random.random((m,m)) 
tm_1 = time.time() 
mat_3 = np.dot(mat_1,mat_2) 
tm_2 = time.time() 
tm_3 = tm_2 - tm_1 
print(tm_3) 

輸出是

2.781277894973755 

正如你所看到的,這些數字都沒有,即使在同一個球場。

EDIT 2

宋哲元在李的要求,這裏是點積玩具的例子。

在R:

mat_1 = matrix(c(1,2,1,2,1,2), nrow = 2, ncol = 3) 
mat_2 = matrix(c(1,1,1,2,2,2,3,3,3), nrow = 3, ncol = 3) 
mat_3 = mat_1 %*% mat_2 
print(mat_3) 

的輸出是:

 [,1] [,2] [,3] 
[1,] 3 6 9 
[2,] 6 12 18 

在八度:

mat_1 = [1,1,1;2,2,2]; 
mat_2 = [1,2,3;1,2,3;1,2,3]; 
mat_3 = mat_1*mat_2 

的輸出是:

mat_3 = 

    3 6 9 
    6 12 18 

在Python:

import numpy as np 

mat_1 = np.array([[1,1,1],[2,2,2]]) 
mat_2 = np.array([[1,2,3],[1,2,3],[1,2,3]]) 
mat_3 = np.dot(mat_1, mat_2) 
print(mat_3) 

的輸出是:

[[ 3 6 9] 
[ 6 12 18]] 

有關矩陣的點產品的更多信息:https://en.wikipedia.org/wiki/Matrix_multiplication

EDIT 3

sessionInfo()的輸出是:

> sessionInfo() 
R version 3.4.0 (2017-04-21) 
Platform: x86_64-w64-mingw32/x64 (64-bit) 
Running under: Windows 7 x64 (build 7601) Service Pack 1 

Matrix products: default 

locale: 
[1] LC_COLLATE=Dutch_Netherlands.1252 LC_CTYPE=Dutch_Netherlands.1252 LC_MONETARY=Dutch_Netherlands.1252 
[4] LC_NUMERIC=C      LC_TIME=Dutch_Netherlands.1252  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

loaded via a namespace (and not attached): 
[1] compiler_3.4.0 tools_3.4.0 

EDIT 4

我試過bigalgebra包,但這似乎並沒有加快速度:

library('bigalgebra') 

N <- 331 
M <- 23152 

mat_1 = matrix(rnorm(N*M,mean=0,sd=1), N, M) 
mat_1 <- as.big.matrix(mat_1) 
mat_2 = matrix(rnorm(N*M,mean=0,sd=1), M, M) 
tm3 <- system.time({ 
    mat_3 = mat_1%*%mat_2 
}) 
print(tm3) 

輸出是:

user system elapsed 
101.79 0.00 101.81 

EDIT 5

詹姆斯建議改變我的隨機產生的矩陣:

N <- 331 
M <- 23152 

mat_1 = matrix(runif(N*M), N, M) 
mat_2 = matrix(runif(M*M), M, M) 
tm3 <- system.time({ 
    mat_3 = mat_1%*%mat_2 
}) 
print(tm3) 

的輸出是:

user system elapsed 
102.46 0.05 103.00 
+2

R的矩陣運算速度取決於您的R版本,操作系統以及它是否鏈接了BLAS庫。一種簡單的方法是安裝Microsoft R Open,或者您可以將它連接到[Intel MKL](https ://software.intel.com/en-us/articles/using-intel-mkl-with-r)。 [查看更多](https://simplystatistics.org/2016/01/21/parallel-blas-in-r/)。 –

+0

@李哲源ZheyuanLi:如果你的意思是我想要點產品,那麼是嗎?據我所知,這三種實現都採用兩個矩陣的點積,或者我錯過了什麼? – BdB

+0

8核:R:4至5核,Python:7至8核,八進制:8核。所以確實看起來R使用大約一半的可用處理能力 – BdB

回答

1

根據knb和Zheyuan Li的回覆,我開始研究優化的BLAS軟件包。我遇到了GotoBlas,OpenBLAS和MKL,例如here

我的結論是,MKL遠遠超過默認的BLAS。

看來R必須從源碼構建,才能合併MKL。相反,我發現R Open。這有MKL(可選)內置,因此安裝非常輕鬆。

用下面的代碼:

N <- 331 
M <- 23152 

mat_1 = matrix(rnorm(N*M,mean=0,sd=1), N, M) 
mat_2 = matrix(rnorm(N*M,mean=0,sd=1), M, M) 
tm3 <- system.time({ 
    mat_3 = mat_1%*%mat_2 
}) 
print(tm3) 

的輸出是:

user system elapsed 
    10.61 0.10 3.12 

這樣,一個解決這個問題的方法是使用MKL而不是默認BLAS。

但是,經過調查,我的真實生活矩陣非常稀疏。通過使用Matrix軟件包,我可以充分利用這一優勢。在實踐中,我使用它如Matrix(x = mat_1, sparse = TRUE),其中mat_1將是高度稀疏的矩陣。這將執行時間縮短到3秒左右。

6

這是一個簡單的操作??矩陣乘法在線性代數計算中一直是一個昂貴的操作。

其實我覺得它速度很快。在這個大小的矩陣乘法有

2 * 23.152 * 23.152 * 0.331 = 354.8 GFLOP 

用100秒你的表現是3.5 GFLOPs。請注意,在大多數機器上,性能至多爲0.8 GLOP - 2 GFLOP,除非您擁有優化的BLAS庫。

如果您認爲其他地方的實施更快,請檢查使用優化的BLAS或並行計算的可能性。 R使用標準的BLAS來做這件事,而且沒有並行性。


重要

從R-3.4.0,更多的工具可以與BLAS。

首先,sessionInfo()現在返回鏈接的BLAS庫的完整路徑。是的,這並不指向符號鏈接,而是最終的共享對象!這裏的其他答案只是表明了這一點:它有OpenBLAS。

時間結果(在另一個答案中)意味着並行計算(通過OpenBLAS中的多線程)已到位。我很難說出所用線程的數量,但看起來像超線程,因爲「系統」的插槽相當大!

二,options現在可以通過matprod設置矩陣乘法的方法。儘管這是爲了處理NA/NaN而推出的,但它也提供了性能測試!

  • 「內部」是未優化的三重循環嵌套中的實現。這是用C編寫的,並且與F77中編寫的標準(參考)BLAS具有相同的性能;
  • 「default」,「blas」和「default.simd」表示使用鏈接的BLAS進行計算,但檢查NA和NaN的方法不同。如果R與標準BLAS相關聯,那麼正如所說的那樣,它與「內部」具有相同的性能;但否則我們會看到顯着的提振。另請注意,R團隊表示將來可能會刪除「default.simd」。
1

我有一個類似的機器:Linux的PC,16 GB內存,英特爾4770K,

sessionInfo()

R version 3.4.0 (2017-04-21) 
Platform: x86_64-pc-linux-gnu (64-bit) 
Running under: Ubuntu 16.04.2 LTS 

Matrix products: default 
BLAS: /usr/lib/openblas-base/libblas.so.3 
LAPACK: /usr/lib/libopenblasp-r0.2.18.so 

locale: 
[1] LC_CTYPE=en_US.UTF-8  LC_NUMERIC=C    LC_TIME=de_DE.UTF-8  LC_COLLATE=en_US.UTF-8  
[5] LC_MONETARY=de_DE.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=de_DE.UTF-8  LC_NAME=C     
[9] LC_ADDRESS=C    LC_TELEPHONE=C    LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] knitr_1.15.1 clipr_0.3.2 tibble_1.3.0 colorout_1.1-2 

loaded via a namespace (and not attached): 
[1] compiler_3.4.0 tools_3.4.0 Rcpp_0.12.10 

在我的機器相關的輸出,您的代碼段需要約5秒(開始RStudio,創建的空.R文件,跑片斷,輸出):

user system elapsed 
27.608 5.524 4.920 

段:

N <- 331 
M <- 23152 

mat_1 = matrix(rnorm(N*M,mean=0,sd=1), N, M) 
mat_2 = matrix(rnorm(N*M,mean=0,sd=1), M, M) 
tm3 <- system.time({ 
     mat_3 = mat_1 %*% mat_2 
}) 
print(tm3)