[悲報] numpy, scipyをIntel MKLで転生させたけどそんなに早くならなかった

numpy, scipyは数値計算のライブラリ。自分で作らなくてもやりたいことはほぼ揃っています。numpyやscipyの計算部分はCやFortranで作られてるから高速というのは有名な話ですが、とはいえ行列計算はopen blasが使用されているとのこと。Intel CPUつんでるマシンならIntel MKL使ったら早くなるんじゃね?っていうことで、やってみました。

対象マシン

MacBook Pro (15-inch, 2018)
プロセッサ 2.9 GHz Intel Core i9
メモリ 32 GB 2400 MHz DDR4

numpy scipy with openblas

open blasが紐付いてるかどうか確認してみる。

>>> import numpy
>>> numpy.show_config()
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
>>> import scipy
>>> scipy.show_config()
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]

とりあえず下記のコードでタイム測定してみました。

import numpy as np
import time
import scipy.linalg.blas

N = 10000

A = np.random.rand(N,N)
B = np.random.rand(N,N)

t1 = time.time()
C = scipy.linalg.blas.dgemm(alpha=1.0, a=A, b=B)
t2 = time.time()
print(t2-t1)

結果は以下。

$ python test.py
12.556735038757324
$ python test.py
12.65819001197815
$ python test.py
12.273000955581665

平均で12.496秒でした。

numpy scipy with Intel MKL

では、Intel MKLを試してみましょう。ちなみにIntel MKLのインストールは以下参照。

こういうときvenvが便利です。globalの環境を汚しません。下記のように、”.numpy-site.cfg”にmklのパスを記載してあげてからインストールします。

$ python -m venv venv
$ source ./venv/bin/activate
(venv) $ echo "[mkl]
library_dirs = /opt/intel/mkl/lib/intel64
include_dirs = /opt/intel/mkl/include
mkl_libs = mkl_rt
lapack_libs =" > .numpy-site.cfg
(venv) $ pip install --no-binary :all: numpy
(venv) $ pip install --no-binary :all: scipy

インストール終了後、intel MKLに紐付いているか確認。

>>> import numpy
>>> numpy.show_config()
blas_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
blas_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
lapack_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
lapack_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
>>> import scipy
>>> scipy.show_config()
lapack_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
lapack_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
blas_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
blas_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/include', '/opt/intel/compilers_and_libraries_2019.1.144/mac/mkl/lib']

上と同じコードで計算を走らせてみましょう。

(venv) $ python test.py
11.162160873413086
(venv) $ python test.py
11.657418966293335
(venv) $ python test.py
11.576632022857666

平均時間は11.465秒でした。少し早くなってように思いますが、誤差の範囲でしょうか?期待していたほど早くはなりませんでした。

C/C++での計算結果

同じコードをC/C++で計算させたものが下記です。

-O2オプションだとpythonとほぼ同じですね。python素晴らしい。

「C++、お前の本気はこんなものなのか!?」ってことで、-O3 オプションをつけてコンパイルしてみました。結果は、約7.5秒!やりました。C++の面目を保ちました。

$ c++ -DMKL_ILP64 -m64 -I${MKLROOT}/include  ${MKLROOT}/lib/libmkl_intel_ilp64.a ${MKLROOT}/lib/libmkl_intel_thread.a ${MKLROOT}/lib/libmkl_core.a -liomp5 -lpthread -lm -ldl -O3 -std=c++11 -o dgemm_mkl dgemm_mkl.cpp
$ ./dgemm_mkl
cblas_dgemm with 10000 * 10000 matrix.
Realtime: 7.507 sec.
CPU time: 44.7587sec.

まとめ

numpy, scipyをintel MKLでインストールしてみましたら、ちょっとだけ早くなりました。が、思ってたほど劇的には変わりませんでした。Openblasってすごいんですね。コンパイルに時間かかるので、あんまりコスパは高くないかと。まぁ、コンパイルは最初の一回だけなんですが。

Reference

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です