What-If ツールと Vertex AI を使用した財務 ML モデルの構築

1. 概要

このラボでは、What-If ツールを使用して、XGBoost モデルを分析します。モデルを分析したら、Cloud の新しい Vertex AI にデプロイします。

学習内容

次の方法を学習します。

  • ホストされたノートブックで、公開されている住宅ローン データセットを使用して XGBoost モデルをトレーニングする
  • What-If ツールを使用してモデルを分析する
  • XGBoost モデルを Vertex AI にデプロイする

このラボを Google Cloud で実行するための総費用は約 $1 です。

2. Vertex AI の概要

このラボでは、Google Cloud で利用できる最新の AI プロダクトを使用します。Vertex AI は Google Cloud 全体の ML サービスを統合してシームレスな開発エクスペリエンスを提供します。以前は、AutoML でトレーニングしたモデルやカスタムモデルにそれぞれ個別のサービスを介してアクセスする必要がありましたが、Vertex AI は、これらの個別のサービスを他の新しいプロダクトとともに 1 つの API にまとめます。既存のプロジェクトを Vertex AI に移行することもできます。ご意見やご質問がありましたら、サポートページからお寄せください。

Vertex AI には、エンドツーエンドの ML ワークフローをサポートするさまざまなプロダクトが含まれています。このラボでは、以下でハイライト表示されたプロダクト(予測と Notebooks)を取り上げます。

Vertex プロダクトの概要

3. XGBoost の概要

XGBoost は、ディシジョン ツリー勾配ブースティングを使用して予測モデルを構築する機械学習フレームワークです。ツリー内のさまざまなリーフノードに関連付けられたスコアに基づいて、複数のディシジョン ツリーをアンサンブルします。

次の図は、天気予報に基づいてスポーツ ゲームを実施するかどうかを評価する単純なディシジョン ツリー モデルのビジュアリゼーションです。

ツリーモデルの例

このモデルに XGBoost を使用する理由従来のニューラル ネットワークは、画像やテキストなどの非構造化データで最高のパフォーマンスを発揮することが示されていますが、ディシジョン ツリーは、この Codelab で使用する住宅ローン データセットなどの構造化データで非常に優れたパフォーマンスを発揮することがよくあります。

4. 環境を設定する

この Codelab を実行するには、課金が有効になっている Google Cloud Platform プロジェクトが必要です。プロジェクトを作成するには、こちらの手順を行ってください。

ステップ 1: Compute Engine API を有効にする

Compute Engine に移動し、まだ有効になっていない場合は [有効にする] を選択します。これはノートブック インスタンスを作成するために必要です。

ステップ 2: Vertex AI API を有効にする

[Vertex] セクションに移動し、[**Vertex AI API を有効にする**]をクリックします。

Vertex ダッシュボード

ステップ 3: Notebooks インスタンスを作成する

Cloud コンソールの [Vertex] セ/クション で [Notebooks] をクリックします。

ノートブックを選択する

[新しいインスタンス] を選択します。次に、インスタンス タイプとして [TensorFlow Enterprise 2.3]、[GPU なし] を選択します。

TFE インスタンス

デフォルトのオプションを使用して、[作成] をクリックします。インスタンスが作成されたら、[JUPYTERLAB を開く] を選択します。

ステップ 4: XGBoost をインストールする

JupyterLab インスタンスが開いたら、XGBoost パッケージを追加する必要があります。

これを行うには、ランチャーから [ターミナル] を選択します。

次に、次のコマンドを実行して、Vertex AI でサポートされている最新バージョンの XGBoost をインストールします。

pip3 install xgboost==1.2

完了したら、ランチャーから Python 3 ノートブック インスタンスを開きます。ノートブックで作業を開始する準備ができました。

ステップ 5: Python パッケージをインポートする

ノートブックの最初のセルに次のインポートを追加して、セルを実行します。実行するには、上部メニューの右矢印ボタンを押すか、command-enter を押します。

import pandas as pd
import xgboost as xgb
import numpy as np
import collections
import witwidget

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.utils import shuffle
from witwidget.notebook.visualization import WitWidget, WitConfigBuilder

5. データをダウンロードして処理する

