Slide 1

Slide 1 text

実験の再現性と効率化の話 (Docker と Serialization 周辺) @smly 2016-07-04 ビッグデータ基盤勉強会@筑波⼤学

Slide 2

Slide 2 text

Agenda データ分析のためのエンジニアリング⾯における⼯夫の話をします. 1.  Workflow (Reproducible Research) 2.  Serialization (Blosc) 3.  Docker (AWS + Docker Machine) Disclaimer: スパコンや⼤企業レベルのノード数のコンピューターを扱う話ではない. 個⼈研究者や野良研究者がなるべく安価にマシンリソースを活⽤する話です

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

ディレクトリ構造:データの配置 ~/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

Slide 6

Slide 6 text

ディレクトリ構造:コード ~/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 には特徴量の定義

Slide 7

Slide 7 text

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 で仮想化して管理する.後述

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Agenda データ分析のためのエンジニアリング⾯における⼯夫の話をします. 1.  Workflow (Reproducible Research) 2.  Serialization (Blosc) 3.  Docker (AWS + Docker Machine) 予測モデルを作るには「特徴量作成」 「パラメータチューニング」「前処理」 「アンサンブルのための個別モデル」な どを何度も試⾏錯誤する. そのためには中間ファイルを⼤量に書き 出すためシリアライズは重要な話

Slide 10

Slide 10 text

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 などのインメモリシステムで共通のメモリレイアウトを使うことで, システム間のオーバーヘッドを減らすことを⽬指したプロジェクト

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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 ⽬のグループ

Slide 14

Slide 14 text

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]]))

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

疎⾏列の保存:MATLAB Format ▶  SciPy は疎⾏列の保存⽅法として MATLAB Format をサポート ▶  しかし⾏列サイズに上限があるので⼤きな疎⾏列には使えない –  4GB 以上の⼤きな⾏列を保存することができない –  N-gram feature を扱う場合,問題となり得る –  圧縮すると保存に時間がかかり,圧縮しないとサイズが⼤きい –  何度も繰り返しセーブ・ロードする⽤途には向かない…

Slide 18

Slide 18 text

疎⾏列の保存: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]]))

Slide 19

Slide 19 text

疎⾏列の保存: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

Slide 20

Slide 20 text

Benchmark (Dense Matrix) 実験設定1: ランダムな密⾏列 np.random.random((1e7, 30)) 圧縮の難しい密⾏列で np.savez_compressed は無駄 無圧縮と同等の時間 ファイルサイズ 実⾏時間

Slide 21

Slide 21 text

Benchmark (Dense Matrix) 実験設定2: 実データ(Cervical Cancer Screening)の⼀部変数 無圧縮と同等あるいはそれ以上の速さで圧縮 無圧縮と同等の時間 ファイルサイズ 実⾏時間

Slide 22

Slide 22 text

Benchmark (Dense Matrix) 実験設定3:実データ(Springleaf contest)の変数 VAR_0002 を保存 圧縮できる密⾏列で np.savez はディスクの無駄 ファイルサイズ 実⾏時間 圧縮できる場⾯での np.savez は無駄が⼤きい

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Amazon AWS ▶  S3 + EC2 spot instance の組 み合わせは財布に優しい ▶  しかし GPU instance は半年前 から価格が暴⾛している ▶  素直に On-Demand instance を借りたほうが良い場合もある

Slide 25

Slide 25 text

それではたくさんのサーバーを使ったときの事例を⾒てみましょう image source: h.ps://twi.er.com/ultrais.er/status/554280474042847233

Slide 26

Slide 26 text

あるデータ分析コンテストでの利⽤例 (1/2) S3 は「同⼀リージョン間の転送料は無料」 そこまで極端な負担にはならない

Slide 27

Slide 27 text

あるデータ分析コンテストでの利⽤例 (2/2) EC2 はスポットインスタンスでコストを抑えることができる. (m4.10xlarge を 2000 時間で 1k USD は安い)

Slide 28

Slide 28 text

扱うものが増えると管理ができなくなる # 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 台とか増えると管理がつらくなる ⼤量のイメージ, 中間ファイル,スナップショット, ボリューム…

Slide 29

Slide 29 text

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 ⾃⾝を拡張)

Slide 30

Slide 30 text

⽤途ごとに 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

Slide 31

Slide 31 text

コマンド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

Slide 32

Slide 32 text

Remote Docker Host をどのように使いこなすか

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

FirePlug でのイメージビルド ベースとなる Image から⼿元のファイルを追加した仮想イメージを作成 Remote Docker Host でビルドするための転送サイズは⼩さい コピーしたくないファイルは .dockerignore にルール追加 Base Image (smly/alpine-kaggle) One-time Image c7df017aaeeb (987.4 MB) 68fbf78112b5 (18.43 kB) Client PC (current directory)

Slide 36

Slide 36 text

コンテナではなく 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

Slide 37

Slide 37 text

まとめ •  分析・実験結果を発展させるためには「再現性の確保」や 「プロセスの効率化」が重要となる.Workflow を適切に設計する ことで実験の⼿戻りを最⼩限に抑えることができる •  「中間ファイルを頻繁に書き出す」ためには⾼速なシリアライズが 可能なツールが必要となる.Blosc による⾼速な圧縮・シリアライ ズはこの要件を満たす •  Docker による仮想化はクラウドサービスを使う上でも,再現性を 確保する上でも効果的である.