Pythonにおける機械学習モデルチューニングのためのHyperoptのスケーリング

[Scaling Hyperopt to Tune Machine Learning Models in Python](https://databricks.com/blog/2019/10/29/scaling-hyperopt-to-tune-machine-learning-models-in-python.html)の翻訳です。

:::note warn
**注意**
- 本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
- 2019年の記事です。
:::

> 以下で説明されているステップを再現するために[Hyperoptのノートブック](https://docs.microsoft.com/en-us/azure/databricks/applications/machine-learning/automl-hyperparam-tuning/#hyperopt-overview)をトライしてみてください。詳細は[オンデマンドのウェビナー](https://databricks.com/blog/2019/07/18/automated-hyperparameter-tuning-scaling-and-tracking-on-demand-webinar-and-faqs-now-available.html)をご覧ください。

[Hyperopt](https://github.com/hyperopt/hyperopt)は、Pythonにおける機械学習モデルのチューニングのための最も人気のあるオープンソースライブラリです。Hyperopt 0.2.1が[Apache Spark](https://databricks.com/jp/spark/about)を通じて分散チューニングをサポートしたことを発表できることを嬉しく思っています。新たな`SparkTrials`クラスを用いることで、Sparkクラスターでハイパーパラメーターチューニングをスケールさせることができます。`SparkTrials`はJoseph Bradley、Hanyu Cui、Lu Wang、Weichen Xu、Liang Zhang (Databricks)とMax Pumperla (Konduit)の貢献によるものです。

# Hyperoptとは？

[Python](https://www.python.org/)で記述された、オープンソースのハイパーパラメーターチューニングのライブラリです。2019年10月時点で月当たり44万5千のPyPIダウンロード、Githubには3800以上のスターが付いており、急激な導入と強力なコミュニティサポートを示しています。データサイエンティストに対して、Hyperoptはハイパーパラメーター、モデルタイプに対する検索を行う一般的なAPIを提供します。Hyperoptは2つのチューニングアルゴリズムを提供します。ランダムサーチとベイジアンメソッドであるTree of Parzen Estimatorsです。

開発者に対して、Hyperoptはアルゴリズムと計算バックエンドに対するプラグイン可能なAPIを提供します。我々は、Apache Sparkによって支援される新たな計算バックエンドを開発するために、このプラグイン可能性を活用しました。

# SparkによるHyperoptのスケールアウト

新たな`SparkTrials`クラスを用いることで、チューニングのジョブをSparkクラスターに分散させるようにHyperoptに指示することができます。当社はDatabricksで開発されましたが、この[ハイパーパラメーターチューニングのAPI](https://databricks.com/blog/2019/07/18/automated-hyperparameter-tuning-scaling-and-tracking-on-demand-webinar-and-faqs-now-available.html)は複雑なチューニングをジョブを計算的に分散させるために多くのDatabricksのお客様によって推進され、オープンソースのHyperoptプロジェクトへの貢献となり、最新リリースで利用できるようになりました。

ハイパーパラメーターチューニングとモデル選択には、多くのケースで数百、数千のモデルが関わってきます。`SparkTrials`はこれらのトレーニングタスクのバッチを並列で実行し、Sparkのエグゼキューターごとに一つのタスクを割り当てることで、チューニングを大幅にスケールアウトすることができます。Hyperoptと`SparkTrials`を活用するには、シンプルにHyperoptの`fmin()`関数に`SparkTrials`オブジェクトを引き渡します。

```py:Python
from hyperopt import SparkTrials

best_hyperparameters = fmin(
fn = training_function,
space = search_space,
algo = hyperopt.tpe,
max_evals = 64,
trials = SparkTrials())
```

完全なサンプルコードは、[Hyperopt documentation on SparkTrials](http://hyperopt.github.io/hyperopt/scaleout/spark/)を確認してください。

内部では、`fmin()`はテストすべき新規のハイパーパラメーターチューニングの設定を生成し、これらを`SparkTrials`に引き渡します。以下の図では、どのように`SparkTrials`がこれらのタスクを、クラスター上で非同期に実行するのかを示しています。

**(A)** Hyperoptの主要なロジックはSparkドライバーで実行され、新規のハイパーパラメーター設定を計算します。
**(B)** ワーカーが新規タスクに対する準備ができたら、Hyperoptは当該ハイパーパラメーター設定に対するシングルタスクのSparkジョブをキックします。
**(C)** 単一のSparkエグゼキューターで実行されるタスク内では、新たなMLモデルをトレーニングし評価するために、ユーザーコードが実行されます。
**(D)** 処理が完了すると、Sparkタスクは損失を含む結果をドライバーに返却します。

これらの新たな結果は、将来的なタスクに対してより優れたハイパーパラメーター設定を計算するためにHyperoptで活用されます。
![](https://databricks.com/wp-content/uploads/2019/10/hyperopt_parameters_testing_using_spark_trials.png)

`SparkTrials`は、一台のSparkワーカーで個々のモデルをフィッティングし評価するので、scikit-learnやシングルマシンのTensorflowのような、シングルマシンのMLモデルとワークフローに限定されます。Apache Spark MLlibやHorovodのような分散MLアルゴリズムに対しては、Hyperoptのデフォルトの`Trials class`を活用することができます。

# SparkTrials活用の実践

`SparkTrials`にはキーとなる2つのパラメーターがあります。`parallelism`(実行する並列トライアルの最大数、デフォルトはSparkエグゼキューターの数となります)と`timeout`(fminに許可される最大処理時間(秒)であり、デフォルトはNone)です。 

`parallelism`パラメーターは、以下の図で説明されているガイドラインを用いて、`fmin()`に対する`max_evals`と組み合わせて設定することができます。Hyperoptは`parallelism`サイズのバッチで`max_evals`回、ハイパーパラメーターに対する全体の設定をテストします。`parallelism` = `max_evals`の場合、Hyperoptはランダムサーチを行います。テストするために全てのハイパーパラメーターの設定を独立で選択し、並列で評価します。`parallelism` = 1の場合、Hyperoptは繰り返しハイパーパラメーター空間を探索するTree of Parzen Estimatorsのような適合アルゴリズムを完全に活用します。テストされたそれぞれの新規のハイパーパラメーターの設定は、前回の結果に基づいて選択されます。`parallelism`を1と`max_evals`の間に設定することで、スケーラビリティ(迅速に結果を得る)と適合性(時に優れた結果を得る)のトレードオフを選択することができます。望ましい選択は`sqrt(max_evals)`のように中間を取るというものです。
![](https://databricks.com/wp-content/uploads/2019/10/setting_parallelism.png)

チューニングのメリットを説明するために、最近の[ウェビナー](https://databricks.com/blog/2019/07/18/automated-hyperparameter-tuning-scaling-and-tracking-on-demand-webinar-and-faqs-now-available.html)で説明したPyTorchのワークフローを用いて、MNISTデータセットに対して`SparkTrials`とHyperoptを実行します。我々のワークフローでは、手書き数字を予測するための基本的なディープラーニングモデルをトレーニングし、3つのパラメーター：バッチサイズ、学習率、モーメンタムをチューニングしました。これは、p2.xlargeのワーカーとDatabricksランタイム5.5MLを用いたAWSのDatabricksクラスターで実行されました。

以下のプロットでは、`max_evals`を128に固定し、ワーカーの数を変化させました。期待した通り、ワーカーを増やす(より大きい`parallelism`)ことで処理時間を削減できており、線形にスケールアウトできています。
![](https://databricks.com/wp-content/uploads/2019/10/plotting_greater_parallelism.png)

次に、`timeout`を4分に固定してワーカーの数を変化させ、いくつかのトライアルでこの実験を繰り返しました。以下のプロットでは、損失(loss：負の対数尤度、"180m"="0.180")対ワーカー数を示しています。青い点は個々のトライアルであり、赤い線はトレンドを示しているLOESS曲線です。一般的に、`parallelism`を大きくすると、より多くのハイパーパラメーター設定をテストできるので、モデルのパフォーマンスは改善します。Hyperoptは検索に乱数化を用いるので、トライアルごとに挙動が変わることに注意してください。
![](https://databricks.com/wp-content/uploads/2019/10/improved_model_performance.png)

# Hyperopt 0.2.1を使ってみる

`SparkTrials`はHyperopt 0.2.1([PyPi project page](https://pypi.org/project/hyperopt/)から取得できます)で利用でき、Hyperoptは[Databricks機械学習ランタイム \(5\.4以降\)](https://databricks.com/jp/product/machine-learning-runtime)に含まれています。

Hyperoptに関してさらに学びたい、デモやサンプルを見たいのであれば、以下をチェックしてみてください。

- 完全なコードサンプルを含む[プロジェクトの Github\.io ページ](http://hyperopt.github.io/hyperopt/scaleout/spark/)のドキュメント
- Databricksドキュメントにあるサンプルノートブック([AWS](https://docs.databricks.com/applications/machine-learning/automl/hyperopt/index.html)|[Azure](https://docs.microsoft.com/en-us/azure/databricks/applications/machine-learning/automl-hyperparam-tuning/#hyperopt-overview))

Hyperoptはエクスペリメントやモデルの追跡のためにMLflowと組み合わせることができます。このインテグレーションの詳細については、[open\-source MLflow example](https://github.com/mlflow/mlflow/blob/51aa7165a6dea156b66c9bdfeb6bfda9e6d1e9d2/examples/hyperparam/search_hyperopt.py)や[ハイパーパラメーターに関するブログ記事](https://databricks.com/blog/2019/06/07/hyperparameter-tuning-with-mlflow-apache-spark-mllib-and-hyperopt.html)、[ウェビナー](https://databricks.com/blog/2019/07/18/automated-hyperparameter-tuning-scaling-and-tracking-on-demand-webinar-and-faqs-now-available.html)をご覧ください。

Githubプロジェクトページを通じて貢献することが可能です。

- [Github Issues page](https://github.com/hyperopt/hyperopt/issues)でオープンソースの問題をレポートします。
- [Github](https://github.com/hyperopt/hyperopt)のHyperoptに貢献します。

# 関連リソース

- [hyperopt · PyPI](https://pypi.org/project/hyperopt/)
- [Spark \- Hyperopt Documentation](http://hyperopt.github.io/hyperopt/scaleout/spark/)
- [マネージド MLflow](https://databricks.com/product/managed-mlflow)
- [Hyperparameter Tuning with MLflow, Apache Spark MLlib and Hyperopt \- The Databricks Blog](https://databricks.com/blog/2019/06/07/hyperparameter-tuning-with-mlflow-apache-spark-mllib-and-hyperopt.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)