Google Cloud AI Platform、What-if Toolを使ってみた①

# 1. はじめに
 - [Analyzing a financial ML model deployed on AI Platform with the What-If Toolのチュートリアル](https://codelabs.developers.google.com/codelabs/xgb-wit-caip/index.html?index=..%2F..index&_ga=2.105487558.-435112414.1574811865#0)をやります。
 - ただ日本語にしただけの記事です。

# 2. 環境セットアップ
## Step 0: プロジェクトの作成 
 1.  [リソース管理](https://console.cloud.google.com/cloud-resource-manager)のページに行く
 2.  [プロジェクトを作成]
 3.  プロジェクト名を入力して[作成]クリック<img width="548" alt="スクリーンショット 2019-11-27 10.14.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/0f779c06-110c-1c19-4024-51b9a456d57a.png">

## Step 1: Cloud AI Platform Models APIの有効化
1. [AI Platform Models section](https://console.cloud.google.com/ai-platform/models)に移動
2. [APIを有効にする]をクリック<img width="942" alt="スクリーンショット 2019-11-27 10.18.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/571e16b2-7208-3264-8c1c-b5ea24138ba2.png">

## Step 2: Compute Engine APIの有効化
1. [Compute Engine](https://console.cloud.google.com/marketplace/details/google/compute.googleapis.com)のページに移動
2. [有効にする]をクリック<img width="838" alt="スクリーンショット 2019-11-27 10.20.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/0fbb9a59-ff12-6475-624a-5ec3b54d3b42.png">
 
## Step 3: AI Platform Notebooksインスタンスの作成
1. [AI Platform Notebooksセクション](https://console.cloud.google.com/ai-platform/notebooks/instances)に移動
2. [ノートブック]-[新しいインスタンス]から最新の**TF 1.x**の **without GPUs**を選択して作成<img width="938" alt="スクリーンショット 2019-11-27 10.25.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/de30bdb8-f4fa-c346-b83d-a2afa4e936e8.png">
3. インスタンス名を入力して、[作成]をクリック<img width="515" alt="スクリーンショット 2019-11-27 10.31.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/312384ca-927a-6524-2c26-054f7f478c6b.png">
4. インスタンスが作成できたら、[JUPYTERLABを開く]をクリック<img width="938" alt="スクリーンショット 2019-11-27 10.34.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/5722abd3-d45e-7166-ca56-8d647bdce41b.png">

## Step 4: XGBoostのインストール
XGBoostパッケージをターミナルから追加していきます。
1. [Terminal]をクリック<img width="651" alt="スクリーンショット 2019-11-27 10.36.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/f2609ab8-9ad4-0c39-7dcf-834e1fd2992d.png">
2. コマンド実行

```bash 
$ pip3 install xgboost
```

準備完了です。(結構時間かかります。)

## Step 5: Pythonパッケージのインポート
notebookの最初のセルに以下のimport文を記述して実行してください。

```python
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
```
# 3. データのダウンロードと前処理
[mortgageデータセット](https://www.ffiec.gov/hmda/hmdaflat.htm)をXGBoostモデルで学習します。事前に処理された小サイズバージョンを使います。このモデルは住宅ローンを承認できるか否かの判別をします。

## Step 1: 事前処理データのダウンロード
Google Cloud Storageからデータセットを取得できます。Jupyter notebookでgsutilコマンドを実行してダウンロードします。

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

## Step 2: Pandasを使ってデータセットを読込
まずdatatypeを定義するdictionaryを作成します。

```python
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
})
```
定義したdatatypeに沿って、DataFrameを作成します。オリジナルのデータセットはsortされているので、shuffle(sklearnの)するのがポイントです。

```python
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()`で最初の５行をプレビューします。以下のような感じです。
<img width="1517" alt="スクリーンショット 2019-11-27 12.58.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/9d24a69d-5219-e15b-7341-4401d7fb5407.png">

`approved`カラムが予測対象です。1が承認、0が否認を示します。

approvedの分散度合いを見るために、以下のコマンドを実行します。

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

labels = data['approved'].values
data = data.drop(columns=['approved'])
```
66%くらいが承認となっているはずです。

## Step 3: カテゴリカル値のダミーカラムを作成
このデータセットはカテゴリカル値を含みますが、XGBoostは数値のみしか扱えません。pandasの`get_dummies`を使って[on-hot encoding](https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/)で変換します。

ダミーカラムの作成のために以下のコマンドを実行します。

```python
dummy_columns = list(data.dtypes[data.dtypes == 'category'].index)
data = pd.get_dummies(data, columns=dummy_columns)
data.head()
```
`purchaser_type`が変換された後の様子
<img width="553" alt="スクリーンショット 2019-11-27 13.07.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/2838127a-0738-d57e-eacd-00c2e438d003.png">

## Step 4: 訓練データとテストデータの分割
訓練データとテストデータに分割することは機械学習では重要なコンセプトです。データの大半を訓練データに使って、後ほど残りをテストデータに使います。

Scikit Learnのfunctionの`train_test_split`を使う以下のコードを実行します。

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

学習前の準備が終わりました。

# 4. XGBoostモデルのビルド、学習、評価
## Step 1: XGBoostモデルの定義
モデルの作成はとてもシンプルです。`XGBClassifier`を使ってモデルを作り、`objective`に目的のアルゴリズムを指定します。今回は単純な２値のクラス分類で、ロジスティック回帰を指定します。`reg:logistic`を使います。

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

`fit()`で学習を実行します。

```python
model.fit(x_train, y_train)
```
学習は数分かかります。

## Step 2: モデルのaccuracyを評価

`predict()`を使って予測をします。
Scikit Learnの`accuracy_score`を使って、accuracyを計算します。

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

だいたい*87%*くらいになるはずです。

## Step 3: モデルの保存
モデルをデプロイするために以下のコードでローカルにモデルを保存します。

```python
model.save_model('model.bst')
```

# 5. Cloud AI Platformにモデルをデプロイする
ローカルで動いたモデルをクラウドにデプロイします。

## Step 1: Cloud Storage bucketの作成
まずは環境変数の定義をします。

```
# Update these to your own GCP project, model, and version names
GCP_PROJECT = 'financial-ml-260301'
MODEL_BUCKET = 'gs://financial_ml_bucket'
VERSION_NAME = 'v1'
```
XGBoostモデルファイルをCloud AI Platformに格納する準備ができました。

`gsutil`コマンドを実行してbucketを作成します。

```python
!gsutil mb $MODEL_BUCKET
```

## Step 2: モデルをCloud Storageにコピー
以下のコマンドでモデルファイルをCloud Storageにコピーします。

```python
!gsutil cp ./model.bst $MODEL_BUCKET
```

google cloud consoleのstorage browserでコピーされたことを確認することができます。<img width="954" alt="スクリーンショット 2019-11-27 13.32.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/05b935a4-84ac-2725-451f-215e5559c0db.png">



## Step 3: モデルの作成とデプロイ
最初にgcloud CLIでprojectの設定をします。

```python
!gcloud config set project $GCP_PROJECT
```

`ai-platform`コマンドで新しいモデルを作成します。`xgb_mortgage`と呼びます。

```python
!gcloud ai-platform models create xgb_mortgage
```

以下のコマンドでモデルをデプロイします。

```python
!gcloud ai-platform versions create $VERSION_NAME \
--model=xgb_mortgage \
--framework='XGBOOST' \
--runtime-version=1.14 \
--origin=$MODEL_BUCKET \
--python-version=3.5 \
--project=$GCP_PROJECT
```

AI Platform consoleの[model section](https://console.cloud.google.com/ai-platform/models?project=financial-ml-260301&folder=&organizationId=)で新しいバージョンがデプロイされている様子が見れます。
<img width="1119" alt="スクリーンショット 2019-11-27 13.45.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/0a5851ab-ae5e-e319-a158-291d433e9272.png">

デプロイ完了まで２ー3分かかります。

## Step 4: デプロイしたモデルのテスト
テストセットをJSONファイルで保存します。

```python
%%writefile predictions.json
[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]
```

以下のコードでモデルのテストを実行します。

```python
prediction = !gcloud ai-platform predict --model=xgb_mortgage --json-instances=predictions.json --version=$VERSION_NAME
print(prediction)
```

1に近い値が出力され、承認が予測できていると思います。

# 6. What-if Toolによるモデルの解釈

## Step 1: What-if Toolの可視化
What-if Toolに接続するため、テストセットのサブセットが必要です。Numpy arrayを500作成しましょう。

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

`WitConfigBuilder`を使っていきます。今回のモデルは2クラススコアが期待できるので、任意の`adjust_prediction`パラメータを使います。以下のコードで正しいフォーマットに変換します。

```python
def adjust_prediction(pred):
  return [1 - pred, pred]

config_builder = (WitConfigBuilder(test_examples.tolist(), data.columns.tolist() + ['mortgage_status'])
  .set_ai_platform_model(GCP_PROJECT, MODEL_NAME, VERSION_NAME, adjust_prediction=adjust_prediction)
  .set_target_feature('mortgage_status')
  .set_label_vocab(['denied', 'approved']))
WitWidget(config_builder, height=800)
```

以下のような図が表示されます。
<img width="1382" alt="スクリーンショット 2019-11-27 14.00.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271751/eb3bd1d0-9e64-59bd-8f87-b2461b84464c.png">



[続く](https://qiita.com/yuxzux/items/d0527fc53c059572258a)・・・