はじめに
Rubyで線形代数・機械学習アルゴリズムの実装を行う場合、SciRubyのNMatrixが最適だろう。 このNMatrixで、 RやPythonのNumpyと同様に、後ろで叩いているBLAS/LAPACKを、OpenBLASやIntel MKLに変えることで、高速化することを考えた。 しかし、Macでは、BLAS/LAPACKはAccelerate Frameworkに含まれていて、OpenBLASに変えるまでもなく十分に速かった。 環境は、MacBook、Intel Core m3 1.1Ghz、メモリ8G、macOS Sierra 10.12.6 である。
行列積での実行速度の計測
まずは、素のNMatrixと、MacのBLAS/LAPACKを使う場合の実行速度を計測した。 インストールは、gemからもできるが、測定条件を一致させるため最新版をビルドする方法を採用した。
$ git clone https://github.com/SciRuby/nmatrix.git $ cd nmatrix/ $ bundle install $ bundle exec rake compile nmatrix_plugins=lapacke $ bundle exec rake spec nmatrix_plugins=lapacke $ bundle exec rake install nmatrix_plugins=lapacke
単純な行列積で、実行速度を計測する。行列積が速くなると色々と嬉しい。
require 'nmatrix' require 'benchmark' Benchmark.bm do |x| x.report do 50.times do a = NMatrix.random [1000, 1000] b = NMatrix.random [1000, 1000] c = a.dot b end end end
これを、実行すると以下の様になる。
$ ruby test_nmat.rb user system total real 53.790000 1.400000 55.190000 ( 56.935680)
さらにLAPACKプラグインの実行速度を確認するため、require ‘nmatrix'を、
require 'nmatrix/lapacke'
と変更する。これを実行すると、素のNMatrixと比較してグンと速くなった。
$ ruby test_nmat.rb user system total real 23.050000 1.090000 24.140000 ( 18.840261)
OpenBLASに差し替えた場合での実行速度
OpenBLASは、Homebrewでインストールできる。 「–build-from-source」や「–with-openmp」といったオプションも指定できるが、 何も指定しないものが、行列積では最も速かった。
brew install openblas
「ext/nmatrix_lapacke/extconf.rb」を編集して、OpenBLASを使用するようにする。
... #ldefaults = {lapack: ["/usr/local/lib"].delete_if { |d| !Dir.exists?(d) } } ldefaults = {lapack: ["/usr/local/opt/openblas/lib"] } ... #$libs += " -llapack " $libs += " -L/usr/local/opt/openblas/lib -lopenblas " ...
NMatrixを再インストールする。
$ gem uninstall namtrix nmatix-lapacke $ bundle exec rake clean $ bundle exec rake compile nmatrix_plugins=lapacke $ bundle exec rake spec nmatrix_plugins=lapacke $ bundle exec rake install nmatrix_plugins=lapacke
OpenBLASを叩くLAPACKプラグインという状態なので、
require 'nmatrix/lapacke'
とする。実行してみると、LAPACKの結果と大差ないものとなった。
$ ruby test_nmat.rb user system total real 27.400000 4.530000 31.930000 ( 17.920017)
特異値分解での実行速度の計測
以下の特異値分解を含むプログラムでも比較を行った。
require 'nmatrix/lapacke' require 'benchmark' Benchmark.bm do |x| x.report do 50.times do a = NMatrix.random [200, 2000] b = a.dot a.transpose # b.gesvd end end end
LAPACKを使用した場合では、
$ ruby test_nmat2.rb user system total real 6.040000 0.300000 6.340000 ( 5.908795)
となり、OpenBLASを使用した場合では、
$ ruby test_nmat2.rb user system total real 27.220000 4.920000 32.140000 ( 16.595134)
となった。OpenBLASよりもLAPACKの方が速く、 MacではAccelerate FrameworkのBLAS/LAPACKを使用した方が良いことがわかる。
ちなみに、Intel MKLでも試したが、Accelerate FrameworkのBLAS/LAPACKの方が速かった。 また、Intel MKLでは、rake spec した際にコケてしまった。
おわりに
MacでNMatrixを使用する場合は、
gem install nmatrix nmatrix-lapacke
として、
require 'nmatrix/lapacke'
とすれば良い。