Common Lispで行列演算: LLA(Lisp Linear Algebra)を使う

Common LispでCPUを使った行列演算を高速にやりたいときは、BLASLAPACKといった、専用に書かれた外部ライブラリを呼ぶことになる。そのためのラッパーライブラリとして、LLA (Lisp Linear Algebra)がある。
LLAでは、普通のReference BLAS以外にもOpenBLAS(旧GotoBLAS)、ATLAS、MKLを使える。このうちマルチスレッド対応なのはATLASとOpenBLAS、MKLだが、ATLASはソースコードからビルドしないとオートチューンが効かない。Ubuntuでapt-getで入るATLASはシングルスレッドでしか動かないらしい(ubuntu 14.04でBLASを使う)。とはいえOpenBLAS と ATLAS の性能を R 上で比較するを見る限り、オートチューンできたとしてもATLASよりはOpenBLASを使った方が多分速い。

OpenBLASのインストール

OpenBLASはUbuntuならapt-getですぐに入る。

sudo apt-get install libopenblas-base
sudo apt-get install libopenblas-dev

MKLのインストール

MKL(Math Kernel Library)はintel謹製の数値計算ライブラリで、intel製のマルチコアCPUの性能をフルに引き出すことができるとされる。
無償版はintelのページで個人情報を登録するとダウンロードできる。1GBくらいある。ダウンロード画面で表示される製品登録キーがインストール時に必要なのでメモっておくことを忘れずに。

インストール自体は、GUIインストーラがあるのでrootで起動して指示に従っていけばいい。その場合インストール先は/opt/intel/以下になる。

LLAのインストールと設定

LLAはquicklispから簡単にインストールできる。

(ql:quickload :lla)

外部ライブラリのパスを cl-user::*lla-configuration* に設定する。LLAをロードする以前に設定する必要があるので~/.sbclrc等の処理系の初期化ファイルに書いておくといい。ライブラリのパスは環境によって変わってるかもしれないのでlocate等で適当に調べる。

;; 普通のlibblasを使う場合
(defvar *lla-configuration*
  '(:libraries ("/usr/lib/libblas/libblas.so.3.0")))

;; openblasを使う場合
(defvar *lla-configuration*
  '(:libraries ("/usr/lib/openblas-base/libblas.so.3")))

;; intel MKLを使う場合
(defvar *lla-configuration*
  '(:libraries ("/usr/lib/x86_64-linux-gnu/libgomp.so.1"
                "/lib/x86_64-linux-gnu/libpthread.so.0"
                "/opt/intel/compilers_and_libraries_2016.1.150/linux/compiler/lib/intel64_lin/libiomp5.so"
                "/opt/intel/compilers_and_libraries_2016.1.150/linux/mkl/lib/intel64_lin/libmkl_rt.so"
                )))

行列積で各ライブラリの実行速度を比較

こちらの記事Python (NumPy) と Common Lisp (LLA) で行列積の実行速度を比較するのコードを使って実験する。
関数lla:mmで行列積が計算できる。行列はsingle-float型の2次元配列とする。ベクトルであっても2次元配列とする必要がある。
ランダムに初期化したN×N行列2つの掛け算を各Nについて100回実行した時間を計測する。環境はUbuntu14.04+Core i5 6440 (4コア)。

simpleは素のCommon Lispで型指定して最適化オプションなども付けて実装した行列積。simpleとblasはシングルスレッドなので遅い。メーカー謹製のMKLが一番速いと思っていたのだが、結果は何故かOpenBLASの方が速かった。

2016/2/19追記

こちらの記事Common Lispで高速行列演算に、上記の素のCommon Lispの行列積を、ループのインライン展開(アンローリング)やキャッシングによって更に最適化したもの(on-register-gemm)があったのでそれを図に追加してみた。

GPUがある場合

より大きなサイズの行列演算はGPUを使った方が速い。Nvidia製のCUDA対応のGPUを持っているなら、cl-cudaベースのMGL-MATが使える。
MGL-MATの作者(cl-libsvmの作者でもある)はディープラーニング等を含む機械学習ライブラリMGLを作っている。MGLでは、CPUの場合はLLAを、GPUがある場合はMGL-MATを使って行列演算をする。
次はMGLを試してみようと思う。