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

Optuna on Kubeflow Pipeline 分散ハイパラチューニング

2kyym
April 23, 2020

Optuna on Kubeflow Pipeline 分散ハイパラチューニング

社内の勉強会等で発表した内容を改変したものです。
MOVの「お客様探索ナビ」にOptunaを用いたハイパーパラメータチューニングを組み込んだ経緯、実際のチューニングフロー、コードベースでの解説、実験評価について、Optunaのチュートリアルを交えつつまとめました。
タイトルに分散とありますがKFP上の話なので厳密には並列です。

2kyym

April 23, 2020
Tweet

More Decks by 2kyym

Other Decks in Programming

Transcript

  1. Optuna on Kubeflow Pipeline 分散ハイパラチューニング 2020.04.23 Mobility Technologies システム開発統括部 AIシステム部

    MLエンジニアリング第一グループ(出向) 築山将央 / Masao Tsukiyama / @2kyym 1
  2. DeNA TechCon 2020 #denatechcon アジェンダ •Optuna 導入の背景 •Optuna 概観とチュートリアル •Kubeflow

    Pipelines 概観 •Optuna on KFP チューニングフロー •コードベースでの解説 •実験と評価  
  3. DeNA TechCon 2020 #denatechcon お客様探索ナビへのOptuna導入の背景 要望 • Value Iterator(強化学習コンポーネント)のハイパラをチューニングしたい •

    モデル学習時のパラメータでないことに注意 • もともとはアルゴリズムチームメンバーの経験をもとに決定していたが、最適か不明 • ユースケース • 新地域でのリリース時にチューニング(地域によって最適パラメータが変わる可能性) • 既存地域でも定期的にチューニング(傾向変化によって最適パラメータが変わる可能性)  
  4. DeNA TechCon 2020 #denatechcon シミュレーションによるパフォーマンス評価の概要 • LightGBMモデルによって、30分区切りで道路ごとの需要と供給を予測 • 予測値をもとにValue Iterator(VI)が道路ごとのValueを算出、経路が引かれる

    • 経路に従うとどの程度の営収が得られるかをシミュレーション • つまり、VIのハイパラを変えてシミュレーションし営収を最大化できるパラメータを探す   お客様探索ナビへのOptuna導入の背景
  5. DeNA TechCon 2020 #denatechcon 概要 • PFNが開発したハイパーパラメータチューニングのフレームワーク • 2018年12月に公開、2020年1月に正式リリース •

    特徴 • 複数試行を分散・並列して実行できる(分散最適化が楽) • Define-by-run(試行時の探索空間を定義)で目的関数が直感的に書ける • 試行のPruningによるパフォーマンス向上 • デフォルト最適化アルゴリズムはTPE(Tree-structured Parzen Estimator) • 他のものも選べる Optunaについて   https://github.com/optuna/optuna
  6. DeNA TechCon 2020 #denatechcon Optunaチュートリアル   import optuna def

    objective(trial): x = trial.suggest_uniform("x", -10, 10) return (x - 2) ** 2 study = optuna.create_study(direction="minimize") study.optimize(objective, n_trials=100)
  7. DeNA TechCon 2020 #denatechcon Optunaチュートリアル   import optuna def

    objective(trial): x = trial.suggest_uniform("x", -10, 10) return (x - 2) ** 2 study = optuna.create_study(direction="minimize") study.optimize(objective, n_trials=100) ໨తؔ਺ʢࢼߦ͝ͱͷॲཧʣ
  8. DeNA TechCon 2020 #denatechcon Optunaチュートリアル   import optuna def

    objective(trial): x = trial.suggest_uniform("x", -10, 10) return (x - 2) ** 2 study = optuna.create_study(direction="minimize") study.optimize(objective, n_trials=100) 4UVEZνϡʔχϯάͷ୯Ґɹɹ5SJBMࢼߦͷ୯Ґ ໨తؔ਺ʢࢼߦ͝ͱͷॲཧʣ
  9. DeNA TechCon 2020 #denatechcon Optunaチュートリアル   study.best_params: 全Trial中の最善パラメータを返す >>

    {‘x’: 1.9926578647650126} study.best_trial: 全Trial中の最善Trial Objectを返す >> FrozenTrial(number=26, state=<TrialState.COMPLETE: 1>, params={'x': 1.9926578647650126}, value=5.390694980884334e-05, datetime_start=xx, datetime_complete=xx, trial_id=26) study.trials: 全Trial Objectのリストを返す >> [FrozenTrial(number=0, …), …] Study Object • 過去Trialの情報などを抽出できる
  10. DeNA TechCon 2020 #denatechcon パラメータのSuggest Optunaチュートリアル   # ΧςΰϦύϥϝʔλ

    optimizer = trial.suggest_categorical("optimizer", ["MomentumSGD", "Adam"]) # ੔਺ύϥϝʔλ num_layers = trial.suggest_int("num_layers", 1, 3) # Ұ༷෼෍ dropout_rate = trial.suggest_uniform("dropout_rate", 0.0, 1.0) # ର਺Ұ༷෼෍ learning_rate = trial.suggest_loguniform("learning_rate", 1e-5, 1e-2) # ཭ࢄҰ༷෼෍ drop_path_rate = trial.suggest_discrete_uniform("drop_path_rate", 0.0, 1.0, 0.1)
  11. DeNA TechCon 2020 #denatechcon Optunaチュートリアル   Storage(Trial, Study情報の格納先)の種類 •

    InMemoryStorage • 特に指定しなければこれ • Trial結果の永続化ができないが、ローカルリソースのみでチューニングならOK • RDBStorage • MySQL, PostgreSQL, SQLite が使える • Study, Trial のログが残る。分散最適化ならこっち • チューニングの中断・再開ができたり、可視化ができたり何かと便利 • 今回はCloudSQLでMySQLを立てっぱなしにした
  12. DeNA TechCon 2020 #denatechcon Kubeflow Pipelineについて そもそもKubeflowとは • “The Machine

    Learning Toolkit for Kubernetes”(公式サイトより) • 機械学習のサイクルをKubernetes上で実行するためのOSSツール群   IUUQTXXXLVCFqPXPSHEPDTTUBSUFELVCFqPXPWFSWJFX
  13. DeNA TechCon 2020 #denatechcon Kubeflow Pipelineについて Kubeflow Pipelines (KFP) とは

    • 機械学習に特化したワークフローエンジン • バックは Argo で、UIで実験パラメータの管理ができたり、個々人のログを一覧できたり • Airflowは運用向き、KFPは実験向きという印象(Airflowが実験向きでなさすぎる)   
  14. DeNA TechCon 2020 #denatechcon KFPで動くシミュレータ概要 シミュレーションパイプライン • 7日分のジョブ(予測値から Value 計算→経路引く→営収計算)を並列実行

    • ログをBQに格納後、それらを集計して Summary と Result Notebook を出力 • シミュレーションジョブの環境変数にVIパラメータを渡せばその値で実行できる   γϛϡϨʔγϣϯຊମ ϩάग़ྗ /PUFCPPL 4VNNBSZग़ྗ
  15. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   import optuna

    def objective(trial): # 1.VI parameterΛsuggest # 2.ͦͷparameterͰsimulation jobΛdeploy # 3.ऴྃޙɺӦऩ஋Λूܭ return Ӧऩ஋ study = optuna.create_study(direction="maximize") study.optimize(objective, n_trials=100, n_jobs=5) ӦऩͳͷͰNBYJNJ[F ࢼߦ਺ ฒྻ࣮ߦ਺ ࢼߦ͝ͱʹߦ͍͍ͨॲཧ
  16. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Cloud SQL(MySQL) ローカル開発環境 Storage永続化のためにCloudSQLを用意
  17. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Deploy
  18. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 create_study() Study,Trialの情報はCloudSQLから取得
  19. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Simulation Job 1 Simulation Job 2 Simulation Job 3 Simulation Job 4 Simulation Job 5 study.optimize() 5つのSimulation Pipelineを同時にデプロイ (中身は14ページ目のもの) 5スレッド並列でobjective()が実行される
  20. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Simulation Job 1 Simulation Job 2 Simulation Job 3 Simulation Job 4 Simulation Job 5 %POF %POF %POF %POF %POF 各スレッドでPipelineがCompleteするまで待機
  21. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 営収値を集計し、結果をStorageに格納
  22. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Trialログを取得し、次のパラメータをsuggest
  23. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Simulation Job 6 Simulation Job 7 Simulation Job 8 Simulation Job 9 Simulation Job 10 suggestされたパラメータでデプロイ この流れを繰り返す
  24. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Deploy この処理の部分
  25. DeNA TechCon 2020 #denatechcon   def deploy_optuna(c, comment=None): code_id

    = deploy_settings(c, comment=task_name) resource_setting = format_resource_setting( c.resource_setting, settings["master_cpu"], settings["master_memory"], settings["master_node_pool"], ) pipeline = wf.create_optuna_pipeline(code_id, optuna_settings, resource_setting) wf.compile_pipeline(code_id, pipeline, pipeline_filename) return wf.run_pipeline(code_id, user, pipeline_filename) Optuna Job のデプロイ KFP Pipeline functionを生成 (次ページ) リソース指定 Pipelineデプロイ
  26. DeNA TechCon 2020 #denatechcon   def create_optuna_pipeline(code_id, optuna_settings, resource_setting):

    @kfp.dsl.pipeline(name=code_id) def pipeline(config=json.dumps(optuna_settings)): base_url = optuna_settings["base_url"] msg = code_id + " is {{workflow.status}} " + base_url + "/{{workflow.uid}}" exit_task = create_slack_notification_op(msg) with dsl.ExitHandler(exit_task): create_optuna_op( code_id, optuna_settings, {"USER": "optuna-worker"}, resource_setting ) return pipeline Optuna Jobの KFP Pipeline Function Pipeline func デコレータ exit_taskでSlack通知 ExitHandlerで 終了時タスク指定(成功・失敗問わず) KFP Operator生成(次ページ)
  27. DeNA TechCon 2020 #denatechcon   def create_optuna_op(sim_id, optuna_settings, env_params,

    resource_setting): command = ["inv", "run-optuna"] arguments = [f"--settings={json.dumps(optuna_settings)}"] op = dsl.ContainerOp( name="optuna", image=optuna_settings["image"], command=command, arguments=arguments, file_outputs={"mlpipeline-ui-metadata": "/tmp/mlpipeline-ui-metadata.json"}, ) for k, v in env_params.items(): op.container.add_env_variable(V1EnvVar(name=k, value=v)) op = set_op_resource(op, resource_setting) sidecar = kfp.dsl.Sidecar( name="cloudsqlproxy", image="gcr.io/cloudsql-docker/gce-proxy:1.14", command=[ "/cloud_sql_proxy", "-instances=dena-taxifms-sec-mi-dev-gcp:us-central1:optuna=tcp:3306", ], ) op.add_sidecar(sidecar) return op Optuna Jobの KFP Operator KFP Operator作成 Operatorリソース定義 SidecarにCloudSQL Proxy Imageを指定 add_sidecar() で設定可
  28. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Simulation Job 1 Simulation Job 2 Simulation Job 3 Simulation Job 4 Simulation Job 5 study.optimize() 5つのSimulation Pipelineを同時にデプロイ (中身は14ページ目のもの) 5スレッド並列でobjective()が実行される これらの処理の部分
  29. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 Simulation Job 1 Simulation Job 2 Simulation Job 3 Simulation Job 4 Simulation Job 5 %POF %POF %POF %POF %POF 各スレッドでPipelineがCompleteするまで待機 これらの処理の部分
  30. DeNA TechCon 2020 #denatechcon Optuna チューニングのフロー   KFP Cluster

    Optuna Job Cloud SQL(MySQL) ローカル開発環境 営収値を集計し、結果をStorageに格納 これらの処理の部分
  31. DeNA TechCon 2020 #denatechcon   def run_optuna(c, study_name="optuna", settings=None,

    comment=None): study = optuna.create_study( direction="maximize", study_name=study_name, storage=settings["study_storage"], load_if_exists=True, ) study.optimize( create_objective(settings, study_name), n_trials=settings["max_n_trials"], n_jobs=settings["n_jobs"], catch=(kfp_server_api.rest.ApiException, exceptions.UnexpectedExit), ) Optuna Job 中でチューニング実行 営収の最大化なので maximize storage= mysql+pymysql://{user}:{password}@localhost/{cloudsql_datasetname} 目的関数の指定(次ページ) n_trials: 試行回数 n_jobs: 並列試行数
  32. DeNA TechCon 2020 #denatechcon   def create_objective(optuna_settings, study_name): def

    objective(trial): for k, v in optuna_settings["parameters"].items(): csv_args[k] = getattr(trial, v["distribution"])( v["name"], v["min_value"], v["max_value"] ) csv_path = f"{study_name}_{trial.trial_id}.csv" make_setting_csv(csv_path, **csv_args) completed_trials = len( [ trial.state for trial in trial.study.trials if trial.state == optuna.structs.TrialState.COMPLETE ] ) if completed_trials >= settings["n_trials"]: print("Number of completed trials:", str(completed_trials)) print("Best trial:", trial.study.best_trial) return 並列Trialの中身 1 指定した分布ごとにparameterをsuggest (内部で過去Trialのログを参照) パラメータの探索範囲はconfigに持っている (LightGBMTuner使えば決めなくていいらしい) シミュレーション用の設定ファイル作成 正常に終了したシミュレーションジョブ数を集計 (シミュレーションジョブが稀に死ぬため)
  33. DeNA TechCon 2020 #denatechcon   code_id, pipeline_filename = run(

    c, csv_path=csv_path, days=settings["days"], memory=settings[“worker_memory"], build_only=True, ) run_result = wf.run_pipeline(code_id, user, pipeline_filename) run_name = wf.wait_for_simulation_completion(run_result) bqla = BigQueryLogAnalyzer(run_name) summary, metrics_cols = bqla.create_summary( cost_table=settings["cost_table"] ) summary_mean = summary.groupby("config_id")[metrics_cols].mean() return float(summary_mean.revenue) シミュレーションジョブが完了するまで待機 BQからシミュレーションのログを抽出し営収を集計 (既存機能) 結果の営収値を返す シミュレーションのPipeline Function作成 (既存機能) 並列Trialの中身 2
  34. DeNA TechCon 2020 #denatechcon Optuna on KFPのつらみ 課題 • 二重デプロイ構成になっている

    • Optuna Job と大量の Simulation Job という構成で、少々分かりづらい • 1つのJob(パイプライン)でチューニングを完結させるのは不可能ではないが厳しい • 7日分のシミュレーションを分散できず、1Pod内ですべて行う必要がある • シミュレーションをブラックボックスとして扱い、チューニングのロジックと疎結合にでき ているので今のままで良いという意見もあった  
  35. DeNA TechCon 2020 #denatechcon Optuna on KFPのつらみ   Simulation

    Job • このパイプラインが5並列、計100個できる ೔෼ͷγϛϡϨʔγϣϯΛฒྻ࣮ߦ
  36. DeNA TechCon 2020 #denatechcon 実験 実験設定 • Trial数: 100(最大Trial数は150, 50回までのfailを許容)

    • 収束することを確認 • 並列Trial数: 5 • 探索パラメータ • GAMMA(割引率): loguniform, 0.80-0.99 • WAY_COST_WEIGHT(道路コスト重み): loguniform, 0.01-0.20 • MAX_WAITING_TIME(最大許容待ち時間): int, 250-350 • 他にもパラメータは様々あるが、Trial数を抑えるために特に効きそうな3つを選択  
  37. DeNA TechCon 2020 #denatechcon 実験 評価 • 2019/10/1 - 2019/10/7

    期間のシミュレーションでチューニング • 2019/10/8 - 2020/2/29 の期間で以下を比較し評価 • Optunaで得たパラメータを用い、予測値(モデル)でValue計算 • Optunaで得たパラメータを用い、統計値(非モデル)でValue計算 • デフォルトパラメータを用い、予測値(モデル)でValue計算 • デフォルトパラメータを用い、統計値(非モデル)でValue計算 • 予測値を使わず統計値で経路を引く場合もあるので、双方の評価が必要  
  38. DeNA TechCon 2020 #denatechcon 実験 結果 • 営収向上 • 予測値(モデル)を用いたシミュレーションでは平均して営収が1.4%ほど向上

    • 統計値(非モデル)を用いたシミュレーションでは平均して営収が2.2%ほど向上 • 重めのアルゴリズム施策が上手くいった場合と同程度の上がり幅 • 既に本番リリース済み  
  39. DeNA TechCon 2020 #denatechcon 今後の展望 検証や自動化など • Trial数を増やし、さらに多くのパラメータで試して営収向上するか? • チューニング対象の期間が直近のほうがパフォーマンスが上がるか?

    • 並列実行数の上限はどの程度か? • 5並列では直列とパフォーマンスの差なし • 定期チューニングの実行、評価とデプロイの自動化 お客様探索ナビ以外への適用 • 実は他にもいろいろ開発中のプロダクトがある • 他プロダクトのシミュレータでもKFPを用いているので、汎用的に使えそう  
  40. DeNA TechCon 2020 #denatechcon 感想 Optunaの良かった点 • 分散並列化のハードルがやはり低い • ワークフローとDBさえ用意すれば、コード自体はかなり書きやすい

    • SDKがなにげに充実していて使いやすい • Study Object から欲しい情報を大体得られる、挙動も不可解でない • カスタム性が高い • 今回はやっていないが、Samplerを自前で書けたりするらしい