Python
scipy
numpy
LAPACK
BLAS

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

More than 1 year has passed since last update.

前に書いた記事 で,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)"

ここにあるテストスクリプトを走らせて,速度を確認してみると良いかもしれない.

# 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を以下のように書き換える.

(旧)

__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''

(新)

__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)"