

 **このページの改善にご協力ください** 

このユーザーガイドに貢献するには、すべてのページの右側のペインにある「**GitHub でこのページを編集する**」リンクを選択してください。

# 機械学習のための Amazon EKS で AWS Inferentia インスタンスを使用する
<a name="inferentia-support"></a>

このトピックでは[Amazon EC2 Inf1](https://aws.amazon.com/ec2/instance-types/inf1/) インスタンスを実行中のノードで Amazon EKS クラスターを作成する方法、(オプションで) サンプルアプリケーションをデプロイする方法について説明します。Amazon EC2 Inf1 インスタンスは [AWS インフェクエンティア](https://aws.amazon.com/machine-learning/inferentia/) チップを利用しています。Inf1 チップはクラウド内で高パフォーマンスと低コストの推論を提供するために、AWS によってカスタムビルドされたものです。機械学習モデルは[AWS Neuron](https://aws.amazon.com/machine-learning/neuron/) を使用してコンテナにデプロイされます。Neuron はコンパイラー、ランタイム、および インフェクエンティア チップの機械学習推論パフォーマンスを最適化するプロファイリングツールで構成される software development kit (SDK です。AWSNeuron はTensorFlow、PyTorch、MXNet などの一般的な機械学習フレームワークをサポートしています。

**注記**  
Neuron デバイスの論理 ID は連続している必要があります。複数の Neuron デバイスをリクエストする Pod が、(複数の Neuron デバイスを持つ) `inf1.6xlarge` または `inf1.24xlarge` インスタンスタイプでスケジュールされている場合、Kubernetes スケジューラが連続していないデバイス ID を選択すると、その Pod は起動に失敗します。詳細については、GitHub の「[Device logical IDs must be contiguous](https://github.com/aws/aws-neuron-sdk/issues/110)」を参照してください。

## 前提条件
<a name="inferentia-prerequisites"></a>
+ コンピュータに `eksctl` がインストールされている。インストールされていない場合は`eksctl` ドキュメントの「[インストール](https://eksctl.io/installation)」を参照してください。
+ コンピュータに `kubectl` がインストールされている。詳細については「[`kubectl` および `eksctl` のセットアップ](install-kubectl.md)」を参照してください。
+ (オプション) コンピュータに `python3` がインストールされている。インストールされていない場合は「[Python ダウンロード](https://www.python.org/downloads/)」でインストール手順を参照してください。

## クラスターを作成する
<a name="create-cluster-inferentia"></a>

1. Inf1 Amazon EC2 インスタンスを実行するノードを持つクラスターを作成します。{{inf1.2xlarge}} を任意の [Inf1 インスタンスタイプ](https://aws.amazon.com/ec2/instance-types/inf1/) に置き換えることができます。`eksctl` ユーティリティは`Inf1` インスタンスタイプでノードグループを起動していることを検出し、アクセラレーションされた Amazon EKS 最適化 Amazon Linux AMI のいずれかを使用してノードを起動します。
**注記**  
TensorFlow Serving で[サービスアカウント用の IAM 役割](iam-roles-for-service-accounts.md)を使用することはできません。

   ```
   eksctl create cluster \
       --name inferentia \
       --region region-code \
       --nodegroup-name ng-inf1 \
       --node-type inf1.2xlarge \
       --nodes 2 \
       --nodes-min 1 \
       --nodes-max 4 \
       --ssh-access \
       --ssh-public-key your-key \
       --with-oidc
   ```
**注記**  
出力の次の行の値をメモします。これは後の (オプションの) ステップで使用されます。

   ```
   [9]  adding identity "arn:aws:iam::111122223333:role/eksctl-inferentia-nodegroup-ng-in-NodeInstanceRole-FI7HIYS3BS09" to auth ConfigMap
   ```

   `Inf1` インスタンスでノードグループを起動すると、`eksctl` によって AWS Neuron Kubernetes デバイスプラグインが自動的にインストールされます。このプラグインは、Neuron デバイスをシステムリソースとして Kubernetes スケジューラにアドバタイズします。このスケジューラはコンテナによってリクエストできます。デフォルトの Amazon EKS ノードの IAM ポリシーに加えて、Amazon S3 読み取り専用のアクセスポリシーが追加されます。これにより、後のステップで説明するサンプルアプリケーションで Amazon S3 からトレーニングされたモデルをロードできるようになります。

1. すべての Pod が正しく起動していることを確認します。

   ```
   kubectl get pods -n kube-system
   ```

   簡略化された出力:

   ```
   NAME                                   READY   STATUS    RESTARTS   AGE
   [...]
   neuron-device-plugin-daemonset-6djhp   1/1     Running   0          5m
   neuron-device-plugin-daemonset-hwjsj   1/1     Running   0          5m
   ```

## (オプション) TensorFlow Serving アプリケーションイメージのデプロイ
<a name="deploy-tensorflow-serving-application"></a>

トレーニング済みモデルはインフェクエンティア インスタンスにデプロイする前に、インフェクエンティア ターゲットにコンパイルする必要があります。続行するにはAmazon S3 に保存されている [Neuron optimized TensorFlow](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/neuron-guide/neuron-frameworks/tensorflow-neuron/index.html) モデルが必要になります。SavedModel がまだない場合は[Neuron 互換の ResNet50 モデルの作成](https://docs.aws.amazon.com/dlami/latest/devguide/tutorial-inferentia-tf-neuron.html)についてのチュートリアルに従って、結果の SavedModel を S3 にアップロードします。ResNet-50 は画像認識のタスクに使用される一般的な機械学習モデルです。Neuron モデルのコンパイルについての詳細は「AWS ディープラーニング AMI デベロッパーガイド」の「[AWS インフェクエンティア チップと DLAMI](https://docs.aws.amazon.com/dlami/latest/devguide/tutorial-inferentia.html)」を参照してください。

サンプルのデプロイメントマニフェストではAWS ディープラーニング Containers によって提供される TensorFlow の事前構築済みの推論サービングコンテナが管理されます。コンテナ内には、AWS Neuron ランタイムと TensorFlow Serving アプリケーションがあります。Neuron 用に最適化された事前構築済みの Deep Learning Containers の完全なリストは、GitHub で[利用可能なイメージ](https://github.com/aws/deep-learning-containers/blob/master/available_images.md#neuron-inference-containers)に保持されます。起動時に、DLC は Amazon S3 からモデルを取得し、保存したモデルで Neuron TensorFlow Serving を起動して、予測リクエストのために待機します。

サービングアプリケーションに割り当てられる Neuron デバイスの数はデプロイメント yaml で `aws.amazon.com/neuron` リソースを変更することで調整できます。TensorFlow Serving と Neuron ランタイム間の通信は GRPC 経由で行われることに注意してください。GRPC では`IPC_LOCK` 機能をコンテナに追加する必要があります。

1. 「[クラスターを作成する](#create-cluster-inferentia)」のステップ 1 で作成したノードのインスタンス役割に `AmazonS3ReadOnlyAccess` IAM ポリシーを追加します。これはサンプルアプリケーションが Amazon S3 からトレーニングされたモデルをロードできるようにするために必要です。

   ```
   aws iam attach-role-policy \
       --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
       --role-name eksctl-inferentia-nodegroup-ng-in-NodeInstanceRole-FI7HIYS3BS09
   ```

1. 次の内容で、`rn50_deployment.yaml` という名前のファイルを作成します。希望の設定に合わせて、リージョンコードとモデルパスを更新します。モデル名はクライアントが TensorFlow サーバーにリクエストを行う際の識別を目的としています。この例ではモデル名を使用してサンプルの ResNet50 のクライアントスクリプトと照合します。このスクリプトは後のステップで予測リクエストを送信する際に使用されます。

   ```
   aws ecr list-images --repository-name neuron-rtd --registry-id 790709498068 --region us-west-2
   ```

   ```
   kind: Deployment
   apiVersion: apps/v1
   metadata:
     name: eks-neuron-test
     labels:
       app: eks-neuron-test
       role: master
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: eks-neuron-test
         role: master
     template:
       metadata:
         labels:
           app: eks-neuron-test
           role: master
       spec:
         containers:
           - name: eks-neuron-test
             image: 763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-inference-neuron:1.15.4-neuron-py37-ubuntu18.04
             command:
               - /usr/local/bin/entrypoint.sh
             args:
               - --port=8500
               - --rest_api_port=9000
               - --model_name=resnet50_neuron
               - --model_base_path=s3://${your-bucket-of-models}/resnet50_neuron/
             ports:
               - containerPort: 8500
               - containerPort: 9000
             imagePullPolicy: IfNotPresent
             env:
               - name: AWS_REGION
                 value: "us-east-1"
               - name: S3_USE_HTTPS
                 value: "1"
               - name: S3_VERIFY_SSL
                 value: "0"
               - name: S3_ENDPOINT
                 value: s3.us-east-1.amazonaws.com
               - name: AWS_LOG_LEVEL
                 value: "3"
             resources:
               limits:
                 cpu: 4
                 memory: 4Gi
                 aws.amazon.com/neuron: 1
               requests:
                 cpu: "1"
                 memory: 1Gi
             securityContext:
               capabilities:
                 add:
                   - IPC_LOCK
   ```

1. モデルをデプロイします。

   ```
   kubectl apply -f rn50_deployment.yaml
   ```

1. 次の内容で、`rn50_service.yaml` というファイルを作成します。予測リクエストを受け入れるために HTTP ポートと gRPC ポートが開かれます。

   ```
   kind: Service
   apiVersion: v1
   metadata:
     name: eks-neuron-test
     labels:
       app: eks-neuron-test
   spec:
     type: ClusterIP
     ports:
       - name: http-tf-serving
         port: 8500
         targetPort: 8500
       - name: grpc-tf-serving
         port: 9000
         targetPort: 9000
     selector:
       app: eks-neuron-test
       role: master
   ```

1. TensorFlow モデル提供アプリケーション用の Kubernetes サービスを作成します。

   ```
   kubectl apply -f rn50_service.yaml
   ```

## (オプション) TensorFlow Serving サービスに対する予測を行う
<a name="make-predictions-against-tensorflow-service"></a>

1. ローカルでテストするにはgRPC ポートを `eks-neuron-test` サービスに転送します。

   ```
   kubectl port-forward service/eks-neuron-test 8500:8500 &
   ```

1. 次の内容で `tensorflow-model-server-infer.py` という Python スクリプトを作成します。このスクリプトはサービスフレームワークである gRPC を介して推論を実行します。

   ```
   import numpy as np
   import grpc
   import tensorflow as tf
   from tensorflow.keras.preprocessing import image
   from tensorflow.keras.applications.resnet50 import preprocess_input
   from tensorflow_serving.apis import predict_pb2
   from tensorflow_serving.apis import prediction_service_pb2_grpc
   from tensorflow.keras.applications.resnet50 import decode_predictions
   
   if __name__ == '__main__':
      channel = grpc.insecure_channel('localhost:8500')
      stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
      img_file = tf.keras.utils.get_file(
          "./kitten_small.jpg",
          "https://raw.githubusercontent.com/awslabs/mxnet-model-server/master/docs/images/kitten_small.jpg")
      img = image.load_img(img_file, target_size=(224, 224))
      img_array = preprocess_input(image.img_to_array(img)[None, ...])
      request = predict_pb2.PredictRequest()
      request.model_spec.name = 'resnet50_inf1'
      request.inputs['input'].CopyFrom(
          tf.make_tensor_proto(img_array, shape=img_array.shape))
      result = stub.Predict(request)
      prediction = tf.make_ndarray(result.outputs['output'])
      print(decode_predictions(prediction))
   ```

1. スクリプトを実行して、予測をサービスに送信します。

   ```
   python3 tensorflow-model-server-infer.py
   ```

   出力例は次のとおりです。

   ```
   [[(u'n02123045', u'tabby', 0.68817204), (u'n02127052', u'lynx', 0.12701613), (u'n02123159', u'tiger_cat', 0.08736559), (u'n02124075', u'Egyptian_cat', 0.063844085), (u'n02128757', u'snow_leopard', 0.009240591)]]
   ```