EKSで機械学習 #9 SageMaker Operaterの導入

# はじめに
このシリーズでは Amazon EKSで機械学習を行っていきたいと思います

# シリーズ目次
EKSで機械学習 #1 準備編
EKSで機械学習 #2 クラスター作成編
EKSで機械学習 #3 Managed Worker Node作成編
EKSで機械学習 #4 GPU Managed Worker Node作成編
EKSで機械学習 #5 Cluster AutoScaler設定編
EKSで機械学習 #6 HPAの設定
EKSで機械学習 #7 EFSの設定
EKSで機械学習 #8 Argo CDを利用したCD環境の構築
EKSで機械学習 #9 SageMaker Operaterの導入（この記事）



# この記事の目的
Kubernetes上で機械学習を行う方法として、k8s上で機械学習ワークロードを動かすという方法と
k8sをSageMakerを動かす箱として利用する方法(SageMaker Operator)を利用する方法があります。
今回は、その後者の方法をやってみましょう。

# 参考した記事
https://qiita.com/taishin/items/1f08bd28b3fc99bbed7e
こちらを参考にさせていただきました。ありがとうございます。

# eksctlで sagemaker-operator用のnamespace, service account と IAM roleの作成

作成

```sh
eksctl create iamserviceaccount --cluster=ml --name=sagemaker-k8s-operator-default --namespace=sagemaker-k8s-operator-system --attach-policy-arn=arn:aws:iam::aws:policy/AmazonSageMakerFullAccess --region=us-west-2 --approve
```

IAM roleの確認

```sh
eksctl get iamserviceaccount --cluster=ml --region=us-west-2 | grep sagemaker
sagemaker-k8s-operator-system   sagemaker-k8s-operator-default  arn:aws:iam::xxxxx:role/eksctl-ml-addon-iamserviceaccount-sagemaker-Role1-1PN5ZWS5FIIYY
```

このIAM roleで ``` eks.amazonaws.com/role-arn ``` の部分を置き換えます。

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::xxxxx:role/eksctl-ml-addon-iamserviceaccount-sagemaker-Role1-1PN5ZWS5FIIYY
  name: sagemaker-k8s-operator-default
  namespace: sagemaker-k8s-operator-system
```

applyします

```sh

k apply -f installer.yaml
```

確認します

```shell
kubectl get crd | grep sagemaker
batchtransformjobs.sagemaker.aws.amazon.com         2020-03-04T15:25:49Z
endpointconfigs.sagemaker.aws.amazon.com            2020-03-04T15:25:49Z
hostingdeployments.sagemaker.aws.amazon.com         2020-03-04T15:25:49Z
hyperparametertuningjobs.sagemaker.aws.amazon.com   2020-03-04T15:25:49Z
models.sagemaker.aws.amazon.com                     2020-03-04T15:25:49Z
trainingjobs.sagemaker.aws.amazon.com               2020-03-04T15:25:49Z
```

```shell

kubectl -n sagemaker-k8s-operator-system get pods
NAME                                                         READY   STATUS    RESTARTS   AGE
sagemaker-k8s-operator-controller-manager-5cd7df4d74-zc599   2/2     Running   0          17m
```


これでインストールできていることは確認できました

# S3バケットとデータの用意
こちらも参考Qiitaそのままです。
一点注意としては、SageMakerとS3バケットは同じリージョンである必要があります。
（EKSは同じリージョンである必要はないと思いますが、運用を考えると同じリージョンになるかと思います）
S3バケットは新規で作っても、既存のものがあれば、それを使いまわしてもOKです。私は使いまわしました。

```shell

curl -O https://raw.githubusercontent.com/ozt-ca/tjo.hatenablog.samples/master/r_samples/public_lib/jp/mnist_reproduced/short_prac_train.csv
curl -O https://raw.githubusercontent.com/ozt-ca/tjo.hatenablog.samples/master/r_samples/public_lib/jp/mnist_reproduced/short_prac_test.csv

aws s3 cp short_prac_test.csv  s3://xxxxxx/sagemaker-operator/validation/
aws s3 cp short_prac_train.csv s3://xxxxxx/sagemaker-operator/train/
```

# SageMaker用のIAM roleの作成
これも既存のものがあれば使いまわしてもOKです。
これはEKSが使うIAM roleではなく、あくまでEKSからkickされたsagemakerが利用するIAM roleです。
新規で作成する場合は参考Qiitaと同じです

# トレーニングジョブの実行
以下のyamlを実行しました
変更点は、ECRのイメージと、roleaArmと、S3バケットです。


```yaml

apiVersion: sagemaker.aws.amazon.com/v1
kind: TrainingJob
metadata:
  name: xgboost-mnist
