Serveur d'impression

Amazon EKS prend désormais en charge les instances EC2 Inf1: idk.dev – Serveur d’impression

Par Titanfall , le 17 juin 2020 - 10 minutes de lecture

Amazon Elastic Kubernetes Service (EKS) est rapidement devenu un choix de premier plan pour les charges de travail d'apprentissage automatique. Il combine l'agilité des développeurs et l'évolutivité de Kubernetes, avec la large sélection de types d'instances Amazon Elastic Compute Cloud (EC2) disponibles sur AWS, tels que les familles C5, P3 et G4.

À mesure que les modèles deviennent plus sophistiqués, l'accélération matérielle est de plus en plus nécessaire pour fournir des prévisions rapides à haut débit. Aujourd'hui, nous sommes très heureux d'annoncer que les clients AWS peuvent désormais utiliser les instances Amazon EC2 Inf1 sur Amazon Elastic Kubernetes Service, pour des performances élevées et le coût de prédiction le plus bas dans le cloud.

Une introduction aux instances EC2 Inf1
Les instances Inf1 ont été lancées lors d'AWS re: Invent 2019. Elles sont alimentées par AWS Inferentia, une puce personnalisée construite à partir de zéro par AWS pour accélérer les charges de travail d'inférence d'apprentissage automatique.

Les instances Inf1 sont disponibles en plusieurs tailles, avec 1, 4 ou 16 puces Inferentia AWS, avec jusqu'à 100 Gbps de bande passante réseau et jusqu'à 19 Gbps de bande passante EBS. Une puce AWS Inferentia contient quatre NeuronCores. Chacun met en œuvre un moteur de multiplication de matrice de réseau systolique hautes performances, qui accélère massivement les opérations d'apprentissage en profondeur typiques telles que la convolution et les transformateurs. Les NeuronCores sont également équipés d'un grand cache sur puce, ce qui permet de réduire les accès à la mémoire externe, ce qui économise du temps d'E / S dans le processus. Lorsque plusieurs puces AWS Inferentia sont disponibles sur une instance Inf1, vous pouvez partitionner un modèle entre elles et le stocker entièrement dans la mémoire cache. Alternativement, pour servir des prédictions multimodèles à partir d'une seule instance Inf1, vous pouvez partitionner les NeuronCores d'une puce AWS Inferentia sur plusieurs modèles.

Compilation de modèles pour les instances EC2 Inf1
Pour exécuter des modèles d'apprentissage automatique sur des instances Inf1, vous devez les compiler en une représentation matériellement optimisée à l'aide du kit AWS Neuron SDK. Tous les outils sont facilement disponibles sur l'AWS Deep Learning AMI, et vous pouvez également les installer sur vos propres instances. Vous trouverez des instructions dans la documentation Deep Learning AMI, ainsi que des didacticiels pour TensorFlow, PyTorch et Apache MXNet dans le référentiel AWS Neuron SDK.

Dans la démonstration ci-dessous, je vais vous montrer comment déployer un modèle optimisé pour Neuron sur un cluster EKS d'instances Inf1, et comment servir des prédictions avec TensorFlow Serving. Le modèle en question est le BERT, un modèle de pointe pour les tâches de traitement du langage naturel. Il s'agit d'un énorme modèle avec des centaines de millions de paramètres, ce qui en fait un excellent candidat pour l'accélération matérielle.

Création d'un cluster EKS d'instances EC2 Inf1
Tout d'abord, construisons un cluster avec deux instances inf1.2xlarge. Je peux facilement le faire avec eksctl, l'outil en ligne de commande pour provisionner et gérer les clusters EKS. Vous pouvez trouver les instructions d'installation dans la documentation EKS.

Voici le fichier de configuration de mon cluster. Eksctl détecte que je lance un groupe de nœuds avec un type d'instance Inf1 et démarre vos nœuds de travail à l'aide de l'AMI accélérée optimisée EKS.

apiVersion: eksctl.io/v1alpha5
type: ClusterConfig
métadonnées:
  nom: cluster-inf1
  région: us-west-2
nodeGroups:
  - nom: ng1-public
    instanceType: inf1.2xlarge
    minSize: 0
    maxSize: 3
    souhaitéCapacité: 2
    ssh:
      permettre: vrai

Ensuite, j'utilise eksctl pour créer le cluster. Ce processus prendra environ 10 minutes.

$ eksctl create cluster -f inf1-cluster.yaml

Eksctl installe automatiquement le plug-in de périphérique Neuron dans votre cluster. Ce plugin annonce les appareils Neuron au planificateur Kubernetes, qui peut être demandé par des conteneurs dans une spécification de déploiement. Je peux vérifier avec kubectl que le conteneur de plug-in de périphérique fonctionne correctement sur les deux instances Inf1.

