LoginSignup
4
6

More than 5 years have passed since last update.

AWS SageMaker 組み込み手法を使う際の投げ方

Last updated at Posted at 2018-06-05

意外とフォーマットが共通じゃないのでメモ。
新しいのを試したら追加していく。

Estimator : LinearLiner

ファイル作成

  1. 訓練・バリデーション・テストに分割(以降テストはファイル化不要)
  2. dense_tensor形式に変換
  3. s3に直接書き込み(下記の例ではファイル名はcsvがついているが、csvではない)
from sklearn.model_selection import train_test_split
import sagemaker.amazon.common as smac

def upload_file(data, s3_bucket, prefix, fname, key=None):
    buf = io.BytesIO()
    smac.write_numpy_to_dense_tensor(buf, np.array(data.drop(key, axis=1).as_matrix()).astype('float32'), np.array(data[key].as_matrix()).astype('float32'))
    buf.seek(0)
    s3_bucket.Object(os.path.join(prefix, fname)).upload_fileobj(buf)
    return 's3://{}/{}/{}'.format(s3_bucket.name, prefix, fname)

df_origin = pd.read_csv(fname)
train_data, validation_data, test_data = np.split(df_origin.sample(frac=1, random_state=1729), [int(0.7 * len(df_origin)), int(0.9 * len(df_origin))])

s3_bucket = boto3.resource('s3').Bucket(bucket)
s3_train_data = upload_file(data=train_data, s3_bucket=s3_bucket, prefix=os.path.join(prefix,'train'), fname='train.csv', key='Class')
s3_validation_data = upload_file(data=validation_data, s3_bucket=s3_bucket, prefix=os.path.join(prefix,'validation'), fname='validation.csv', key='Class')

モデル定義~デプロイまで

# SageMakerのセッション
sess = sagemaker.Session()
# sagemakerのestimatorへ必要項目を指定
linear = sagemaker.estimator.Estimator(get_region_path('linear-learner'),
                                       get_execution_role(), 
                                       train_instance_count=1, 
                                       train_instance_type='ml.m4.xlarge',
                                       output_path='s3://{}/{}/output'.format(bucket, prefix),
                                       sagemaker_session=sess)
# ハイパーパラメーターの指定
linear.set_hyperparameters(feature_dim=30,
                           mini_batch_size=100,
                           predictor_type='binary_classifier',
                           epochs=10,
                           num_models=32,
                           loss='absolute_loss')
# モデルフィッティングと出力先の指定(S3)
linear.fit({'train': s3_train_data, 'validation': s3_validation_data})

# デプロイ
from sagemaker.predictor import csv_serializer, json_deserializer
linear_predictor = linear.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')
linear_predictor.content_type = 'text/csv'
linear_predictor.serializer = csv_serializer
linear_predictor.deserializer = json_deserializer

予測

linear-learnerは二次元配列の形で渡せば一度に推定してくれる。
以下は参考にしたページに倣っていくつかに分割して推定してから統合している。

predictions = np.array([])
test_data_arr = test_data.drop(['Class'], axis=1).as_matrix()
split_array = np.array_split(test_data_arr, int(test_data_arr.shape[0] / float(100) + 1))
for array in split_array:
    _predictions = linear_predictor.predict(array)['predictions']
    for predict in _predictions:
        predictions = np.round(np.append(predictions, predict['score']))

結果

y_test = test_data['Class'].as_matrix()
print confusion_matrix(y_test, predictions)
print accuracy_score(y_test, predictions)
print precision_score(y_test, predictions)
print recall_score(y_test, predictions)
print f1_score(y_test, predictions)

Estimator : XG-Boost

ファイル作成

svmlight形式しか(たぶん)受け付けない。
デフォルトはsvmlightだが、content_typeを指定することでcsvも使える。
xgb = sagemaker.estimator.Estimator()で宣言したあと、xgb.content_type = 'text/csv'で変更できる。
実行の際、各ファイルが入っているディレクトリのアドレスしか渡さない(分割されたファイルに対応?)ので、関係ないファイルが入っているとエラーが出る。

from sklearn.datasets import dump_svmlight_file
dump_svmlight_file(X=train_data.drop('Class', axis=1), y=train_data['Class'], f='train.libsvm')
dump_svmlight_file(X=validation_data.drop('Class', axis=1), y=validation_data['Class'], f='validation.libsvm')

s3_bucket.Object(os.path.join(prefix, 'train_libsvm/train.libsvm')).upload_file('train.libsvm')
s3_bucket.Object(os.path.join(prefix, 'validation_libsvm/validation.libsvm')).upload_file('validation.libsvm')

s3_input_train = sagemaker.s3_input(s3_data='s3://{}/{}/train_libsvm/'.format(bucket, prefix), content_type='libsvm')
s3_input_validation = sagemaker.s3_input(s3_data='s3://{}/{}/validation_libsvm/'.format(bucket, prefix), content_type='libsvm')

モデル定義~デプロイまで

ここはほとんど変わらない。投げるパラメータが違う程度。