ffiec.gov の 住宅ローン データセットを使用して、XGBoost モデルをトレーニングします。元のデータセットに前処理を行い、モデルのトレーニングに使用する小規模なバージョンを作成しました。モデルは、特定の住宅ローン申請が承認されるかどうかを予測します。

ステップ 1: 前処理済みのデータセットをダウンロードする

Google Cloud Storage でデータセットのバージョンを利用できます。ダウンロードするには、Jupyter ノートブックで次の gsutil コマンドを実行します。

!gsutil cp 'gs://mortgage_dataset_files/mortgage-small.csv' .

ステップ 2: Pandas でデータセットを読み取る

Pandas DataFrame を作成する前に、各列のデータ型の dict を作成して、Pandas がデータセットを正しく読み取れるようにします。

COLUMN_NAMES = collections.OrderedDict({
 'as_of_year': np.int16,
 'agency_code': 'category',
 'loan_type': 'category',
 'property_type': 'category',
 'loan_purpose': 'category',
 'occupancy': np.int8,
 'loan_amt_thousands': np.float64,
 'preapproval': 'category',
 'county_code': np.float64,
 'applicant_income_thousands': np.float64,
 'purchaser_type': 'category',
 'hoepa_status': 'category',
 'lien_status': 'category',
 'population': np.float64,
 'ffiec_median_fam_income': np.float64,
 'tract_to_msa_income_pct': np.float64,
 'num_owner_occupied_units': np.float64,
 'num_1_to_4_family_units': np.float64,
 'approved': np.int8
})

次に、上記のデータ型を渡して DataFrame を作成します。元のデータセットが特定の順序で並んでいる場合は、データをシャッフルすることが重要です。これを行うには、最初のセルでインポートした shuffle という sklearn ユーティリティを使用します。

data = pd.read_csv(
 'mortgage-small.csv',
 index_col=False,
 dtype=COLUMN_NAMES
)
data = data.dropna()
data = shuffle(data, random_state=2)
data.head()

data.head() を使用すると、Pandas でデータセットの最初の 5 行をプレビューできます。上記のセルを実行すると、次のような出力が表示されます。

住宅ローン データセットのプレビュー

これらは、モデルのトレーニングに使用する特徴です。最後までスクロールすると、最後の列 approved が表示されます。これは予測するものです。値 1 は特定の申請が承認されたことを示し、0 は拒否されたことを示します。

データセット内の承認済み / 拒否済みの値の分布を確認し、ラベルの numpy 配列を作成するには、次のコマンドを実行します。

# Class labels - 0: denied, 1: approved
print(data['approved'].value_counts())

labels = data['approved'].values
data = data.drop(columns=['approved'])

データセットの約 66% に承認済みの申請が含まれています。

ステップ 3: カテゴリ値のダミー列を作成する

このデータセットにはカテゴリ値と数値が混在していますが、XGBoost ではすべての特徴が数値である必要があります。XGBoost モデルでは、ワンホット エンコードを使用してカテゴリ値を表すのではなく、Pandas の get_dummies 関数を利用します。

get_dummies は、複数の有効な値を持つ列を受け取り、0 と 1 のみを含む一連の列に変換します。たとえば、「青」と「赤」の有効な値を持つ「色」という列がある場合、get_dummies はこれを「color_blue」と「color_red」という 2 つの列に変換し、すべてのブール値は 0 と 1 になります。

カテゴリ特徴のダミー列を作成するには、次のコードを実行します。

dummy_columns = list(data.dtypes[data.dtypes == 'category'].index)
data = pd.get_dummies(data, columns=dummy_columns)

data.head()

今回はデータをプレビューすると、単一の特徴(下の purchaser_type など)が複数の列に分割されます。

Pandas のダミー列

ステップ 4: データをトレーニング セットとテストセットに分割する

機械学習の重要なコンセプトは、トレーニング データとテストデータの分割です。データの大部分を使用してモデルをトレーニングし、残りをそれまでに遭遇したことがないデータでモデルをテストするために取っておきます。

次のコードをノートブックに追加します。このコードでは、Scikit-learn 関数 train_test_split を使用してデータを分割します。

x,y = data.values,labels
x_train,x_test,y_train,y_test = train_test_split(x,y)

