Mais conteúdo relacionado
Semelhante a Optuna on Kubeflow Pipeline 分散ハイパラチューニング (20)
Optuna on Kubeflow Pipeline 分散ハイパラチューニング
- 1. Optuna on Kubeflow Pipeline
分散ハイパラチューニング
2020.04.23
Mobility Technologies システム開発統括部 AIシステム部 MLエンジニアリング第一グループ(出向)
築山将央 / Masao Tsukiyama / @2kyym
1
- 12. DeNA TechCon 2020
#denatechcon
概要
• PFNが開発したハイパーパラメータチューニングのフレームワーク
• 2018年12月に公開、2020年1月に正式リリース
• 特徴
• 複数試行を分散・並列して実行できる(分散最適化が楽)
• Define-by-run(試行時の探索空間を定義)で目的関数が直感的に書ける
• 試行のPruningによるパフォーマンス向上
• デフォルト最適化アルゴリズムはTPE(Tree-structured Parzen Estimator)
• 他のものも選べる
Optunaについて
https://github.com/optuna/optuna
- 16. 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の情報などを抽出できる
- 17. 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)
- 18. DeNA TechCon 2020
#denatechcon
Optunaチュートリアル
Storage(Trial, Study情報の格納先)の種類
• InMemoryStorage
• 特に指定しなければこれ
• Trial結果の永続化ができないが、ローカルリソースのみでチューニングならOK
• RDBStorage
• MySQL, PostgreSQL, SQLite が使える
• Study, Trial のログが残る。分散最適化ならこっち
• チューニングの中断・再開ができたり、可視化ができたり何かと便利
• 今回はCloudSQLでMySQLを立てっぱなしにした
- 21. DeNA TechCon 2020
#denatechcon
Kubeflow Pipelineについて
Kubeflow Pipelines (KFP) とは
• 機械学習に特化したワークフローエンジン
• バックは Argo で、UIで実験パラメータの管理ができたり、個々人のログを一覧できたり
• Airflowは運用向き、KFPは実験向きという印象(Airflowが実験向きでなさすぎる)
- 24. 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)
- 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
各スレッドでPipelineがCompleteするまで待機
- 32. 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されたパラメータでデプロイ
この流れを繰り返す
- 35. 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デプロイ
- 36. 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生成(次ページ)
- 37. 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() で設定可
- 38. 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()が実行される
これらの処理の部分
- 39. 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
各スレッドでPipelineがCompleteするまで待機
これらの処理の部分
- 41. 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: 並列試行数
- 42. 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使えば決めなくていいらしい)
シミュレーション用の設定ファイル作成
正常に終了したシミュレーションジョブ数を集計
(シミュレーションジョブが稀に死ぬため)
- 43. 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
- 44. DeNA TechCon 2020
#denatechcon
Optuna on KFPのつらみ
課題
• 二重デプロイ構成になっている
• Optuna Job と大量の Simulation Job という構成で、少々分かりづらい
• 1つのJob(パイプライン)でチューニングを完結させるのは不可能ではないが厳しい
• 7日分のシミュレーションを分散できず、1Pod内ですべて行う必要がある
• シミュレーションをブラックボックスとして扱い、チューニングのロジックと疎結合にでき
ているので今のままで良いという意見もあった
🤔
- 47. 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つを選択
- 48. DeNA TechCon 2020
#denatechcon
実験
評価
• 2019/10/1 - 2019/10/7 期間のシミュレーションでチューニング
• 2019/10/8 - 2020/2/29 の期間で以下を比較し評価
• Optunaで得たパラメータを用い、予測値(モデル)でValue計算
• Optunaで得たパラメータを用い、統計値(非モデル)でValue計算
• デフォルトパラメータを用い、予測値(モデル)でValue計算
• デフォルトパラメータを用い、統計値(非モデル)でValue計算
• 予測値を使わず統計値で経路を引く場合もあるので、双方の評価が必要
- 50. DeNA TechCon 2020
#denatechcon
今後の展望
検証や自動化など
• Trial数を増やし、さらに多くのパラメータで試して営収向上するか?
• チューニング対象の期間が直近のほうがパフォーマンスが上がるか?
• 並列実行数の上限はどの程度か?
• 5並列では直列とパフォーマンスの差なし
• 定期チューニングの実行、評価とデプロイの自動化
お客様探索ナビ以外への適用
• 実は他にもいろいろ開発中のプロダクトがある
• 他プロダクトのシミュレータでもKFPを用いているので、汎用的に使えそう