Table of Contents
Les modèles d’apprentissage profond jouent un rôle essentiel dans les pipelines algorithmiques, qui sont des flux de travail traitant des entrées à travers une série d’algorithmes pour produire des sorties. Ces modèles AI ont des exigences de ressources très différentes de leurs homologues classiques, notamment une utilisation plus élevée de la mémoire, une dépendance à des accélérateurs matériels spécialisés et des demandes de calcul accrues.
Défis de traitement des entrées à grande échelle
Dans cet article, nous abordons un défi courant : le traitement efficace des entrées à grande échelle via des pipelines algorithmiques intégrant des modèles d’apprentissage profond. Une solution typique consiste à exécuter plusieurs tâches indépendantes, chacune responsable du traitement d’une seule entrée. Cette configuration est souvent gérée avec des frameworks d’orchestration de tâches. Cependant, lorsque des modèles d’apprentissage profond sont impliqués, cette approche peut s’avérer inefficace, car charger et exécuter le même modèle dans chaque processus individuel peut conduire à une contention des ressources et à des limitations d’échelle.
Alors que les modèles AI deviennent de plus en plus courants dans les pipelines algorithmiques, il est crucial de revisiter la conception de ces solutions.
Avantages du serveur d’inférence centralisé
Nous évaluons ici les avantages de l’inférence centralisée, où un serveur d’inférence dédié gère les demandes de prédiction provenant de plusieurs tâches parallèles. Nous définissons un expérience avec un pipeline de traitement d’images basé sur un classificateur d’images ResNet-152, traitant 1 000 images individuelles.
Nous comparons la performance en termes de temps d’exécution et d’utilisation des ressources entre deux implémentations :
- Inférence décentralisée : chaque tâche charge et exécute le modèle de manière indépendante.
- Inférence centralisée : toutes les tâches envoient des demandes d’inférence à un serveur d’inférence dédié.
Expérience réalisée
Nous avons mené nos expériences sur une instance Amazon EC2 c5.2xlarge, disposant de 8 vCPUs et 16 GiB de mémoire, en utilisant une image de machine virtuel PyTorch Deep Learning. Nous avons activé l’environnement PyTorch avec la commande appropriée.
Étape 1 : Création d’un point de contrôle de modèle TorchScript
Nous créons un point de contrôle pour le modèle ResNet-152 et le sérialisons à l’aide de TorchScript :
import torch
from torchvision.models import resnet152, ResNet152_Weights
model = resnet152(weights=ResNet152_Weights.DEFAULT)
model = torch.jit.script(model)
model.save("resnet-152.pt")
Étape 2 : Fonction d’inférence du modèle
Notre fonction d’inférence exécute les étapes suivantes :
- Charger le modèle ResNet-152.
- Charger une image d’entrée.
- Prétraiter l’image pour correspondre au format d’entrée attendu par le modèle.
- Exécuter l’inférence pour classifier l’image.
- Post-traiter la sortie du modèle pour retourner les cinq meilleures prédictions d’étiquettes.
Étape 3 : Exécution de tâches d’inférence parallèles
Nous définissons une fonction qui démarre des processus parallèles, chacun traitant une entrée d’image unique. Cette fonction gère le nombre total d’images à traiter et le maximum de tâches concurrentes.
def process_image(image_id):
print(f"Processing image {image_id} (PID: {os.getpid()})")
predict(image_id)
Estimations des processus maximum
Bien que le nombre optimal de processus concurrents soit déterminé empiriquement, nous pouvons estimer une limite supérieure basée sur la mémoire système et la taille du fichier de point de contrôle.
Les résultats de l’expérience montrent que la saturation de la mémoire se produit à 50 processus concurrents, alors que le débit maximal est atteint à 8 tâches concurrentes.
Les inefficacités de l’exécution indépendante des modèles
Exécuter des tâches parallèles qui chargent et exécutent chacune le modèle de manière indépendante crée des inefficacités significatives :
- Chaque processus doit allouer des ressources mémoire appropriées pour stocker sa propre copie du modèle AI.
- Les modèles AI sont gourmands en calcul ; les exécuter dans plusieurs processus parallèles peut mener à une contention des ressources.
- Le chargement de fichiers de points de contrôle et l’initialisation du modèle dans chaque processus ajoutent des frais généraux.
Une alternative plus efficace consiste à centraliser l’exécution d’inférence à l’aide d’un serveur d’inférence dédié, ce qui élimine le chargement redondant du modèle et réduit l’utilisation globale des ressources système.
Configuration de TorchServe
Nous pouvons emballer le modèle et ses fichiers associés dans un fichier archive « *.mar* », le format requis pour le déploiement sur TorchServe.
mkdir model_store
torch-model-archiver \
--model-name resnet-152 \
--serialized-file resnet-152.pt \
--handler image_classifier \
--version 1.0 \
--export-path model_store
Configuration de TorchServe
Nous créons un fichier config.properties pour définir le fonctionnement de TorchServe :
model_store=model_store
load_models=resnet-152.mar
default_workers_per_model=1
job_queue_size=100
Résultats obtenus
En utilisant un serveur d’inférence centralisé, nous avons non seulement augmenté le débit global de plus du double, mais également libéré des ressources CPU significatives pour d’autres tâches de calcul.
Les résultats des tests montrent également des améliorations considérables lors de l’activation de l’inférence par lots, augmentant le débit de 26,5 %. De plus, la configuration de plusieurs travailleurs d’inférence a permis une amélioration de 36 % du débit.
Prochaines étapes
Nous avons démontré les avantages d’une solution d’inférence centralisée et pouvons explorer plusieurs façons d’optimiser cette configuration. Cela comprend l’utilisation de gestionnaires d’inférence personnalisés et des configurations avancées du serveur d’inférence, entre autres.