モデルを構築してトレーニングする準備が整いました。

6. XGBoost モデルを構築、トレーニング、評価する

ステップ 1: XGBoost モデルを定義してトレーニングする

XGBoost でのモデルの作成は簡単です。XGBClassifier クラスを使用してモデルを作成し、特定の分類タスクに適した objective パラメータを渡すだけです。この場合は、二項分類の問題があり、モデルが (0,1) の範囲の単一の値を出力するようにするため、reg:logistic を使用します。0 は承認されず、1 は承認されます。

次のコードは、XGBoost モデルを作成します。

model = xgb.XGBClassifier(
    objective='reg:logistic'
)

1 行のコードでモデルをトレーニングできます。fit() メソッドを呼び出し、トレーニング データとラベルを渡します。

model.fit(x_train, y_train)

ステップ 2: モデルの精度を評価する

トレーニング済みのモデルを使用して、predict() 関数でテストデータの予測を生成できるようになりました。

次に、Scikit-learn の accuracy_score() 関数を使用して、テストデータでのパフォーマンスに基づいてモデルの精度を計算します。テストセットの各例について、実際の値とモデルの予測値を渡します。

y_pred = model.predict(x_test)
acc = accuracy_score(y_test, y_pred.round())
print(acc, '\n')

精度は 87% 程度になりますが、機械学習には常にランダム性があるため、多少異なる場合があります。

ステップ 3: モデルを保存する

モデルをデプロイするには、次のコードを実行してローカル ファイルに保存します。

model.save_model('model.bst')

7. What-If ツールを使用してモデルを解釈する

ステップ 1: What-If ツールの可視化を作成する

What-If ツールをローカル モデルに接続するには、テスト例のサブセットと、それらの例の実際の値を渡す必要があります。500 個のテスト例とその実際のラベルの Numpy 配列を作成しましょう。

num_wit_examples = 500
test_examples = np.hstack((x_test[:num_wit_examples],y_test[:num_wit_examples].reshape(-1,1)))

What-If ツールをインスタンス化するには、WitConfigBuilder オブジェクトを作成して、分析するモデルを渡すだけです。

What-If ツールは、モデル内の各クラス(この場合は 2 つ)のスコアのリストを必要とするため、What-If ツールで XGBoost の predict_proba メソッドを使用します。

config_builder = (WitConfigBuilder(test_examples.tolist(), data.columns.tolist() + ['mortgage_status'])
  .set_custom_predict_fn(model.predict_proba)
  .set_target_feature('mortgage_status')
  .set_label_vocab(['denied', 'approved']))
WitWidget(config_builder, height=800)

可視化の読み込みには 1 分ほどかかります。読み込まれると、次のようになります。

What-If ツールの初期ビュー

y 軸はモデルの予測を示します。1 は信頼度の高い approved 予測、0 は信頼度の高い denied 予測です。x 軸は、読み込まれたすべてのデータポイントの広がりです。

ステップ 2: 個々のデータポイントを調べる

What-If ツールのデフォルト ビューは [データポイント エディタ] タブです。ここで、個々のデータポイントをクリックして特徴を確認し、特徴の値を変更して、その変更が個々のデータポイントに対するモデルの予測にどのように影響するかを確認できます。

次の例では、0.5 のしきい値に近いデータポイントを選択しました。この特定のデータポイントに関連付けられた住宅ローン申請は、CFPB から発生しました。その特徴を 0 に変更し、agency_code_Department of Housing and Urban Development (HUD) の値を 1 に変更して、このローンが HUD から発生した場合にモデルの予測がどうなるかを確認しました。

What-If ツールの左下のセクションでわかるように、この特徴を変更すると、モデルの approved 予測が 32% 大幅に減少しました。これは、ローンの発生元機関がモデルの出力に大きな影響を与える可能性があることを示していますが、確認するにはさらに分析を行う必要があります。

UI の左下部分では、各データポイントの実際の値を確認し、モデルの予測と比較することもできます。

ステップ 3: 反事実分析

次に、任意のデータポイントをクリックし、[最も近い反事実データポイントを表示] スライダを右に移動します。

