Sagemakerリソースを使ったMLパイプライン構築【2/3】

# はじめに
アドテク業界のインフラエンジニアとして、機械学習基盤をお世話をしている中で、アーキテクチャ改善を提案したので、せっかくなのでその内容を2回に分けて紹介したいと思います。(第一回の記事は[こちら](https://qiita.com/ririco/items/e90dddcc2f9863a167ea))

今回は使ったサービスについて、概要や使い方、APIまわりをまとめていきたいと思います。

# アーキテクチャ
下記、MLPipeline構築の部分のみ切り取ったアーキテクチャです。
ここでは、今回採用したサービスの概要や採用理由などを紹介していきます。

![architecture_new_qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/34420e92-5732-8193-4696-921c816f28cc.png)

## MWAA (Amazon Managed Workflows for Apache Airflow)
- ワークフロー管理システムであるApatch AirFlowを、AWSマネジメントサービスとして提供したもの
- 様々なワークフロー管理システムがあるが、既存環境(Airflow)を流用できる＆マネージド化していくというところで、MWAAを採用
- MLOpsレベル2->3に移行する際は、Sagemaker Pipelineを採用し、Sagemakerですべて完結させたい (学習コストがかかる、コードの大幅な書き換えが必要などあるが)

## Sagemaker Processing Job
- SageMaker APIにより、インスタンス上で指定のDocker Imageからコンテナを起動し、処理を実行してくれるサービス
- データ前処理、後処理、特徴量エンジニアリングといったデータ処理関連のジョブをSageMaker上で行うことが想定されている
- ジョブ実行方法を合わせさえすれば、学習、評価、推論など、元々想定されているワークフロー以外で使うことも可能
- 今回の構成では、商用環境・実験環境のデータ前処理のワークフローで使用している

## Sagemaker Training Job
- SageMaker APIにより、インスタンス上で指定のDocker Imageからコンテナを起動し、処理を実行してくれるサービス
- (Processing Jobとは違い) 実行時にInput(学習データ等)/Output(モデル、メトリック等)を指定することができる
- ジョブの流れのイメージとしては、S3からInputデータを読み込む→ 処理実行→ OutputデータをS3に書き込むという感じ
- 主に学習をSageMaker上で行うことが想定されている
- ジョブ実行方法を合わせさえすれば、評価や推論など、元々想定されているワークフロー以外で使うことも可能
- 今回の構成では、商用環境・実験環境の学習・評価のワークフローで使用している

![train_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/e04969db-c63b-b469-6208-03e869d9cf1f.png)

## Sagemaker Studio
- すべての機械学習開発ステップを実行するための専用ツールにアクセスできるウェブベースの統合開発環境
- 下記、Studio上でできること具体例
    - Jupyter Notebookでのコードの記述と実行 (SageMaker Notebook)
    - MLワークフローの自動化 (SageMaker Pipelines)
    - モデルのバージョン管理 (Sagemaker Model Registry)
    - モデルのデプロイとモデルによる予測のパフォーマンスの監視 (SageMaker Model Monitor・SageMaker Clarify)
    - 学習の追跡・デバッグ (Sagemaker Experiment) 
- 今回の構成では、Sagemaker Studioのサービスの中で、下記を使用している
    - SageMaker Notebook: 実験作業環境
    - Sagemaker Experiment: 商用環境・実験環境の学習・評価の追跡・デバッグで使用している

## Sagemaker Experiment
- SageMaker Studio のツールの一つ
- 反復的なモデル開発において、Inputデータ、アルゴリズム、パラメータ、環境設定、学習精度等を自動的に追跡、一元管理してくれる
- ビジュアルインターフェイスで表示、分析、比較が可能
- ビジュアルインターフェイスの内容を、Dataframe化することも可能

# Sagemakerサービスの使い方
## Sagemaker Training Jobで学習・評価する
Sagemaker Training Jobで学習・評価処理を実行したい場合、下記の2つの方法があります。

- ①AWSが提供しているビルド済みDocker Imageを使う
- ②独自のDocker Imageを使う

今回は既に(Argo上で動かしている)Docker Imageが存在しており、それを引き継ぐ形で構築をしたいため、②の方法を採用します。
独自のコンテナを、SageMakerで動作するように適合するために、sagemaker-training-toolkit というツールキットを使います

### SageMaker Training Toolkit 
SageMaker Training Toolkitは、予め作成した独自のDockerコンテナに追加することで、SageMakerと互換性を持たせて、Sagemakeモデル学習をすることができるライブラリです。
コンテナにSageMaker Training Toolkitを追加し、学習・評価処理を実行させるためには、下記を行う必要があります。

https://github.com/aws/sagemaker-training-toolkit

#### ① sagemaker-training のインストール
下記のようにDockerfileに 記述することで、SageMaker Training Toolkitを追加することができます。
これにより、既存のDockerコンテナをSagemaker-containerとして動作させることができます。
```
RUN pip3 install sagemaker-training
```

#### ② 専用ディレクトリ構成に沿った処理コードの配置
Sagemaker-containerでは、/opt/ml/ディレクトリが予約されており、このディレクトリ配下で処理が実行されます。
その中で、/opt/ml/code/配下にあるコードが、処理対象として認知されます。
そのため下記のように、処理コードを/opt/ml/code/配下にコピーするよう、Dockerfileに記述する必要があります。
```
COPY train.py /opt/ml/code/
```

##### Sagemaker-containerのディレクトリ構成
Sagemaker-containerのディレクトリ構成は、SageMaker APIでのジョブ呼び出し時に指定した各種パラメータと紐づいています。
(処理コードの修正をする段階に入ったときに、このディレクトリ構成の理解が重要になってきます)
```
/opt/ml/
├── input/
│    ├── config/
│    │    └── hyperparameters.json  # APIで定義されたハイパーパラメータがJsonファイル化され配置される
│    │
│    └── data/
│        ├── <channel_name>/ # channel_nameはInputデータのラベルのようなもの
│        │    └── <input data>  # APIで指定した学習データ(S3 prefix)がダウンロードされる
│        └── <channel_name>/
│             └── <model>  # APIで指定した'model_uri'(S3 prefix)がダウンロードされる
│
├── code/  # ここに配置されているコードが、学習コードとして認識され、実行される
│  
├── model/  # ジョブ完了後、ここに配置されている単一のモデルファイルがtarで圧縮され、APIで指定した'output_path'(S3 prefix)にアップロードされる
│
├── output/  # モデル以外のアーティファクトがここに配置され、ジョブ完了後にAPIで指定した'output_path'(S3 prefix)にアップロードされる
│
└── failure/  # ジョブ失敗時にログ等のOutputがここに配置され、ジョブ完了後にAPIで指定した'output_path'(S3 prefix)にアップロードされる
```

#### ③ エントリポイントの定義
エントリポイントとは、(/opt/ml/code/ディレクトリ内のコードの中で)コンテナの起動時に実行するコードのことで、環境変数「SAGEMAKER_PROGRAM」で定義します。
下記のように、コンテナの起動時に実行するコードを、SAGEMAKER_PROGRAMとして定義するよう、Dockerfileに記述する必要があります。
```
ENV SAGEMAKER_PROGRAM main.py
```

必要に応じて、Sagemaker-containerの[他の環境変数](https://github.com/aws/sagemaker-training-toolkit/blob/master/ENVIRONMENT_VARIABLES.md)も、Dockerfileの記述により定義することもできます。

### SageMaker API
学習・評価処理の呼び出しは、SageMaker Python SDKの、「sagemaker.estimator.Estimator」を使います。

https://sagemaker.readthedocs.io/en/stable/api/training/estimators.html#sagemaker.estimator.EstimatorBase

流れとしては、まずestimator(SagemakerTrainingJobに引き渡す学習設定)を定義し、
```
estimator = sagemaker.estimator.Estimator(
    [引数1],
    [引数2],
    [引数3]
)
```
estimatorを元に、SagemakerTrainingJobを実行します。
```
estimator.fit()
```

今回、学習・評価のジョブ実行環境をSagemakerに移行したことで、旧構成(Argo)ではコード内で定義していた多くの学習に関するパラメータ(ハイパーパラメータや学習データ、環境変数など)を、SagemakerAPIでのジョブ呼び出し時に指定することができるようになりました。
これにより、モデル学習・評価の実験のしやすさという観点からも、改善されたと思います。

## Sagemaker Processing Jobでデータ前処理をする
これはSagemaker Training Jobの使い方とかぶる部分が多いので、詳細は割愛します。

### SageMaker API
データ前処理の呼び出しは、SageMaker Python SDKの、「sagemaker.processing.Processor」を使います。

https://sagemaker.readthedocs.io/en/stable/api/training/processing.html

## Sagemaker Experimentで学習・評価の追跡をする
### コンポーネント
- experiment: runの集合体。
- trial: runを束ねるもののようだが、古いコンポーネントっぽく、あまり意識する必要なし
- run: 学習処理毎に、runが作成され、Input/Outputや各種パラメータを追跡してくれる

### SageMaker Python SDK
SageMaker Python SDKの、「sagemaker.experiments.Run」を使います。

https://sagemaker.readthedocs.io/en/stable/experiments/sagemaker.experiments.html

（実際の書き方は、今回は割愛します）
流れとしては、まずExperiment関連のパラメータを入れたRunインスタンスを作成し、
```
with Run(
    [引数1],
    [引数2],
    [引数3],
) as run:
```
その上で学習・評価処理用のSagemaker API(sagemaker.estimator.Estimator)を呼び出し、ジョブを実行します。
```
    estimator = sagemaker.estimator.Estimator(
        [引数1],
        [引数2],
        [引数3]
    )
    estimator.fit()
```
ジョブ実行開始とともに、RunインスタンスがAPI内で指定したパラメータを追跡し、完了後Experimentのビジュアルインターフェイスで表示、分析、比較することができます。
![スクリーンショット 2023-12-09 163057.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/95c5bc68-1cd4-e581-69c4-4fd1553ae4c6.png)

# おわりに
Sagamaker APIですが、今回紹介したのはごく一部なので、他も色々試してよりよいMLPipelineを目指していきたいなと思いました。
Sagamakerをこれから導入してみたい方の参考になれば、うれしく思います。