MLflowにおけるモデル評価

[How to Evaluate Models Using MLflow \- The Databricks Blog](https://www.databricks.com/blog/2022/04/19/model-evaluation-in-mlflow.html)の翻訳です。

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

現在の多くのデータサイエンティストやMLエンジニアは、モデルを管理するためにMLflowを活用しています。MLflowはMLライフサイクの全ての側面の管理を可能にするオープンソースのプラットフォームであり、実験、再現性確保、デプロイメント、モデルレジストリの様な機能を提供しています。MLモデルの開発における重要なステップは、新しいデータセットに対するパフォーマンスの評価です。

# モチベーション

## なぜモデルを評価するのでしょうか？

モデルの評価はMLライフサイクルの重要なパートです。これによって、データサイエンティストは自身のモデルのパフォーマンスの計測、解釈、説明が可能となります。モデルがなぜそのように動作しているのかに関して洞察を提供することで、モデル開発のタイムフレームを加速します。特にMLモデルの複雑性が増加するにつれて、MLモデルのパフォーマンスを迅速に観測、理解できる能力は、ML開発ジャーニーを成功させるためには重要となってきます。

# MLflowにおけるモデル評価の状態

これまでは、ユーザーは分類モデルと回帰モデルの両方の評価をサポートする[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate) APIを通じて[python\_function \(pyfunc\)モデルフレーバー](https://www.mlflow.org/docs/latest/models.html#pyfunc-model-flavor)のMLflowモデルのパフォーマンスを評価することができました。これは、ビルトインのタスク固有のパフォーマンスメトリクス、パフォーマンスのプロット、モデルの説明を計算して[MLflowトラッキングサーバー](https://www.mlflow.org/docs/latest/tracking.html#tracking)に記録します。

ビルトインの評価メトリックのセットに含まれないカスタムメトリクスを用いてMLflowモデルを評価するには、カスタムモデル評価器のプラフインを定義する必要がありました。これには、[ModelEvaluatorインタフェース](https://github.com/mlflow/mlflow/blob/4e444efdf73c710644ee039b44fa36a31d716f69/mlflow/models/evaluation/base.py#L449)を実装するカスタム評価器クラスの作成、[MLflowプラフイン](https://www.mlflow.org/docs/latest/plugins.html#writing-your-own-mlflow-plugins)の一部として、評価器エントリーポイントの登録が含まれます。この厳密性と複雑性はユーザにとっては受け入れ難いものです。

内部の顧客サーベイによると、回答者の75%が精度やロスの様な基本的なメトリクスに加えて、頻繁あるいは常に特殊なビジネスフォーカスのメトリクスを使用していると回答しました。データサイエンティストはビジネスゴール(例:コンバージョン率)をより説明し、モデルの予測結果自身によって捕捉されない追加の経験則を含めるために、多くの場合これらのメトリクスを活用しています。

この記事では、ユーザー定義のカスタムメトリクスを用いてMLflowモデルを評価するための簡単かつ便利な方法をご紹介します。この機能によって、データサイエンティストはモデル評価ステージで容易にこのロジックを組み込むことができ、追加の後段の分析なしに、最もパフォーマンスの良いモデルをクイックに特定することができます。

# 使い方

## ビルトインのメトリクス

MLflowでは、分類、回帰モデルの両方に対して一般的に使われるパフォーマンスやモデル説明可能性に関するメトリクスのセットを同梱していまうs。これらのメトリクスによるモデルの評価はわかりやすいものです。必要なのは、テストデータとターゲットを含む評価データセットを作成し、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を呼び出すことです。

モデルのタイプによって、異なるメトリクスが計算されます。ビルトインメトリクスに関する最新の情報については、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)のAPIドキュメントの[Default Evaluator behavior section](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)をご覧下さい。

### サンプル

ビルトインメトリクスによる分類MLflowモデルの評価方法を示すシンプルなサンプルです。

最初に必要なライブラリをインポートします。

```py:Python
import xgboost
import shap
import mlflow
from sklearn.model_selection import train_test_split
```

次にデータセットを分割し、モデルをフィッティングさせ、評価データセットを作成します。

```py:Python
# load UCI Adult Data Set; segment it into training and test sets
X, y = shap.datasets.adult()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

# train XGBoost model
model = xgboost.XGBClassifier().fit(X_train, y_train)

# construct an evaluation dataset from the test set
eval_data = X_test
eval_data["target"] = y_test
```

最後にMLflowランをスタートし、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を呼び出します。

```py:Python
with mlflow.start_run() as run:
   model_info = mlflow.sklearn.log_model(model, "model")
   result = mlflow.evaluate(
       model_info.model_uri,
       eval_data,
       targets="target",
       model_type="classifier",
       dataset_name="adult",
       evaluators=["default"],
   )
```

MLflowのUIで、記録されたメトリクスとアーティファクトを確認することができます。
![](https://www.databricks.com/wp-content/uploads/2022/04/db-142-blog-img-1.jpg)
![](https://www.databricks.com/wp-content/uploads/2022/04/db-142-blog-img-2.jpg)

## カスタムメトリクス

カスタムメトリクスでモデルを評価するには、シンプルにカスタムメトリックの関数のリストを[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate) APIに渡します。

### 関数定義の要件

カスタムメトリックの関数は、以下の順序で2つの必須のパラメーター、1つのオプションのパラメーターを受け取る必要があります:

1. `eval_df`: `prediction`と`target`カラムを持つPandasあるいはSparkデータフレーム。

    例：モデルの出力が3つの値のベクトルである場合、データフレーム`eval_df`は以下の様になります。
![](https://www.databricks.com/wp-content/uploads/2022/04/db-142-blog-img-3.jpg)

1. `builtin_metrics`: ビルトインメトリクスを含むディクショナリー。

    例：回帰モデルにおいては、`builtin_metrics`は以下の様になります。

   ```json:JSON
    {
       "example_count": 4128,
       "max_error": 3.815,
       "mean_absolute_error": 0.526,
       "mean_absolute_percentage_error": 0.311,
       "mean": 2.064,
       "mean_squared_error": 0.518,
       "r2_score": 0.61,
       "root_mean_squared_error": 0.72,
       "sum_on_label": 8520.4
    }
    ```

1. (オプション)`artifacts_dir`: カスタムメトリック関数が生成されたアーティファクトをMLflowに記録する前に一時的に保存するために使用する一時ディレクトリのパス。

    例：環境に応じて見え方が異なることに注意してください。例えば、MacOSの場合は以下の様に見えます。

    ```
    /var/folders/5d/lcq9fgm918l8mg8vlbcq4d0c0000gp/T/tmpizijtnvo
    ```

    `artifacts_dir`以外の場所にファイルアーティファクトが保存される際、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)の実行が完了するまで、これらが永続化される様にしてください。

### 戻り値の要件

関数は生成されたメトリクスを表現するディクショナリーを返却し、オプションとして生成されたアーティファクトを表現する二つ目のディクショナリーを返却しなくてはなりません。両方のディクショナリーにおいては、それぞれのエントリーのキーは、対応するメトリックやアーティファクトの名前を表します。

それぞれのメトリックはスカラーでなくてはいけませんが、アーティファクトを定義する方法は複数あります。

- アーティファクトファイルへのパス
- JSONオブジェクトの文字列表現
- pandasデータフレーム
- numpyのarray
- matplotlibの図
- デフォルトのプロトコルによってpickleされるその他のオブジェクト

より詳細については、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)のドキュメントを参照ください。

### サンプル

カスタムメトリクスを使う実際のサンプルを見ていきましょう。このために、[California Housing](https://scikit-learn.org/stable/datasets/real_world.html#california-housing-dataset)データセットからトイモデルを作成します。

```py:Python
from sklearn.linear_model import LinearRegression
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
import mlflow
import os
```

次にデータセットとモデルをセットアップします。

```py:Python
# loading the California housing dataset
cali_housing = fetch_california_housing(as_frame=True)

# split the dataset into train and test partitions
X_train, X_test, y_train, y_test = train_test_split(
   cali_housing.data, cali_housing.target, test_size=0.2, random_state=123
)

# train the model
lin_reg = LinearRegression().fit(X_train, y_train)

# creating the evaluation dataframe
eval_data = X_test.copy()
eval_data["target"] = y_test
```

ここがエキサイティングな部分です。カスタムメトリクス関数の定義です！

```py:Python
def example_custom_metric_fn(eval_df, builtin_metrics, artifacts_dir):
   """
   This example custom metric function creates a metric based on the ``prediction`` and
   ``target`` columns in ``eval_df`` and a metric derived from existing metrics in
   ``builtin_metrics``. It also generates and saves a scatter plot to ``artifacts_dir`` that
   visualizes the relationship between the predictions and targets for the given model to a
   file as an image artifact.
   """
   metrics = {
       "squared_diff_plus_one": np.sum(np.abs(eval_df["prediction"] - eval_df["target"] + 1) ** 2),
       "sum_on_label_divided_by_two": builtin_metrics["sum_on_label"] / 2,
   }
   plt.scatter(eval_df["prediction"], eval_df["target"])
   plt.xlabel("Targets")
   plt.ylabel("Predictions")
   plt.title("Targets vs. Predictions")
   plot_path = os.path.join(artifacts_dir, "example_scatter_plot.png")
   plt.savefig(plot_path)
   artifacts = {"example_scatter_plot_artifact": plot_path}
   return metrics, artifacts
```

最後に、これら全てをつなぎ合わせて、MLflowランをスタートして[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)を呼び出します。

```py:Python
with mlflow.start_run() as run:
   mlflow.sklearn.log_model(lin_reg, "model")
   model_uri = mlflow.get_artifact_uri("model")
   result = mlflow.evaluate(
       model=model_uri,
       data=eval_data,
       targets="target",
       model_type="regressor",
       dataset_name="cali_housing",
       custom_metrics=[example_custom_metric_fn],
   )
```

デフォルトのメトリクス、アーティファクトと共に記録されたカスタムメトリクスやカスタムアーティファクトを確認することができます。ランのページの赤枠の領域が、記録されたカスタムメトリクスとカスタムアーティファクトを示しています。
![](https://www.databricks.com/wp-content/uploads/2022/04/db-142-blog-img-4.jpg)

## プログラムから評価結果にアクセスする

ここまでは、MLflow UIでビルトインとカスタムメトリクスの評価結果を見てきました。しかし、[mlflow\.evaluate](https://mlflow.org/docs/latest/python_api/mlflow.html#mlflow.evaluate)によって返却される[EvaluationResult](https://www.mlflow.org/docs/latest/python_api/mlflow.models.html#mlflow.models.EvaluationResult)オブジェクトを通じてプログラムからアクセスすることもできます。上述のカスタムメトリクスの例を続けて、プログラムからどの様に評価結果にアクセスできるのかを見ていきましょう。(ここでは、[EvaluationResult](https://www.mlflow.org/docs/latest/python_api/mlflow.models.html#mlflow.models.EvaluationResult)のインスタンスが`result`であると仮定します。)

メトリクスの名前とスカラー値の両方を含む`result.metrics`ディクショナリーを通じて計算されたメトリクスすセットにアクセスすることができます。`result.metrics`の中身は以下の様なものとなります。

```json:JSON
{
   'example_count': 4128,
   'max_error': 3.8147801844098375,
   'mean_absolute_error': 0.5255457157103748,
   'mean_absolute_percentage_error': 0.3109520331276797,
   'mean_on_label': 2.064041664244185,
   'mean_squared_error': 0.5180228655178677,
   'r2_score': 0.6104546894797874,
   'root_mean_squared_error': 0.7197380534040615,
   'squared_diff_plus_one': 6291.3320597821585,
   'sum_on_label': 8520.363989999996,
   'sum_on_label_divided_by_two': 4260.181994999998
}
```

同様に、`result.artifacts`ディクショナリーを通じて一連のアーティファクトにアクセスすることができます。それぞれのエントリーの値は[EvaluationArtifact](https://www.mlflow.org/docs/latest/python_api/mlflow.models.html#mlflow.models.EvaluationArtifact)オブジェクトとなります。`result.artifacts`は以下の様になります。

```json:JSON
{
   'example_scatter_plot_artifact': ImageEvaluationArtifact(uri='some_uri/example_scatter_plot_artifact_on_data_cali_housing.png'),
   'shap_beeswarm_plot': ImageEvaluationArtifact(uri='some_uri/shap_beeswarm_plot_on_data_cali_housing.png'),
   'shap_feature_importance_plot': ImageEvaluationArtifact(uri='some_uri/shap_feature_importance_plot_on_data_cali_housing.png'),
   'shap_summary_plot': ImageEvaluationArtifact(uri='some_uri/shap_summary_plot_on_data_cali_housing.png')
}
```

## サンプルノートブック

- [Short Example](https://www.databricks.com/wp-content/uploads/notebooks/custom-metrics-short-example.html)
- [Comprehensive Example](https://www.databricks.com/wp-content/uploads/notebooks/custom-metrics-comprehensive-example.html)

# 内部動作

以下の図では、すべてが内部でどの様に動作しているのかを説明しています。
![](https://www.databricks.com/wp-content/uploads/2022/04/db-142-blog-img-5.png)

# まとめ

この記事では以下をカバーしました。

- モデル評価の重要性と現在MLflowで何がサポートされているのか。
- MLflowユーザーがカスタムメトリクスを自分のMLflowモデルに組み込むことがなぜ重要なのか。
- デフォルトメトリクスによるモデル評価方法。
- カスタムメトリクスによるモデル評価方法。
- 背後でMLflowがどのようにモデル評価を行なっているのか。


### Databricks 無料トライアル

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