[初心者向け] はじめてのSageMaker みんな大好きアイリスデータを使って組み込みアルゴリズムで分類してみる
はじめに
おはようございます、もきゅりんです。
最近は個人的な取り組みの一環として、機械学習の学習に取り組み始めました。
さて、AWSで機械学習に取りかかるならば、Amazon SageMaker。
まずは、組み込みアルゴリズムのLinearLearner。
そんなオレは、ML beginner。
(LinearLearnerが何だ?という話は、ドキュメントを確認して欲しいのですが、ターゲットの分類や予測したい数値を推定するために使用される、教師あり学習アルゴリズムです。)
初めてのデータセットは、みんな大好きな Iris でやってみます。
作業の流れは、完全に下記の通りで進めます。
なお、自分は専門的なデータサイエンティストでも何でもないので、無駄、非効率な作業を行っているかもしれない点、ご了承下さい。
前提
- IAM権限を設定・更新できること
やること
3つの品種のIris(お花です)を、個体が持つ特徴(花びらの長さとか幅とか)だけで分類しようぜ!
が趣旨です。
- S3バケットの作成
- SageMakerノートブックインスタンスの作成
- Jupyterノートブックの作成
- データのロード、データを探索、処理、S3アップロード
- モデルでの学習
- モデルのデプロイ
- モデルの検証
- 後片付け
1. S3バケットの作成
S3バケットはコンソールでも何でもデフォルト設定で作成すれば問題ないです。
このバケットは、元のデータや加工したデータを格納します。
aws s3 mb s3://YOUR_BUCKT_NAME
2. SageMakerノートブックインスタンスの作成
さて、ここからドキドキの初めての体験です。
コンソールからSageMakerにいきます。
先ほど作成したS3バケットへのIAMロールを作成します。
そしたら作成します。
3. Jupyterノートブックの作成
ステータスが Inservice
になったことを確認したら、ノートブックを開きます。
4. データのロード、データを探索、処理、S3アップロード
データのロード
Iris
なのでsklearnのデータセットからロードしちゃいます。
import numpy as np import os from sklearn import datasets iris = datasets.load_iris()
とくに今回はデータ探索を行うことはありません。
データはサンプルサイズは150,特徴量が4つです。
iris['data'].shape
データの分割
訓練データ、検証データ、テストデータに分割していきます。
地道にデータを分けていきます。
まずはテストデータとして20%を取り分けます。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(iris['data'],iris['target'],test_size=0.2, random_state=42)
AWSでは、第1列目に教師データ(今回はラベル)がある必要があるようなので、データを加工します。
test_set = np.insert(X_test, 0, y_test, axis=1)
今度は検証データを分割します。
from sklearn.model_selection import train_test_split X_train, X_validation, y_train, y_validation = train_test_split(X_train,y_train,random_state=42)
テストデータ同様、教師データを最初の列に挿入します。
train_set = np.insert(X_train, 0, y_train, axis=1) valid_set = np.insert(X_validation, 0, y_validation, axis=1)
それぞれのデータのサイズを確認します。
test_set.shape
valid_set.shape
train_set.shape
教師データが挿入されたので、 column
は5つになっています。
データのアップロード
それぞれのデータをS3バケットにアップロードします。
%%time import os import boto3 import re import copy import time import io import struct from time import gmtime, strftime from sagemaker import get_execution_role role = get_execution_role() region = boto3.Session().region_name bucket='YOUR_BUCKET_NAME' # Replace with your s3 bucket name prefix = 'sagemaker/test' # Used as part of the path in the bucket where you store data bucket_path = 'https://s3-{}.amazonaws.com/{}'.format(region,bucket) # The URL to access the bucket def convert_data(): data_partitions = [('train', train_set), ('validation', valid_set), ('test', test_set)] for data_partition_name, data_partition in data_partitions: print('{}: {} {}'.format(data_partition_name, data_partition[0].shape, data_partition[1].shape)) labels = [t.tolist() for t in data_partition[:,0]] features = [t.tolist() for t in data_partition[:,1:5]] if data_partition_name != 'test': examples = np.insert(features, 0, labels, axis=1) else: examples = features np.savetxt('data.csv', examples, delimiter=',') key = "{}/{}/examples".format(prefix,data_partition_name) url = 's3://{}/{}'.format(bucket, key) boto3.Session().resource('s3').Bucket(bucket).Object(key).upload_file('data.csv') print('Done writing to {}'.format(url)) convert_data()
S3バケットを見に行くとちゃんとありました。
5. モデルでの学習
例では XGB
ですが、Linear-Learner
に変更します。
import sagemaker from sagemaker.amazon.amazon_estimator import get_image_uri container = get_image_uri(boto3.Session().region_name, 'linear-learner')
前ステップ4でアップロードしたS3から訓練データと検証データをダウンロードし、トレーニングの出力を保存する場所を設定します。
train_data = 's3://{}/{}/{}'.format(bucket, prefix, 'train') validation_data = 's3://{}/{}/{}'.format(bucket, prefix, 'validation') s3_output_location = 's3://{}/{}/{}'.format(bucket, prefix, 'linear-learner_model_sdk') print(train_data)
モデルのハイパーパラメータを設定します。
特徴量は4、分類する種類は3なので、それぞれ設定します。
linear_model = sagemaker.estimator.Estimator(container, role, train_instance_count=1, train_instance_type='ml.c4.xlarge', output_path=s3_output_location, sagemaker_session=sagemaker.Session()) linear_model.set_hyperparameters(feature_dim=4,num_classes=3, mini_batch_size=32, predictor_type='multiclass_classifier')
訓練(検証)を行うためのチャネルという概念があり、ここでは train
と validation
の両方のチャネルを作ります。
train
とか片方だけのチャネルでも可能のようです。
train_channel = sagemaker.session.s3_input(train_data, content_type='text/csv') valid_channel = sagemaker.session.s3_input(validation_data, content_type='text/csv') data_channels = {'train': train_channel, 'validation': valid_channel}
訓練データと検証データを使って訓練を開始します。
linear_model.fit(inputs = data_channels, logs=True)
完了すると下記のようなメッセージが表示されます。
2020-XX-XX XX:XX:XX Uploading - Uploading generated training model 2020-XX-XX XX:XX:XX Completed - Training job completed Training seconds: 38 Billable seconds: 38
トレーニングのログ(CloudWatchLogs)をダッシュボードから移動します。
とりあえず accuracy
とかパッと分かりやすそうな値が良さそうなのが分かりますね。
6. モデルのデプロイ
訓練されたモデルをエンドポイントにデプロイすることもできますが、特にエンドポイントは必要ないのでバッチ変換します。
ステップ4で、S3バケットにアップロードしているコードを確認頂ければお分かりだと思いますが、テストデータは特徴量のみのデータとなっています。
ここでは、特徴量のみを与えられているテストデータを元に、分類してみるぞ!という作業です。
ちなみに、機械学習で「バッチ」とは大雑把に言うと、全部一度にってことです。
# The location of the test dataset batch_input = 's3://{}/{}/test/examples'.format(bucket, prefix) # The location to store the results of the batch transform job batch_output = 's3://{}/{}/batch-inference'.format(bucket, prefix) transformer = linear_model.transformer(instance_count=1, instance_type='ml.c4.xlarge', output_path=batch_output) transformer.transform(data=batch_input, data_type='S3Prefix', content_type='text/csv', split_type='Line') transformer.wait()
7. モデルの検証
モデルから予測された予測を答え合わせします。
テストデータから予測したファイルをダウンロードします。
s3.Bucket(bucket).download_file(prefix + '/batch-inference/examples.out', 'batch_results')
ちょっとファイルを整形します。
(何かうまいやり方がありそうだけど...)
with open('batch_results', "r") as f: s = f.read() s = s.replace("{\"predicted_label\":", "") with open('batch_results_fixed', "w") as f: f.write(s) arr = [] f=open('batch_results_fixed','r') for line in f: l = line.split(',')[0] arr.append(float(l)) f.close
結果です。
results = np.array(arr) compare = results == test_set[:,0] print(np.count_nonzero(compare == True))
あれ、、、全部正解しちゃいましたよ。
前に自分のローカルで試したときは、何個か不正解が出た気がします。
LinearLearner、優秀ですね。
8. 後片付け
不用ならインスタンスは削除しましょう。
S3バケットも忘れずサヨナラしましょう。
aws s3 rm s3://YOUR_BUCKT_NAME
以上です。
SageMakerのお作法にちょっと面食らったりしましたが、慣れてくれば色々とスムーズ進められそうです。
とりあえず距離は縮まりました。
どなたかのお役に立てば幸いです。