25 points par xguru 2024-07-31 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Les grands modèles de langage (LLM) sont trop volumineux pour être exécutés sur du matériel standard et, avec généralement des milliards de paramètres, nécessitent des GPU dotés d'une grande quantité de VRAM
  • De plus en plus de recherches se concentrent donc sur la réduction de la taille de ces modèles via un meilleur entraînement, des adaptateurs, etc., et l'une des principales techniques de ce domaine est la quantification (Quantization)

Part 1: le « problème » des grands modèles de langage

  • Les LLM (Large Language Model) sont nommés en fonction du nombre de paramètres qu'ils contiennent
  • Ces modèles contiennent généralement des milliards de paramètres (principalement des poids), ce qui peut entraîner un coût de stockage considérable
  • Lors de l'inférence, les activations sont produites par le produit des entrées et des poids, et peuvent elles aussi être très volumineuses
  • On cherche donc à représenter des milliards de valeurs de la manière la plus efficace possible tout en minimisant l'espace nécessaire pour stocker une valeur donnée

Comment représenter des valeurs numériques

  • Une valeur donnée est souvent représentée sous forme de nombre à virgule flottante (nombre réel)
  • Ces valeurs sont représentées en « bits », et la norme IEEE-754 décrit comment les bits indiquent une fonction parmi le signe, l'exposant et la mantisse (fraction) pour représenter une valeur
  • Plus il y a de bits utilisés pour représenter une valeur, plus la précision est généralement élevée
  • Plus il y a de bits disponibles, plus l'éventail des valeurs représentables est grand

Contraintes mémoire

  • Si l'on suppose un modèle de 70 milliards de paramètres, l'utilisation de FP32 (full-precision) nécessite à elle seule 280 Go de mémoire pour charger le modèle
  • Il est donc crucial de minimiser le nombre de bits utilisés pour représenter les paramètres du modèle, mais lorsque la précision diminue, l'exactitude du modèle baisse généralement aussi
  • L'objectif est de réduire le nombre de bits servant à représenter les valeurs tout en conservant la précision, et c'est précisément là qu'intervient la quantification

Part 2: introduction à la quantification

  • La quantification vise à réduire la précision des paramètres du modèle d'une largeur de bit élevée (par ex. flottant 32 bits) vers une largeur de bit plus faible (par ex. entier 8 bits)
  • À chaque réduction du nombre de bits, un mapping est effectué pour « compresser » les paramètres d'origine dans une représentation à faible précision

Types de données courants

FP16

  • En passant de FP32 à FP16 (half precision), la plage de valeurs que FP16 peut prendre devient bien plus réduite que celle de FP32

BF16

  • Pour obtenir une plage de valeurs similaire à FP32, le bfloat16, une sorte de « FP32 tronqué », a été introduit
  • BF16 utilise le même nombre de bits positifs que FP16, mais peut couvrir une plage de valeurs plus large et est souvent utilisé dans les applications de deep learning

INT8

  • Quand on réduit encore le nombre de bits, on se rapproche d'une représentation basée sur des entiers plutôt que sur des flottants

Quantification symétrique

  • La plage des valeurs flottantes d'origine est mappée vers une plage symétrique centrée sur 0 dans l'espace quantifié
  • Dans l'espace flottant, la valeur quantifiée de 0 est exactement 0 dans l'espace quantifié

Quantification asymétrique

  • Contrairement à la quantification symétrique, elle n'est pas symétrique autour de 0
  • Elle mappe la valeur minimale (β) et la valeur maximale (α) de la plage flottante vers les valeurs minimale et maximale de la plage quantifiée
  • C'est l'une des méthodes appelées quantification par zero-point

