[AWS]SageMakerで独自の学習コンテナをインフラエンジニア目線でデプロイしてみるHello World!!

コンニチハ、千葉です。

SageMakerをインフラエンジニア目線で使ってみます。つまり、機械学習関連ではなく「コンテナを動かすためのインフラ」、「バッチ的何か」という観点で使ってみます。なので今回は、機械学習関連の単語は使いません!! インフラエンジニアが、データサイエンティストをインフラ面でサポートできることを目的として書きます。

まずは整理

機械学習のフローとして大きく、学習用データの用意、コード開発、学習(バッチ実行)、推論API構築(モデルのデプロイ)みたいな感じになります。 このフローに対して、SageMakerはそれぞれ機能が用意されています。

SageMakerとしては、以下4つの機能があります。

  • ラベリングジョブ:学習するためのインプットにラベルつける機能です。例えば、バスケなのかサッカーな のか画像分類を手動で簡単に実施できるUIが提供されます。
  • ノートブック:一言で言うと開発環境です。Jypyter Notebook環境を数クリックで構築できます。Jypyter Notebookでトレーニング用のコード開発やサンプルコードを試せます。
  • トレーニング:一言でいうとバッチコンテナの実行環境です。AWSで提供しているアルゴリズム、または独自開発した開発した独自アルゴリズムをコンテナにパックして実行します。
  • 推論:一言でいうとAPIサーバーの実行環境です。作ったモデルをデプロイし、API経由で結果を取得できるような機能です。AWSでいうと、RekognitionとかLexみたいなエンドポイントを自分で作れます。

今回やること

今回は学習用のコンテナをデプロイして、トレーニングジョブを実行してみます。フローで言うと学習にあたる部分です。

インフラエンジニア目線として、機械学習要素なしのコンテナをデプロイしてみます。機械学習するコンテナではなく、ファイルをcatしたり、lsしたり、ファイル置いたりっていうスクリプトを実行し探索してみたいと思います。

以下を処理するコンテナを用意してみました。

  • S3上のファイルの読み込み(学習用データの読み込みを想定)
  • 学習で利用する変数の読み込みと表示(ハイパーパラメータの読み込みを想定)
  • ファイルを作成し、S3へ配置(学習した結果出力されるモデルの配置を想定)
  • ログをCloudWatch Logsへ出力

以上のシンプルなコンテナを作って、デプロイして理解を深めてみましょう。

やってみた

コンテナフォルダ構成

コンテナ配下のフォルダ構成です。どんなフォルダ構成になるかを整理します。 ユーザーで用意する必要があるのは、「/opt/program/train」スクリプトだけです。他は、SageMakerが用意します。

/opt
    ├──program
    │   └─ train
    └──ml
        ├── input
        │   ├── config
        │   │   ├── hyperparameters.json
        │   │   ├── inputdataconfig.json
        │   │   └── resourceconfig.json
        │   └── data
        │       └── <channel_name>
        │           └── <input data>
        ├── model
        │   └── <model files>
        └── output
            └── failure
  • /opt/program/train:トレーニングジョブが実行するスクリプトです。任意のスクリプトを配置します。
  • /opt/ml:自動で作成されるフォルダでトレーニングジョブで指定した情報が格納されます。自動で作成されるのでで作成不要です。
  • /opt/ml/input/data/<channel_name>:トレーニングジョブで指定した、S3上のファイルがコピーされます
  • /opt/ml/model:ここに出力したファイルがS3へアップロードされます。生成したファイルを格納します。

さらに詳しく知りたい方は、以下のブログをご覧ください。

Amazon SageMakerで独自の学習/推論用コンテナイメージを作ってみる

trainスクリプト

トレーニングジョブ(学習ジョブ)実行時に実行されるスクリプトtrainを作ります。トレーニングジョブを実行するとdocker run image名 trainでコンテナが実行されるはずです。(ドキュメントに記載がないですが挙動的な推察) *今回はbashで書いてますが、RubyとかPythonとかGoとか、なんでもいいです。

今回、trainスクリプトでやることは

  • コンフィグ情報の確認/opt/ml/input/configをlsし、ファイルをcatする
  • S3からコピーされたファイルの確認/opt/ml/input/data/<channel_name>をlsし、ファイルをcatする
  • S3にファイルを配置/opt/ml/modelに、ファイルを置く。配置したファイルがS3へアップロードされているか確認する

で、どんな感じでコンテが実行され、どんな情報を取得できるか探索してみたいと思います。

trainスクリプト

実際のtrainスクリプトです。catとlsとdateしか使ってません、シンプルです。

#!/bin/bash

# /opt/ml/input/configをlsし、ファイルをcatする

echo "ls /opt/ml/input/config"
ls /opt/ml/input/config
for i in `find /opt/ml/input/config -type f`;do
 echo cat file:$i
 cat $i
done

# /opt/ml/input/data/```をlsし、ファイルをcatする

