Servez 3,000 50 modèles d'apprentissage en profondeur sur Amazon EKS avec AWS Inferentia pour moins de XNUMX $ de l'heure

Nœud source: 1146468

De plus en plus de clients ressentent le besoin de créer des pipelines d'inférence d'apprentissage automatique (ML) plus grands, évolutifs et plus rentables dans le cloud. En dehors de ces conditions préalables de base, les exigences des pipelines d’inférence ML en production varient en fonction du cas d’utilisation métier. Une architecture d'inférence typique pour des applications telles que les moteurs de recommandation, l'analyse des sentiments et le classement des annonces doit servir un grand nombre de modèles, avec un mélange de modèles classiques de ML et d'apprentissage profond (DL). Chaque modèle doit être accessible via un point de terminaison d'interface de programmation d'application (API) et être capable de répondre dans les limites d'un budget de latence prédéfini à partir du moment où il reçoit une requête.

Dans cet article, nous décrivons une architecture d'inférence, développée en collaboration avec l'équipe Commerce Einstein de Salesforce, basée sur Service Amazon Elastic Kubernetes (Amazon EKS) pour non seulement répondre aux prérequis de base, mais également regrouper des milliers de modèles PyTorch DL uniques dans une architecture évolutive. Nous explorons un mélange de Cloud de calcul élastique Amazon (Amazon EC2) (c5, g4dn, Inf1) pour développer une conception optimale du point de vue du coût et des performances. Pour répondre à ces exigences, nous construisons le service d'inférence DL sur Amazon EKS à l'aide API rapide, un serveur API léger et efficace basé sur Python, et développer une stratégie de regroupement de modèles pour partager efficacement les ressources de calcul et de mémoire entre les modèles. Pour tester en charge l'architecture, nous utilisons un modèle PyTorch open source de traitement du langage naturel (NLP) de huggingface.com (bert-base-cased, environ 800 Mo) et simulez des milliers de clients envoyant des requêtes simultanées au pool de services. Nous utilisons Inférence AWS, la puce ML personnalisée sur les instances Inf1, pour regrouper et servir 3,000 50 modèles PyTorch uniques tout en maintenant le coût inférieur à 70 $/heure (tarification à la demande), avec une latence aller-retour de 90 millisecondes (P100) par rapport à notre objectif de XNUMX millisecondes. Vous pouvez étendre cette approche d'architecture et d'optimisation à n'importe quel modèle DL personnalisé.

Vue d'ensemble de la solution

Ce qui suit est une architecture simple, évolutive et hautement disponible basée sur une infrastructure Amazon EKS standard qui peut être déployée dans les zones de disponibilité.

Le cluster Amazon EKS comporte plusieurs groupes de nœuds, avec une famille d'instances EC2 par groupe de nœuds. Chaque groupe de nœuds peut prendre en charge différents types d'instances, tels que CPU (c5), GPU (g4dn) et AWS Inferentia (Inf1), et peut regrouper plusieurs modèles par instance pour maximiser le nombre de modèles servis. Ensuite, l'application de service de modèle et les dépendances du framework DL sont conteneurisées, et ces images de conteneur sont stockées sur Registre des conteneurs élastiques Amazon (AmazonECR). Les images de conteneur sont déployées sur le cluster à l'aide de manifestes de déploiement et de service, personnalisés pour chaque famille d'instances. L'application de diffusion de modèles télécharge les artefacts de modèle à partir de Service de stockage simple Amazon (Amazon S3) lors de l'initialisation du serveur, ce qui réduit la taille des images de conteneur sur Amazon ECR et dissocie les données du modèle de la définition du service.

Des services comme cluster-autoscaler, horizontal-pod-autoscaler, aws-load-balancer-controller, metrics-server, nginx-ingress-controller, neuron-device-plugin-daemonsetet une nvidia-device-plugin-daemonset sont déployés sur le cluster selon les besoins. Cette conception s'appuie sur les coredns Kubernetes pour la résolution de noms des points de terminaison de service au sein du cluster. Chaque modèle est adressable via une combinaison de nom DNS et de nom de modèle. Par exemple, http://<model server ID>.<name space>.svc.cluster.local:8080/predictions/<model id>.

