AWS公式資料で挑むMLS認定(11)-Amazon SageMakerチュートリアル(XGBoostモデルの構築)

##### [前回] [AWS公式資料で挑むMLS認定(10)-Amazon SageMakerの基本](https://qiita.com/mingchun_zhao/items/12e1753774815168adff)

## はじめに

今回は、Amazon SageMaker公式チュートリアルを通してみます。
抽象的な理論を、実践しながら理解するのが近道と感じますので。

※ 余談: 検証に必要なAWS料金について
以前AWS Innovateセッション視聴し、頂いた`AWSクレジット`で賄っています。

## Amazon SageMakerのおさらい

- 機械学習(ML)モデルを迅速に構築、トレーニング、デプロイ可能な、フルマネージド型サービス
- 通常、MLモデルのPoCと本番移行は複雑で時間がかかる
    - モデルのトレーニングに、膨大な量のデータ管理が必要
    - トレーニングに最適なアルゴリズムを選択する必要
    - トレーニングに必要な計算能力(インフラストラクチャ)の管理が必要
- Amazon SageMakerを使用することで
    - MLモデルの構築とデプロイが簡単になる
    - 幅広い選択肢から適切なアルゴリズムとフレームワークを選択可能
    - ペタバイト規模のモデルトレーニングに必要なインフラを使用可能で管理不要

## チュートリアルの概要

- AWSハンズオンチュートリアル
[Amazon SageMaker を使用して機械学習モデルを構築、トレーニング、デプロイ](https://aws.amazon.com/jp/getting-started/hands-on/build-train-deploy-machine-learning-model-sagemaker/)

- チュートリアルのシナリオ
    - 銀行で働く機械学習デベロッパーという設定
    - ミッションは、顧客が預金証書(CD)の申し込みを行うかの予測モデルを開発

- チュートリアルで学ぶ内容
    - SageMakerノートブックインスタンスを作成
    - データの準備
    - データから学習するため、モデルのトレーニング
    - モデルのデプロイ
    - MLモデルのパフォーマンス評価

- トレーディングに使用するデータセット
    - `Bank Marketing Data Set`を使用
        - データセットに含まれる内容
            - 顧客の人口統計
            - マーケティングイベントへの反応
            - 外部環境要因に関する情報
    - データはラベル付けされている
        - データセットの列には、銀行からオファーされた商品に顧客が申し込みを行ったか否かが示されている
    - カリフォルニア大学アーバイン校により監修された機械学習リポジトリから公開されている

### チュートリアルのゴール

- Amazon SageMakerを使用し、機械学習モデル`XGBoost`を
    - 構築
    - トレーニング
    - デプロイ
    - モニタリング

- XGBoost(eXtreme Gradient Boosting / 勾配ブースティング回帰木)とは
    - 勾配ブースティング決定木(Gradient Boosting Decision Tree)アルゴリズムを実装したオープンソースのライブラリ
    - 勾配ブースティングと呼ばれるアンサンブル学習と、決定木を組み合わせた手法
    - 勾配ブースティングとは
        - 教師あり学習アルゴリズム
        - 回帰や分類などのタスクのための機械学習手法
        - 弱い予測モデル(weak prediction model)のアンサンブルの形で予測モデルを生成
    - アンサンブルとは
        - モデルの汎化性能を向上させるため、個々に学習した複数モデルを融合させる方法
        - 汎化性能とは、モデル学習時に訓練データだけでなく、未知の新たなデータを予測できる性能(能力)
            - 例えば、天気予測モデルで明日の天気を当てられるか
    - XGBoostの機能
        - 回帰、分類(バイナリとマルチクラス)、ランキング問題に使用可能
        - 様々なデータ型、関係、分布を処理可能
        - 様々なファインチューニング可能ハイパーパラメータを処理可能

## チュートリアル開始

### ステップ1: データ準備用にAmazon SageMakerノートブックインスタンスを作成

#### 主な作業

- データのダウンロード/処理に使用するノートブックインスタンスを作成
- Amazon SageMakerからS3へのアクセスに必要なIAMロールを作成

#### 作業手順

- a. Amazon SageMakerコンソールにサインインし
    - 右上のAWSリージョンを選択
        - 今回は`アジアパシフィック(東京)`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/b305c116-d339-229e-b66e-8d4b1259381e.png)

- b. 左側のナビゲーションペインで
    - `ノートブックインスタンス`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/90ca25a2-f73c-0e41-9b3a-729dff69a56b.png)

- c. `ノートブックインスタンスの作成`ページの`ノートブックインスタンス設定`ボックスで
    - 次のフィールドに入力
        - `ノートブックインスタンス名`
            - `SageMaker-Tutorial`と入力
        - `ノートブックインスタンスタイプ`
            - `ml.t2.medium`を選択
        - `Elastic Inference`
            - デフォルトの`なし`のまま