Mapping de plage et clipping

  • Si l'on mappe toute la plage d'un vecteur, les valeurs aberrantes peuvent faire converger toutes les petites valeurs vers la même représentation low-bit, ce qui fait perdre le pouvoir de distinction
  • On peut à la place choisir d'appliquer un clipping sur certaines valeurs
  • Le clipping consiste à définir une autre plage dynamique des valeurs d'origine de sorte que toutes les valeurs aberrantes prennent la même valeur
  • L'erreur de quantification des valeurs non aberrantes diminue fortement, mais celle des valeurs aberrantes augmente

Calibration

Poids (et biais)

  • Les poids et les biais peuvent être considérés comme des valeurs statiques connues avant l'exécution du modèle
  • Comme les biais sont bien moins nombreux que les poids, ils sont conservés avec une précision plus élevée (par ex. INT16), et l'effort principal de la quantification porte sur les poids
  • Parmi les techniques de calibration pour des poids statiques et connus, on trouve la sélection manuelle d'un percentile de la plage d'entrée, l'optimisation de l'erreur quadratique moyenne (MSE) entre les poids d'origine et les poids quantifiés, ou encore la minimisation de l'entropie (divergence KL) entre les valeurs d'origine et les valeurs quantifiées

Activations

  • Les entrées sont continuellement mises à jour dans l'ensemble du LLM et sont généralement appelées « activations »
  • Comme ces valeurs changent à chaque fois que des données d'entrée sont injectées dans le modèle pendant l'inférence, il est difficile de les quantifier avec précision
  • Ces valeurs sont mises à jour après chaque couche cachée ; on ne peut donc savoir ce qu'elles seront pendant l'inférence qu'au moment où les données traversent effectivement le modèle

Part 3: quantification post-entraînement (PTQ - Post-Training Quantization)

Quantification dynamique

  • Les activations sont collectées après le passage des données dans une couche cachée
  • Cette distribution des activations sert à calculer les valeurs de zero-point (z) et de facteur d'échelle (s) nécessaires pour quantifier la sortie
  • Le processus est répété chaque fois que les données traversent une nouvelle couche. Ainsi, chaque couche possède ses propres valeurs z et s et son propre schéma de quantification

Quantification statique

  • Les valeurs de zero-point (z) et de facteur d'échelle (s) sont calculées à l'avance, et non pendant l'inférence
  • Pour les trouver, on utilise un jeu de données de calibration fourni au modèle afin de collecter ces distributions potentielles
  • Lors de l'inférence réelle, les valeurs s et z ne sont pas recalculées et sont utilisées globalement pour quantifier toutes les activations
  • En général, la quantification dynamique est légèrement plus précise, car elle cherche à calculer des valeurs s et z à chaque couche cachée, mais cela peut augmenter le temps de calcul
  • À l'inverse, la quantification statique est moins précise, mais plus rapide puisqu'elle connaît déjà les valeurs s et z

Le domaine de la quantification 4 bits

  • Descendre sous les 8 bits s'est avéré difficile, car l'erreur de quantification augmente à chaque bit perdu
  • Exploration de deux méthodes couramment partagées sur HuggingFace : GPTQ et GGUF

GPTQ

  • L'une des méthodes les plus connues pour quantifier en 4 bits
  • Elle utilise une quantification asymétrique et procède couche par couche, chaque couche étant traitée indépendamment avant de passer à la suivante
  • Pendant ce processus de quantification couche par couche, les poids de la couche sont d'abord transformés à l'aide de l'inverse de la Hessienne, c'est-à-dire la dérivée seconde de la fonction de perte du modèle, qui indique à quel point la sortie du modèle est sensible aux variations de chaque poids
  • En termes simples, cela montre l'(inverse de l')importance de chaque poids dans la couche
  • Dans la matrice hessienne, les poids associés à de petites valeurs sont plus importants, car de faibles changements sur ces poids peuvent entraîner de grandes variations des performances du modèle

GGUF

  • GPTQ est une bonne méthode de quantification pour exécuter l'ensemble d'un LLM sur GPU, mais on ne dispose pas toujours d'une telle capacité
  • On peut à la place utiliser GGUF pour déporter toutes les couches du LLM sur le CPU
  • Cela permet d'utiliser à la fois le CPU et le GPU lorsqu'il n'y a pas assez de VRAM