これを選択すると、選択した元のデータポイントに最も類似した特徴値を持つデータポイントが表示されますが、予測は逆になります。 特徴値をスクロールして、2 つのデータポイントの違いを確認できます(違いは緑色で太字でハイライト表示されます)。

ステップ 4: 部分依存プロットを確認する

各特徴がモデルの予測に全体的にどのように影響するかを確認するには、[部分依存プロット] チェックボックスをオンにして、[グローバル部分依存プロット] が選択されていることを確認します。

ここでは、HUD から発生したローンは拒否される可能性がわずかに高いことがわかります。このグラフの形状は、機関コードがブール値の特徴であるため、値は 0 または 1 になります。

applicant_income_thousands は数値の特徴です。部分依存プロットでは、収入が多いほど申請が承認される可能性がわずかに高くなりますが、20 万ドル程度までです。20 万ドルを超えると、この特徴はモデルの予測に影響しません。

ステップ 5: 全体的なパフォーマンスと公平性を調べる

次に、[パフォーマンスと公平性] タブに移動します。ここでは、混同行列、PR 曲線、ROC 曲線など、提供されたデータセットに対するモデルの結果に関する全体的なパフォーマンス統計が表示されます。

混同行列を表示するには、グラウンド トゥルースの特徴として mortgage_status を選択します。

この混同行列は、モデルの正誤の予測を合計の割合として示しています。 [Actual Yes / Predicted Yes] と [Actual No / Predicted No] の正方形を足すと、モデルと同じ精度になります(この場合は約 87% ですが、ML モデルのトレーニングにはランダム性があるため、モデルによって多少異なる場合があります)。

しきい値スライダーを操作して、モデルがローンの approved を予測する前に返す必要がある陽性分類スコアを上げ下げし、精度、偽陽性、偽陰性がどのように変化するかを確認することもできます。この場合、精度は 0.55 のしきい値で最も高くなります。

次に、左側の [Slice by] プルダウンで loan_purpose_Home_purchase を選択します。

データの 2 つのサブセットのパフォーマンスが表示されます。「0」スライスはローンが住宅購入用ではない場合を示し、「1」スライスはローンが住宅購入用の場合を示します。2 つのスライス間の精度、偽陽性率、偽陰性率を確認して、パフォーマンスの違いを探します。

行を展開して混同行列を確認すると、モデルは住宅購入のローン申請の約 70% で「承認済み」と予測し、住宅購入以外のローンの場合は 46% のみと予測しています(正確な割合はモデルによって異なります)。

左側のラジオボタンで [Demographic parity] を選択すると、2 つのしきい値が調整され、両方のスライスで同様の割合の申請者に対してモデルが approved を予測します。これにより、各スライスの精度、偽陽性、偽陰性はどのように変化しますか?

ステップ 6: 特徴の分布を調べる

最後に、What-If ツールの [Features] タブに移動します。データセット内の各特徴の値の分布が表示されます。

このタブを使用して、データセットのバランスが取れていることを確認できます。たとえば、データセット内のローンは、Farm Service Agency から発生したものが非常に少ないようです。モデルの精度を高めるために、データが利用可能な場合は、その機関からのローンを追加することを検討してください。

ここでは、What-If ツールのデータ探索のアイデアをいくつか説明しました。このツールを自由に試してみてください。他にも探索できる領域がたくさんあります。

8. モデルを Vertex AI にデプロイする

モデルはローカルで動作していますが、このノートブックだけでなく、どこからでも予測を行えるようにしたいと考えています。このステップでは、クラウドにデプロイします。

ステップ 1: モデルの Cloud Storage バケットを作成する

まず、この Codelab の残りの部分で使用する環境変数を定義しましょう。以下の値に、Google Cloud プロジェクトの名前、作成する Cloud Storage バケットの名前(グローバルに一意である必要があります)、モデルの最初のバージョンのバージョン名を入力します。

# Update the variables below to your own Google Cloud project ID and GCS bucket name. You can leave the model name we've specified below:
GCP_PROJECT = 'your-gcp-project'
MODEL_BUCKET = 'gs://storage_bucket_name'
MODEL_NAME = 'xgb_mortgage'

これで、XGBoost モデル ファイルを保存する Storage バケットを作成する準備ができました。デプロイ時に、Vertex AI がこのファイルを指すようにします。

