BERT mange votre argent : quantification et ONNXRuntime pour économiser de l'argent

Les contributeurs
Mathias Leys
Ingénieur en machine learning
Aucun élément trouvé.
S'abonner à la newsletter
Partager cet article

En 2020, nous avons formé et mis en libre accès le premier modèle néerlandais GPT2, dans différentes tailles. Bien entendu, nous avons voulu partager cette expérience avec le monde entier en mettant à disposition les modèles, le code et une belle application qui illustre son utilisation.

Mais cette belle application a un coût, littéralement...

En l'état : Le modèle HuggingFace au service d'une application Python

Actuellement, un modèle HF est hébergé dans une application Python Flask, qui utilise l'API de pipeline de la bibliothèque HF.

Un microservice de routage dirige les utilisateurs vers le microservice de desserte de modèle approprié en fonction de la demande de l'utilisateur, à savoir s'il souhaite s'adresser au modèle GPT2-small de 117M de paramètres ou au modèle GPT2-medium de 345M de paramètres.

PS : si vous êtes curieux de savoir comment nous avons formé ce modèle néerlandais GPT2 : nous l'avons parfaitement décrit (si nous le disons nous-mêmes) dans ce blogpost. Si vous voulez vous amuser avec ces modèles néerlandais, vous pouvez les trouver sur notre page HF Hub.

L'application finale destinée à l'utilisateur se présente comme suit :

Essayez-le vous-même sur le site https://gpt2.ml6.eu/nl

La configuration actuelle présente toutefois quelques difficultés :

Les réponses prennent un certain temps à être générées, en particulier avec le modèle de taille moyenne, ce qui réduit l'expérience de l'utilisateur.

Deuxièmement, le conteneur est assez grand en raison des modèles de grande taille :

  • l'échelonner automatiquement à zéro pour réduire les coûts, mais avoir un temps de démarrage important à partir d'un démarrage à froid
  • le laisser fonctionner en permanence, en brûlant de l'argent

Dans cet article, nous allons donc améliorer ce composant de service de modèle en le quantifiant pour le rendre plus fluide, sans perdre trop de qualité expressive.

Quantification pour réduire l'empreinte

Nous n'allons pas entrer dans les détails de la quantification. Si vous voulez en savoir plus, nous avons écrit un article de blog sur ce sujet et sur d'autres aspects de l'efficacité des modèles ici.

TDLR: en réduisant la précision des poids dans les couches linéaire et d'intégration de fp32 à int8 par une action de mappage, l'empreinte mémoire d'un modèle est considérablement réduite !

source : https://rasa.com/blog/compressing-bert-for-faster-prediction-2/

La quantification est un domaine très actif, c'est pourquoi un certain nombre de bibliothèques proposent des options pour quantifier votre modèle :

Bien que nous soyons de grands fans de la direction prise par Optimum, dans ce billet, nous avons utilisé la dernière solution, en raison de la grande aide apportée à la quantification GPT2 par le biais d'exemples et d'aides dédiées.

Si vous n'êtes là que pour le code, vous pouvez trouver tout le code de ce blogpost en cliquant sur le lien suivant!

La quantification à l'aide de l'ORT ne comporte que trois étapes simples :

1. Convertir le modèle PyTorch en modèle ONNX

Toutes les transformations à venir se font à travers la bibliothèque ONNXRuntime (ORT), il est donc logique que ces étapes nécessitent un binaire ONNX. Ceci peut facilement être fait en utilisant HF + ORT :

2. Optimiser le modèle

L'optimisation d'un modèle implique un certain nombre d'opérations visant à rationaliser le graphique du modèle. L'une d'entre elles consiste à fusionner des opérations séquentielles en une seule étape.

3. Quantifier le modèle

C'est ici que se produit la quantification proprement dite ou, en d'autres termes, la mise en correspondance des valeurs de poids FP32 avec la plage de valeurs INT8.

L'exécuter à l'aide de l'ORT

Pour utiliser l'artefact du modèle (fichier binaire ONNX), nous avons bien sûr besoin d'un runtime pour l'héberger. Il n'y a pas de meilleur runtime pour ONNX que ONNXRuntime