Part 4: entraînement conscient de la quantification (QAT - Quantization Aware Training)

  • Dans la troisième partie, nous avons vu comment quantifier un modèle après l'entraînement, mais cette approche a l'inconvénient de ne pas tenir compte du processus d'entraînement réel
  • C'est précisément là qu'intervient le Quantization Aware Training (QAT). Contrairement au PTQ, le QAT vise à apprendre la procédure de quantification pendant l'entraînement
  • Le QAT tend à être plus précis que le PTQ, car la quantification est déjà prise en compte durant l'entraînement

L'ère des LLM 1 bit : BitNet

  • BitNet représente les poids du modèle avec un seul bit, soit -1 soit 1
  • Cela se fait en injectant directement le processus de quantification dans l'architecture Transformer
  • L'architecture Transformer constitue la base de la plupart des LLM et se compose d'opérations incluant des couches linéaires
  • BitNet remplace ces couches linéaires par ce qu'on appelle BitLinear

Quantification des poids

  • Pendant l'entraînement, les poids sont stockés en INT8 puis quantifiés en 1 bit à l'aide de la stratégie de base, la fonction signe
  • Concrètement, on recentre la distribution des poids autour de 0, puis on attribue -1 à tout ce qui se trouve à gauche de 0 et 1 à tout ce qui se trouve à droite

Quantification des activations

  • Pour quantifier les activations, BitLinear utilise la quantification absmax afin de convertir les activations de FP16 en INT8, car la multiplication matricielle (×) nécessite une précision plus élevée

Déquantification

  • On a suivi α (la plus grande valeur absolue parmi les activations) et β (la valeur absolue moyenne des poids), et ces valeurs aideront ensuite à déquantifier les activations en FP16
  • Les activations de sortie sont remises à l'échelle avec {α, γ} puis déquantifiées dans leur précision d'origine

Tous les grands modèles de langage font 1,58 bit

  • BitNet 1.58b a été introduit pour améliorer les problèmes de passage à l'échelle mentionnés précédemment
  • Avec cette nouvelle méthode, chaque poids du modèle ne prend plus seulement les valeurs -1 ou 1, mais peut désormais aussi valoir 0, devenant ainsi ternaire
    • Fait intéressant, le simple ajout de 0 améliore fortement BitNet et accélère nettement le calcul

La puissance du 0

  • Pourquoi l'ajout de 0 constitue-t-il une amélioration aussi importante ? Tout est lié à la multiplication matricielle
  • Avec des poids quantifiés à 1,58 bit, on peut non seulement accélérer fortement le calcul puisqu'il ne reste plus que des multiplications à effectuer, mais aussi filtrer les caractéristiques

Quantification

  • Pour réaliser la quantification des poids, BitNet 1.58b utilise la quantification absmean, une variante de la quantification absmax vue plus haut
  • Elle compresse simplement la distribution des poids et utilise la moyenne absolue (α) pour quantifier les valeurs, qui sont ensuite arrondies à -1, 0 ou 1
  • Par rapport à BitNet, la quantification des activations est identique à une exception près : au lieu d'ajuster les activations à la plage [0, 2ᵇ⁻¹], on utilise désormais la quantification absmax pour les ajuster à [-2ᵇ⁻¹, 2ᵇ⁻¹]
  • La quantification à 1,58 bit a nécessité (principalement) deux astuces :
    • l'ajout de 0 pour créer une représentation ternaire [-1, 0, 1]
    • la quantification absmean pour les poids
  • « BitNet b1.58 13B est plus efficace qu'un LLM FP16 3B en termes de latence, d'utilisation mémoire et de consommation d'énergie »

  • On peut donc obtenir un modèle léger grâce à cette quantification computationnellement efficace à 1,58 bit

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.