numpy・scipyでマルチスレッドBLAS・LAPACKを使う

[前に書いた記事](http://qiita.com/_akisato/items/9227b8f17026f3bd76c1) で，python・numpy・scipyをrootを取らずにソースからインストールする方法について述べた．

しかし，上記の方法は以下の問題点がある．
* 遅い．
* すごく遅い．
* とてつもなく遅い．

BLASやLAPACKがマルチスレッド対応になっていないのがその原因．Intel MKLを買うほどお金もないので，OpenBLASを使うことにする．

参考記事は以下の2つ．
* Building Numpy and Scipy with OpenBLAS2 （日本語） https://lucidfrontier45.wordpress.com/2012/02/26/building-numpy-and-scipy-with-gotoblas2/
* Numpy/Scipy with OpenBLAS for Ubuntu 12.04 （英語） http://osdf.github.io/blog/numpyscipy-with-openblas-for-ubuntu-1204.html

# OpenBLAS

SurviveGotoBLASを使う．まずはスタティックライブラリのビルド．

```
# wget http://prs.ism.ac.jp/~nakama/SurviveGotoBLAS2/SurviveGotoBLAS2_3.14.tar.gz
# tar xzf SurviveGotoBLAS2_3.14.tar.gz
# cd survivegotoblas2_3.14
# vim Makefile.rule
TARGET=X86_64
BINARY=64
USE_THREAD=1
USE_OPENMP=1
NUM_THREADS=12    # CPUの数に応じて調節する
NO_CBLAS=1    # CBLASはあとでビルドする
NO_LAPACK=1    # LAPACKもあとでビルドする
# make all -j 4
# cp libgoto2.a ~/lib    # 永続的に残す場所（ここでは~/lib）へコピー
```

Theanoのようにダイナミックリンクライブラリを要求するパッケージもあるので，.soも作る．

```
# mkdir tmp
# cd tmp
# cp ../libgoto2.a .
# ar -x libgoto2.a    # .aを.oに分解
# gfortran -shared -lpthread -lgomp  -o libgoto2.so *.o
# cp libgoto2.so ~/lib    # 永続的に残す場所へコピー
# export BLAS=~/lib/libgoto2.so    # なくても良いかも
```

# CBLAS

SurviveGotoBLASに入っているものを使っても良いが，ここでは自分でビルドする．先ほどビルドしたBLASを忘れずにCBLASビルド時に指定．.soを作るところ（下から2行目）で忘れがちになるので，要注意．

```
# wget http://www.netlib.org/blas/blast-forum/cblas.tgz
# tar xzf cblas.tgz
# cd CBLAS
# cp Makefile.LINUX Makefile.in
# vim Makefile.in
BLLIB = ~/lib/libgoto2.a    # ここでBLASを参照
CBLIB = ../lib/libcblas.a    # CBLASの出力先
LOADER = $(FC) -lpthread
CFLAGS = -O3 -m64 -fPIC -DADD_
FFLAGS = -O3 -m64 -fPIC
# make all -j 4
# cp lib/libcblas.a ~/lib    # 永続的に残す場所へコピー
# gfortran -L${HOME}/lib -lgoto2 -shared -o libcblas.so *.o
# cp libcblas.so ~/lib    # 永続的に残す場所へコピー
```

# LAPACK

これも自分でビルドする．これまでに作ったライブラリをLAPACKビルド時に指定．

```
# wget http://www.netlib.org/lapack/lapack.tgz
# tar xzf lapack.tgz
# cd lapack
# cp INSTALL/make.inc.gfortran make.inc
# vi make.inc
OPTS =  -O3 -m64 -fPIC
NOOPT = -O0 -m64 -fPIC
LOADOPTS = -L${HOME}/lib -lgoto2 -lcblas
# make lapacklib -j 4
# cp liblapack.a ~/lib    # 永続的に残す場所へコピー
# mkdir tmp
# cd tmp
# cp ../liblapack.a .
# ar -x liblapack.a    # .aを.oに分解
# gfortran -L${HOME}/lib -lgoto2 -lcblas -shared -o liblapack.so *.o
# cp liblapack.so ~/lib
# export LAPACK=~/lib/liblapack.so    # なくても良いかも
```

# Numpy

ビルド前にsite.cfgを編集して，そこでBLAS,LAPACKを参照させることがポイント．

```
# wget http://sourceforge.net/projects/numpy/files/NumPy/1.9.0/numpy-1.9.0.tar.gz/download --no-check-certificate
# tar xzf numpy-1.9.0.tar.gz
# cd numpy-1.9.0
# cp site.cfg.example site.cfg
# vim site.cfg
[DEFAULT]
library_dirs = ${HOME}/lib
[atlas]
atlas_libs = goto2,cblas
# python setup.py build
# python setup.py install
```

ちゃんと動いているかどうか，念のためテスト．たぶんここではエラーは出ないはず．

```
# python -c "import numpy; numpy.test(verbose=2)"
```

[ここ](https://gist.github.com/osdf/3842524#file_test_numpy.py)にあるテストスクリプトを走らせて，速度を確認してみると良いかもしれない．

```
# python test_numpy.py

```

# Scipy

```
# wget http://sourceforge.net/projects/scipy/files/scipy/0.14.0/scipy-0.14.0.tar.gz/download
# tar xzvf scipy-0.14.0.tar.gz
# cd scipy-0.14.0
# vim site.cfg
[DEFAULT]
library_dirs = ${HOME}/lib
[atlas]
atlas_libs = lapack,goto2,cblas
```

ここで，scipy/lib/lapack/\_\_init\_\_.pyを以下のように書き換える．

（旧）

```py:__init_old__.py
from scipy.linalg import flapack
from scipy.linalg import clapack
_use_force_clapack = 1
if hasattr(clapack,'empty_module'):
    clapack = flapack
    _use_force_clapack = 0
elif hasattr(flapack,'empty_module'):
    flapack = clapack''
```

（新）

```py:__init__.py
from scipy.linalg import flapack
clapack = flapack
_use_force_clapack = 0
```

最後にビルドインストールして終わり．

```
# python setup.py build
# python setup.py install
```

こちらもテストをしてみる．たまに失敗するかもしれないけれども，

```
# python -c "import numpy; numpy.test(verbose=2)"
```