ノートブック内から次の gsutil コマンドを実行して、Regional Storage バケットを作成します。

!gsutil mb -l us-central1 $MODEL_BUCKET

ステップ 2: モデルファイルを Cloud Storage にコピーする

次に、XGBoost の保存済みモデルファイルを Cloud Storage にコピーします。次の gsutil コマンドを実行します。

!gsutil cp ./model.bst $MODEL_BUCKET

Cloud コンソールの Storage ブラウザに移動して、ファイルがコピーされたことを確認します。

ステップ 3: モデルを作成してエンドポイントにデプロイする

モデルをクラウドにデプロイする準備がほぼ整いました。Vertex AI では、1 つのモデルに複数のエンドポイントを含めることができます。まずモデルを作成し、そのモデル内にエンドポイントを作成してデプロイします。

まず、gcloud CLI を使用してモデルを作成します。

!gcloud beta ai models upload \
--display-name=$MODEL_NAME \
--artifact-uri=$MODEL_BUCKET \
--container-image-uri=us-docker.pkg.dev/cloud-aiplatform/prediction/xgboost-cpu.1-2:latest \
--region=us-central1

artifact-uri パラメータは、XGBoost モデルを保存した Storage の保管場所を指します。container-image-uri パラメータは、サービングに使用するビルド済みコンテナを Vertex AI に伝えます。このコマンドが完了したら、Vertex コンソールの [モデル] セクションに移動して、新しいモデルの ID を取得します。こちらをご覧ください

コンソールからモデル ID を取得する

その ID をコピーして変数に保存します。

MODEL_ID = "your_model_id"

次に、このモデル内にエンドポイントを作成します。これを行うには、次の gcloud コマンドを使用します。

!gcloud beta ai endpoints create \
--display-name=xgb_mortgage_v1 \
--region=us-central1

完了すると、ノートブックの出力にエンドポイントの場所が記録されます。エンドポイントが projects/project_ID/locations/us-central1/endpoints/endpoint_ID. のようなパスで作成された行を探します。次に、以下の値を上記で作成したエンドポイントの ID に置き換えます。

ENDPOINT_ID = "your_endpoint_id"

エンドポイントをデプロイするには、次の gcloud コマンドを実行します。

!gcloud beta ai endpoints deploy-model $ENDPOINT_ID \
--region=us-central1 \
--model=$MODEL_ID \
--display-name=xgb_mortgage_v1 \
--machine-type=n1-standard-2 \
--traffic-split=0=100

エンドポイントのデプロイには 5 ~ 10 分ほどかかります。エンドポイントのデプロイ中に、コンソールの [モデル] セクションに移動します。モデルをクリックすると、エンドポイントがデプロイされていることがわかります。

デプロイが正常に完了すると、読み込みスピナーが緑色のチェックマークに変わります。

ステップ 4: デプロイしたモデルをテストする

デプロイしたモデルが動作していることを確認するには、gcloud を使用して予測を行い、テストします。まず、テストセットの例を含む JSON ファイルを保存します。

%%writefile predictions.json
{
  "instances": [
    [2016.0, 1.0, 346.0, 27.0, 211.0, 4530.0, 86700.0, 132.13, 1289.0, 1408.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]
  ]
}

次の gcloud コマンドを実行して、モデルをテストします。

!gcloud beta ai endpoints predict $ENDPOINT_ID \
--json-request=predictions.json \
--region=us-central1

出力にモデルの予測が表示されます。この例は承認されたため、1 に近い値が表示されます。

9. クリーンアップ

このノートブックを引き続き使用する場合は、未使用時にオフにすることをおすすめします。Cloud コンソールの Notebooks UI で、ノートブックを選択して [停止] をクリックします。

このラボで作成したリソースをすべて削除する場合は、ノートブック インスタンスを停止するのではなく、削除します。

デプロイしたエンドポイントを削除するには、Vertex コンソールの [エンドポイント] セクションに移動して、削除アイコンをクリックします。

ストレージ バケットを削除するには、Cloud コンソールのナビゲーション メニューで [ストレージ] に移動してバケットを選択し、[削除] をクリックします。