- d. `アクセス許可と暗号化`セクションの`IAMロール`プルダウンメニューで
    - `新しいロールの作成`を選択
    - `IAMロールを作成する`ダイアログボックスで
        - `任意のS3バケット`を選択
        - 右下の`ロールの作成`ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/eea23411-0e8d-cd45-6a5e-28bdcde7a682.png)

- e. 右下の`ノートブックインスタンスを作成`ボタンをクリック
    - `ノートブックインスタンス`セクションで
        - 新しい`SageMaker-Tutorial`ノートブックインスタンスが`保留中`ステータスで表示される
        - ステータス`InService`に変わったら、ノートブック準備完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/253325ae-f106-aa7f-c865-8e4167c77202.png)


### ステップ 2: データの準備

#### 主な作業

- Amazon SageMakerノートブックインスタンスを使用し、機械学習モデルのトレーニングに必要なデータを前処理
- そのデータをAmazon S3にアップロード

#### 作業手順
- a. `Jupyterを開く`を選択

- b. Jupyterで`新規`を選択し、`Nodebook`プルダウンメニューから`conda_python3`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/d70cd2e5-207d-6c0b-3e53-d1131333d36d.png)

- c. Jupyterノートブックの新しいコードセルで
    - 以下のコードをコピー/貼り付ける
        - コードの内容
            - 必要なライブラリをインポート
            - データの準備
            - MLモデルのトレーニングとデプロイに必要な環境変数を定義
    - `実行`を選択
```python
# import libraries
import boto3, re, sys, math, json, os, sagemaker, urllib.request
from sagemaker import get_execution_role
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import Image
from IPython.display import display
from time import gmtime, strftime
from sagemaker.predictor import csv_serializer

# Define IAM role
role = get_execution_role()
prefix = 'sagemaker/DEMO-xgboost-dm'
my_region = boto3.session.Session().region_name # set the region of the instance

# this line automatically looks for the XGBoost image URI and builds an XGBoost container.
xgboost_container = sagemaker.image_uris.retrieve("xgboost", my_region, "latest")

print("Success - the MySageMakerInstance is in the " + my_region + " region. You will use the " + xgboost_container + " container for your SageMaker endpoint.")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/8c3d5cbd-39fa-b7ff-7933-39677907da2a.png)

- d. S3バケットを作成し、お客様データを格納
    - 以下のコードをコピーし、次のコードセルに貼り付ける
    - `bucket_name`を一意のS3バケット名に置き換える
    - `実行`を選択
```
bucket_name = 'mytest-s3-bucket-name'
s3 = boto3.resource('s3')
try:
    if  my_region == 'us-east-1':
      s3.create_bucket(Bucket=bucket_name)
    else: 
      s3.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={ 'LocationConstraint': my_region })
    print('S3 bucket created successfully')
except Exception as e:
    print('S3 error: ',e)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/153c54f0-07e2-ff77-806b-6bc9a68cf6fc.png)

- e. SageMakerインスタンスにデータをダウンロードし、データフレームにロード
    - 以下のコードをコピーし、次のコードセルに貼り付ける
    - `実行`を選択
```
try:
  urllib.request.urlretrieve ("https://d1.awsstatic.com/tmt/build-train-deploy-machine-learning-model-sagemaker/bank_clean.27f01fbbdf43271788427f3682996ae29ceca05d.csv", "bank_clean.csv")
  print('Success: downloaded bank_clean.csv.')
except Exception as e:
  print('Data load error: ',e)

try:
  model_data = pd.read_csv('./bank_clean.csv',index_col=0)
  print('Success: Data loaded into dataframe.')
except Exception as e:
    print('Data load error: ',e)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/f918f52a-4151-ed20-3271-c0081cef94f5.png)

- f. データをシャッフルし、トレーニングデータとテストデータに分割
    - 以下のコードをコピーし、次のコードセルに貼り付ける
        - コードの内容
            - トレーニングデータとしてデータの70%(顧客)を使用
                - 勾配ベースの最適化を使用し、モデルパラメータを繰り返し改良
                - 勾配ベースの最適化とは
                    - モデル損失関数の勾配を使用し
                    - モデルエラーを最小化するモデルパラメータ値を見つける方法
            - テストデータとして残りの30%(顧客)を使用
                - モデルのパフォーマンス評価
                - モデルの汎化性能を測定
    - `実行`を選択
```
train_data, test_data = np.split(model_data.sample(frac=1, random_state=1729), [int(0.7 * len(model_data))])
print(train_data.shape, test_data.shape)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/ddefbaf5-ebdb-ba4f-d21d-2317e72c7470.png)

### ステップ3: MLモデルをトレーニング

#### 主な作業

‐ トレーニングデータセットを使用し、機械学習モデルをトレーニング