Pour la personnalisation des noms DNS, nous pouvons utiliser un manifeste d'entrée.

L'architecture est configurée pour s'exécuter en cinq étapes simples : créer, tracer, compresser, déployer et tester. Le référentiel de code est accessible dans le GitHub dépôt.

  1. L'étape de génération crée le conteneur de base pour le type d'instance sélectionné, en installant toutes les couches de base nécessaires dans le conteneur.
  2. L'étape de trace compile le modèle. Pour maximiser les performances sur les instances GPU, les modèles ont été sérialisés au format TorchScript à l'aide des bibliothèques PyTorch (torch.jit.trace). Pour les instances Inf1, le Neurone AWS L'intégration native du SDK avec PyTorch a été exploitée pour compiler les modèles au format Neuron bfloat16. Voici l'extrait de code permettant de tracer un modèle qui s'exécute dans bfloat16 sur AWS Inferentia ou Automatic Mixed Precision (AMP) sur une instance GPU :
print('nTracing model ...')
example_inputs = ( torch.cat([inputs['input_ids']] * batch_size,0), torch.cat([inputs['attention_mask']] * batch_size,0)
)
os.makedirs(f'traced-{model_name}', exist_ok=True)
torch.set_num_threads(6)
if 'inf' in processor: model_traced = torch.neuron.trace(model, example_inputs, verbose=1, compiler_workdir=f'./traced-{model_name}/compile_wd_{processor}_bs{batch_size}_seq	{sequence_length}_pc{pipeline_cores}', compiler_args = ['--neuroncore-pipeline-cores', str(pipeline_cores)])
else: model_traced = torch.jit.trace(model, example_inputs)

  1. L'étape pack emballe le modèle dans un conteneur avec FastAPI, ce qui permet également de regrouper plusieurs modèles dans le même conteneur.
  2. L'étape de déploiement exécute le modèle dans le runtime configuré (tel que Kubernetes ou Docker) et facilite la gestion du cycle de vie complet des conteneurs du serveur de modèles. L'extrait de code suivant définit les options d'exécution et lance le conteneur dans un environnement d'exécution configuré :
echo "Runtime: $runtime"
echo "Processor: $processor" if [ "$runtime" == "docker" ]; then server=0 while [ $server -lt $num_servers ]; do run_opts="--name ${app_name}-${server} -e NUM_MODELS=$num_models -e POSTPROCESS=$postprocess -e QUIET=$quiet -P" if [ "$processor" == "gpu" ]; then run_opts="--gpus 0 ${run_opts}" fi CMD="docker run -d ${run_opts} ${registry}${model_image_name}${model_image_tag}" echo "$CMD" eval "$CMD" server=$((server+1)) done
elif [ "$runtime" == "kubernetes" ]; then kubectl create namespace ${namespace} --dry-run=client -o yaml | kubectl apply -f - ./generate-yaml.sh kubectl apply -f ${app_dir}
else echo "Runtime $runtime not recognized"
fi

  1. La dernière étape exécute des tests sur les serveurs de modèles déployés dans l'environnement d'exécution.

Emballage de bacs modèles ML

Le regroupement des modèles PyTorch ML sur les instances EC2 est essentiel pour partager efficacement les ressources de calcul et de mémoire entre les modèles. La tâche consistant à emballer les modèles peut être formulée et résolue comme un problème de sac à dos 0-1 en utilisant l'optimisation combinatoire. Ce qui suit est la formulation mathématique du conditionnement en bac ; nnumériques jumeaux (digital twin models) est soumis à une contrainte de mémoire processeur maximale (Mmax) et l'utilisation (Cmax). Cette approche recommande un regroupement optimal des modèles sur un ensemble minimal d'instances EC2.

Le nombre de bacs est surdimensionné pour initialiser le problème avec une solution triviale d'un modèle par bac et élagué pour atteindre l'objectif avec un nombre minimal de bacs.

