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 ワークフローをサポートするさまざまなプロダクトが含まれています。このラボでは、以下でハイライト表示されたプロダクト(Prediction と Notebooks)を取り上げます。

Vertex プロダクトの概要

3. XGBoost の概観

XGBoost は、ディシジョン ツリー勾配ブーストを使用して予測モデルを作成する ML フレームワークです。ツリー内の異なるリーフノードに関連付けられたスコアに基づいて、複数のディシジョン ツリーをアンサンブルします。

下の図は、天気予報に基づいてスポーツの試合を開催するかどうかを評価する単純なディシジョン ツリー モデルの可視化です。

ツリーモデルの例

このモデルに XGBoost を使用する理由従来のニューラル ネットワークは、画像やテキストなどの非構造化データに対して最高のパフォーマンスを発揮することがわかっていますが、ディシジョン ツリーは多くの場合、この Codelab で使用する住宅ローンのデータセットのような構造化データに対して非常に効果的です。

4. 環境をセットアップする

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

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

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

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

Cloud コンソールの [Vertex] セクションに移動し、[Vertex AI API を有効にする] をクリックします。

Vertex ダッシュボード

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

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

ノートブックを選択する

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

TFE インスタンス

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

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

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

そのためには、ランチャーからターミナルを選択します。

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

pip3 install xgboost==1.2

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

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

ノートブックの最初のセルに次の import を追加してセルを実行します。実行するには、上部のメニューにある右矢印ボタンを押すか、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 のみを含む一連の列に変換します。たとえば、値が「blue」と「red」の列「color」があるとします。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: データをトレーニング セットとテストセットに分割する

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

ノートブックに次のコードを追加します。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)の範囲内の単一の値(承認されていない場合は 0、承認されている場合は 1)を出力する必要があるため、reg:logistic を使用します。

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

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

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

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% になるはずですが、ML には常にランダム性の要素があるため、精度は若干異なります。

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

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

model.save_model('model.bst')

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

ステップ 1: シミュレーション ツールの可視化を作成する

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 だった場合のモデルの予測にどのような影響があるかを確認しました。

シミュレーション ツールの左下のセクションに示すように、この特徴量を変更すると、モデルの approved 予測が 32% 大幅に低下しました。これは、ローンを行っている代理店がモデルの出力に強い影響を与えることを示しています。ただし、これを確認するにはさらなる分析が必要です。

UI の左下では、各データポイントのグラウンド トゥルース値を表示して、モデルの予測と比較することもできます。

ステップ 3: 反事実分析

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

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

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

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

このグラフから、HUD からのローンは拒否される可能性が若干高いことがわかります。代理店コードはブール値の特徴であるため、値は 0 または 1 のいずれかになります。

applicant_income_thousands は数値特徴です。Partial Dependence Plot では、所得が高いほど申請が承認される可能性がわずかに高まりますが、最大で 20 万ドル程度であることがわかります。20 万ドルを超えると、この特徴量はモデルの予測に影響しません。

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

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

正解ラベルの特徴として mortgage_status を選択し、混同行列を表示します。

この混同行列は、モデルの正しい予測と誤った予測を合計の割合で示しています。実際のはい / 予測されたはい実際のいいえ / 予測されたいいえの 2 乗を合計すると、モデルと同じ精度になります(この例では約 87% ですが、ML モデルのトレーニングにはランダム性の要素があるため、モデルは若干異なる可能性があります)。

また、しきい値スライダーを試し、ローンの予測 approved を決定する前にモデルが返す必要がある陽性分類スコアを増減して、精度、偽陽性、偽陰性がどのように変化するかを確認することもできます。この場合、しきい値 .55 付近で精度が最も高くなります。

次に、左側の [スライス条件] プルダウンで [loan_purpose_Home_purchase] を選択します。

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

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

左側のラジオボタンから [人口学的等価性] を選択すると、両方のスライスにおいて、申請者の割合が類似するように、2 つのしきい値が調整されます。approvedこれにより、各スライスの精度、偽陽性、偽陰性にどのような影響がありますか?

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

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

このタブでは、データセットのバランスを確認できます。たとえば、データセット内のローンのうち、農業サービス局が提供したものはごくわずかです。モデルの精度を高めるために、データが利用可能であれば、その機関からのローンを追加することを検討できます。

ここでは、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 モデルファイルを保存するストレージ バケットを作成できるようになりました。デプロイ時に Vertex AI をこのファイルに指すようにします。

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

!gsutil mb -l us-central1 $MODEL_BUCKET

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

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

!gsutil cp ./model.bst $MODEL_BUCKET

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

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

これで、モデルをクラウドにデプロイする準備が整いました。Vertex AI では、モデルに複数のエンドポイントを保持できます。まずモデルを作成し、次にそのモデル内にエンドポイントを作成してデプロイします。

まず、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 コンソールのナビゲーション メニューで [ストレージ] に移動してバケットを選択し、[削除] をクリックします。