$ kubectl get pods -n kube-system
NOM READY STATUS RESTARTS AGE
aws-node-tl5xv 1/1 Fonctionnement 0 14h
aws-node-wk6qm 1/1 Fonctionnement 0 14h
coredns-86d5cbb4bd-4fxrh 1/1 Fonctionnement 0 14h
coredns-86d5cbb4bd-sts7g 1/1 Fonctionnement 0 14h
kube-proxy-7px8d 1/1 Fonctionnement 0 14h
kube-proxy-zqvtc 1/1 Fonctionnement 0 14h
neuron-device-plugin-daemonset-888j4 1/1 Fonctionnement 0 14h
neuron-device-plugin-daemonset-tq9kc 1/1 Fonctionnement 0 14h

Ensuite, je définis les informations d'identification AWS dans un secret Kubernetes. Ils me permettront de récupérer mon modèle BERT stocké dans S3. Veuillez noter que les deux clés doivent être codées en base64.

apiVersion: v1
genre: Secret
métadonnées:
  nom: aws-s3-secret
type: Opaque
Les données:
  AWS_ACCESS_KEY_ID:  
  AWS_SECRET_ACCESS_KEY: 

Enfin, je stocke ces informations d'identification sur le cluster.

$ kubectl apply -f secret.yaml

Le cluster est correctement configuré. Maintenant, construisons un conteneur d’application stockant une version Neuron de TensorFlow Serving.

Création d'un conteneur d'application pour TensorFlow Serving
Le Dockerfile est très simple. Nous partons d'une image de base d'Amazon Linux 2. Ensuite, nous installons l'AWS CLI et le package TensorFlow Serving disponibles dans le référentiel Neuron.

D'AMAZONLINUX: 2
RUN yum install -y awscli
RUN echo $ '[neuron] n
nom = Neuron YUM Repository n
baseurl = https: //yum.repos.neuron.amazonaws.com n
enabled = 1 '> /etc/yum.repos.d/neuron.repo
RUN rpm --import https://yum.repos.neuron.amazonaws.com/GPG-PUB-KEY-AMAZON-AWS-NEURON.PUB
RUN yum install -y tensorflow-model-server-neuron

Je crée l'image, crée un référentiel Amazon Elastic Container Registry et envoie l'image dessus.

$ docker build. -f Dockerfile -t tensorflow-model-server-neuron
$ docker tag IMAGE_NAME 123456789012.dkr.ecr.us-west-2.amazonaws.com/inf1-demo
$ aws ecr create-repository --repository-name inf1-demo
$ docker push 123456789012.dkr.ecr.us-west-2.amazonaws.com/inf1-demo

Notre conteneur d'application est prêt. Maintenant, définissons un service Kubernetes qui utilisera ce conteneur pour servir les prédictions BERT. J'utilise un modèle qui a déjà été compilé avec le SDK Neuron. Vous pouvez compiler le vôtre en utilisant les instructions disponibles dans le référentiel Neuron SDK.

Déployer BERT en tant que service Kubernetes
Le déploiement gère deux conteneurs: le conteneur d'exécution Neuron et mon conteneur d'application. Le runtime Neuron fonctionne comme une image de conteneur sidecar et est utilisé pour interagir avec les puces AWS Inferentia. Au démarrage, ce dernier configure l'AWS CLI avec les informations d'identification de sécurité appropriées. Ensuite, il récupère le modèle BERT de S3. Enfin, il lance TensorFlow Serving, chargeant le modèle BERT et attendant les demandes de prédiction. À cet effet, les ports HTTP et grpc sont ouverts. Voici le manifeste complet.

genre: Service
apiVersion: v1
métadonnées:
  nom: eks-neuron-test
  Étiquettes:
    application: eks-neuron-test
spec:
  ports:
  - nom: http-tf-servant
    port: 8500
    targetPort: 8500
  - nom: grpc-tf-servant
    port: 9000
    targetPort: 9000
  sélecteur:
    application: eks-neuron-test
    rôle: maître
  type: ClusterIP
---
type: Déploiement
apiVersion: apps / v1
métadonnées:
  nom: eks-neuron-test
  Étiquettes:
    application: eks-neuron-test
    rôle: maître
