Amazon SageMaker Experimentsを試してみた #reinvent

2019.12.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

最初に

こんにちはデータアナリティクス事業本部のyoshimです。
re:Invent2019にて「Amazon SageMaker Experiments」のリリースが発表されたので、「どんな機能なのかを整理」した後に、AWSから提供されているサンプルスクリプトを試しに実行してみました。

目次

1.Amazon SageMaker Experimentsとは

Amazon SageMaker Experiments」はざっくり言うと「実験結果の管理をサポートする」機能です。
機械学習のモデルを開発している時は色々な実験をして結果を比較して、といった工程が発生するのでこの管理が簡単にできると嬉しいですよね。

「Amazon SageMaker Experiments」がなんなのか、をより詳細に把握するために公式の紹介文を確認します。

Introducing Amazon SageMaker Experiments First, let’s define core concepts:

  • A trial is a collection of training steps involved in a single training job. Training steps typically includes preprocessing, training, model evaluation, etc. A trial is also enriched with metadata for inputs (e.g. algorithm, parameters, data sets) and outputs (e.g. models, checkpoints, metrics).
  • An experiment is simply a collection of trials, i.e. a group of related training jobs.

「Amazon SageMaker Experiments」のコアコンセプトとして、下記の2点が挙げられています。

  • trialは1つのトレーニングJOBを実行するために付随する諸々の工程(ex.前処理、トレーニング、モデルの評価)の集まりであり、メタデータを付与することが可能
  • experimentはtrialの集まり

Running your training jobs on SageMaker or SageMaker Autopilot, all you have to do is pass an extra parameter to the Estimator, defining the name of the experiment that this trial should be attached to. All inputs and outputs will be logged automatically.

SageMaker、もしくはSageMaker Autopilot上でトレーニングJOBを実行する、といった条件で「Amazon SageMaker Experiments」を利用するために必要なことは「Estimator」に「そのtrialがどのexperimentsに紐づけられるか」といったことを定義したパラメータを追加すればよく、全ての入力と出力は自動的にログとして出力されます。

Once you’ve run your training jobs, the SageMaker Experiments SDK lets you load experiment and trial data in the popular pandas dataframe format

「SageMaker Experiments SDK」を使うことで、「experiment」、「trial」のデータをPandasのDataFrame形式で取得することが可能、とのことです。
PandasのDataFrame形式でデータを受け取ることができれば、あとは自分が見たい形に好きに加工できて可視化までできますね。

ここまででなんとなくの雰囲気は掴めたので、早速サンプルスクリプトを実行してみましょう。

2.やってみた

今回はこちらの内容を実際に手を動かして確認してみました。
内容としては「NNの隠れ層の数のみを変更する」という実験結果の管理をサンプルとして実行してみる、というものです。

本エントリーでは、このサンプルスクリプトの要点のみを抽出します。

2-1.trackerの作成

メタ情報を「trial」に付与するために「tracker」を作成します。
ここでは、前処理のパラメータとインプットデータのS3パスをメタ情報として指定しています。

with Tracker.create(display_name="Preprocessing", sagemaker_boto_client=sm) as tracker:
    tracker.log_parameters({
        "normalization_mean": 0.1307,
        "normalization_std": 0.3081,
    })
    # we can log the s3 uri to the dataset we just uploaded
    tracker.log_input(name="mnist-dataset", media_type="s3/uri", value=inputs)

Trackerで引き渡せる情報についてはTrackerをご確認ください。

2-2.experimentの作成

続いて、今回新しく実行するので新規に「experiment」を作成しました。
(当然、既にexperimentが作成済ならこの処理は不要です。)

experiment名はAWSアカウント、リージョンごとに一意とする必要があります。

from smexperiments.experiment import Experiment

mnist_experiment = Experiment.create(
    experiment_name=f"yoshim-mnist-hand-written-digits-classification-20191207",
    description="Classification of mnist hand-written digits", 
    sagemaker_boto_client=sm)