La visualisation suivante montre un exemple d'allocation de regroupement de bacs pour 78 modèles, chacun avec des exigences de mémoire et de calcul uniques. Dans cet exemple, 78 modèles ont été regroupés dans 23 instances (g4dn, Inf1) avec une mémoire maximale cible spécifiée (7.4 Go) et une capacité de calcul (83 %). La légende des couleurs indique l'index du modèle.

Nous pouvons utiliser la méthode précédente pour regrouper de manière optimale les modèles entre les instances. Le tableau suivant résume les résultats du regroupement de casiers pour les instances Inf1 et g4dn. Nous avons choisi ces familles d'instances car le modèle NLP basé sur un transformateur nécessite une accélération matérielle pour atteindre la latence attendue. Nous avons pu regrouper plus de modèles dans Inf1.6xlarge (mémoire de 48 Go) par rapport à g4dn.12xlarge (mémoire de 192 Go) car la capacité de diffusion automatique du compilateur Neuron convertit automatiquement les modèles FP32 en bfloat 16 bits pour maximiser le débit.

Modèle Instance EC2 Type de serveur Nombre de modèles emballés par instance Prix ​​par instance
(Sur demande), $/h
Prix ​​par heure modèle
($)
bert-base-case inf1.2xlarge API rapide 24 0.362 0.015
bert-base-case g4dn.xlarge API rapide 18 0.526 0.029
bert-base-case inf1.xlarge API rapide 11 0.228 0.020
bert-base-case inf1.6xlarge API rapide 76 1.180 0.015
bert-base-case g4dn.12xlarge API rapide 72 3.912 0.054

Méthodologie de test et observations

Pour charger les tests à grande échelle, nous avons simulé plus de 40 clients envoyant des requêtes simultanées au pool de tests (chargement à partir de plusieurs clients). Charger le système avec davantage de requêtes utilisateur augmente le débit au détriment de la latence ; les tests ont été conçus pour balayer la courbe débit-latence afin de trouver des points de données avec une utilisation optimisée des ressources. Nous avons mesuré le débit et la latence (P50, P90, P95) et résumé les résultats selon quatre mesures : latence, débit (inférences par seconde), nombre de modèles servis par instance et coût. De plus, nous avons créé des tests pour simuler des requêtes mono-séquentielles et mono-aléatoires en utilisant curl pour envoyer une requête GET ou POST à ​​chaque modèle du pool de test. Le but de ces expériences était de mesurer la latence optimale à laquelle on peut s’attendre, comme référence.

Nous avons mené plusieurs expériences pour trouver le regroupement de modèles optimal sur des ensembles minimaux d'instances EC2 qui entraînerait les performances les plus élevées au coût le plus bas. Le tableau suivant résume certains de ces résultats de tests. Les meilleurs résultats ont été observés lors de l'utilisation de 40 instances Inf1.6xl avec la mise en cache DNS activée, desservant 3,040 6,230 modèles avec un débit de 66 90 requêtes par seconde en 47.2 millisecondes (latence P32) pour un coût de 1.6 $/heure (à la demande). Le meilleur déploiement d'instances mixtes, utilisant 21 instances inf4xl et 12 g3,048dn.248xl, a abouti à 119.91 2 modèles servis, mais avec un débit beaucoup plus faible à XNUMX requêtes par seconde avec un coût horaire accru de XNUMX $/heure. Bien que nous n'ayons pas utilisé les instances Spot ECXNUMX comme levier d'optimisation des coûts dans cette architecture, nous vous recommandons fortement d'utiliser Spot si votre charge de travail d'inférence est flexible dans le temps et tolérante aux pannes. Le tableau suivant résume nos observations pour tous les types d'instances.