spec:
  hyperParameters:
    - name: max_depth
      value: "5"
    - name: eta
      value: "0.2"
    - name: gamma
      value: "4"
    - name: min_child_weight
      value: "6"
    - name: silent
      value: "0"
    - name: objective
      value: multi:softmax
    - name: num_class
      value: "10"
    - name: num_round
      value: "10"
  algorithmSpecification:
    trainingImage: 433757028032.dkr.ecr.us-west-2.amazonaws.com/xgboost:1
    trainingInputMode: File
  roleArn: arn:aws:iam::xxxxxx:role/service-role/AmazonSageMaker-ExecutionRole-20181129T145995
  region: us-west-2
  outputDataConfig:
    s3OutputPath: s3://xxxxx/sagemaker-operator/output/
  resourceConfig:
    instanceCount: 1
    instanceType: ml.m4.xlarge
    volumeSizeInGB: 5
  stoppingCondition:
    maxRuntimeInSeconds: 86400
  inputDataConfig:
    - channelName: train
      dataSource:
        s3DataSource:
          s3DataType: S3Prefix
          s3Uri: s3://xxxxxxxx/sagemaker-operator/train/
          s3DataDistributionType: FullyReplicated
      contentType: text/csv
      compressionType: None
    - channelName: validation
      dataSource:
        s3DataSource:
          s3DataType: S3Prefix
          s3Uri: s3://xxxxx/sagemaker-operator/validation/
          s3DataDistributionType: FullyReplicated
      contentType: text/csv
      compressionType: None
  tags:
    - key: tagKey
      value: tagValue
```


実行します

```shell
kubectl apply -f xgboost-mnist-trainingjob.yaml
```

確認します

```yaml

kubectl describe trainingjob 
Name:         xgboost-mnist
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"sagemaker.aws.amazon.com/v1","kind":"TrainingJob","metadata":{"annotations":{},"name":"xgboost-mnist","namespace":"default"...
API Version:  sagemaker.aws.amazon.com/v1
Kind:         TrainingJob
Metadata:
  Creation Timestamp:  2020-03-04T15:38:22Z
  Finalizers:
    sagemaker-operator-finalizer
  Generation:        2
  Resource Version:  523025
  Self Link:         /apis/sagemaker.aws.amazon.com/v1/namespaces/default/trainingjobs/xgboost-mnist
  UID:               2e405e13-5e2e-11ea-bae0-064fcde809be
Spec:
  Algorithm Specification:
    Training Image:       433757028032.dkr.ecr.us-west-2.amazonaws.com/xgboost:1
    Training Input Mode:  File
  Hyper Parameters:
    Name:   max_depth
    Value:  5
    Name:   eta
    Value:  0.2
    Name:   gamma
    Value:  4
    Name:   min_child_weight
    Value:  6
    Name:   silent
    Value:  0
    Name:   objective
    Value:  multi:softmax
    Name:   num_class
    Value:  10
    Name:   num_round
    Value:  10
  Input Data Config:
    Channel Name:      train
    Compression Type:  None
    Content Type:      text/csv
    Data Source:
      S 3 Data Source:
        S 3 Data Distribution Type:  FullyReplicated
        S 3 Data Type:               S3Prefix
        S 3 Uri:                     s3://xxxx/sagemaker-operator/train/
    Channel Name:                    validation
    Compression Type:                None
    Content Type:                    text/csv
    Data Source:
      S 3 Data Source:
        S 3 Data Distribution Type:  FullyReplicated
        S 3 Data Type:               S3Prefix
        S 3 Uri:                     s3://xxxxxxx/sagemaker-operator/validation/
  Output Data Config:
    S 3 Output Path:  s3://txxxxxxx/sagemaker-operator/output/
  Region:             us-west-2
  Resource Config:
    Instance Count:     1
    Instance Type:      ml.m4.xlarge
    Volume Size In GB:  5
  Role Arn:             arn:aws:iam::xxxxx:role/service-role/AmazonSageMaker-ExecutionRole-20181129T145995
  Stopping Condition:
    Max Runtime In Seconds:  86400
  Tags:
    Key:              tagKey
    Value:            tagValue
  Training Job Name:  xgboost-mnist-2e405e135e2e11eabae0064fcde809be
```

SageMakerの画面からも念の為確認します。
こんな感じでJobが実行されていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/8079f112-6dcd-c048-3d3b-717192a56a5c.png)

# Tips
- 同じyamlを実行しても、unchangeになる。（新規でjobが実行されない)
- 当たり前だけど、同じ内容でファイル名だけ変えて、applyしてもunchangeになる
- metadataのnameを変えるとそれ以外は同じ内容でも違うjobとして実行される（Pipelineに組み込むならnameを動的に変える？運用をする必要がある？)
- deleteをすると、実行中のSageMaker JobはStopされる
- （思いつくたびに追記)


# まとめ
EKS上でSageMaker Operatorを利用して機械学習ジョブを実行しました。
この記事ではトレーニングだけですが、推論も時間があればやってみようと思います。