#### 作業手順

- a. Jupyterノートブックの新しいコードセルで
    - 以下のコードをコピーし、貼り付ける
        - コードの内容
            - トレーニングデータのヘッダーと最初の列を再フォーマットし、S3バケットからデータをロード
            - Amazon SageMakerの事前構築済みXGBoostアルゴリズムの使用に必要
    - `実行`を選択
```
pd.concat([train_data['y_yes'], train_data.drop(['y_no', 'y_yes'], axis=1)], axis=1).to_csv('train.csv', index=False, header=False)
boto3.Session().resource('s3').Bucket(bucket_name).Object(os.path.join(prefix, 'train/train.csv')).upload_file('train.csv')
s3_input_train = sagemaker.inputs.TrainingInput(s3_data='s3://{}/{}/train'.format(bucket_name, prefix), content_type='csv')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/62008833-a729-6168-cbfa-709ff625d4c8.png)

- b. Jupyterノートブックの次のコードセルで
    - 以下のコードをコピーし、貼り付ける
        - コードの内容
            - Amazon SageMakerセッションを設定
            - XGBoostモデル(予測ツール)のインスタンスを作成
            - モデルのハイパーパラメーターを定義
    - `実行`を選択
```
sess = sagemaker.Session()
xgb = sagemaker.estimator.Estimator(xgboost_container,role, instance_count=1, instance_type='ml.m4.xlarge',output_path='s3://{}/{}/output'.format(bucket_name, prefix),sagemaker_session=sess)
xgb.set_hyperparameters(max_depth=5,eta=0.2,gamma=4,min_child_weight=6,subsample=0.8,silent=0,objective='binary:logistic',num_round=100)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/e794fd10-996e-bf41-4cb4-9d5684bfe1c5.png)

- c. トレーニングジョブを開始
    - 以下のコードをコピーし、次のコードセルに貼り付ける
        - コードの内容
            - `ml.m4.xlarge`インスタンスで勾配最適化を使用し、モデルをトレーニング
    - `実行`を選択
```
xgb.fit({'train': s3_input_train})
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/de9fee44-6744-546c-5dc0-3eb08f7bafe2.png)

- 数分待つと、Jupyterノートブックにトレーニングログが生成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/72d1f94c-478f-50f1-a269-4c7ff8c27a25.png)

```
2022-05-22 05:53:36 Starting - Starting the training job...
2022-05-22 05:54:03 Starting - Preparing the instances for trainingProfilerReport-1653198815: InProgress
.........
2022-05-22 05:55:30 Downloading - Downloading input data...
2022-05-22 05:56:06 Training - Downloading the training image......
2022-05-22 05:57:02 Training - Training image download completed. Training in progress..Arguments: train
[2022-05-22:05:57:05:INFO] Running standalone xgboost training.
[2022-05-22:05:57:05:INFO] Path /opt/ml/input/data/validation does not exist!
[2022-05-22:05:57:05:INFO] File size need to be processed in the node: 3.38mb. Available memory size in the node: 8420.92mb
[2022-05-22:05:57:05:INFO] Determined delimiter of CSV input is ','
[05:57:05] S3DistributionType set as FullyReplicated
[05:57:06] 28831x59 matrix with 1701029 entries loaded from /opt/ml/input/data/train?format=csv&label_column=0&delimiter=,
[05:57:06] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 30 extra nodes, 14 pruned nodes, max_depth=5
[0]#011train-error:0.100482
[05:57:06] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 30 extra nodes, 14 pruned nodes, max_depth=5
[1]#011train-error:0.099858
... ... ...
[05:57:10] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 0 extra nodes, 38 pruned nodes, max_depth=0
[98]#011train-error:0.093927
[05:57:10] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 0 extra nodes, 32 pruned nodes, max_depth=0
[99]#011train-error:0.093892

2022-05-22 05:57:25 Uploading - Uploading generated training model
2022-05-22 05:57:25 Completed - Training job completed
Training seconds: 115
Billable seconds: 115
```

### ステップ4: モデルのデプロイ

#### 主な作業

- Amazon SageMakerのエンドポイントに対し、訓練されたモデルをデプロイ
- リフォーマット済みCSVデータをロード
- モデルを実行し、予測を作成

#### 作業手順

- a. Jupyterノートブックの新しいコードセルで
    - 以下のコードをコピーし、貼り付ける
        - コードの内容
            - モデルをサーバーにデプロイ
            - アクセス可能なSageMakerエンドポイントを作成
    - `実行`を選択
```
xgb_predictor = xgb.deploy(initial_instance_count=1,instance_type='ml.m4.xlarge')
```

- 数分待つと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/8fbb79e9-7294-029d-433a-07edbbb0395a.png)

- b. テストデータの顧客が、銀行商品に申し込みを行うか予測
    - 以下のコードを次のコードセルにコピー
    - `実行`を選択
```
from sagemaker.serializers import CSVSerializer