# SageMakerのセッション
sess = sagemaker.Session()
# sagemakerのestimatorへ必要項目を指定
xgb = sagemaker.estimator.Estimator(get_region_path('xgboost'),
                                       get_execution_role(), 
                                       train_instance_count=1, 
                                       train_instance_type='ml.m4.xlarge',
                                       output_path='s3://{}/{}/output'.format(bucket, 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)
# モデルフィッティングと出力先の指定(S3)
xgb.fit({'train': s3_input_train, 'validation': s3_input_validation})

# デプロイ
xgb_predictor = xgb.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')
xgb_predictor.content_type = 'text/csv'
xgb_predictor.serializer = csv_serializer
xgb_predictor.deserializer = json_deserializer

予測

linear-learnerと違って一度に複数のサンプルを投げられない。

test_data_arr = test_data.drop(['Class'], axis=1).as_matrix()
predictions_xgb = [xgb_predictor.predict(array) for array in test_data_arr]

結果

一緒なので割愛

TensorFlow

上記二つはEstimatorの中に含まれていたが、これは別なので投げ方もかなり違う。

importから

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import io
import time
import json
import sagemaker.amazon.common as smac
from sklearn.model_selection import train_test_split

ファイル作成

訓練とテストに分割する。(バリデーションが使えるかは未確認)
目的変数が一番最後の列になったcsv形式。

最初と二番目の列が、それぞれそのデータに含まれる【サンプル数・特徴量数】でないといけない。
(最後の列に目的変数が入るので、【特徴量数+1】列のデータになっていることに注意)
pandas DataFrameからto_csvする際は、index=Falseをすること。

df_origin = pd.read_csv('creditcard.csv')
train_df, test_df = train_test_split(df_origin)
train_df.rename(columns={train_df.columns[0]:len(train_df), train_df.columns[1]:30}, inplace=True)
test_df.rename(columns={test_df.columns[0]:len(test_df), test_df.columns[1]:30}, inplace=True)
train_df.to_csv('cc_training.csv',index=False)
test_df.to_csv('cc_test.csv',index=False)

import boto3
s3 = boto3.resource('s3')
bucket = 'creditcard.nk'
s3.Object(bucket, 'cc/cc_training.csv').upload_file('cc_training.csv')
s3.Object(bucket, 'cc/cc_test.csv').upload_file('cc_test.csv')
s3.Object(bucket, 'cc/iris_training.csv').upload_file('iris_training.csv')
s3.Object(bucket, 'cc/iris_test.csv').upload_file('iris_test.csv')
train_data_location = 's3://creditcard.nk/cc'

モデル定義~デプロイ

モデル定義ファイル

別途モデル定義ファイルをローカルの作業ディレクトリに置く必要がある。
このファイル内で、【特徴量数・クラス数・隠れ層の数】を指定する。
以下に含まれる4つの関数は、すべて必須。

define_tensorflow.py
import numpy as np
import os
import tensorflow as tf

INPUT_TENSOR_NAME = 'inputs'


def estimator_fn(run_config, params):
    feature_columns = [tf.feature_column.numeric_column(INPUT_TENSOR_NAME, shape=[30])]
    return tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                      hidden_units=[30, 60, 120, 60, 30],
                                      n_classes=2,
                                      config=run_config)


def serving_input_fn(params):
    feature_spec = {INPUT_TENSOR_NAME: tf.FixedLenFeature(dtype=tf.float32, shape=[30])}
    return tf.estimator.export.build_parsing_serving_input_receiver_fn(feature_spec)()


def train_input_fn(training_dir, params):
    """Returns input function that would feed the model during training"""
    return _generate_input_fn(training_dir, 'cc_training.csv')


def eval_input_fn(training_dir, params):
    """Returns input function that would feed the model during evaluation"""
    return _generate_input_fn(training_dir, 'cc_test.csv')


def _generate_input_fn(training_dir, training_filename):
    training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
        filename=os.path.join(training_dir, training_filename),
        target_dtype=np.int,
        features_dtype=np.float32)

    return tf.estimator.inputs.numpy_input_fn(
        x={INPUT_TENSOR_NAME: np.array(training_set.data)},
        y=np.array(training_set.target),
        num_epochs=None,
        shuffle=True)()

これを参照する形でモデル定義する。

jupyterインスタンス内でのモデル定義~デプロイ

from sagemaker import get_execution_role

#Bucket location to save your custom code in tar.gz format.
custom_code_upload_location = 's3://creditcard.nk/customcode/tensorflow_cc'

#Bucket location where results of model training are saved.
model_artifacts_location = 's3://creditcard.nk/artifacts'

#IAM execution role that gives SageMaker access to resources in your AWS account.
role = get_execution_role()
from sagemaker.tensorflow import TensorFlow

cc_estimator = TensorFlow(entry_point='cc_tensorflow.py',
                            role=role,
                            output_path=model_artifacts_location,
                            code_location=custom_code_upload_location,
                            train_instance_count=1,
                            train_instance_type='ml.m4.xlarge',
                            training_steps=1000,
                            evaluation_steps=100)
train_data_location = 's3://creditcard.nk/cc'
#region = boto3.Session().region_name
#train_data_location = 's3://sagemaker-sample-data-{}/tensorflow/iris'.format(region)

cc_estimator.fit(train_data_location)
tf_predictor = cc_estimator.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')
from sagemaker.tensorflow.predictor import csv_serializer
tf_predictor.content_type = 'text/csv'
tf_predictor.serializer = csv_serializer

予測

こちらも一度に複数のサンプルを投げられない。
加えて非常にややこしい形で返ってくる。
ごちゃっとしてdict型の中に、各クラスの確率がdict型で入っている。
以下は2クラスなので、クラス0の確率を取り出している。
(['classes']の後ろを[1]にするとクラス1の確率になる)

test_array = test_df.drop('Class',axis=1).as_matrix()
pred_score = []
for array in test_array:
    _res = tf_predictor.predict(array)['result']['classifications'][0]['classes'][0]['score']
    pred_score.append(_res)
predictions_tf = np.round(pred_score)

結果

割愛

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6