{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ML Enablement Workshop: サービスの解約率改善シナリオ クラウド活用編\n", "\n", "## コンテンツ\n", "\n", "1. 背景\n", "1. 環境構築\n", "1. 学習をスケールする\n", "1. モデルをホスティングする\n", " 1. 性能評価\n", " 1. エンドポイントの削除\n", "1. Notebookを移行する\n", "\n", "---\n", "\n", "## 1.背景\n", "\n", "サービスの解約率を改善するために、 Studio Lab では機能的・コンピューティングリソース的に不十分な状況に直面することがあるかもしれません。例えば、重要なデータは Studio Lab に持ち出せないかもしれませんし、モデルを学習する、本番同等のトランザクションで検証するのに Studio Lab では力不足かもしれません。本Notebookでは、 Studio Lab では不十分な状況に直面した時に Amazon SageMaker を使用し機械学習の価値検証を継続する方法を解説します。 Studio Lab には AWS の機能を呼び出す AWS SDK がインストール済みで、 SageMaker への Notebook の移行を行う方法も整備されています。\n", "\n", "![Studio Lab to SageMaker](images/sagemaker_001.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## 2.環境構築\n", "\n", "### 2.1 Studio Lab の環境構築\n", "\n", "本 Notebook を動かすための環境構築手順は本体のシナリオと同じため、先に [customer_churn.ipynb](./customer_churn.ipynb) を参照し環境構築を行ってください。\n", "Jupyter Notebookの右上にある虫の隣のボタンをクリックしカーネルを切り替えます。\n", "\n", "![environment_setup_002.png](./images/002.png)\n", "\n", "### 2-2. AWS へ接続するための環境構築\n", "今回のサンプルでは、Studio Lab で動かしている Notebook 上ではなく AWS 環境上でモデルを学習およびデプロイして使い方を確かめてみます。そのためには、Notebook から AWS 環境にアクセスする必要があります。その認証情報をこのステップでは設定します。\n", "\n", "IAM ユーザーを作成し、そこから得られるアクセスキーとシークレットキーを登録します\n", "AWSへアクセスするためのユーザー (IAM ユーザー) を作成します。IAM ユーザーの作成方法は以下のページを参考にします。名前は任意ですが、以降では`sagemaker-studio-lab-access`として扱います。\n", "\n", "- https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_users_create.html#id_users_create_console\n", "\n", "まずは、AWS のコンソール画面を開いて左上の検索窓で「IAM」と検索します。トップに出てくる IAM をクリックして IAM のサービスページを開きます。\n", "\n", "![](./images/aws_settings/001_IAM_search.png)\n", "\n", "左側メニューから、「ユーザー」をクリックして IAM ユーザーの設定画面に遷移します。\n", "\n", "![](./images/aws_settings/002_IAM_user.png)\n", "\n", "次に、「ユーザーを追加」をクリックしてユーザーの作成を開始します。\n", "\n", "![](./images/aws_settings/003_user_create.png)\n", "\n", "ユーザー名に「sagemaker-studio-lab-access (画像では whisper-sample-user)」(他の名称でも大丈夫です)、「アクセスキー - プログラムによるアクセス」にチェックをつけます。\n", "\n", "![](./images/aws_settings/004_user_info.png)\n", "\n", "「次のステップ」をクリックします。 \n", "その後「既存のポリシーを直接アタッチ」を選択し、ポリシーの検索で「SageMakerFullAccess」と入力します。そうすると「AWSSageMakerFullAccess」のポリシー候補が現れるのでこれを選択します。\n", "\n", "![](./images/aws_settings/005_user_policy.png)\n", "\n", "次に、検索窓に「PowerUserAccess」と検索し候補に出てきた「PowerUserAccess」を選択します。 \n", "\n", "![](./images/aws_settings/006_user_poweruseraccess.png)\n", "\n", "「次のステップ」をクリックするとタグの設定画面が出てきますが、ここは特に入力せずにスキップします。 \n", "\n", "これまでに設定した項目の確認ページが出てくるので問題なければ「ユーザーの作成」をクリックします。\n", "\n", "![](./images/aws_settings/007_user_confirmation.png) \n", "\n", "無事ユーザーが作成されるとユーザーキーとシークレットキーが表示されるのでメモに残しておきます。これらの情報を使って Studio Lab 経由で AWS 環境にアクセスを行います。 \n", "**ここで取得されるクレデンシャル情報の扱いには十分注意してください**。\n", "\n", "![](./images/aws_settings/008_user_credentials.png)\n", "\n", "\n", "次に、 Studio Lab の画面に戻って先ほど取得したアクセスキーなどの情報を登録していきます。 \n", "\n", "画面上部のメニューから 「File -> New -> Terminal」 と選択してターミナルの起動をします。 \n", "![](./images/aws_settings/009_start_terminal.png)\n", "\n", "開かれたターミナルで `aws configure` を実行します。\n", "そこでアクセスキーとシークレットキーを聞かれるので先ほどメモした値を入力します。 \n", "\n", "![](./images/aws_settings//010_aws_configure.png)\n", "\n", "以上で、認証情報の設定は完了です。ではこれから実際にモデルを動かしていきましょう。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2-3. SageMaker Training Instance が利用する IAM ロールを作成する\n", "\n", "学習を実行するインスタンスの権限となる、 IAM ロールを作成します。 IAM ロールの作成方法は以下のページを参考にします。名前は任意ですが、以降では`SageMakerStudioLabExecuteRole`として扱います。 \n", "\n", "- https://docs.aws.amazon.com/ja_jp/glue/latest/dg/create-an-iam-role-sagemaker-notebook.html\n", "\n", "AWS のコンソール画面に戻ります。 \n", "先ほどと同様の手順で IAM のサービス画面を開き、「ロール」を左側のメニューから選択します。 \n", "IAM ロールの画面が開かれたら「ロールの作成」ボタンをクリックします。 \n", "\n", "![](./images/aws_settings//011_role_create.png) \n", "\n", "ロールの作成画面が表示されたら信頼されるエンティティタプとして「AWS のサービス」を選択し、ユースケースのところは下の検索欄から「SageMaker」などと検索して SageMaker を選択します。\n", "\n", "![](./images/aws_settings//012_role_entity.png)\n", "\n", "「次へ」をクリックし、「AmazonSageMakerFullAccess」のポリシーがアタッチされていることを確認します。 \n", "\n", "![](./images/aws_settings//013_role_policy.png)\n", "\n", "「次へ」をクリックし、Role 名を設定します。「StudioLabExecuteRole(画像では StudioLabWhisperExecutionRole)」と入力し、他の項目はいじらずに「ロールを作成」をクリックします。 \n", "こちらの Role 名も自由に設定して問題ありません。 \n", "\n", "![](./images/aws_settings//014_role_name.png)\n", "\n", "作成した IAM ロールのリソースネームである ARN を取得します。 \n", "IAM ロールの画面から、検索欄で「StudioLabExecuteRole(画像では StudioLabWhisperExecutionRole)」などと入力して先ほど作成した IAM ロールを探して選択します。 \n", "\n", "![](./images/aws_settings//015_role_search.png) \n", "\n", "IAM ロールの詳細情報が表示されるので、ARN の隣にあるコピーボタンをクリックして ARN をコピーします。\n", "![](./images/aws_settings//016_role_arn_copy.png) \n", "\n", "コピペした値を置き換えて role の値を設定します。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "role = \"arn:aws:iam::000000000000:role/SageMakerStudioLabExecuteRole\" # コピペした値で置き換える" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "では、はじめていきましょう、はじめに利用するライブラリを読み込んでおきます。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# Define IAM role\n", "from pathlib import Path\n", "import boto3\n", "import sagemaker\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "\n", "data_root = Path(\"../../data/\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 3.学習をスケールする\n", "\n", "Studio Lab の GPU では性能、稼働時間が足りない場合 AWS で学習を行うことができます。学習を始める前に、学習データをAmazon S3にアップロードしSageMakerから利用できるようにします。\n", "\n", "※事前に `customer_churn.ipynb` のシナリオを実行しデータを作成しておく必要があります。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "sagemaker_session = sagemaker.Session()\n", "input_train = sagemaker_session.upload_data(path=str(data_root.joinpath('interim/churn_train.csv')), key_prefix='sagemaker/DEMO-xgboost-churn')\n", "input_validation = sagemaker_session.upload_data(path=str(data_root.joinpath('interim/churn_validation.csv')), key_prefix='sagemaker/DEMO-xgboost-churn')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`input_train` と `input_validation` にはアップロードしたファイルのS3パスが保存されています。これらは csv ファイルで、学習させるには以下のようなデータである必要がありますが、先の前処理の段階でこのようなデータ形式に変換しているため、追加の処理は必要ありません。\n", "\n", "- 1列目が予測対象のデータ\n", "- ヘッダ行はなし\n", "\n", "学習に使ったモデルは XGBoost でしたので、 Amazon SageMaker が用意している XGBoost のコンテナを利用して学習します。このコンテナは、ファイルをデフォルトで libsvm 形式と認識するため、`TrainingInput`という関数を利用して、`content_type='text/csv'`を明示的に指定します。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# from sagemaker.session import s3_input\n", "from sagemaker.inputs import TrainingInput\n", "\n", "content_type='text/csv'\n", "s3_input_train = TrainingInput(input_train, content_type=content_type)\n", "s3_input_validation = TrainingInput(input_validation, content_type=content_type)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Amazon SageMaker は、マネージドで、分散学習が設定済みで、リアルタイム推論のためのホスティングも可能な XGBoost コンテナを用意しています。 リージョンごと、アルゴリズムごとに用意されているコンテナの URI は [Docker レジストリパスとサンプルコード](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/sagemaker-algo-docker-registry-paths.html)で確認できます。XGBoost のコンテナの場所を取得しましょう。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'354813040037.dkr.ecr.ap-northeast-1.amazonaws.com/sagemaker-xgboost:1.2-1'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "container = sagemaker.image_uris.retrieve(\"xgboost\", boto3.Session().region_name, \"1.2-1\")\n", "container" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "それでは学習を始めましょう。学習のためにハイパーパラメータを指定したり、学習のインスタンスの数やタイプを指定することができます。XGBoost における主要なハイパーパラメータは以下のとおりです。\n", "\n", "- `max_depth` アルゴリズムが構築する木の深さをコントロールします。深い木はより学習データに適合しますが、計算も多く必要で、overfiting になる可能性があります。たくさんの浅い木を利用するか、少数の深い木を利用するか、モデルの性能という面ではトレードオフがあります。\n", "- `subsample` 学習データのサンプリングをコントロールします。これは overfitting のリスクを減らしますが、小さすぎるとモデルのデータが不足してしまいます。\n", "- `num_round` ブースティングを行う回数をコントロールします。以前のイテレーションで学習したときの残差を、以降のモデルにどこまで利用するかどうかを決定します。多くの回数を指定すると学習データに適合しますが、計算も多く必要で、overfiting になる可能性があります。\n", "- `eta` 各ブースティングの影響の大きさを表します。大きい値は保守的なブースティングを行います。\n", "- `gamma` ツリーの成長の度合いをコントロールします。大きい値はより保守的なモデルを生成します。\n", "\n", "XGBoostのhyperparameterに関する詳細は [GitHub](https://github.com/dmlc/xgboost/blob/master/doc/parameter.rst) もチェックしてください。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2022-09-15 12:22:20 Starting - Starting the training job...ProfilerReport-1663244539: InProgress\n", "...\n", "2022-09-15 12:23:13 Starting - Preparing the instances for training.........\n", "2022-09-15 12:24:45 Downloading - Downloading input data...\n", "2022-09-15 12:25:12 Training - Downloading the training image.........\n", "2022-09-15 12:26:48 Uploading - Uploading generated training model[2022-09-15 12:26:36.718 ip-10-0-172-176.ap-northeast-1.compute.internal:1 INFO utils.py:27] RULE_JOB_STOP_SIGNAL_FILENAME: None\n", "INFO:sagemaker-containers:Imported framework sagemaker_xgboost_container.training\n", "INFO:sagemaker-containers:Failed to parse hyperparameter objective value binary:logistic to Json.\n", "Returning the value itself\n", "INFO:sagemaker-containers:No GPUs detected (normal if no gpus installed)\n", "INFO:sagemaker_xgboost_container.training:Running XGBoost Sagemaker in algorithm mode\n", "INFO:root:Determined delimiter of CSV input is ','\n", "INFO:root:Determined delimiter of CSV input is ','\n", "INFO:root:Determined delimiter of CSV input is ','\n", "INFO:root:Determined delimiter of CSV input is ','\n", "INFO:root:Single node training.\n", "INFO:root:Train matrix has 3500 rows and 99 columns\n", "INFO:root:Validation matrix has 1000 rows\n", "[0]#011train-error:0.11743#011validation-error:0.12700\n", "[1]#011train-error:0.10429#011validation-error:0.10800\n", "[2]#011train-error:0.09714#011validation-error:0.10700\n", "[3]#011train-error:0.08600#011validation-error:0.10300\n", "[4]#011train-error:0.08457#011validation-error:0.09700\n", "[5]#011train-error:0.08143#011validation-error:0.09200\n", "[6]#011train-error:0.07714#011validation-error:0.08700\n", "[7]#011train-error:0.07343#011validation-error:0.08300\n", "[8]#011train-error:0.07029#011validation-error:0.07700\n", "[9]#011train-error:0.06914#011validation-error:0.07800\n", "[10]#011train-error:0.06657#011validation-error:0.07900\n", "[11]#011train-error:0.06543#011validation-error:0.07300\n", "[12]#011train-error:0.06343#011validation-error:0.07500\n", "[13]#011train-error:0.06286#011validation-error:0.07000\n", "[14]#011train-error:0.06286#011validation-error:0.07200\n", "[15]#011train-error:0.06400#011validation-error:0.07100\n", "[16]#011train-error:0.06286#011validation-error:0.07200\n", "[17]#011train-error:0.06200#011validation-error:0.06900\n", "[18]#011train-error:0.06000#011validation-error:0.06900\n", "[19]#011train-error:0.06000#011validation-error:0.06700\n", "[20]#011train-error:0.05971#011validation-error:0.06300\n", "[21]#011train-error:0.05914#011validation-error:0.06600\n", "[22]#011train-error:0.05914#011validation-error:0.06700\n", "[23]#011train-error:0.05857#011validation-error:0.07000\n", "[24]#011train-error:0.05800#011validation-error:0.06900\n", "[25]#011train-error:0.05800#011validation-error:0.06900\n", "[26]#011train-error:0.05629#011validation-error:0.06600\n", "[27]#011train-error:0.05571#011validation-error:0.06500\n", "[28]#011train-error:0.05514#011validation-error:0.06700\n", "[29]#011train-error:0.05486#011validation-error:0.06700\n", "[30]#011train-error:0.05571#011validation-error:0.06700\n", "[31]#011train-error:0.05371#011validation-error:0.06700\n", "[32]#011train-error:0.05143#011validation-error:0.06500\n", "[33]#011train-error:0.05200#011validation-error:0.06400\n", "[34]#011train-error:0.05229#011validation-error:0.06200\n", "[35]#011train-error:0.05114#011validation-error:0.06100\n", "[36]#011train-error:0.05114#011validation-error:0.06100\n", "[37]#011train-error:0.05000#011validation-error:0.05800\n", "[38]#011train-error:0.05000#011validation-error:0.06000\n", "[39]#011train-error:0.04886#011validation-error:0.05900\n", "[40]#011train-error:0.04771#011validation-error:0.05800\n", "[41]#011train-error:0.04657#011validation-error:0.06000\n", "[42]#011train-error:0.04629#011validation-error:0.06000\n", "[43]#011train-error:0.04600#011validation-error:0.06100\n", "[44]#011train-error:0.04429#011validation-error:0.06200\n", "[45]#011train-error:0.04400#011validation-error:0.06100\n", "[46]#011train-error:0.04400#011validation-error:0.06100\n", "[47]#011train-error:0.04200#011validation-error:0.06100\n", "[48]#011train-error:0.04229#011validation-error:0.06000\n", "[49]#011train-error:0.04229#011validation-error:0.06100\n", "[50]#011train-error:0.04114#011validation-error:0.06300\n", "[51]#011train-error:0.04086#011validation-error:0.06300\n", "[52]#011train-error:0.04086#011validation-error:0.06300\n", "[53]#011train-error:0.04200#011validation-error:0.06200\n", "[54]#011train-error:0.04229#011validation-error:0.06200\n", "[55]#011train-error:0.04086#011validation-error:0.06400\n", "[56]#011train-error:0.04086#011validation-error:0.06400\n", "[57]#011train-error:0.04086#011validation-error:0.06400\n", "[58]#011train-error:0.04057#011validation-error:0.06600\n", "[59]#011train-error:0.04086#011validation-error:0.06600\n", "[60]#011train-error:0.04086#011validation-error:0.06600\n", "[61]#011train-error:0.04086#011validation-error:0.06600\n", "[62]#011train-error:0.04057#011validation-error:0.06700\n", "[63]#011train-error:0.04057#011validation-error:0.06900\n", "[64]#011train-error:0.03914#011validation-error:0.06900\n", "[65]#011train-error:0.03886#011validation-error:0.06900\n", "[66]#011train-error:0.03857#011validation-error:0.06800\n", "[67]#011train-error:0.03857#011validation-error:0.06600\n", "[68]#011train-error:0.03857#011validation-error:0.06500\n", "[69]#011train-error:0.03600#011validation-error:0.06500\n", "[70]#011train-error:0.03629#011validation-error:0.06300\n", "[71]#011train-error:0.03629#011validation-error:0.06300\n", "[72]#011train-error:0.03600#011validation-error:0.06300\n", "[73]#011train-error:0.03571#011validation-error:0.06300\n", "[74]#011train-error:0.03571#011validation-error:0.06200\n", "[75]#011train-error:0.03571#011validation-error:0.06200\n", "[76]#011train-error:0.03543#011validation-error:0.06200\n", "[77]#011train-error:0.03686#011validation-error:0.06300\n", "[78]#011train-error:0.03686#011validation-error:0.06400\n", "[79]#011train-error:0.03686#011validation-error:0.06300\n", "[80]#011train-error:0.03714#011validation-error:0.06400\n", "[81]#011train-error:0.03657#011validation-error:0.06500\n", "[82]#011train-error:0.03657#011validation-error:0.06500\n", "[83]#011train-error:0.03629#011validation-error:0.06400\n", "[84]#011train-error:0.03629#011validation-error:0.06400\n", "[85]#011train-error:0.03543#011validation-error:0.06300\n", "[86]#011train-error:0.03543#011validation-error:0.06300\n", "[87]#011train-error:0.03400#011validation-error:0.06300\n", "[88]#011train-error:0.03457#011validation-error:0.06200\n", "[89]#011train-error:0.03429#011validation-error:0.06100\n", "[90]#011train-error:0.03429#011validation-error:0.06200\n", "[91]#011train-error:0.03457#011validation-error:0.06200\n", "[92]#011train-error:0.03429#011validation-error:0.06100\n", "[93]#011train-error:0.03457#011validation-error:0.06400\n", "[94]#011train-error:0.03457#011validation-error:0.06300\n", "[95]#011train-error:0.03457#011validation-error:0.06400\n", "[96]#011train-error:0.03457#011validation-error:0.06300\n", "[97]#011train-error:0.03457#011validation-error:0.06400\n", "[98]#011train-error:0.03486#011validation-error:0.06300\n", "[99]#011train-error:0.03457#011validation-error:0.06300\n", "\n", "2022-09-15 12:27:26 Completed - Training job completed\n", "ProfilerReport-1663244539: NoIssuesFound\n", "Training seconds: 148\n", "Billable seconds: 148\n" ] } ], "source": [ "sess = sagemaker.Session()\n", "\n", "hyperparameters = {\"max_depth\":\"5\",\n", " \"eta\":\"0.2\",\n", " \"gamma\":\"4\",\n", " \"min_child_weight\":\"6\",\n", " \"subsample\":\"0.8\",\n", " \"objective\":\"binary:logistic\",\n", " \"num_round\":\"100\"}\n", "\n", "xgb = sagemaker.estimator.Estimator(container,\n", " role, \n", " hyperparameters=hyperparameters,\n", " instance_count=1, \n", " instance_type='ml.m4.xlarge',\n", " sagemaker_session=sess)\n", "\n", "xgb.fit({'train': s3_input_train, 'validation': s3_input_validation}) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "学習ジョブは AWS Console からも確認できます。\n", "\n", "![sagemaker_007.png](images/sagemaker_007.png)\n", "\n", "学習したモデルは S3 に格納されています。" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'s3://sagemaker-ap-northeast-1-585936743357/sagemaker-xgboost-2022-09-15-12-22-19-369/output/model.tar.gz'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xgb.model_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 4.モデルをホスティングする\n", "\n", "A/B テストを行う場合などは、別々に学習したモデルを API サーバーとして立てる必要があるかもしれません。 SageMaker では、学習が終われば`deploy()`を実行することで、エンドポイントを作成してモデルをデプロイできます。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-------!" ] } ], "source": [ "xgb_predictor = xgb.deploy(initial_instance_count=1, instance_type = 'ml.m4.xlarge')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "デプロイしたモデルは AWS Console から確認できます。\n", "\n", "![sagemaker_008.png](images/sagemaker_008.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4-1.性能評価\n", "\n", "ホスティングしたモデルを使用し、簡単に予測を行うことができます。予測は http の POST の request を送るだけです。\n", "endpoint は `numpy` の `array` を受け取ることができないため、[`CSVSerializer`](https://sagemaker.readthedocs.io/en/stable/api/inference/serializers.html#sagemaker.serializers.CSVSerializer) を設定して `numpy` の `array` を csv 形式に変換して送ります。 逆に、endpoint から取得する時は csv からリストに変換します。" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "xgb_predictor.serializer = sagemaker.serializers.CSVSerializer()\n", "xgb_predictor.deserializer = sagemaker.deserializers.CSVDeserializer()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "先のノートブックで作成済みのテストデータを受け取ると、これをデフォルト500行ずつのデータにわけて、エンドポイントに送信する `predict` という関数を用意します。あとは `predict` を実行して予測結果を受け取ります。 " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def predict(data, rows=500):\n", " split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))\n", " predictions = []\n", " for array in split_array:\n", " predictions.append(np.array(xgb_predictor.predict(array), dtype=np.float32))\n", "\n", " return np.concatenate(predictions, axis=1)\n", "\n", "test_data = pd.read_csv(data_root.joinpath('interim/churn_test.csv'), header=None)\n", "predictions = predict(test_data.values[:, 1:]) # 0列目はラベルのため除外" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "機械学習の性能を比較評価する方法はいくつかありますが、単純に、予測値と実際の値を比較しましょう。今回は、顧客が離反する `1` と離反しない `0` を予測しますので、この混同行列を作成します。" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
predictions0.01.0
actual
023518
111236
\n", "
" ], "text/plain": [ "predictions 0.0 1.0\n", "actual \n", "0 235 18\n", "1 11 236" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.crosstab(index=test_data.iloc[:, 0], columns=np.round(predictions), rownames=['actual'], colnames=['predictions'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_注意点, アルゴリズムにはランダムな要素があるので結果は必ずしも一致しません._\n", "\n", "評価の方法は、本体の Notebook を参照してください。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4-2. エンドポイントの削除\n", "\n", "SageMaker 推論エンドポイントは起動したままだとコストがかかります。不要な場合は削除します。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "xgb_predictor.delete_endpoint()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 5. Notebook を移行する\n", "\n", "社内のデータを扱う場合、 Studio Lab ではセキュリティが気になることがあるかもしれません。 Studio Lab から SageMaker Studio へ移行することで、データやネットワークのセキュリティを自社のセキュリティ基準に合わせて構築することができます。 SageMaker Studio へ移行することで、 Data Wrangler や SageMaker Pipeline を使用して Studio Lab では難しい規模のデータ処理ワークフローを構築することもできます。 SageMaker Studio は、 Studio Lab のエンタープライズ版とイメージ頂くとよいと思います。ほぼ同じインタフェースで、Studio Lab にはない機能の利用、高パフォーマンスのインスタンスでの Notebook の実行ができます。\n", "\n", "![sagemaker_studio_001.png](images/sagemaker_studio_001.png)\n", "\n", "Studio Lab から SageMaker Studio へ移行する方法は [Export Amazon SageMaker Studio Lab environment to Amazon SageMaker Studio](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/studio-lab-use-migrate.html) で紹介されていますが、端的には Git リポジトリを経由して簡単に移行することができます。本節ではその手順を解説します。\n", "\n", "### SageMaker Studio Domain を作成する。\n", "\n", "移行先の SageMaker Studio 環境を作成します。 SageMaker Studio の特徴は、1) JupyterLab のUIを提供するアプリケーションサーバー、2) ノートブックを実行するコンピューティングインスタンス、3) データを保管するボリュームが疎結合になっていることです。1, 2, 3をまとめたアーキテクチャを **SageMaker Studio Domain** と呼んでいます。\n", "\n", "![sagemaker_studio_002](images/sagemaker_studio_002.png)\n", "\n", "今回は SageMaker Studio Domain を作成済みとして、 SageMaker Studio を開いたところからスタートします。\n", "\n", "### SageMaker StudioにNotebookを移行する\n", "\n", "はじめに GitHub からリポジトリを clone します。 Studio Lab と同じように Git の拡張がインストールされているので拡張を使用し簡単に clone することができます。clone を実行するサーバーは JupyterLab のサーバー (JupyterServer App) になります。 clone が終了したら、 `notebooks/scenario_churn/customer_churn.ipynb` を開きます。Notebook を開くためのインスタンス (KernelGateway App) のイメージは Conda があらかじめインストールされている `Data Science` を選択します。 \n", "\n", "![sagemaker_studio_003.png](images/sagemaker_studio_003-1.png)\n", "\n", "![sagemaker_studio_003.png](images/sagemaker_studio_003-2.png)\n", "\n", "JupyterServer App で clone を実行しましたが、 KernelGateway App でも clone したファイルを参照することができます。これは、 EFS でファイルを共有しているためです。\n", "\n", "![sagemaker_studio_004.png](images/sagemaker_studio_004.png)\n", "\n", "現状では環境が作成されていないので、イメージのターミナル (`Image Terminal`) を開いて環境を構築します。\n", "\n", "![sagemaker_studio_005.png](images/sagemaker_studio_005.png)\n", "\n", "`Image Terminal` で実行するコマンドは次の 3 つです。`notebooks/scenario_churn`のフォルダに移動して実行します。Studio Lab では右クリックだけで Conda の環境が作成できましたが、 Studio にはその機能がないため `Image Terminal` でコマンドを使い環境を作成します。\n", "\n", "1. `conda env create -f environment.yml`\n", "2. `conda activate ml-handson-churn`\n", "3. `python -m ipykernel install`\n", "\n", "1 番目のコマンドで環境を作成し、 2 番目のコマンドで作成した `ml-handson-churn` の環境を有効化し 3 番目のコマンドで Notebook から作成した環境が使えるようにしています。\n", "\n", "![sagemaker_studio_006.png](images/sagemaker_studio_006.png)\n", "\n", "全てのコマンドが実行した後、 Notebook を開きます。すると、 Notebook から作成した Kernel が選べるようになっています。\n", "\n", "![sagemaker_studio_007.png](images/sagemaker_studio_007.png)\n", "\n", "後の実行方法は Studio Lab と同じです。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### SageMaker Studio と Studio Lab の違い\n", "\n", "SageMaker Studio で起動しているインスタンスは、一度シャットダウンすると再度環境構築が必要です。これは、次に立ち上がるインスタンスは新しいインスタンスであるためです。 Studio Lab では次に起動したとき環境が維持されていたので、手間がかかる点です。起動しているインスタンスは左側のメニューから確認できます。\n", "\n", "![sagemaker_studio_009.png](images/sagemaker_studio_009.png)\n", "\n", "起動に手間がかかりますが、必要に応じてインスタンスタイプを変えたり複数のインスタンスで Notebook を並行で実行するなど、クラウドならではのスケーラビリティを活かすことができます。\n", "\n", "![sagemaker_studio_010.png](images/sagemaker_studio_010.png)\n", "\n", "GPU インスタンス起動時にエラーが発生する場合、 GPU インスタンスが起動できる上限が 0 になっている可能性があります。 AWS マネジメントコンソールの [Service Quotas](https://console.aws.amazon.com/servicequotas/home/services/sagemaker/quotas) の画面から、制限を選択し必要な分を上限緩和申請してください。利用中のリージョンが選択されていることを確認の上、SageMaker Studio Notebook の GPU インスタンスであれば、例えば `Studio KernelGateway Apps running on ml.g4dn.xlarge instance` を選択してください。\n", "\n", "![sagemaker_studio_011.png](images/sagemaker_studio_011.png)\n", "\n", "Studio Lab での検証に課題があるとき、素早く AWS へ移行できることはプロジェクトの継続性の担保はもちろん、本番運用までのスピード向上にも効果的です。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "interpreter": { "hash": "99f607f2c79ffd9814a22b00079e08a0d69a070c1d0da094d6f294d5d7821e75" }, "kernelspec": { "display_name": "ml-handson-churn:Python", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.6" }, "notice": "Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the \"License\"). You may not use this file except in compliance with the License. A copy of the License is located at http://aws.amazon.com/apache2.0/ or in the \"license\" file accompanying this file. This file is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." }, "nbformat": 4, "nbformat_minor": 4 }