2-3.trialの作成

続いて、「2-2.experimentの作成」で作成したexperimentに紐づける形で「trial」を作成します。
また、「2-1.trackerの作成」で作成したtrackerから「trial_component」を付与します。

# trialの作成
cnn_trial = Trial.create(
    trial_name=trial_name, 
    experiment_name=mnist_experiment.experiment_name,
    sagemaker_boto_client=sm,
)

# trial_componentの付与
preprocessing_trial_component = tracker.trial_component
cnn_trial.add_trial_component(preprocessing_trial_component)

2-4.モデルの学習時にここまでの設定を反映

学習を実行するタイミングで、ここまでの設定を反映してあげればOKです。

# Now associate the estimator with the Experiment and Trial
estimator.fit(
    inputs={'training': inputs}, 
    job_name=cnn_training_job_name,
    
    # trialの情報を指定
    experiment_config={
        "TrialName": cnn_trial.trial_name,
        "TrialComponentDisplayName": "Training",
    },
    wait=True,
)

ここまでで「新規に作成したexperiment」配下に「メタ情報を付与したtrial」を作成し、学習を実行するところまでできました。

2-5.実験結果のデータを絞り込んだ状態で取得する

ここからは、実験結果の内容をどのように利用できるのか、といった点を確認します。
experiment名や諸々の絞り込み条件等を指定することで、簡単にPandasのDFとして結果を取得できるようです。
PandasのDFとして結果を取得できれば後はどうとでもできるので、ここまでのところを楽にできるのは嬉しいですね。

# trial_componentsデータを取得
trial_component_analytics = ExperimentAnalytics(
    sagemaker_session=Session(sess, sm), 

    # 情報を取得するexperiment名
    experiment_name="yoshim-mnist-hand-written-digits-classification-20191207",

    # 取得するtrial-componentを絞り込む条件
    search_expression=search_expression,
    
    # 取得した情報のソート方法の指定
    sort_by="metrics.test:accuracy.max",
    sort_order="Descending",
    
    # 利用するmetricsの絞り込み。指定しない時は全ての情報を取得する
    metric_names=['test:accuracy'],
    
    # 利用するパラメータの絞り込み。指定しない時は全ての情報を取得する
    parameter_names=['hidden_channels', 'epochs', 'dropout', 'optimizer']
)

# PandasのDFとして取得
analytic_table = trial_component_analytics.dataframe()

# 結果の確認
analytic_table.head()

こんな感じの結果が取得できます。
とりあえず欲しいデータに絞り込んでDFとして結果を受け取ることまでできました。

また、ExperimentAnalyticsを確認したところ、「取得する情報を指定しない場合はデフォルトで全ての情報を取得」するようになっているようです。
結構色々な情報が取得できるので、後から確認する際にお世話になりそうです。

2-6.特定のtrialに絞り込んでデータを取得する

今回は各trialで「Preprocessing」、「Training」という「trial component」を設定しています。
なので、下記の通り「特定のtrial」を指定してデータを確認すると2レコード取得できます。
特定の「trial」を調査したい場合は、このように特定の「trial」を指定して内容を確認することとなるかと思います。

lineage_table = ExperimentAnalytics(
    sagemaker_session=Session(sess, sm), 
    search_expression={
        "Filters":[{
            "Name": "Parents.TrialName",
            "Operator": "Equals",
            "Value": hidden_channel_trial_name_map[2]
        }]
    },
    sort_by="CreationTime",
    sort_order="Ascending",
)
lineage_table.dataframe()

ちゃんと「Preprocessing」、「Training」の2レコードが確認できますね。

3.まとめ

個人的には「ツールとしてはとても良さそう」な反面、「複数人で使うことが前提となると、管理ルールをできるだけ早い段階で決めておく」ことも重要だな、と感じました。
(各人が思い思いにリソースを作成してしまうと、後々管理が難しくなりそうなので...)

4.参考