メインコンテンツまでスキップ

Run inference on AWS Inferentia

これで、コンパイルされたモデルを使用して、AWS Inferentiaノード上で推論ワークロードを実行することができます。

推論用のポッドを作成する

推論を実行する画像を確認しましょう:

~$echo $AIML_DL_INF_IMAGE

これはトレーニングに使用したものとは異なるイメージで、推論用に最適化されています。

これで推論用のポッドをデプロイすることができます。これが推論ポッドを実行するためのマニフェストファイルです:

~/environment/eks-workshop/modules/aiml/inferentia/inference/inference.yaml
apiVersion: v1
kind: Pod
metadata:
name: inference
namespace: aiml
labels:
role: inference
spec:
nodeSelector:
node.kubernetes.io/instance-type: inf2.xlarge
containers:
- command:
- sh
- -c
- sleep infinity
image: ${AIML_DL_INF_IMAGE}
name: inference
resources:
limits:
aws.amazon.com/neuron: 1
serviceAccountName: inference
A

推論では、nodeSelectorセクションでinf2インスタンスタイプを指定しています。

B

resourceslimitsセクションでは、このポッドを実行するために再びニューロンコアが必要であることを指定し、APIを公開します。

~$kubectl kustomize ~/environment/eks-workshop/modules/aiml/inferentia/inference \
| envsubst | kubectl apply -f-

再びKarpenterは、今回はニューロンコアが必要なinf2インスタンスが必要な保留中のポッドを検出します。そのため、KarpenterはInferentiaチップを搭載したinf2インスタンスを起動します。以下のコマンドを使用して、インスタンスのプロビジョニングを監視できます:

~$kubectl logs -l app.kubernetes.io/instance=karpenter -n kube-system -f | jq
...
{
  "level": "INFO",
  "time": "2024-09-19T18:53:34.266Z",
  "logger": "controller",
  "message": "launched nodeclaim",
  "commit": "6e9d95f",
  "controller": "nodeclaim.lifecycle",
  "controllerGroup": "karpenter.sh",
  "controllerKind": "NodeClaim",
  "NodeClaim": {
    "name": "aiml-v64vm"
  },
  "namespace": "",
  "name": "aiml-v64vm",
  "reconcileID": "7b5488c5-957a-4051-a657-44fb456ad99b",
  "provider-id": "aws:///us-west-2b/i-0078339b1c925584d",
  "instance-type": "inf2.xlarge",
  "zone": "us-west-2b",
  "capacity-type": "on-demand",
  "allocatable": {
    "aws.amazon.com/neuron": "1",
    "cpu": "3920m",
    "ephemeral-storage": "89Gi",
    "memory": "14162Mi",
    "pods": "58",
    "vpc.amazonaws.com/pod-eni": "18"
  }
}
...

推論ポッドはKarpenterによってプロビジョニングされたノードにスケジュールされるはずです。ポッドが準備完了の状態になっているか確認します:

注記

ノードをプロビジョニングし、EKSクラスターに追加してポッドを起動するまでに最大12分かかる場合があります。

~$kubectl -n aiml wait --for=condition=Ready --timeout=12m pod/inference

以下のコマンドを使用して、ポッドをスケジュールするためにプロビジョニングされたノードに関する詳細情報を取得できます:

~$kubectl get node -l karpenter.sh/nodepool=aiml -o jsonpath='{.items[0].status.capacity}' | jq .

この出力は、このノードが持つ容量を示しています:

{
"aws.amazon.com/neuron": "1",
"aws.amazon.com/neuroncore": "2",
"aws.amazon.com/neurondevice": "1",
"cpu": "4",
"ephemeral-storage": "104845292Ki",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "16009632Ki",
"pods": "58",
"vpc.amazonaws.com/pod-eni": "18"
}

このノードにはaws.amazon.com/neuronが1あることがわかります。Karpenterはポッドが要求したニューロンの数だけのノードをプロビジョニングしました。

推論を実行する

これは、Inferentia上のニューロンコアを使用して推論を実行するために使用するコードです:

~/environment/eks-workshop/modules/aiml/inferentia/inference/inference.py
import os
import time
import torch
import torch_neuronx
import json
import numpy as np

from urllib import request

from torchvision import models, transforms, datasets

## Create an image directory containing a small kitten
os.makedirs("./torch_neuron_test/images", exist_ok=True)
request.urlretrieve(
"https://raw.githubusercontent.com/awslabs/mxnet-model-server/master/docs/images/kitten_small.jpg",
"./torch_neuron_test/images/kitten_small.jpg",
)


## Fetch labels to output the top classifications
request.urlretrieve(
"https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json",
"imagenet_class_index.json",
)
idx2label = []

with open("imagenet_class_index.json", "r") as read_file:
class_idx = json.load(read_file)
idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))]

## Import a sample image and normalize it into a tensor
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

eval_dataset = datasets.ImageFolder(
os.path.dirname("./torch_neuron_test/"),
transforms.Compose(
[
transforms.Resize([224, 224]),
transforms.ToTensor(),
normalize,
]
),
)

image, _ = eval_dataset[0]
image = torch.tensor(image.numpy()[np.newaxis, ...])

## Load model
model_neuron = torch.jit.load("resnet50_neuron.pt")

## Predict
results = model_neuron(image)

# Get the top 5 results
top5_idx = results[0].sort()[1][-5:]

# Lookup and print the top 5 labels
top5_labels = [idx2label[idx] for idx in top5_idx]

print("Top 5 labels:\n {}".format(top5_labels))

このPythonコードは次のタスクを実行します:

  1. 小さな子猫の画像をダウンロードして保存します。
  2. 画像を分類するためのラベルを取得します。
  3. この画像をインポートし、テンソルに正規化します。
  4. 以前に作成したモデルをロードします。
  5. 子猫の画像に対して予測を実行します。
  6. 予測から上位5つの結果を取得し、コマンドラインに出力します。

このコードをポッドにコピーし、以前にアップロードしたモデルをダウンロードして、次のコマンドを実行します:

~$kubectl -n aiml cp ~/environment/eks-workshop/modules/aiml/inferentia/inference/inference.py inference:/
~$kubectl -n aiml exec inference -- pip install --upgrade boto3 botocore
~$kubectl -n aiml exec inference -- aws s3 cp s3://$AIML_NEURON_BUCKET_NAME/resnet50_neuron.pt ./
~$kubectl -n aiml exec inference -- python /inference.py
 
Top 5 labels:
 ['tiger', 'lynx', 'tiger_cat', 'Egyptian_cat', 'tabby']

出力として上位5つのラベルが返ってきます。ResNet-50の事前トレーニング済みモデルを使用して小さな子猫の画像に対して推論を実行しているので、これらの結果は予想通りです。パフォーマンスを向上させるための次のステップとして、独自の画像データセットを作成し、特定のユースケース向けに独自のモデルをトレーニングすることも可能です。これにより予測結果を向上させることができるでしょう。

これでAmazon EKSでAWS Inferentiaを使用するこのラボは終了です。