R中的快速大矩阵乘法

R中的快速大矩阵乘法,r,matrix,R,Matrix,在R中有两个矩阵,我想相乘: a = matrix(rnorm(20*10000, mean=0, sd=5), 20, 10000) b = matrix(rnorm(20*10000, mean=0, sd=5), 20, 10000) t(a)%*%b 考虑到这个矩阵乘法中较大的维数需要大量时间,有没有具体的方法可以加快计算速度?R中是否有任何内置函数可以加快这种乘法?根据您的代码、工作和硬件,有许多方法可以实现这一点 对作业使用“最佳”功能 最简单的方法是使用crossprod,它与t

在R中有两个矩阵,我想相乘:

a = matrix(rnorm(20*10000, mean=0, sd=5), 20, 10000)
b = matrix(rnorm(20*10000, mean=0, sd=5), 20, 10000)
t(a)%*%b

考虑到这个矩阵乘法中较大的维数需要大量时间,有没有具体的方法可以加快计算速度?R中是否有任何内置函数可以加快这种乘法?

根据您的代码、工作和硬件,有许多方法可以实现这一点

  • 对作业使用“最佳”功能
  • 最简单的方法是使用
    crossprod
    ,它与
    t(a)%*%b
    相同(注意-这只会稍微提高速度)

  • 使用(和可能的/)
  • C++可能会提高代码的速度。使用线性代数库可能也会进一步帮助实现这一点(因此Eigen和Armadillo)。然而,这假定您愿意编写一些C++。p>
  • 使用更好的后端
  • 在这一点之后,您将看到BLAS后端,如OpenBLAS、Atlas等。将它们连接到R取决于您的操作系统。如果您使用的是像Ubuntu这样的Debian系统,这是非常容易的。你可以找到一个演示。Armadillo和Eigen等库有时可以进一步利用这些功能

  • GPU计算
  • 如果你有一个GPU(如AMD、NVIDIA等),你可以利用其中的许多内核来大大加快你的计算速度。有一些可能是有用的,包括

    编辑-发表@Jenesaikui对Rcpp益处的评论

    test.cpp

    // [[Rcpp::depends(RcppArmadillo, RcppEigen)]]
    
    #include <RcppArmadillo.h>
    #include <RcppEigen.h>
    
    // [[Rcpp::export]]
    SEXP armaMatMult(arma::mat A, arma::mat B){
        arma::mat C = A * B;
    
        return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMatMult(Eigen::MatrixXd A, Eigen::MatrixXd B){
        Eigen::MatrixXd C = A * B;
    
        return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMapMatMult(const Eigen::Map<Eigen::MatrixXd> A, Eigen::Map<Eigen::MatrixXd> B){
        Eigen::MatrixXd C = A * B;
    
        return Rcpp::wrap(C);
    }
    
    /[[Rcpp::depends(RcppArmadillo,RcppEigen)]]
    #包括
    #包括
    //[[Rcpp::导出]]
    军械司令部(arma::mat A,arma::mat B){
    arma::mat C=A*B;
    返回Rcpp::包装(C);
    }
    //[[Rcpp::导出]]
    SEXP-eigenMatMult(Eigen::MatrixXd A,Eigen::MatrixXd B){
    本征::矩阵xDC=A*B;
    返回Rcpp::包装(C);
    }
    //[[Rcpp::导出]]
    SEXP-eigenMapMatMult(常数特征::映射A,特征::映射B){
    本征::矩阵xDC=A*B;
    返回Rcpp::包装(C);
    }
    
    测试R

    library(Rcpp)
    
    A <- matrix(rnorm(10000), 100, 100)
    B <- matrix(rnorm(10000), 100, 100)
    
    library(microbenchmark)
    sourceCpp("test.cpp")
    microbenchmark(A%*%B, armaMatMult(A, B), eigenMatMult(A, B), eigenMapMatMult(A, B))
    
    Unit: microseconds
                      expr     min       lq     mean   median       uq      max neval
                   A %*% B 885.846 892.1035 933.7457 901.1010 938.9255 1411.647   100
         armaMatMult(A, B) 846.688 857.6320 915.0717 866.2265 893.7790 1421.557   100
        eigenMatMult(A, B) 205.978 208.1295 233.1882 217.0310 229.4730  369.369   100
     eigenMapMatMult(A, B) 192.366 194.9835 207.1035 197.5405 205.2550  366.945   100
    
    库(Rcpp)
    
    A要补充cdeterman的答案: 您可以对密集矩阵乘积使用eigen的内置并行化。为了做到这一点,您需要在openmp激活的情况下进行编译

    // [[Rcpp::depends(RcppArmadillo, RcppEigen)]]
    // [[Rcpp::plugins(openmp)]]
    
    #include <omp.h>
    #include <RcppArmadillo.h>
    #include <RcppEigen.h>
    
    // [[Rcpp::export]]
    SEXP armaMatMult(arma::mat A, arma::mat B){
      arma::mat C = A * B;
      
      return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMatMult(Eigen::MatrixXd A, 
                      Eigen::MatrixXd B, 
                      int n_cores){
      
      Eigen::setNbThreads(n_cores);
      //qDebug()  << Eigen::nbThreads( );
      Eigen::MatrixXd C = A * B;
      
      return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMapMatMult2(const Eigen::Map<Eigen::MatrixXd> A,
                          Eigen::Map<Eigen::MatrixXd> B, 
                          int n_cores){
      
      Eigen::setNbThreads(n_cores);
      Eigen::MatrixXd C = A * B;
      return Rcpp::wrap(C);
    }
    

    你可以尝试使用RealFrimes,这是一个增强的R分布。这里可以用MyPosiro来比较<代码> CouthPoD < /Cord>,可惜速度不太快。@ NBATrends,你是正确的,它不是一个主要的速度增益,但它是下一个逻辑步骤。SUDDL我安装了C++来执行这些操作吗?我试着在r中编写代码,它给了我一个error@kon7如果您使用的是Windows,则需要安装。否则Rcpp、RcppArmadillo、RcppEigen就足够了。我已经安装了R工具,但代码仍然不起作用,在我的windows上尝试代码的具体步骤是什么
    // [[Rcpp::depends(RcppArmadillo, RcppEigen)]]
    // [[Rcpp::plugins(openmp)]]
    
    #include <omp.h>
    #include <RcppArmadillo.h>
    #include <RcppEigen.h>
    
    // [[Rcpp::export]]
    SEXP armaMatMult(arma::mat A, arma::mat B){
      arma::mat C = A * B;
      
      return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMatMult(Eigen::MatrixXd A, 
                      Eigen::MatrixXd B, 
                      int n_cores){
      
      Eigen::setNbThreads(n_cores);
      //qDebug()  << Eigen::nbThreads( );
      Eigen::MatrixXd C = A * B;
      
      return Rcpp::wrap(C);
    }
    
    // [[Rcpp::export]]
    SEXP eigenMapMatMult2(const Eigen::Map<Eigen::MatrixXd> A,
                          Eigen::Map<Eigen::MatrixXd> B, 
                          int n_cores){
      
      Eigen::setNbThreads(n_cores);
      Eigen::MatrixXd C = A * B;
      return Rcpp::wrap(C);
    }
    
    library(microbenchmark)
    
    # Benchmark 1: N = k = 100
    
    N <- 100
    k <- 100
    
    A <- matrix(rnorm(N*k), N, k)
    B <- matrix(rnorm(N*k), k, N)
    
    microbenchmark(A%*%B, 
                   armaMatMult2(A, B),
                   eigenMatMult2(A, B, n_cores = 1),
                   eigenMatMult2(A, B, n_cores = 2),
                   eigenMatMult2(A, B, n_cores = 4),
                   eigenMapMatMult2(A, B, n_cores = 1),
                   eigenMapMatMult2(A, B, n_cores = 2),
                   eigenMapMatMult2(A, B, n_cores = 4), 
                   times = 100
    
    # Unit: microseconds
    #                                 expr   min     lq    mean median     uq   max neval
    #                              A %*% B 535.6 540.75 552.594 551.25 554.50 650.2   100
    #                   armaMatMult2(A, B) 542.0 549.10 560.975 556.35 560.25 738.1   100
    #     eigenMatMult2(A, B, n_cores = 1) 147.1 152.65 159.165 159.65 162.90 180.5   100
    #     eigenMatMult2(A, B, n_cores = 2)  97.1 109.90 124.496 119.60 127.50 391.8   100
    #     eigenMatMult2(A, B, n_cores = 4)  71.7  88.15 155.220 115.55 216.95 507.3   100
    #  eigenMapMatMult2(A, B, n_cores = 1) 139.1 150.10 154.889 154.20 158.35 244.3   100
    #  eigenMapMatMult2(A, B, n_cores = 2)  93.4 105.70 116.808 113.55 120.40 323.7   100
    #  eigenMapMatMult2(A, B, n_cores = 4)  66.8  82.60 161.516 196.25 210.40 598.9   100
    )
    
    # Benchmark 2: N = k = 1000
    
    N <- 1000
    k <- 1000
    
    A <- matrix(rnorm(N*k), N, k)
    B <- matrix(rnorm(N*k), k, N)
    
    microbenchmark(A%*%B, 
                    armaMatMult2(A, B),
                    eigenMatMult2(A, B, n_cores = 1),
                    eigenMatMult2(A, B, n_cores = 2),
                    eigenMatMult2(A, B, n_cores = 4),
                   eigenMapMatMult2(A, B, n_cores = 1),
                   eigenMapMatMult2(A, B, n_cores = 2),
                   eigenMapMatMult2(A, B, n_cores = 4), 
                   times = 100
    )
    
    
    Unit: milliseconds
                                    expr      min        lq      mean    median        uq
                                 A %*% B 597.1293 605.56840 814.52389 665.86650 1025.5896
                      armaMatMult2(A, B) 603.3894 620.25675 830.98947 693.22355 1078.4853
        eigenMatMult2(A, B, n_cores = 1) 131.4696 135.22475 186.69826 193.37870  219.8727
        eigenMatMult2(A, B, n_cores = 2)  67.8948  71.71355 114.52759  74.17380  173.3060
        eigenMatMult2(A, B, n_cores = 4)  41.8564  48.87075  79.55535  72.00705  106.8572
     eigenMapMatMult2(A, B, n_cores = 1) 125.3890 129.26125 175.09933 177.23655  213.0536
     eigenMapMatMult2(A, B, n_cores = 2)  62.2866  65.78785 115.74248  79.92470  167.0217
     eigenMapMatMult2(A, B, n_cores = 4)  35.2977  40.42480  68.21669  63.13655   97.2571
           max neval
     1217.6475   100
     1446.5127   100
      419.2043   100
      217.9513   100
      139.9629   100
      298.2859   100
      230.6307   100
      118.2553   100