Workflow, Serialization & Docker for Kaggle

4742812a011db89b01a52af6722640b8?s=47 @smly
March 04, 2016
2.3k

Workflow, Serialization & Docker for Kaggle

Kohei's slide for Kaggle Tokyo Meetup #1. (written in Japanese)

4742812a011db89b01a52af6722640b8?s=128

@smly

March 04, 2016
Tweet

Transcript

  1. Workflow, Serialization & Docker for Kaggle smly confirm on 2016-03-05

    at Kaggle Tokyo Meetup #1
  2. About :-) 研究開発する Software Engineer ICPC → ICFP contest →

    KDD Cup → Kaggle と趣味を変えてきた. 最近は Game AI (+ Deep Reinforcement Learning) に興味. (as of 2016-03-05)
  3. Agenda ソフトウェア・エンジニアリングをとことん活⽤して 分析コンテストを攻略する話をします 1.  Workflow (Reproducible Research) 2.  Serialization (bloscpack

    & HDF5) 3.  Docker (DockerMachine, alpine-kaggle & fireplug)
  4. Agenda ソフトウェア・エンジニアリングをとことん活⽤して 分析コンテストを攻略する話をします 1.  Workflow (Reproducible Research) 2.  Serialization (bloscpack

    & HDF5) 3.  Docker (DockerMachine, alpine-kaggle & fireplug)
  5. Well-designed Workflow ▶  実験結果の再現性を確保&プロセスの効率化 ▶  “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.
  6. Directory Structure: Data ~/kaggle/telstra:$ tree . ├── data │ ├──

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

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

    特徴量抽出・予測モデル作成・交差確認それぞれの部分をわけて実⾏ できるようにする.並⾏実⾏の役に⽴つ # 交差確認の Fold0 の prediction を “data/output/v1_val_fold0” に保存 $ python v1.py -v -f0 # 交差確認の Fold1 の prediction を “data/output/v1_val_fold1” に保存 $ python v1.py -v -f1 # 交差確認の Fold2 の prediction を “data/output/v1_val_fold2” に保存 $ python v1.py -v -f2 # training data 全体で学習して prediction を “data/output/v1_test” に保存 $ python v1.py -t
  9. Base Class of Predictive Model (base.py) 同じコードを繰り返し書くことメンテナンスの観点から避けるべき 以下のパラメーターを渡せば学習・交差確認・予測などをすべてよろ しくやってくれるような基底クラスを作成する ▶ 

    Serialize した特徴量のファイルリスト ▶  学習器(sklearn の BaseEstimator インスタンス) ▶  予測モデルのパラメータ 基底クラスを継承してパラメータを渡せば, それだけで新しいモデルができる状態にする.
  10. Demo1 from base import BaseModelV4, XGBClassifier FEATURE_LIST = ["feat.group14.blp”] PARAMS

    = { 'n_estimators': 700, 'subsample': 0.8, 'colsample_bytree': 0.7, 'max_depth': 7, 'eta': 0.03, 'objective': 'multi:softprobʼ, 'eval_metric': 'mlogloss', 'num_class': 3, 'seed': 32, } class Modelv60(BaseModelV4): def build_model(self): return XGBClassifier(**self.params) if __name__ == '__main__': m = Modelv60(name="v60”, flist=FEATURE_LIST, params=PARAMS) m.run() ▶  base.py の基底クラスを継承して パラメータと特徴量だけ異なる 新しいモデルを作成する例
  11. Demo2 def percentile_trafo(X): X2 = [] for i in range(X.shape[1]):

    X2.append((rankdata(X[:, i]) / X.shape[0]).reshape((-1, 1))) return np.hstack(X2) class Modelv142(BaseModelV4): def build_model(self): return ETC(**self.params) def load_X(self): X = super(Modelv142, self).load_X() return np.hstack([ X, percentile_trafo(X), ]) ▶  特徴量の前処理をした⾏列と 前処理をしなかった⾏列を ⽔平⽅向に stack したモデル
  12. Agenda ソフトウェア・エンジニアリングをとことん活⽤して 分析コンテストを攻略する話をします 1.  Workflow (Reproducible Research) 2.  Serialization (bloscpack

    & HDF5) 3.  Docker (DockerMachine, alpine-kaggle & fireplug)
  13. Serialization 中間データ(多次元⾏列)をどのように保存するか ▶  かなり昔やってたこと ▶  全部 pickle … 筋が悪い.実⾏時間もファイルサイズもでかい ▶ 

    昔やってたこと ▶  密⾏列: numpy.io.save … まあまあ妥当 ▶  疎⾏列: scipy.io.savemat … でかい.限界ある. ▶  今やってること ▶  密⾏列: bloscpack ▶  疎⾏列: HDF5 + complib=blosc 全部 HDF5 + complib=blosc で良いかもしれない.
  14. Bloscpack Processor cache にデータを転送するようデザインされているので memcpy call より⾼速.SIMD や multi-thread を使⽤

    最新版 python-blosc 1.2.7 は multi-threading に問題があり Downgrade して 1.2.5 を利⽤すれば問題ない
  15. MATLAB Format for Sparse Matrix ▶  ⾏列サイズに上限があるので⼤きな疎⾏列には使えません –  4GB 以上の⼤きな⾏列を保存することができない

    –  N-gram feature を扱う場合,問題となり得る –  圧縮すると保存が遅い –  圧縮しないとファイルサイズ⼤きい
  16. HDF5 Store for Sparse Matrix ▶  疎⾏列を複数のベクトルで圧縮表現 ▶  ベクトルも blosc

    アルゴリズムで圧縮して HDF5 に保存する # 疎⾏列を複数の数値列で圧縮表現して 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]]))
  17. Benchmark (Dense Matrix) 実験設定1: ランダムな密⾏列 np.random.random((1e7, 30)) 圧縮の難しい密⾏列で np.savez_compressed は無駄

  18. Benchmark (Dense Matrix) 実験設定2: Cervical Cancer Screening の⼀部変数を保存 無圧縮と同等あるいはそれ以上の速さで圧縮

  19. Benchmark (Dense Matrix) 実験設定3: Springleaf contest の変数 VAR_0002 を保存 圧縮できる密⾏列で

    np.savez はディスクの無駄
  20. Agenda ソフトウェア・エンジニアリングをとことん活⽤して 分析コンテストを攻略する話をします 1.  Workflow (Reproducible Research) 2.  Serialization (bloscpack

    & HDF4) 3.  Docker (DockerMachine, alpine-kaggle & FirePlug)
  21. Amazon AWS ▶  S3 + EC2 spot instance の組 み合わせは財布に優しい

    ▶  しかし GPU instance は半年前 から価格が暴⾛している ▶  素直に On-Demand instance を借りたほうが良い場合もある
  22. それではたくさんのサーバーを使ったときの事例を⾒てみましょう image source: h.ps://twi.er.com/ultrais.er/status/554280474042847233

  23. Use Case for Cervical Cancer Screening (1) S3 … 同⼀リージョン間の転送料は無料なので優しい

  24. Use Case for Cervical Cancer Screening (2) EC2 … spot

    も使い過ぎると厳しい (でも m4.10xlarge を 2000 時間で 1k USD は安い)
  25. Simple Way to utilize AWS on Cross Validation # 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 台とか増えると管理がつらくなる ⼤量のイメージ, スナップショット, ボリューム… 単純化したい…
  26. 使い捨ての精神で実⾏環境を⾒直す

  27. smly/alpine-kaggle 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
  28. Docker Machine 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
  29. Remote Docker Host をどのように使いこなすか

  30. 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
  31. Workflow on FirePlug FirePlug はコマンド実⾏ごとに Build → Sync → Run

    → Sync する コンテナは使い捨て.イメージも(基本的に)再利⽤しない Client PC AWS 2. rsync 4. rsync 1. docker build 3. docker run Docker Host Container fs mount
  32. Building Step on FirePlug ベースとなる Image から⼿元のファイルを追加した仮想イメージを作成 Remote Docker Host

    でビルドするための転送サイズは⼩さい Base Image (smly/alpine-kaggle) One-time Image c7df017aaeeb (987.4 MB) 68fbf78112b5 (18.43 kB) Client PC (current directory)
  33. コンテナではなく Docker Host 側のファイルシステムに Sync する コンテナを捨てても Sync したファイルは Docker

    Host で保持される Sync 対象は以下の2つから選択: ▶  (Default) クライアント環境から rsync ▶  Docker Host から S3 に aws s3 sync 転送量が増える場合は S3 が便利 (同⼀ AZ 内の転送が課⾦対象外なので) Sync Step on FirePlug 1. docker build 3. docker run Docker Host Container fs mount
  34. Sync Variation / --nosync, --insync, --outsync 実⾏環境(Docker Host)へのファイル転送はオプションで制御 (default) Build

    → Sync (download) → Run → Sync (upload) nosync Build → Sync (download) → Run → Sync (upload) insync Build → Sync (download) → Run → Sync (upload) outsync Build → Sync (download) → Run → Sync (upload) Download … From Client PC (or S3) to Docker Host Upload … From Docker Host to Client PC (or S3)
  35. Initial Configuration / fp --init 初期設定コマンド # 初期設定(空欄の場合はデフォルト値) # S3

    bucket の設定がなければ rsync でクライアントPC のデータディレクトリと同期する $ fp –init [1/4] Enter your project name: telstra [2/4] Enter your s3 bucket name (Default: None): [3/4] Enter data path on local client (Default: data): [4/4] Enter your base docker image (Default: smly/alpine-kaggle): # プログラム実⾏時に毎回ビルドされるイメージの Dockerfile # マウントポイント /data に telstra ディレクトリを作成 # working directory (/root) 直下に同期対象となるディレクトリ /root/data へ symlink を張っている # COPY でクライントPCのファイルをイメージに組み込んでいる(不要なものは .dockerignore で指定) $ cat Dockerfile FROM smly/alpine-kaggle RUN mkdir -p /data/telstra && ln -s /data/telstra /root/data COPY ./ /root/ WORKDIR /root ビルドされるimage 名,S3 上のディレクトリ名 デフォルトは rsync (S3 使わない) ローカル環境上のデータ同期対象 Base Image /<mounpoint>/<projectname> を作り, 作業ディレクトリ上のデータ同期先に synlink
  36. Future work ▶  Documentation ▶  Background 実⾏できるようにする ▶  実⾏中のタスクとサーバーリソースの可視化 (Web

    UI) ▶  Docker Image の Private Registory 対応 ▶  LibFM, RGF, dboost などの各種アルゴリズム対応 image ▶  R ⽤ image ▶  Portability (Windows support) ▶  Compatibility (Docker API Level) ▶  分散アルゴリズム対応,例えば XGBoost (Wormhole) Contributor 募集中です!
  37. 余談 •  Kaggle は Kaggle Script で Docker を使ってる.しかし Kaggle/python

    のイメージサイズは Debian ベースで 6GB. •  ⼀⽅ smly/alpine-kaggle は Alpine ベースで 317MB. Docker Host の増減を頻繁に⾏う場合に有利. •  DataRobot も内部のシステムでスケールさせるために Docker を 使っていると中の⼈が教えてくれた.