Edited at

Pythonのまま高速化するNumba

More than 3 years have passed since last update.

Cythonは結構使ってきたのですが、どうもめんどくさいと思うことがあり(大規模になるとsetup.pyが必要になるなど)、もっと簡単にPythonを高速化するNumbaというものを知りました。llvmでJITするなんてJuliaみたいで素敵じゃないですか。以下の記事を参考に私も挑戦してみました。Numba自体を初めて目にする方はまずリンク先をご覧ください。

今のところは導入方法に関してのみです。


インストール方法


Mac 10.9 with Python2.7の場合

以下で動きました。

sudo easy_install funcsigs enum34 numba

git clone https://github.com/numba/llvmlite
cd llvmlite/
sudo python setup.py install

以下注意です。


  • llvmliteはeasy_installでも入るが、dylibが足りずに実行時エラー(なぜ?)

  • enum34の他にenumというものもeasy_install可能だが、それがあるとエラー


  • 最初にトライしたマシンと別のMac OS 10.9で試したところimport numbaでエラーが出たが、numpyを入れ直したら解決。あまり何も考えずgithubから以下のコマンドでビルドしただけ…。

    git clone https://github.com/numpy/numpy.git numpy_temp
    
    cd numpy_temp
    python setupegg.py bdist_egg
    sudo easy_install dist/*egg



Windows7 64bit Python2.7の場合

Windows7 with WinPython2.7の場合もそのうち挑戦しますが、llvmが必要だったりC++11対応が多分必要だったり64bitが難しそうだったり壁が多そうです… 苦戦すると思いきやAnaconda入れたらそれだけで通りました。Anaconda初めて使ったのですが数値計算かじる可能性があったり自分のPythonコードを高速化したい人は積極的に使って良さそうです。


使用方法と所感

ここも後ほど加筆しますが、敢えて数値計算ではない処理で試すつもりです。理由は、数値計算に対する効果は上述の先人様が既に評価済であることと、今たまたま自分は数値計算ではなく複雑なバイナリデータの読み書きプログラムなどを作っているからです。


PyInstallerで使えるように

PyInstallerを使うとPythonスクリプトをexecutableにできて他人に配布しやすくなったりしますが、numbaを使ったものは実行時に以下のエラーになります。これは、Pythonが動的にdlopenするファイルに関してPyInstallerが収集に失敗していることが原因です。

OSError: dlopen(/var/folders/qk/z4x58g2962q21q5570g2hj0c0000gn/T/_MEIRXXAjg/llvmlite/binding/libllvmlite.dylib, 6): image not found

そこでこのdylibもビルド結果に含めてやりましょう。以下の手順で問題を回避できます。なおPyInstallerはgithubのtag v2.1を使っています。


Macの場合


  1. python pyinstaller/pyinstaller.py --onefile test.py する。このときtest.specができると同時にこのtest.specを元にexeが作られるが、このexeは上記エラー状態。


  2. test.specに以下のように一行足して、libllvmlite.dylibをonefileされたexecutableの中に埋め込むように指示する。

    # -*- mode: python -*-
    
    a = Analysis(['test.py'],
    pathex=['/path/to/main/script'],
    hiddenimports=[],
    hookspath=None,
    runtime_hooks=None)

    # この下の1行が追加
    a.binaries += [("llvmlite/binding/libllvmlite.dylib", "/Library/Python/2.7/site-packages/llvmlite/binding/libllvmlite.dylib", 'BINARY')]

    pyz = PYZ(a.pure)
    exe = EXE(pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    name='test',
    debug=False,
    strip=None,
    upx=True,
    console=True )



  3. python pyinstaller/pyinstaller.py --clean test.specとし、修正後のtest.specで再ビルドする。



Windows Anacondaの場合

(C:¥Anacondaに環境をインストールしたと仮定します) まずAnaconda環境をPyInstallerで使おうとするとNumba関係なくpywintypesが見つからないエラーに遭遇します。が、ここに書いてあった方法でdllをPyInstallerに見つかる場所に置いて解決できました。

cd C:\Anaconda\Lib\site-packages\win32\

copy pywintypes27.dll lib\
copy pythoncom27.dll lib\

あとはMacの場合と同様にllvmlite.dllの調達方法を.specに書けばOKです。C:¥Anacondaにインストールした場合追加すべき一行は以下のようになるはずです。

a.binaries += [("llvmlite/binding/llvmlite.dll", "C:\\Anaconda\\Lib\\site-packages\\llvmlite\\binding\\llvmlite.dll", 'BINARY')]