Amazon SageMakerでLinear Learner(線形学習者)をNotebookインスタンス使わずにやってみた
はじめに
好物はインフラとフロントエンドのかじわらゆたかです。 今回はSagMmakerでビルトインアルゴリズムとして実装されている「Linear Learner(線形学習者)」のチュートリアルを実際にやってみようと思ったのですが、 じょんすみすのエントリーが必要十分な内容になっていたので、違うアプローチを試してみたいと思います。
そんな必要十分なじょんすみすのエントリーはこちら
前準備
Notebookを用いない場合の必要なライブラリ等もわかっていないので、ひとまずPython 3.6環境とAWSCLI Boto3 Sagemarker SDKを導入し、それ以降は適宜入れていこうと思います。
ひとまず上記を導入した際のコマンドを記載しておきます。
pyenv の導入に関してはこちら を参考にしています。
$ pyenv install 3.6.4 $ pyenv virtualenv 3.6.4 MLProm $ pyenv local MLProm $ pip install awscli $ pip install boto3 $ pip install sagemaker
Linear Learner(線形学習者)とは
SageMakerで用いることができる組み込み(built-in)アルゴリズムの一つです。
Sagemakerのドキュメントに以下のように記載されています。
線形モデルは、分類や回帰の問題を解決するために使用される、教師あり学習アルゴリズムです。
また、線形モデルを用いた分類については以下のエントリを参考にしてください。
組み込みアルゴリズム:線形学習者の解説と実践
Notebookを用いないとは言え、進め方自体はNotebookで行っている内容に基づいて進めていきます。
このサンプルでは以下の作業を行います。
- パーミッションと環境変数の設定
- データの取り込み
- データの検査
- データ変換
- 訓練用データのアップロード
- 線形モデルのトレーニング
- モデルのデプロイ
- モデルの検証
- デプロイしたエンドポイントの削除
1. パーミッションと環境変数の設定
この機械学習で用いるS3バケットを作成しておきます。
$aws s3api create-bucket --bucket cm-kajiwara-test-ml
NotebookのサンプルではNotebookのRoleを取得していますが、 取得したRoleを用いるのは線形モデルのトレーニングの箇所のため、 この箇所では取得は行いません。
2. データの取り込み 3. データの検査 4. データ変換 5. 訓練用データのアップロード
Notebook環境ではデータの確認を行っていますが、 Pythonのコードで動かすことを目的としているため、その箇所は省略して実行します。
import time import pickle, gzip, numpy, urllib.request, json import io import numpy as np import sagemaker.amazon.common as smac import boto3 import os start = time.time() # Load the dataset urllib.request.urlretrieve("http://deeplearning.net/data/mnist/mnist.pkl.gz", "mnist.pkl.gz") with gzip.open('mnist.pkl.gz', 'rb') as f: train_set, valid_set, test_set = pickle.load(f, encoding='latin1') # Data conversion vectors = np.array([t.tolist() for t in train_set[0]]).astype('float32') labels = np.where(np.array([t.tolist() for t in train_set[1]]) == 0, 1, 0).astype('float32') buf = io.BytesIO() smac.write_numpy_to_dense_tensor(buf, vectors, labels) buf.seek(0) # Upload training data bucket = 'cm-kajiwara-test-ml' ## input your bucket name. prefix = 'sagemaker/DEMO-linear-mnist' key = 'recordio-pb-data' boto3.resource('s3').Bucket(bucket).Object(os.path.join(prefix, 'train', key)).upload_fileobj(buf) s3_train_data = 's3://{}/{}/train/{}'.format(bucket, prefix, key) print('uploaded training data location: {}'.format(s3_train_data)) e_time = time.time() - start print ("e_time:{0}".format(e_time) + "[s]")
6. 線形モデルのトレーニング
ここで1. で取得しなかったRoleの取得が出てきます。
get_execution_role()
ではNotebookインスタンスに付与したRoleのArnが取得できるのですが、
今回はNotebookインスタンスを用いないためboto3
経由でIAMのAPIを呼び、Roleから取得しています。
import boto3 import sagemaker from sagemaker.amazon.amazon_estimator import get_image_uri container = get_image_uri(boto3.Session().region_name, 'linear-learner') sess = sagemaker.Session() iam = boto3.resource('iam') role = iam.Role('AmazonSageMaker-ExecutionRole-20180810T110280') #InputYourSageMaker Role bucket = 'cm-kajiwara-test-ml' ## input your bucket name. prefix = 'sagemaker/DEMO-linear-mnist' key = 'recordio-pb-data' output_location = 's3://{}/{}/output'.format(bucket, prefix) linear = sagemaker.estimator.Estimator(container, role.arn, train_instance_count=1, train_instance_type='ml.c4.xlarge', output_path=output_location, sagemaker_session=sess) linear.set_hyperparameters(feature_dim=784, predictor_type='binary_classifier', mini_batch_size=200) s3_train_data = 's3://{}/{}/train/{}'.format(bucket, prefix, key) linear.fit({'train': s3_train_data})
7. モデルのデプロイ
今回の実装ではトレーニングに用いたlinerオブジェクトからのデプロイではなく、 トレーニングに用いたジョブ名からLinearLearnerオブジェクトを作成し、デプロイを実施します。
Notebookでのlinerオブジェクトは線形モデルのトレーニング時に生成していますが、 今回のスクリプト実行時ではすでにトレーニング済みの状態で実行することになります。 そのため、上記の方法でLinearLearnerオブジェクトを生成しデプロイを実施する必要があったためです。
from sagemaker.amazon.linear_learner import LinearLearner training_job_name = 'linear-learner-2018-08-14-16-35-26-294' attached_estimator = LinearLearner.attach(training_job_name) attached_estimator.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')
8. モデルの検証
boto3からエンドポイントを実行する方法 もありますが、今回はSageMakerのSDKを用いた方法で行います。
生成されたendpointからRealTimePredictor
オブジェクトを生成し、モデルの検証を進めます。
実際に実装したコードとその実行結果を貼り付けておきます。
from sagemaker.predictor import RealTimePredictor from sagemaker.predictor import csv_serializer, json_deserializer import urllib import gzip import pickle endpoint = 'linear-learner-2018-08-14-16-35-26-294' linear_predictor = RealTimePredictor(endpoint,content_type='text/csv',serializer=csv_serializer,deserializer=json_deserializer) # Load the dataset urllib.request.urlretrieve("http://deeplearning.net/data/mnist/mnist.pkl.gz", "mnist.pkl.gz") with gzip.open('mnist.pkl.gz', 'rb') as f: train_set, valid_set, test_set = pickle.load(f, encoding='latin1') result = linear_predictor.predict(train_set[0][30:31]) print(result)
$ python ./08.py {'predictions': [{'score': 5.051175477888137e-08, 'predicted_label': 0.0}]}
下記の実行にはpandasのインストールが必要でした。 pandasのインストールについては下記の通りです。
pip install pandas
from sagemaker.predictor import RealTimePredictor from sagemaker.predictor import csv_serializer, json_deserializer import urllib import gzip import pickle import numpy as np import pandas as pd endpoint = 'linear-learner-2018-08-14-16-35-26-294' linear_predictor = RealTimePredictor(endpoint,content_type='text/csv',serializer=csv_serializer,deserializer=json_deserializer) # Load the dataset urllib.request.urlretrieve("http://deeplearning.net/data/mnist/mnist.pkl.gz", "mnist.pkl.gz") with gzip.open('mnist.pkl.gz', 'rb') as f: train_set, valid_set, test_set = pickle.load(f, encoding='latin1') predictions = [] for array in np.array_split(test_set[0], 100): result = linear_predictor.predict(array) predictions += [r['predicted_label'] for r in result['predictions']] predictions = np.array(predictions) print(pd.crosstab(np.where(test_set[1] == 0, 1, 0), predictions, rownames=['actuals'], colnames=['predictions']))
$ python ./08-2.py predictions 0.0 1.0 actuals 0 8972 48 1 39 941
9. デプロイしたエンドポイントの削除
import sagemaker endpoint = 'linear-learner-2018-08-14-16-35-26-294' sagemaker.Session().delete_endpoint(endpoint)
$ python ./09.py INFO:sagemaker:Deleting endpoint with name: linear-learner-2018-08-14-16-35-26-294
まとめ
Notebookインスタンスを用いずに、チュートリアルを実行してみました。 Notebookインスタンスを用いたほうが当然容易ですが、 一度つくった環境を再度作りたいと言った用途等には使えたりもするのではないでしょうか? なかなレアなケースだとは思いますが、誰かの一助になれば幸いです。
補足: Python のインストールで失敗
Python 3.6.4 のインストールの際に一度失敗しました。
失敗したときのログは下記の通り
$ pyenv install 3.6.4 python-build: use openssl from homebrew python-build: use readline from homebrew Downloading Python-3.6.4.tar.xz... -> https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz Installing Python-3.6.4... python-build: use readline from homebrew BUILD FAILED (OS X 10.13.6 using python-build 20160602) Inspect or clean up the working tree at /var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366 Results logged to /var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366.log Last 10 log lines: File "/private/var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366/Python-3.6.4/Lib/ensurepip/__main__.py", line 5, in <module> sys.exit(ensurepip._main()) File "/private/var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366/Python-3.6.4/Lib/ensurepip/__init__.py", line 204, in _main default_pip=args.default_pip, File "/private/var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366/Python-3.6.4/Lib/ensurepip/__init__.py", line 117, in _bootstrap return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths) File "/private/var/folders/py/sh50z9ms2836hzybz51jz1fr0000gn/T/python-build.20180814232425.11366/Python-3.6.4/Lib/ensurepip/__init__.py", line 27, in _run_pip import pip zipimport.ZipImportError: can't decompress data; zlib not available make: *** [install] Error 1
xcodeのコマンドラインインターフェースが必要とのことなので、以下のコマンドを実行後、再度実行することでインストールが行えました。
xcode-select --install