R

时间:2017-05-08 16:23:45

标签: r performance matrix matrix-multiplication dot-product

我正在尝试从331x23152和23152x23152矩阵中获取点积。

在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秒才能执行。

我正在运行R-3.4.0 64位,在带有16 GB RAM的i7-4790上运行RStudio v1.0.143。因此,我没想到这个操作需要这么长时间。

我忽略了什么吗?我已经开始研究bigmemory和bigalgebra这些软件包了,但是我无法帮助我们认为这是一个解决方案而无需借助软件包。

修改

为了让您了解时差,这里是Octave的脚本:

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

正如你所看到的,这些数字甚至不在同一个球场。

编辑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

在Octave:

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

编辑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 

编辑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

编辑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 

3 个答案:

答案 0 :(得分:6)

这是一个微不足道的操作?矩阵乘法在线性代数计算中始终是一项昂贵的操作。

其实我觉得它很快。这个大小的矩阵乘法有

cmds.select( 'terrain', r=True )
cmds.select( 'face', add=True )
new_node = cmds.transferAttributes( transferPositions=1 )[0]
cmds.setAttr( new_node +'.searchMethod' , 1 )

100秒,你的表现是3.5 GFLOP。请注意,在大多数机器上,性能最多为0.8 GLOP - 2 GFLOP,除非您有优化的BLAS库。

如果您认为其他地方的实施速度更快,请检查使用优化BLAS或并行计算的可能性。 R使用标准BLAS并没有并行性。

重要

从R-3.4.0开始,BLAS提供了更多工具。

首先,2 * 23.152 * 23.152 * 0.331 = 354.8 GFLOP 现在返回链接的BLAS库的完整路径。是的,这并不是指向符号链接,而是最终的共享对象!这里的另一个答案就是这样:它有OpenBLAS。

时序结果(在另一个答案中)意味着并行计算(通过OpenBLAS中的多线程)到位。我很难说出使用的线程数,但看起来像超线程一样,作为&#34; system&#34;的插槽。很大!

其次,sessionInfo()现在可以通过options设置矩阵乘法方法。虽然这是为了处理NA / NaN而引入的,但它也提供了性能测试!

  • &#34;内部&#34;是非优化的三重循环嵌套中的实现。这是用C语言编写的,并且与用F77编写的标准(参考)BLAS具有相同的性能;
  • &#34;默认&#34;,&#34; blas&#34;和&#34; default.simd&#34;意味着使用链接的BLAS进行计算,但检查NA和NaN的方式不同。如果R与标准BLAS链接,那么如上所述,它与&#34;内部&#34 ;;具有相同的性能。但除此之外,我们看到了显另请注意,R团队表示&#34; default.simd&#34;可能会在将来删除。

答案 1 :(得分:2)

根据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秒钟。

答案 2 :(得分:1)

我有一台类似的机器:Linux PC,16 GB RAM,intel 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)