Pour ce faire, vous pouvez facilement créer une session ORT, qui peut être alimentée avec les entrées typiques requises dans un modèle HF (identifiants de jetons, masques d'attention, etc.) pour produire les logits de sortie :

Facile, n'est-ce pas ? Il y a quelques aspects à prendre en compte lors des séances de TROD pour qu'elles fonctionnent bien:

  • Liaison IO pour éviter la copie de données
  • Post-traitement des logits pour permettre l'échantillonnage top_k et top_p , la recherche de faisceaux, la température, etc. Au lieu d'un décodage avide simple
  • Inclure les apports du passé pour améliorer la performance
  • Détection et traitement des étiquettes spéciales EOS

Nous n'entrerons pas dans le détail de tout le code nécessaire pour chacun de ces aspects, mais vous pouvez les trouver dans le notebook(lien à nouveau) où ils sont implémentés.

L'évaluation

Nous avons donc codé tous ces aspects supplémentaires pour obtenir de bonnes prédictions, et notre modèle tourne allègrement sur une instance Cloud Run, à l'intérieur d'une application Python qui héberge la session ORT. Des jours heureux !

Mais est-ce que c'est bon... ?

Qualité de la génération

Bien entendu, nous voulons nous assurer que nos modèles ne produisent pas de déchets, c'est pourquoi nous allons examiner la qualité de la génération sous plusieurs angles :

La différence entre les logits de sortie

Une première vérification rapide peut être effectuée en comparant les logits de sortie des têtes de modélisation linguistique des deux modèles.

Si le modèle quantifié est effectivement un substitut crédible du modèle normal, les logits de sortie devraient suivre grosso modo la même distribution de valeurs point par point.

Ainsi, en mesurant la différence moyenne, médiane et maximale des valeurs logit, nous pouvons nous faire une première idée de la qualité de la production potentielle :

On constate que les valeurs logit peuvent être très différentes. On constate également que l'impact est moins important pour le modèle GPT2-medium de 345M de paramètres que pour le modèle GPT2-small de 117M.

Bien qu'il s'agisse d'une première indication que nous pourrions perdre de la qualité, cela ne parle pas des véritables capacités expressives des modèles quantifiés. Poursuivons donc :

La perplexité

Heureusement pour nous, il existe une métrique qui permet de mesurer la qualité de la génération de manière plus significative : la perplexité! Les toujours adorables gens de HuggingFace ont écrit une très belle page à ce sujet, ce qu'elle fait, et comment la coder (vous pouvez trouver notre implémentation dans notre notebook).

Nous avons suivi leur approche et mesuré la perplexité sur les 1000 premiers documents de la partition néerlandaise du corpus OSCAR. Il s'agit d'une vaste collection de pages web néerlandaises explorées.

Il est intéressant de noter que l'augmentation de la perplexité est moins importante pour le modèle GPT2 moyen que pour le petit modèle GPT2. Cela signifie que le modèle GPT2 moyen semble souffrir moins de la dégradation du processus de quantification. Cela correspond à ce que nous avons observé lors de la comparaison logit !

L'évaluation humaine

Le meilleur, le champion, le véritable test de la qualité générative !

Voici quelques exemples de générations produites par le modèle non quantifié et le modèle quantifié côte à côte, où nous demandons à chaque modèle de produire les 20 tokens suivants.

Les deux modèles génèrent un échantillonnage, avec top_p=0,95, top_k=50 et température=0,95.

Comparaison de la qualité expressive

D'après ce que l'on peut voir, les deux semblent se débrouiller très bien ! Suffisamment pour la démo en ligne, où seuls quelques jetons suivants sont prédits à chaque fois.

Mais est-ce rapide... ?

Temps de latence

Maintenant que nous savons que les modèles quantifiés sont utilisables, nous pouvons commencer à mesurer la première gêne occasionnée par le déploiement en l'état : le temps de démarrage et la latence des requêtes.

Ici, nous voulons mesurer deux éléments :

le temps de démarrage lorsque le service est démarré à froid

Lorsqu'une instance Cloud Run sans serveur, mise à l'échelle à 0, commence à recevoir des demandes, elle doit effectuer ce que l'on appelle un "démarrage à froid" en déployant et en exécutant votre application de conteneur sur une instance de machine disponible, en récupérant les modèles dans le Cloud Storage et en les chargeant pour commencer à servir les demandes. Bien entendu, cela prend un peu de temps.

Comparons ce "temps de chauffe" entre un service servant les versions non quantifiées et les versions quantifiées :

le temps de latence de la demande

Pour mesurer le temps de réponse de chaque modèle déployé, nous envoyons un barrage de quelques centaines de requêtes séquentielles au microservice déployé. Cette latence implique la latence du réseau, la surcharge du service et le temps de prédiction du modèle.

Nous répétons cette opération un certain nombre de fois, chacune pour une chaîne de longueur variable, car la complexité de calcul de l'auto-attention augmente de façon quadratique avec la longueur de la séquence !

Encore une fois, les modèles quantifiés sont très performants ! La latence semble être réduite d'un facteur 3-4.

Mais est-ce que c'est bon marché... ?

Coût

Le stockage en nuage étant pratiquement gratuit, nous nous intéressons principalement aux coûts d'hébergement et d'exécution du modèle dans un microservice sur Google Cloud Run.

Nous pouvons facilement utiliser la documentation sur les prix de Cloud Run pour obtenir une estimation de prix :

  • L'image quantifiée du modèle gpt2-small + gpt2-medium s'adapte à une machine de 2GB, 1vCPU, totalisant 💲57.02
  • L'image non quantifiée du modèle gpt2-small + gpt2-medium tient sur une machine de 8GB, 2vCPU (parce qu'on ne peut pas avoir une machine 1vCPU pour cette quantité de mémoire), pour un total de 💲134.78

Cela signifie que nous pouvons réduire notre facture de services en nuage d'un facteur de 2,4 !

Et même si le coût du déploiement retravaillé est trop élevé, nous avons clairement montré que le conteneur quantifié plus petit a un temps de préchauffage beaucoup plus faible, ce qui fait de l'autoscale-to-zero une option valable.

A bientôt !

L'utilisation de la quantification et de l'ORT permet clairement d'accélérer le processus et de réduire les coûts !

Profitez de tout l'argent que vous venez d'économiser ! Et restez à l'écoute pour les prochains articles de blog où nous utiliserons Triton Inference Server pour l'hébergement complet des transformateurs, car il s'agit d'une approche plus recommandée que l'option Flask pour le déploiement d'un service de modèle mature.

Postes connexes

Voir tout le contenu
Aucun résultat n'a été trouvé.
Il n'y a pas de résultats correspondant à ces critères. Essayez de modifier votre recherche.
Grand modèle linguistique
Modèles de fondation
Entreprise
Personnes
Données Structurées
Chat GPT
Durabilité
Voix et son
Développement frontal
Protection des données et sécurité
IA responsable/éthique
Infrastructure
Hardware et capteurs
MLOps
IA générative
Natural Language Processing
Vision par ordinateur