質問
RCPParmadilloで書かれた関数とArmadilloライブラリを使用してスタンドアロンC ++プログラムに書かれたものとの間のパフォーマンスの違いを理解しようとしています。たとえば、従来の教科書式を使用して線形モデルの係数を計算する次の簡単な機能を考えてみましょう。
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;
// [[Rcpp::export]]
void simpleLm(NumericMatrix Xr, NumericMatrix yr) {
int n = Xr.nrow(), k = Xr.ncol();
mat X(Xr.begin(), n, k, false);
colvec y(yr.begin(), yr.nrow(), false);
colvec coef = inv(X.t()*X)*X.t()*y;
}
.
1000000x100
のX
マトリックスで実行するのに約6秒かかります。コード(図示せず)内のいくつかのタイミングは、すべての時間がcoef
計算に費やされていることを示した。
X <- matrix(rnorm(1000000*100), ncol=100)
y <- matrix(rep(1, 1000000))
system.time(simpleLm(X,y))
user system elapsed
6.028 0.009 6.040
.
現在、C ++で書かれた非常に類似の関数を検討してからg++
でコンパイルされます。
#include <iostream>
#include <armadillo>
#include <chrono>
#include <cstdlib>
using namespace std;
using namespace arma;
int main(int argc, char **argv) {
int n = 1000000;
mat X = randu<mat>(n,100);
vec y = ones<vec>(n);
chrono::steady_clock::time_point start = chrono::steady_clock::now();
colvec coef = inv(X.t()*X)*X.t()*y;
chrono::steady_clock::time_point end = chrono::steady_clock::now();
chrono::duration<double, milli> diff = end - start;
cout << diff.count() << endl;
return 0;
}
.
ここでは、coef
変数の計算は、RCPパラディロを使用して行われたときのほんの0.5秒、またはわずか1/12の時間だけです。
R 3.1.0、RCPP 0.11.1およびRCPパッキル0.4.200.0でMac OS X 10.9.2を使用しています。 SourceCPP関数を使用してRCPPの例をコンパイルしました。スタンドアロンC ++の例ではArmadillo 4.200.0を使用し、HomeBrew(brew install gfortran
)を使用してMac用のFortranコンパイラもインストールしました。
解決
クイック推測:ネイティブプログラムは加速されたBlasを使用しています、あなたはrビルドはそうではありません。
実際の「行列数学」は、ArmadilloによってBLASライブラリに農作されています。RcpParmadilloを使えば、あなたは何を対抗するかを手に入れます。ネイティブプログラムでは、多分あなたは何か他のものを使う。Rではないのは、プログラムが高速化ライブラリを使用するようになるのと同じくらい簡単かもしれません - 私は本当にOS Xを使用しないようにはわかりません。
しかし、私の(I7、Linux)機械について、時刻は同一の近くにあります。
最初のプログラム、変更されていない:
edd@max:/tmp$ g++ -std=c++11 -O3 -o abiel abiel.cpp -larmadillo -llapack
edd@max:/tmp$ ./abiel
2454
edd@max:/tmp$
.
秒、あなたのプログラムは何かを呼ぶことができる何かに包まれました(下記参照):
R> library(Rcpp)
R> sourceCpp("/tmp/abielviaR.cpp")
R> abielDemo()
2354.41
[1] TRUE
R>
.
ほぼ同じです。
abielviaR.cpp
のコードは続きます。
#include <RcppArmadillo.h>
#include <chrono>
using namespace std;
using namespace arma;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
bool abielDemo() {
int n = 1000000;
mat X = randu<mat>(n,100);
vec y = ones<vec>(n);
chrono::steady_clock::time_point start = chrono::steady_clock::now();
colvec coef = inv(X.t()*X)*X.t()*y;
chrono::steady_clock::time_point end = chrono::steady_clock::now();
chrono::duration<double, milli> diff = end - start;
Rcpp::Rcout << diff.count() << endl;
return true;
}
.
PSあなたは本当に(X'x)^( - 1)xを介してOLSを計算しないでください。