経済学修士残酷物語

東京の経済学修士のブログ。自分の専攻や統計学から最近読んだ本や雑記まで

MacOS版R4.0にOpenBLASをリンクさせる

以前からRの高速化については少し興味があって,この記事を見て割合簡単にできそうだなと思い試してみた記録です. 結論から言うと,自分の環境上ではデフォルトのBLASからOpenBLASに切り替えたところ,ベンチマークでは3~8倍程度高速化しました.特に行列計算での向上が大きく寄与していました.

Rを含めてhomebrewでパッケージ管理をしているのですが,OpenblasとRのリンクについてはbrew単独ではうまくいかなかったのでまとめてみます1

環境

  • OS: MacOS Catalina 10.15.5
$ system_profiler SPHardwareDataType
Hardware:

    Hardware Overview:

      Model Name: MacBook Air
      Model Identifier: MacBookAir9,1
      Processor Name: Quad-Core Intel Core i5
      Processor Speed: 1.1 GHz
      Number of Processors: 1
      Total Number of Cores: 4
      L2 Cache (per Core): 512 KB
      L3 Cache: 6 MB
      Hyper-Threading Technology: Enabled
      Memory: 16 GB
  • R: 4.0.3

homebrewの導入などは省略します.

準備(インストールするもの)

  • gcc:OpenBLASのコンパイル用です.Rをbrew経由で入れている場合は既にインストールされていると思います.brew install gccで入れてください.
  • openblas: こちらもbrewから入れることができます.--build-from-sourceのオプションを付けてソースからビルドしない場合,最適化されないようなので注意してください.
  • ベンチマークスクリプト: R-benchmark-25.Rを用います.乱数生成に際してSuppDistsライブラリが必要ですが,スクリプト内のコメントのように標準の乱数生成関数に変更することもできます.

速度比較

RがリンクしているBLASを確かめる際の手順はこちらの記事を参照してください.

標準BLASの結果

❯ cat R-benchmark-25.R | time R --slave


   R Benchmark 2.5
   ===============
Number of times each test is run__________________________:  3

   I. Matrix calculation
   ---------------------
Creation, transp., deformation of a 2500x2500 matrix (sec):  0.545666666666667
2400x2400 normal distributed random matrix ^1000____ (sec):  0.176
Sorting of 7,000,000 random values__________________ (sec):  0.836999999999999
2800x2800 cross-product matrix (b = a' * a)_________ (sec):  18.3796666666667
Linear regr. over a 3000x3000 matrix (c = a \ b')___ (sec):  9.76233333333334
                      --------------------------------------------
                 Trimmed geom. mean (2 extremes eliminated):  1.64589517363295

   II. Matrix functions
   --------------------
FFT over 2,400,000 random values____________________ (sec):  0.272333333333331
Eigenvalues of a 640x640 random matrix______________ (sec):  0.989333333333339
Determinant of a 2500x2500 random matrix____________ (sec):  3.89733333333334
Cholesky decomposition of a 3000x3000 matrix________ (sec):  6.442
Inverse of a 1600x1600 random matrix________________ (sec):  4.22166666666666
                      --------------------------------------------
                Trimmed geom. mean (2 extremes eliminated):  2.53433902483476

   III. Programmation
   ------------------
3,500,000 Fibonacci numbers calculation (vector calc)(sec):  0.224666666666659
Creation of a 3000x3000 Hilbert matrix (matrix calc) (sec):  0.214666666666668
Grand common divisors of 400,000 pairs (recursion)__ (sec):  0.309333333333323
Creation of a 500x500 Toeplitz matrix (loops)_______ (sec):  0.0759999999999934
Escoufier's method on a 45x45 matrix (mixed)________ (sec):  0.60899999999998
                      --------------------------------------------
                Trimmed geom. mean (2 extremes eliminated):  0.246174647838452


Total time for all 15 tests_________________________ (sec):  46.957
Overall mean (sum of I, II and III trimmed means/3)_ (sec):  1.00887354980068
                      --- End of test ---

R --slave  221.80s user 2.71s system 99% cpu 3:46.49 total

OpenBLASに切り替え

上の記事に従って標準BLASのパスを確認したあとに,brew経由でインストールしたOpenBLASにリンクを張り替えます

$ ln -sf /usr/local/opt/openblas/lib/libopenblas.dylib /usr/local/Cellar/r/4.0.3/lib/R/lib/libRblas.dylib
  • 多くの記事ではbrew install r --with-openblasとしていますが,2020/10/24現在だとinvaid optionのエラーが発生します.今回はシンボリックリンクを張り替えることで対応しました.

OpenBLASの結果

OpenBLASを使用したRの性能を見てみましょう:

❯ cat R-benchmark-25.R | time R --slave

   R Benchmark 2.5
   ===============
Number of times each test is run__________________________:  3

   I. Matrix calculation
   ---------------------
Creation, transp., deformation of a 2500x2500 matrix (sec):  0.509333333333333
2400x2400 normal distributed random matrix ^1000____ (sec):  0.161
Sorting of 7,000,000 random values__________________ (sec):  0.967666666666667
2800x2800 cross-product matrix (b = a' * a)_________ (sec):  0.443666666666666
Linear regr. over a 3000x3000 matrix (c = a \ b')___ (sec):  0.273666666666667
                      --------------------------------------------
                 Trimmed geom. mean (2 extremes eliminated):  0.395451840253713

   II. Matrix functions
   --------------------
FFT over 2,400,000 random values____________________ (sec):  0.223333333333333
Eigenvalues of a 640x640 random matrix______________ (sec):  0.632666666666667
Determinant of a 2500x2500 random matrix____________ (sec):  0.285666666666666
Cholesky decomposition of a 3000x3000 matrix________ (sec):  0.38
Inverse of a 1600x1600 random matrix________________ (sec):  0.448333333333334
                      --------------------------------------------
                Trimmed geom. mean (2 extremes eliminated):  0.365102436446165

   III. Programmation
   ------------------
3,500,000 Fibonacci numbers calculation (vector calc)(sec):  0.253
Creation of a 3000x3000 Hilbert matrix (matrix calc) (sec):  0.212333333333333
Grand common divisors of 400,000 pairs (recursion)__ (sec):  0.261333333333334
Creation of a 500x500 Toeplitz matrix (loops)_______ (sec):  0.0456666666666668
Escoufier's method on a 45x45 matrix (mixed)________ (sec):  0.247999999999998
                      --------------------------------------------
                Trimmed geom. mean (2 extremes eliminated):  0.237062827419034


Total time for all 15 tests_________________________ (sec):  5.34566666666667
Overall mean (sum of I, II and III trimmed means/3)_ (sec):  0.324681290870627
                      --- End of test ---

R --slave  62.53s user 4.91s system 191% cpu 35.241 total

行列演算が30~40倍,コレスキー分解なども10倍程度速くなっており,冒頭で挙げた記事とも整合的な結果が出ました.

homebrewは楽で良いのですが,設定の最適化をする際にはこうして面倒を見る必要があるなという印象です.

参考資料


  1. 後々確認するとRのdependencyにopenblasが含まれており全くの無駄記事を書いている気分になりましたが,私の環境では標準BLASの方にリンクされていたのでそういうパターンもあるようです.