Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実験の再現性と効率化の話(Docker と Serialization 周辺)

@smly
July 05, 2016
3k

実験の再現性と効率化の話(Docker と Serialization 周辺)

2016-07-04 ビッグデータ基盤勉強会での発表資料です.Kaggle Tokyo Meetup #1 の資料から主に Serialization の Blosc まわりの説明を加筆しています.

@smly

July 05, 2016
Tweet

Transcript

  1. Agenda データ分析のためのエンジニアリング⾯における⼯夫の話をします. 1.  Workflow (Reproducible Research) 2.  Serialization (Blosc) 3. 

    Docker (AWS + Docker Machine) Disclaimer: スパコンや⼤企業レベルのノード数のコンピューターを扱う話ではない. 個⼈研究者や野良研究者がなるべく安価にマシンリソースを活⽤する話です
  2. Well-designed Workflow Patterns ▶  分析・実験結果を発展させるためには「再現性の確保」や 「プロセスの効率化」が重要となる. ▶  “Patterns for Research

    in Machine Learning” –  http://arkitus.com/patterns-for-research-in-machine-learning/ –  Always, always use version control. –  Separate code from data. –  Separate input data, working data and output data. –  Modify input data with care. –  Save everything to disk frequently. –  Separate options from parameters. –  Do not use global variables. –  Record the options used to generate each run of the algorithm. –  Make it easy to sweep options. –  Make it easy to execute only portions of the code.
  3. ディレクトリ構造:データの配置 ~/kaggle/telstra:$ tree . ├── data │ ├── input │

    │ ├── train.csv │ │ ├── test.csv │ │ └── cv_id.csv │ ├── working │ └── output ├── trunk │ └── table_schema.xlsx ├── Dockerfile ├── base.py ├── model.py └── feat.py ▶  データとコードを分離 ▶  ⼊⼒,出⼒,中間データの分離 ▶  交差確認のインデックスファイル ▶  その他ファイルは trunk
  4. ディレクトリ構造:コード ~/kaggle/telstra:$ tree . ├── data │ ├── input │

    │ ├── train.csv │ │ ├── test.csv │ │ └── cv_id.csv │ ├── working │ └── output ├── trunk │ └── table_schema.xlsx ├── Dockerfile ├── base.py ├── model.py └── feat.py ▶  base.py には各⼊⼒ファイルの ファイルパスを定義した定数や 予測モデルの基底クラスなど ▶  model.py で基底クラスを継承して 個別の予測モデルを定義 ▶  feat.py には特徴量の定義
  5. Make it easy to execute only portions of the code

    特徴量抽出・予測モデル作成・交差確認それぞれの部分をわけて実⾏ できるようにする.異なるサーバーで並⾏実⾏する際に役に⽴つ # 交差確認の Fold0 の prediction を “data/output/v1_val_fold0” に保存 [cluster001]$ python model.py -v -f0 -m v1 # 交差確認の Fold1 の prediction を “data/output/v1_val_fold1” に保存 [cluster002]$ python model.py -v -f1 -m v1 # 交差確認の Fold2 の prediction を “data/output/v1_val_fold2” に保存 [cluster003]$ python model.py -v -f2 -m v1 # training data 全体で学習して prediction を “data/output/v1_test” に保存 [cluster004]$ python model.py –t -m v1 実⾏環境が問題となることも(ソフトウェアバージョンの不⼀致など) → 実⾏環境を Docker で仮想化して管理する.後述
  6. Agenda データ分析のためのエンジニアリング⾯における⼯夫の話をします. 1.  Workflow (Reproducible Research) 2.  Serialization (Blosc) 3. 

    Docker (AWS + Docker Machine) 予測モデルを作るには「特徴量作成」 「パラメータチューニング」「前処理」 「アンサンブルのための個別モデル」な どを何度も試⾏錯誤する. そのためには中間ファイルを⼤量に書き 出すためシリアライズは重要な話
  7. Feather R, Python のデータフレームオブジェクトを Apache Arrow*1 の メモリレイアウトで “ファイル” に保存する補完的なライブラリ

    ▶  R, Python (Pandas) のデータフレームを “ファイル” に保存して お互いの環境で読み込むことができる ▶  ただし 2016年7⽉現在ではバージョン間の安定性を保証しない.データ圧 縮を⾏わない.発展途上(あるいは実験的)なライブラリである import feather import pandas as pd import numpy as np arr = np.random.randn(10000000) # 10% nulls arr[::10] = np.nan df = pd.DataFrame({'column_{0}'.format(i): arr for i in range(10)}) feather.write_dataframe(df, 'test.feather') library(feather) x <- runif(1e7) x[sample(1e7, 1e6)] <- NA # 10% NAs df <- as.data.frame(replicate(10, x)) write_feather(df, 'test.feather') *1: Spark, Drill, Impala などのインメモリシステムで共通のメモリレイアウトを使うことで, システム間のオーバーヘッドを減らすことを⽬指したプロジェクト
  8. Blosc: A BLOcked Shuffler & Compressor 数値データを lightweight かつ⾼速に serialize

    するためにデザインさ れた meta-compressor.⾼い圧縮率を捨て,速さを重視する ▶  Blocking による分割統治を⾏うことでマルチスレッド対応 ▶  Bitshuffle により数値データに対して⾼速で⾼い圧縮率 ▶  SIMD を積極的に使う FastLZ ベースの compressor がデフォルト Blosc のインメモリデータ構造でデータを扱うことで memcpy() より⾼速 にデータを処理することができる (補⾜:メモリから CPU への転送で CPU Starvation が発⽣する.blocking して並列化できる ようにしたり圧縮した状態でデータを保持しておいて,CPU へ転送して展開したほうが,その ままの状態で保持して CPU へ転送するよりも速いという話.逸脱するので割愛)
  9. Blocking techniques Dataset を個別の block に分割して別々のスレッドで処理する. Block ⻑は L1, L2

    cache に収まるサイズにデザインされている (compression level 6 までは L1 に,6 より上は L2 にフィット) Image source: h.p://www.slideshare.net/PyData/blosc-sending-data-from-memory-to-cpu-and-back-faster-than-memcpy-by-francesc-alted
  10. Shuffling による圧縮率の向上 圧縮の前処理として:データストリーム上のバイト単位のデータ順序 を規則的に⼊れ替えることで圧縮率の向上を図る - “A compression scheme for radio

    data in high performance computing” http://arxiv.org/abs/1503.00638 - “New 'bitshuffle' filter“ http://blosc.org/blog/new-bitshuffle-filter.html 00 1 00 00 01 00 23 00 00 17 00 43 00 00 2B 00 56 00 00 38 01 17 2B 38 00 00 00 00 00 00 00 00 00 00 00 00 Blosc では SIMD (SSE/AVX2) をサポートした bit-level の shuffle (Bitshuffle) が実装されている. 1 byte ⽬のグループ 2 byte ⽬のグループ 3 byte ⽬のグループ 4 byte ⽬のグループ
  11. HDF5 における blosc サポート (ndarray) Python ではデータコンテナ HDF5 を管理する PyTables

    package が blosc をサポートしている.ndarray を HDF5 に保存する例: # ndarray を HDF5 に保存 import tables as tb import numpy as np def save(X, filepath): with tb.open_file(filepath, 'w') as f: filters = tb.Filters(complevel=5, complib='blosc') data_ = f.create_earray(f.root, 'data', tb.Float32Atom(), shape=(0,), filters=filters) shape_ = f.create_earray(f.root, 'shape', tb.Int32Atom(), shape=(0,), filters=filters) data_.append(X.ravel()) shape_.append(np.array([X.shape[0], X.shape[1]]))
  12. HDF5 における blosc サポート (ndarray) Python ではデータコンテナ HDF5 を管理する PyTables

    package が blosc をサポートしている.ndarray を HDF5 に保存する例: # ndarray を HDF5 に保存 import tables as tb import numpy as np def load(filepath): with tb.open_file(filepath, ‘r') as f: l = f.root.shape[0] n = f.root.shape[1] X = f.root.data[:] return X.reshape((l, n))
  13. HDF5 における blosc サポート (pandas) Pandas.DataFrame の中間ファイルへの保存にも使うことができる (内部的に PyTables 実装を使っている)

    # DataFrame を HDF5 に保存 import pandas as pd IRIS_CSV = 'http://www.ats.ucla.edu/stat/data/binary.csv’ iris = pd.read_csv(IRIS_CSV) # Save & Load iris.to_hdf('iris.h5', 'table', complib='blosc’) iris = pd.read_hdf('iris.h5', 'table')
  14. 疎⾏列の保存:MATLAB Format ▶  SciPy は疎⾏列の保存⽅法として MATLAB Format をサポート ▶  しかし⾏列サイズに上限があるので⼤きな疎⾏列には使えない

    –  4GB 以上の⼤きな⾏列を保存することができない –  N-gram feature を扱う場合,問題となり得る –  圧縮すると保存に時間がかかり,圧縮しないとサイズが⼤きい –  何度も繰り返しセーブ・ロードする⽤途には向かない…
  15. 疎⾏列の保存:HDF5 Store ▶  疎⾏列を複数のベクトルで圧縮表現 ▶  ベクトルも blosc アルゴリズムで圧縮して HDF5 に保存する

    # 疎⾏列 CSC Matrix を複数の数値列で圧縮表現して HDF5 に保存する def savemat(X, filepath): X = ss.csc_matrix(X) with tables.open_file(filepath, 'w') as f: filters = tables.Filters(complevel=5, complib='blosc') out_data = f.create_earray( f.root, 'data', tables.Float32Atom(), shape=(0,), filters=filters) out_indices = f.create_earray( f.root, 'indices', tables.Int32Atom(), shape=(0,), filters=filters) out_indptr = f.create_earray( f.root, 'indptr', tables.Int32Atom(), shape=(0,), filters=filters) out_shape = f.create_earray( f.root, 'shape', tables.Int32Atom(), shape=(0,), filters=filters) out_data.append(X.data) out_indices.append(X.indices) out_indptr.append(X.indptr) out_shape.append(np.array([X.shape[0], X.shape[1]]))
  16. 疎⾏列の保存:HDF5 Store ▶  疎⾏列を複数のベクトルで圧縮表現 ▶  ベクトルも blosc アルゴリズムで圧縮して HDF5 に保存する

    # ロードする def loadmat(filepath): with tb.open_file(filepath, 'r') as f: l = f.root.shape[1] n = f.root.shape[0] X = ss.csr_matrix( (f.root.data[:], f.root.indices[:], f.root.indptr[:]), shape=(l, n)) X = ss.csc_matrix(X.T) return X
  17. Amazon AWS ▶  S3 + EC2 spot instance の組 み合わせは財布に優しい

    ▶  しかし GPU instance は半年前 から価格が暴⾛している ▶  素直に On-Demand instance を借りたほうが良い場合もある
  18. 扱うものが増えると管理ができなくなる # 3fold CV の各 fold を 3 台の EC2

    instance で並⾏して計算 dev$ ssh –i kaggle-ws.pem \ ubuntu@aws01 \ "cd /home/ubuntu/ws; bash run.sh python v1.py -v -f0” dev$ ssh –i kaggle-ws.pem \ ubuntu@aws02 \ "cd /home/ubuntu/ws; bash run.sh python v1.py -v -f1” dev$ ssh –i kaggle-ws.pem \ ubuntu@aws03 \ "cd /home/ubuntu/ws; bash run.sh python v1.py -v -f2" # run.sh git pull aws s3 sync s3://mybucket/cervical data $* aws s3 sync data s3://mybucket/cervical サーバーの台数が 10 台とか増えると管理がつらくなる ⼤量のイメージ, 中間ファイル,スナップショット, ボリューム…
  19. Docker で実⾏環境を使い捨てる KVM などのハイパーバイザー型仮想化技術と異 なり,Linux コンテナ (LXC) と cgroups のリ

    ソース管理機能を活⽤するツール 仮想ハードウェアのエミュレーションやゲスト OSの起動などのオーバーヘッドがないので,プ ロセス実⾏が⾮常に⾼速.Web システム以外に 分析環境を⼿軽に提供する場⾯でも使われてい る パッケージ郡をまとめたイメージや NVIDIA の CUDA Toolkit インストール済みイメージなど: - ref: “Kaggle R docker image” https://github.com/Kaggle/docker-rstats - ref: “Data-Science-Notebook” https://github.com/dnc1994/Data-Science-Notebook - ref: “NVIDIA Docker” https://github.com/NVIDIA/nvidia-docker (* Docker ⾃⾝を拡張)
  20. ⽤途ごとに Docker イメージを作成する Kaggle のデータ分析コンテストのために作ったコンパクトなイメージ Alpine Linux に miniconda と

    XGBoost 0.47 を同梱 サイズは 317MB (Virtual Size=994.7 MB).Docker Hub で⾃動ビルド # 動作確認 dev$ docker pull smly/alpine-kaggle Using default tag: latest latest: Pulling from smly/alpine-kaggle (snip) # 実⾏ dev$ docker run --rm -i smly/alpine-kaggle \ python -c "import xgboost; print(xgboost.__version__)” 0.4
  21. コマンド1つで Docker Host を作成 a # スポットリクエストで Docker Host を

    AWS 上に作成する (c3.8xlarge を 5 USD で⼊札) $ docker-machine create \ --driver amazonec2 \ --amazonec2-vpc-id vpc-43537026 \ --amazonec2-subnet-id subnet-9cfbaeeb \ --amazonec2-region us-west-2 \ --amazonec2-zone a \ --amazonec2-instance-type c3.8xlarge \ --amazonec2-root-size 20 \ --amazonec2-ami ami-16b1a077 \ --amazonec2-security-group kaggle-srck \ --amazonec2-request-spot-instance \ --amazonec2-spot-price 5 aws01 Running pre-create checks... Creating machine... (aws01) Launching instance... (aws01) Waiting for spot instance... (aws01) Created spot instance request %v sir-0396hlmq Waiting for machine to be running, this may take a few minutes... Detecting operating system of created instance... Waiting for SSH to be available... (snip) Docker is up and running! To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env aws01
  22. FirePlug: A Plug to Remote Docker Hosts # あらかじめ docker

    host を⽤意しておく. $ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS aws01 - amazonec2 Running tcp://52.36.102.243:2376 v1.9.1 aws02 - amazonec2 Running tcp://52.36.102.244:2376 v1.9.1 # ⼿元の分析環境でスクリプト beat_the_benchmark.py を実⾏する $ python beat_the_benchmark.py [0] train-auc:0.820364 [1] train-auc:0.813448 [2] train-auc:0.827770 [3] train-auc:0.828806 # AWS 上の Docker host 上でカレントディレクトリのスクリプト beat_the_benchmark.py を実⾏ $ fp python beat_the_beanchmark.py Run python beat_the_benchmark.py on aws01... Sending build context to Docker daemon 18.43 kB (snip) [0] train-auc:0.820364 [1] train-auc:0.813448 “fp” を先頭に付けるだけで,ローカル環境のコードを Docker Host で実⾏ https://github.com/smly/fireplug
  23. AWS 上で Docker を使うときのフロー FirePlug はコマンド実⾏ごとに Build → Sync →

    Run → Sync する コンテナは使い捨て.イメージも(基本的に)再利⽤しない Client PC AWS 2. rsync 4. rsync 1. docker build 3. docker run Docker Host Docker Container fs mount
  24. コンテナではなく Docker Host 側のファイルシステムに Sync する コンテナを捨てても Sync したファイルは Docker

    Host で保持される Sync ⽅法は以下の2つから選択: ▶  (Default) クライアント環境から rsync ▶  Docker Host から S3 に aws s3 sync 転送量が増える場合は S3 が便利 (同⼀ AZ 内の転送が課⾦対象外なので) Docker Host とのファイル同期 1. docker build 3. docker run Docker Host Container fs mount