spec:
  répliques: 2
  sélecteur:
    matchLabels:
      application: eks-neuron-test
      rôle: maître
  modèle:
    métadonnées:
      Étiquettes:
        application: eks-neuron-test
        rôle: maître
    spec:
      volumes:
        - nom: chaussette
          emptyDir: 
      conteneurs:
      - nom: eks-neuron-test
        image: 123456789012.dkr.ecr.us-west-2.amazonaws.com/inf1-demo:latest
        commander: ["/bin/sh","-c"]
        args:
          - "mkdir ~ / .aws / &&
           écho '[eks-test-profile]'> ~ / .aws / informations d'identification &&
           echo AWS_ACCESS_KEY_ID = $ AWS_ACCESS_KEY_ID >> ~ / .aws / credentials &&
           echo AWS_SECRET_ACCESS_KEY = $ AWS_SECRET_ACCESS_KEY >> ~ / .aws / credentials;
           / usr / bin / aws --profile eks-test-profile s3 sync s3: // jsimon-inf1-demo / bert / tmp / bert &&
           / usr / local / bin / tensorflow_model_server_neuron --port = 9000 --rest_api_port = 8500 --model_name = bert_mrpc_hc_gelus_b4_l24_0926_02 --model_base_path = / tmp / bert / ""
        ports:
        - containerPort: 8500
        - containerPort: 9000
        imagePullPolicy: Toujours
        env:
        - nom: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              clé: AWS_ACCESS_KEY_ID
              nom: aws-s3-secret
        - nom: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              clé: AWS_SECRET_ACCESS_KEY
              nom: aws-s3-secret
        - nom: NEURON_RTD_ADDRESS
          valeur: unix: /sock/neuron.sock

        Ressources:
          limites:
            cpu: 4
            mémoire: 4Gi
          demande:
            cpu: "1"
            mémoire: 1Gi
        volumeMounts:
          - nom: chaussette
            mountPath: / sock

      - nom: neuron-rtd
        image: 790709498068.dkr.ecr.us-west-2.amazonaws.com/neuron-rtd:1.0.6905.0
        securityContext:
          capacités:
            ajouter:
            - SYS_ADMIN
            - IPC_LOCK

        volumeMounts:
          - nom: chaussette
            mountPath: / sock
        Ressources:
          limites:
            énormes pages-2Mi: 256Mi
            aws.amazon.com/neuron: 1
          demande:
            mémoire: 1024Mi

j'utilise kubectl pour créer le service.

$ kubectl create -f bert_service.yml

Quelques secondes plus tard, les pods sont opérationnels.

$ kubectl get pods
NOM READY STATUS RESTARTS AGE
eks-neuron-test-5d59b55986-7kdml 2/2 Fonctionnement 0 14h
eks-neuron-test-5d59b55986-gljlq 2/2 Fonctionnement 0 14h

Enfin, je redirige le port de service 9000 vers le port local 9000, pour permettre à mon client de prédiction de se connecter localement.

$ kubectl port-forward svc / eks-neuron-test 9000: 9000 &

Maintenant, tout est prêt pour la prédiction, alors invoquons le modèle.

Prédire avec BERT sur EKS et Inf1
Le fonctionnement interne du BERT dépasse le cadre de ce billet. Ce modèle particulier attend une séquence de 128 jetons, codant les mots de deux phrases que nous aimerions comparer pour l'équivalence sémantique.

Ici, je ne suis intéressé que par la mesure de la latence des prédictions, donc les données factices sont bonnes. Je construis 100 requêtes de prédiction stockant une séquence de 128 zéros. Je les envoie au point de terminaison TensorFlow Serving via grpc et je calcule le temps de prédiction moyen.

import numpy as np
importer grpc
importer tensorflow en tant que tf
à partir de tensorflow_serving.apis import predict_pb2
de tensorflow_serving.apis import prediction_service_pb2_grpc
temps d'importation

si __name__ == '__main__':
    channel = grpc.insecure_channel ('localhost: 9000')
    stub = prediction_service_pb2_grpc.PredictionServiceStub (canal)
    request = predite_pb2.PredictRequest ()
    request.model_spec.name = 'bert_mrpc_hc_gelus_b4_l24_0926_02'
    i = np.zeros ([1, 128], dtype = np.int32)
    request.inputs['input_ids'].CopyFrom (tf.contrib.util.make_tensor_proto (i, forme = i.shape))
    request.inputs['input_mask'].CopyFrom (tf.contrib.util.make_tensor_proto (i, forme = i.shape))
    request.inputs['segment_ids'].CopyFrom (tf.contrib.util.make_tensor_proto (i, forme = i.shape))

    latences = []
    pour i dans la plage (100):
        start = time.time ()
        result = stub.Predict (demande)
        latencies.append (time.time () - start)
        print ("Inférence réussie: ". format (i))
    print ("Ran  infère avec succès. Latency average = ". format (len (latences), np.average (latences)))

En moyenne, la prédiction a pris 5,92 ms. En ce qui concerne BERT, c'est plutôt bien!

A réussi 100 inférences. Latence moyenne = 0,05920819044113159

Dans la vie réelle, nous serions certainement en train de regrouper les demandes de prédiction afin d'augmenter le débit. Si nécessaire, nous pourrions également évoluer vers de plus grandes instances Inf1 prenant en charge plusieurs puces Inferentia, et offrir encore plus de performances de prédiction à faible coût.

Commencer
Les utilisateurs de Kubernetes peuvent se déployer Amazon Elastic Compute Cloud (EC2) Instances Inf1 sur Amazon Elastic Kubernetes Service aujourd'hui dans le États-Unis Est (Virginie du Nord) et Ouest américain (Oregon) Régions. À mesure que le déploiement d'Inf1 progresse, vous pourrez les utiliser avec Amazon Elastic Kubernetes Service dans davantage de régions.

Essayez-le et envoyez-nous vos commentaires via vos contacts de support AWS habituels, sur le forum AWS pour Amazon Elastic Kubernetes Service, ou sur la feuille de route des conteneurs sur Github.

– Julien

Click to rate this post!
[Total: 0 Average: 0]

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.