test_data_array = test_data.drop(['y_no', 'y_yes'], axis=1).values #load the data into an array
xgb_predictor.serializer = CSVSerializer() # set the serializer type
predictions = xgb_predictor.predict(test_data_array).decode('utf-8') # predict!
predictions_array = np.fromstring(predictions[1:], sep=',') # and turn the prediction into an array
print(predictions_array.shape)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/e2643bf4-4d97-e0e2-7424-aa02e7a24b3f.png)

### ステップ5: モデルの性能評価

#### 主な作業

- 機械学習モデルの性能と正確性を評価

#### 作業手順

- Jupyterノートブックの新しいコードセルで
    - 以下のコードをコピーし、貼り付ける
        - コードの内容
            - 混同行列で実値と予測値を比較
                - 混同行列とは、アルゴリズムの性能を可視化するための特有の表配置
                    - 誤差行列(error matrix)とも呼ばれる
    - `実行`を選択
```
cm = pd.crosstab(index=test_data['y_yes'], columns=np.round(predictions_array), rownames=['Observed'], colnames=['Predicted'])
tn = cm.iloc[0,0]; fn = cm.iloc[1,0]; tp = cm.iloc[1,1]; fp = cm.iloc[0,1]; p = (tp+tn)/(tp+tn+fp+fn)*100
print("\n{0:<20}{1:<4.1f}%\n".format("Overall Classification Rate: ", p))
print("{0:<15}{1:<15}{2:>8}".format("Predicted", "No Purchase", "Purchase"))
print("Observed")
print("{0:<15}{1:<2.0f}% ({2:<}){3:>6.0f}% ({4:<})".format("No Purchase", tn/(tn+fn)*100,tn, fp/(tp+fp)*100, fp))
print("{0:<16}{1:<1.0f}% ({2:<}){3:>7.0f}% ({4:<}) \n".format("Purchase", fn/(tn+fn)*100,fn, tp/(tp+fp)*100, tp))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/033267dc-0ff8-c800-765f-b00b52093956.png)

- 予測結果の分析
    - テストデータにおける顧客の90%に対し、預金証書申込みの予測精度
        - 申込者に対する予測精度: 65%(278/429)
        - 非申込者に対する予測精度: 90%(10,785/11,928)

### ステップ6: クリーンアップ

#### 主な作業

- チュートリアルで使用したリソースを終了
※ 重要: リソースを終了しないと料金が発生します

#### 作業手順

- a. エンドポイントを削除
    - Jupyterノートブックで、以下のコードをコピーし、貼り付ける
    - `実行`を選択
```
xgb_predictor.delete_endpoint(delete_endpoint_config=True)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/154fdd7b-a994-1e39-646a-529d955f5f76.png)

- b. トレーニングアーティファクトとS3バケットを削除
    - Jupyterノートブックで、次のコードをコピーし、貼り付ける
    - `実行`を選択
```
bucket_to_delete = boto3.resource('s3').Bucket(bucket_name)
bucket_to_delete.objects.all().delete()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/692654bb-8b83-036f-099c-6aa517796d37.png)

- c. SageMaker Notebookを削除
    - SageMaker Notebookを停止
        - SageMakerコンソールを開く
        - 左メニューの`ノートブック`で、`ノートブックインスタンス`を選択
        - チュートリアル用に作成したノートブックインスタンスを選択
        - `アクション`から`停止`を選択
        - ノートブックインスタンスが停止するまで数分待つ
            - `ステータス`が`Stopped`に変わったら、次のステップに進む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/e747d152-7a75-f348-a9ef-5ebb23c695bc.png)
    - SageMaker Notebookを削除
        - `アクション`を選択
        - `削除`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/b7417aaf-04d7-e2fd-566e-680a6ece4824.png)

### チュートリアルのまとめ

- Amazon SageMakerを使用し、機械学習モデルの下記操作を勉強
    - 準備
    - トレーニング
    - デプロイ
    - 評価
- Amazon SageMakerの特徴
    - トレーニングデータへの接続が速い
    - アプリケーションに最適なアルゴリズムと枠組みを選択
        - MLモデルの構築が容易
    - ペタバイト規模のモデル訓練に必要なインフラストラクチャを管理

## おわりに

Amazon SageMakerのチュートリアルを実施しました。
感想は`使い勝手がよい`でした。
再度、各フェーズの理論根拠を、ソースコードレベルで、
しっかり復習する必要ありそうです。
次回も、Amazon SageMaker続きます。お楽しみに。

##### [次回] [AWS公式資料で挑むMLS認定(12)-Amazon SageMaker Studio](https://qiita.com/mingchun_zhao/items/03233a731280ea2cdfcb)