Exp. # Cas
(nombre x type)
Des modèles photo (nombre) Réponse séquentielle (SP) Réponse aléatoire (SP) Cadence de production (demande/s) Latence avec charge P90 (SP) Coût à la demande ($/h)
1 3 x inf1.6xl 144 21 – 32 21 – 30 142 57 3.54
2 5 x inf1.6xl 240 23 – 35 21 – 35 173 56 5.9
3 21 x inf1.6xl 1008 23 – 39 23 – 35 218 24 24.78
4 32 x inf1.6xl 1536 26 – 33 25 – 37 217 23 37.76
5 4 x g4dn.12xl 288 27 – 34 28 – 37 178 30 15.64
6 14 x g4dn.12xl 1008 26 – 35 31 – 41 154 30 54.76
7 32 x inf1.6xl +
21 x g4dn.12xl
3048 27 – 35 24 – 45 248 28 119.91
8 40 x inf1.6xl 3002 24 – 31 25 – 38 1536 33 47.2
9 40 x inf1.6xl
(Avec mise en cache DNS)
3040 24 – 31 25 – 38 6230 66 47.2

Conclusion

Grâce à cette architecture évolutive, nous avons pu étendre l'inférence sur 3,000 100 modèles PyTorch, atteignant une latence cible de 50 millisecondes, tout en maintenant les coûts sous la barre des 2 $/heure (à la demande) en optimisant les coûts en regroupant efficacement les modèles sur un ensemble minimal. des instances EC1. Parmi tous les tests, les instances InfXNUMX ont généré le débit le plus élevé, le coût le plus bas, le temps de réponse le plus rapide et le taux de conditionnement des bacs maximal par rapport aux autres instances. Les clients AWS aiment Snap, Airbnb, Sprinklr et bien d'autres utilisent AWS Inferentia pour obtenir les performances les plus élevées et les coûts les plus bas sur une variété de déploiements. Bien que le modèle DL testé nécessite l'utilisation de l'accélération matérielle sur les types d'instances Inf1 et g4dn, vous pouvez faire correspondre d'autres types de modèles avec différents types d'instances (Inf1, CPU, GPU) et des modèles de packs bin en conséquence en utilisant la méthodologie décrite.

Apprenez-en davantage sur la puce AWS Inferentia et Instances EC2 Inf1 pour commencer à exécuter vos propres pipelines ML personnalisés sur AWS Inferentia à l'aide de l'outil SDK Neuron.


À propos des auteurs

Alex Yankoulski est un architecte de solutions principal spécialisé dans les charges de travail autonomes utilisant des conteneurs. Alex est un architecte d'infrastructures et de logiciels full-stack pratique et a construit des plates-formes utilisant Docker pour aider à accélérer le rythme de l'innovation en appliquant les technologies de conteneurs aux problèmes d'ingénierie, de science des données et d'IA. Au cours des 10 dernières années, il a travaillé à la lutte contre le changement climatique, à la démocratisation de l'IA et du ML et à rendre les voyages plus sûrs, les soins de santé meilleurs et l'énergie plus intelligente.

Mahadevan Balasubramaniam est un architecte de solutions principal pour l'informatique autonome avec près de 20 ans d'expérience dans le domaine de l'apprentissage profond infusé par la physique, créant et déployant des jumeaux numériques pour les systèmes industriels à grande échelle. Mahadevan a obtenu son doctorat en génie mécanique du Massachusetts Institute of Technology et compte plus de 25 brevets et publications à son actif.

Sundar Ranganathan est le responsable du développement commercial, ML Frameworks au sein de l'équipe Amazon EC2. Il se concentre sur les charges de travail ML à grande échelle sur les services AWS comme Amazon EKS, Amazon ECS, Elastic Fabric Adapter, AWS Batch et Amazon SageMaker. Son expérience comprend des rôles de direction dans la gestion et le développement de produits chez NetApp, Micron Technology, Qualcomm et Mentor Graphics.

Josué Corréa est un membre principal du personnel technique de Salesforce travaillant au sein de l'équipe Commerce Einstein. Joshua a une profonde passion pour la création d'infrastructures évolutives, résilientes et rentables pour l'apprentissage automatique. Joshua aime travailler à l'intersection du génie logiciel et de la science des données pour mettre en production des modèles de pointe.

Source : https://aws.amazon.com/blogs/machine-learning/serve-3000-deep-learning-models-on-amazon-eks-with-aws-inferentia-for-under-50-an-hour/

Horodatage:

Plus de Blog sur l'apprentissage automatique AWS