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] をクリックします。

ノートブックを選択

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

TFE インスタンス

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

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

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

ランチャーから [ターミナル] を選択します。

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

pip3 install xgboost==1.2

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

ステップ 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 を作成する前に、Pandas がデータセットを正しく読み取るように、各列のデータ型の dict を作成します。

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 のみを持つ一連の列に変換します。たとえば「color」という列があり値には「blue」を指定できます。「red」がget_dummies はこれを「color_blue」という 2 つの列に変換しますと「color_red」すべてのブール値の 0 と 1 が返されます。

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

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

data.head()

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

Pandas のダミー列

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

ML の重要なコンセプトの一つに、トレーニングとテストの分割があります。データの大部分をモデルのトレーニングに使用し、残りは未知のデータでモデルをテストするために取っておきます。

ノートブックに次のコードを追加し、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 パラメータを渡すことだけです。ここでは、2 項分類の問題があり、モデルが(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% になるはずですが、ML には常にランダム性の要素があるため、精度は若干異なります。

ステップ 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: Partial Dependence Plot を確認する

各特徴量がモデルの予測全体にどう影響するかを確認するには、[Partial Dependence Plots] ボックスをオンにして、[Global Partial Dependence plots] を選択します。

このグラフから、HUD からのローンは拒否される可能性が若干高いことがわかります。交通機関コードはブール型の特徴量であり、値は 0 または 1 のみであるため、グラフはこの形状になっています。

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

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

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

混同行列を表示するには、正解特徴として mortgage_status を選択します。

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

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

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

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

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

左側のラジオボタンから [ユーザー属性の同等性] を選択すると、モデルが両方のスライスの同程度の応募者に対して approved と予測するように 2 つのしきい値が調整されます。各スライスの精度、偽陽性、偽陰性にはどう影響するでしょうか。

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

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

このタブを使用すると、データセットのバランスがとれていることを確認できます。たとえば、データセット内のローンは農業サービス庁から発行されたものはほとんどないように見えるでしょう。モデルの精度を向上させるため、データが利用可能であれば、その機関からのローンを追加することを検討できます。

ここでは、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 コマンドを実行して、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 モデルを保存したストレージの場所を指します。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 コンソールのナビゲーション メニューで [ストレージ] に移動してバケットを選択し、[削除] をクリックします。