echo "ls /opt/ml/input/data/train"
ls /opt/ml/input/data/train
for i in `find /opt/ml/input/data/train -type f`;do
 echo cat file:$i
 cat $i
done

# /opt/ml/modelに、ファイルを置く。配置したファイルがS3へアップロードされているか確認する
date
echo `date "+%Y-%m-%d-%H-%M-%S"` > /opt/ml/model/`date "+%Y-%m-%d-%H-%M-%S"`

trainファイルにはchmod +xを実施し、実行権限を付与しておきましょう。

Dockerfile

Dockerfileを書いて、イメージ作ってECRにプッシュしておきましょう。(イメージのビルド、ECRへのプッシュの仕方は省略) Dockerfileはこんな感じで用意しました。

FROM ubuntu

RUN mkdir -p /opt/program
COPY  train /opt/program/
ENV PATH $PATH:/opt/program
ENTRYPOINT ["/bin/bash"]

トレーニングジョブの実行

環境ができたのでトレーニングジョブを実行してみましょう! SageMaker SDKを利用してトレーニングジョブを実行できますが、今回はマネージメントコンソールからジョブを実行してみます。

こんな感じでトレーニングジョブを作りました。

まず、今回ECRにpushしたコンテナを指定、インスタンスタイプやインスタンス数、ボリュームサイズを指定します。

次に、コンテナで取得するパラメータ、チャネル(入力データがあるS3)、出力先のS3を指定します。

実行結果を見てみる

実際にトレーニングジョブを実行しました。スクリプトを実行しましたが、どんな挙動だったかを確認してみます。

実行ログの確認

コンテナの標準出力は、CloudWatch Logsに出力されます。こちらから、実行したスクリプトの結果を確認してみます。 標準出力に出した情報が、CloudWatch Logsに出力されています。デバッグが捗りそうです。

/opt/ml/input/configをlsし、ファイルをcatする

このディレクトリ配下には、ジョブで指定したハイパーパラメータなど、トレーニングジョブで指定した情報や、その他の情報がファイルがJSON形式で保存されていました。

/opt/ml/input/config/hyperparameters.json > ジョブで指定したパラメータ

{
    "ore": "dayo"
    "kojima": "dayo",
}

/opt/ml/input/config/init-config.json > ジョブで定義した情報

{
    "inputMode": "FILE",
    "channels": {
        "train": {
            "s3DataSource": {
                "s3DataType": "S3_PREFIX",
                "s3Uri": "s3://xxxx/",
                "s3DataDistributionType": "FULLY_REPLICATED",
                "attributeNames": null
            },
            "fileSystemDataSource": null,
            "compressionType": "NONE",
            "recordWrapper": "NONE",
            "shuffleConfig": null,
            "inputMode": "FILE",
            "sharded": false
        }
    },
    "hostConfig": {
        "clusterSize": 1,
        "hostNumber": 1
    },
    "enableDataAgentDownloads": false
}

/opt/ml/input/config/resourceconfig.json > 複数コンテナで分散処理する場合に利用するコンテナ情報

{
    "current_host": "algo-1",
    "hosts": [
        "algo-1"
    ],
    "network_interface_name": "ethwe"
}

/opt/ml/input/config/inputdataconfig.json > チャンネル情報(S3からのデータコピー)

    "train": {
        "TrainingInputMode": "File",
        "S3DistributionType": "FullyReplicated",
        "RecordWrapperType": "None"
    }
}

/opt/ml/input/data/<channel_name>をlsし、ファイルをcatする

このディレクトリにはS3上のデータがコンテナ内にロードされていることを確認してみます。 inputに指定したS3上に、index.htmlだけおてい見ました。

cat /opt/ml/input/data/train/index.html
test

コンテナ上にコピーされてますね。trainはジョブで指定したチャネル名なので任意に指定できます。 チャネルは複数追加できるので、training、validation、testingのようなデータをそれぞれ指定することもできます。

https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/your-algorithms-training-algo.html

/opt/ml/modelに、ファイルを置く。配置したファイルがS3へアップロードされているか確認する

スクリプトで出力したファイルがS3へアップロードされているか確認します。スクリプトでdateコマンドでファイルを/opt/ml/modelへ出力しています。

S3を確認したところ、tar.gzファイルが保存されてます。展開して中身を見てみました。

スクリプトで出力したファイルがS3上にアップロードされていることを確認できました!

さいごに

SageMakerの学習ジョブがどのような挙動になっているかを確認しました。挙動が確認できたので、独自コンテナ作ってデプロイして、学習実行するという一連の流れをサポートできそうです。 実行内容的にはAWS Batch使って自前で環境用意することもできそうですが、SageMakerを利用することで、S3連携やインスタンスタイプやインスタンス数を指定しての実行、ハイパーパラメータをいろいろ試すようなジョブの実行方法が用意されているので、便利そうですね。