やること
互いにssh接続できるマシンをipyparallelでクラスタ化する。
ルート権限はない。
とりあえず1ノードをマスター(jupyter notebook サーバとipyparallelコントローラ)、
全ノードがスレーブ(ipyparallelエンジン)になるように設定する。
作業は全部マスターノード上でok。
環境
Ubuntu 14.04
host1, host2, host3, host4
- それぞれパスワードなし公開鍵でログイン可能
- /home 以下はNFSをマウント
- 全部ユーザ名は
user
Anaconda
$ conda --version
conda 4.4.6
$ which python
/home/user/anaconda3/bin/python
$ python --version
Python 3.6.3 :: Anaconda custom (64-bit)
jupyter
$ jupyter --version
4.3.0
ipyparallel
$ python -c "import ipyparallel; print(ipyparallel.__version__)"
6.0.2
インストール
$ conda install ipyparallel
設定
Jupyterでの IPython Clusters tab の有効化
$ ipcluster nbextension enable --user
--user
をつけないとよくわからないパスのjupyterを探してしまう。
クラスタ用のprofile, kernelspec の設定
ipyparallelはipythonのprofile単位で設定を保存するが
その設定をjupyter上で切り替えられるように。
プロファイル作成
$ ipython profile create --parallel --name=parallel
kernelspec作成
$ jupyter kernelspec install --user --name=parallel
kernelspec確認
$ jupyter kernelspec list
Available kernels:
parallel /home/user/.local/share/jupyter/kernels/parallel
python3 /home/user/anaconda3/share/jupyter/kernels/python3
もしかしたらkernelspec作成で--user
いらないかも。
作成したkernelspecでのipython profileを設定
{
"argv": [
"/home/user/anaconda3/bin/python",
"-m",
"ipykernel_launcher",
"-f",
"{connection_file}",
"--profile",
"parallel"
],
"display_name": "parallel",
"language": "python"
}
"--profile", "parallel"
を追加した。
ipyparallelの設定ファイルの編集
# SSHでエンジン(ノード)を起動
c.IPClusterEngines.engine_launcher_class = 'SSH'
# NFSなのでファイルの同期はしない
c.SSHLauncher.to_fetch = []
c.SSHLauncher.to_send = []
c.SSHEngineSetLauncher.engines = {
host:{
# 各ノードで一つずつカーネルを起動
'n':1,
# パスの設定はログイン時にしかしていないのでここで絶対パスで指定
'engine_cmd':['/home/user/anaconda3/bin/python',
'-m', 'ipyparallel.engine']}
for host in ['host1', 'host2', 'host3', 'host4']
}
# 詳しいことはめんどいのでセキュリティガン無視で全部許可
c.RegistrationFactory.ip = '*'
c.HubFactory.client_ip = '*'
c.HubFactory.engine_ip = '*'
c.HubFactory.monitor_ip = '*'
起動
$ ipcluster start --profile=parallel
各ノードでエンジンが起動していないときは--debug
フラグをつけると色々情報が出る。
これで無事起動するならjupyterのipython clustersタブでも起動できるようになる。
確認
import ipyparallel as ipp
c = ipp.Client()
print(c.ids)
def test():
import os, socket
return os.getcwd(), socket.gethostname()
print(c[:].apply_sync(test))
ちゃんと実行できてホスト名が出てくればok。
実行すればわかるけどワーキングディレクトリは同期されないから注意がいる。
追記
AsyncResultオブジェクトに対するautocomplete (TAB)はデフォルトだとカーネルが停止する。
次の設定をnotebookの先頭に書いておくと解決した。
詳しいことは時間ある時にでも。。。
%config Completer.use_jedi = False
追記その2
シェルコマンドのバカパラ実行例
https://gist.github.com/emakryo/c00e8484c0844fa646ca9fea8350d2cb
追記その3
autoreload が部分的にしか動かない
import bar
def foo_func():
return bar.bar_func()
def bar_func():
return 10
でbar_func
をいじって再び実行すると
ローカルではfoo_func
もbar_func
も正しく実行されるが
クラスタ上ではbar_func
しか正しく実行されない。
sync_import
を使った場合でも一緒。
workaroundとしてはipclusterを再起動すればとりあえず動きはするが
いちいち再起動するのはめんどくさい。
追記その4
モジュールのリロードはimportlib.reload
を使えばできる。
def reload(mod_names):
import sys
from importlib import reload
for m in mod_names:
if m in sys.modules:
reload(sys.modules[m])
c = ipp.Client()
c[:].apply_sync(reload, ['my_module'])
参照
- http://ipyparallel.readthedocs.io/en/stable/process.html (ipyparallel設定)
- http://jupyter.readthedocs.io/en/latest/migrating.html (kernelspecとprofileについて)
- https://qiita.com/tomochiii/items/8b937f15c79a0c3eae0e (kernelspec)