機械学習モデルの解析に新たな風を! Phoenixを使ってみる

## はじめに

本記事では、機械学習モデルの解析ライブラリであるPhoenixを解説します。Phonenixでは、入力データの迅速な可視化やパフォーマンスの確認、問題点の抽出とその改善を手助けなどができます。


![ 2023-06-27 22.58.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/a76a7dc8-7d8f-01ea-9f83-de8f5ade8aac.png)

上記は埋め込みベクトルをUMAPで次元削減し、HDBSCANでクラスタリングした結果の図です。(全てPhoenixが自動で行ってくれます。)


:::note
おすすめポイント
:::
1. 入力データとモデルの出力を関連づけることでより深い考察が可能である点
1. クラスタリングや次元削減の結果をもとに特徴のある入力データを特定&Exportでき、今後の改善に活かしやすい点　


- GitHub 
https://github.com/Arize-ai/phoenix

- ドキュメント
https://docs.arize.com/phoenix

## Phoenixとは

Phoenixとは、機械学習モデルの迅速な可視化やパフォーマンスの確認、問題点の抽出とその改善を手助けするライブラリです。

![ 2023-06-22 15.33.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/60f8e0f6-c334-6e1a-aaf7-e1388e035909.png)

Phoenixは2023年6月現在、以下の領域のモデルに対応しています。

- Tabular - Regression, Classification 
- CV(Computer Vision) - Image classification
- NLP
- LLM


## Phoenixの書き方
Phoenixの基本的な使い方は以下です。

```python
import phoenix as px

# スキーマの定義
schema = px.Schema(
    # 特徴量のカラムの設定
    feature_column_names=[
        "sepal_length",
        "sepal_width",
        "petal_length",
        "petal_width",
    ],
    # 正解ラベルのカラムの設定
    actual_label_column_name="target",
    # 予測ラベルのカラムの設定
    prediction_label_column_name="prediction",
)

# データフレームとスキーマの紐付け
train_ds = px.Dataset(train_df, schema, "training")
prod_ds = px.Dataset(prod_df, schema, "production")

# セッションの開始
session = px.launch_app(prod_ds, train_ds)
# or just one dataset
# session = px.launch_app(prod_ds)
```

まずはデータセットは、1つもしくは2つ(訓練データセットと検証データセットなど)用意します。2つのデータセットを用意する場合は、データセット間のコホートの確認ができます。

スキーマ(`px.Schema`)ではデータセットのカラムの情報(特徴量なのか、予測したいラベルなのか)を指定します。

そして`px.Dataset`でデータフレームとスキーマの紐付けを行い、`px.launch_app`でセッションの開始します。

## PhoenixによるEmbedding

PhoenixにはEmbedding機能があります。Embeddingにより入力データから特徴ベクトルを生成することができます。
使用例は以下です。

```python
from arize.pandas.embeddings import EmbeddingGenerator, UseCases

df = df.reset_index(drop=True)

generator = EmbeddingGenerator.from_use_case(
    use_case=UseCases.CV.IMAGE_CLASSIFICATION,
    model_name="google/vit-base-patch16-224-in21k",
    batch_size=100
)
df["image_vector"] = generator.generate_embeddings(
    local_image_path_col=df["local_path"]
)
```

## Phoenixの使用例(画像分類)
### プログラム
実際にPhoenixの開発チームが用意しているサンプルコードを解説していきます。

まずは画像データを読み込みます。

```python
import pandas as pd
import phoenix as px

train_df = pd.read_parquet(
    "http://storage.googleapis.com/arize-assets/phoenix/datasets/unstructured/cv/human-actions/human_actions_training.parquet"
)
prod_df = pd.read_parquet(
    "http://storage.googleapis.com/arize-assets/phoenix/datasets/unstructured/cv/human-actions/human_actions_production.parquet"
)
```

`train_df`は訓練画像のデータフレームであり、`prod_df`はテスト画像のデータフレームです。
`train_df`のカラムは以下です。

- prediction_id: 各データポイントの一意な識別子
- prediction_ts: 予測のUnixタイムスタンプ
- url: 画像データへのリンク
- image_vector: 各画像を表す埋め込みベクトル
- actual_action: 各画像の正解ラベル
- predicted_action: 画像の予測ラベル

`prod_df`には各画像の正解ラベル(`actual_action`)が含まれておりません。


次にスキーマを定義して、データフレームと紐付けます。

```python
train_schema = px.Schema(
    timestamp_column_name="prediction_ts",
    prediction_label_column_name="predicted_action",
    actual_label_column_name="actual_action",
    embedding_feature_column_names={
        "image_embedding": px.EmbeddingColumnNames(
            vector_column_name="image_vector",
            link_to_data_column_name="url",
        ),
    },
)

prod_schema = px.Schema(
    timestamp_column_name="prediction_ts",
    prediction_label_column_name="predicted_action",
    embedding_feature_column_names={
        "image_embedding": px.EmbeddingColumnNames(
            vector_column_name="image_vector",
            link_to_data_column_name="url",
        ),
    },
)

prod_ds = px.Dataset(dataframe=prod_df, schema=prod_schema, name="production")
train_ds = px.Dataset(dataframe=train_df, schema=train_schema, name="training")
```
`timestamp_column_name`はデータに時系列性がある場合にのみ設定します。

`prediction_label_column_name`は予測ラベルのカラム名、`actual_label_column_name`は正解ラベルのカラム名です。

`embedding_feature_column_names`は入力データの埋め込みベクトルを設定でき、`px.EmbeddingColumnNames`の`vector_column_name`でカラム名を設定します。またデータのリンクがある場合は`link_to_data_column_name`でデータのリンクを設定できます。

最後にセッションを開始します。

```Python
session = px.launch_app(primary=prod_ds, reference=train_ds)
```

### PhoneixのGUI
セッションを開くと以下の画面が出ます。



![ 2023-07-05 21.32.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/9471d1bc-626c-6d5e-c769-7726dd2c7fcc.png)

ここでDimensions->predicted_actionを選択すると、以下のような統計情報を確認することができます。

![ 2023-07-05 21.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/8a61244d-1188-8724-e08c-2a72fea7ca4d.png)

次にEmbeddings->image_embeddingを選択すると、埋め込みベクトルをUMAPで次元削減し、HDBSCANでクラスタリングした結果が出力されます。

![ 2023-07-05 21.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/bfefbe73-f3ce-89b1-49b4-ddc1d720da0a.png)

クラスターのクリックするとデータの詳細を確認することができます。

![ 2023-07-05 21.42.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/da43cf92-413b-cbf7-ef48-c52e10a41a57.png)


このクラスターの画像は粒状のノイズが多いことがわかります。このように問題のある入力データを見つけた際は、Exportから出力できます。

また`Color By`から`correctness`を選択すると、モデルが正解したデータ、不正解したデータを簡単に可視化することができます。

![ 2023-07-05 21.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/765041a4-5daf-0792-e606-dcafb766b716.png)

他にもHDBSCANやUMAPの設定を変更することができたり、指定した時刻のデータをピックアップすることもできます。

### その他
Phoenix開発チームが公開しているNotebookの例は以下です。

https://docs.arize.com/phoenix/tutorials/notebooks

## 最後に
みなさんもPhoenixを使って機械学習モデルの解析をしてみませんか？


Phoenixを開発しているチームが弊社と似た名前（ARISE）で驚きました。