nouvelles

Des milliers de mots d'informations techniques ! Un guide de quantification incontournable pour les ingénieurs LLM, des illustrations visuelles révèlent comment compresser de grands modèles

2024-07-31

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina


Nouveau rapport de sagesse

Editeur : Service éditorial

[Introduction à la nouvelle sagesse] Face à l'échelle de paramètres en expansion progressive du LLM, les développeurs et les chercheurs sans H100 ont trouvé de nombreuses façons de compenser, et la technologie de « quantification » en fait partie. Ce guide visuel utilise diverses illustrations pour résumer de manière exhaustive les concepts de base et les méthodes de branchement de la « quantification ».

Les grands modèles de langage (LLM) sont souvent trop volumineux pour être exécutés sur du matériel grand public. Ces modèles peuvent comporter plus de milliards de paramètres et nécessitent souvent des GPU dotés d’une grande mémoire pour accélérer le processus d’inférence.

Par conséquent, de plus en plus de recherches ont commencé à se concentrer sur la manière de réduire le modèle, par exemple en améliorant les méthodes de formation ou en utilisant des adaptateurs. L'une des principales techniques dans ce domaine est appelée quantification.

L'ingénieur ML Maarten Grootendorst a écrit un article de blog qui présente spécifiquement la technologie de quantification dans le contexte de la modélisation du langage et explore les concepts associés un par un à l'aide de méthodes visuelles pour nous aider à construire une compréhension intuitive de la technologie.


Dans cet article de blog, Maarten explore diverses méthodes, cas d'utilisation et principes derrière la quantification.

La table des matières et le contenu de l'article sont présentés dans la figure ci-dessous. Il présente principalement les deux méthodes de quantification post-formation (PTQ) et de formation basée sur la quantification (QAT). Il est recommandé aux lecteurs ayant une connaissance de base en IA de sauter. directement à la partie de quantification symétrique :


Première partie : le « problème » du LLM

Les « grands modèles de langage » sont importants en termes de nombre de paramètres de modèle, atteignant généralement des milliards (principalement des poids).

Non seulement les coûts de stockage de ces paramètres sont assez élevés, mais la quantité de calcul lors de la phase d’inférence est également importante.

Lors de l'inférence, la valeur d'activation est le produit de l'entrée et du poids, donc plus le nombre de poids est grand, plus la valeur d'activation est grande.


Par conséquent, nous souhaitons représenter des milliards de valeurs aussi efficacement que possible, minimisant ainsi l'espace requis pour stocker les paramètres.

Commençons par le début et explorons comment les valeurs sont représentées avant d'optimiser.

Comment représenter des valeurs numériques

Les valeurs numériques sont généralement stockées sous forme de nombres à virgule flottante (ou simplement flottants) : un nombre positif ou négatif avec une virgule décimale.

Ces valeurs sont représentées par des chiffres binaires sur chaque bit.

La norme IEEE-754 décrit comment les chiffres de chaque chiffre représentent une valeur spécifique. Plus précisément, il existe trois mappages : signe, exposant ou décimal (mantisse).


Ces trois parties peuvent être combinées pour calculer la valeur représentée sur la base d'un ensemble de valeurs binaires :


Plus il y a de chiffres utilisés, plus la valeur numérique est précise. Par exemple, le formulaire FP32 peut être précis avec plus de chiffres après la virgule que le FP16 :


limite de mémoire

Plus il y a de chiffres disponibles, non seulement plus la valeur est précise, mais aussi plus la plage de valeurs pouvant être représentées est large.


Étant donné un nombre de bits et une représentation, la plage de valeurs pouvant être représentée est appelée plage dynamique, et la distance entre deux valeurs adjacentes est appelée précision.


Une caractéristique intéressante de cette représentation est que nous pouvons calculer la quantité de mémoire dont l'appareil a besoin pour stocker une valeur donnée.

Puisque chaque octet en mémoire contient 8 bits, nous pouvons créer une formule de base pour la plupart des formes de nombres à virgule flottante :


Dans les applications réelles, de nombreux autres facteurs affectent la quantité de graphiques/de mémoire requise lors de l'inférence, tels que la taille du contexte et l'architecture du modèle.

Imaginez maintenant que nous ayons un modèle avec 70 milliards de paramètres. La plupart des modèles eux-mêmes sont représentés à l'aide de nombres à virgule flottante de 32 bits (souvent appelés pleine précision), ce qui nécessite 280 Go de mémoire pour charger le modèle.


Mais si tous les paramètres peuvent être exprimés sous forme de nombres à virgule flottante de 16 bits, la taille de la mémoire requise peut être directement réduite d'une fois.

Par conséquent, il est très intéressant de minimiser le nombre de représentations des paramètres du modèle (non seulement pour l’inférence mais aussi pour la formation).

Cependant, cette approche n’est pas sans coût. La précision du modèle diminue généralement à mesure que le nombre de bits de représentation diminue, ce qui entraîne une diminution de la précision.

Nous voulons réduire le nombre de chiffres utilisés pour représenter une valeur tout en conservant la précision... c'est là que les techniques de quantification s'avèrent utiles.

Partie 2 : Introduction à la quantification

Nous savons maintenant que le but de la quantification est de réduire la précision des paramètres du modèle depuis des largeurs de bits plus élevées (telles que les nombres à virgule flottante de 32 bits) vers des largeurs de bits inférieures (telles que des entiers de 8 bits).


Lors de la réduction du nombre de bits représentant les paramètres d'origine, il y a généralement une perte d'une certaine précision (granularité).

Pour rendre cet effet plus intuitif, nous pouvons utiliser les couleurs des photos comme analogie. Par exemple, sélectionnez n'importe quelle image (à gauche), mais utilisez seulement 8 couleurs (à droite) :


Notez que le cookie agrandi semble plus « granuleux » que l’original.

De même, l'objectif principal de la quantification est de réduire le nombre de bits (couleurs) requis pour représenter les paramètres d'origine tout en conservant autant de précision que possible des paramètres d'origine.

Types de données courants

Tout d’abord, examinons les types de données courants et l’impact de leur utilisation à la place d’une représentation 32 bits (appelée pleine précision ou FP32).

FP16

Le premier est un exemple de passage de 32 bits à 16 bits (appelé demi-précision ou FP16) à virgule flottante :


La plage de valeurs possibles pour le FP16 est beaucoup plus petite que celle du FP32.

BF16

Afin d'obtenir une plage numérique similaire au FP32 d'origine, le bfloat 16 a été introduit comme un type « FP32 tronqué » :


BF16 utilise le même nombre de bits que FP16, mais ajoute un bit exponentiel, ce qui lui permet d'obtenir une plage de valeurs plus large et est souvent utilisé dans le domaine de l'apprentissage profond.

INT8

À mesure que vous réduisez davantage le nombre de bits, la représentation se rapproche d’un nombre entier plutôt que d’un nombre à virgule flottante. Par exemple, en passant de FP32 à INT8 qui n'a que 8 bits, soit seulement 1/4 du nombre de bits d'origine :


Chaque fois que le nombre de bits est réduit, un mappage est effectué pour « compresser » la représentation FP32 originale en moins de bits.

Mais en fonctionnement réel, nous n'avons pas besoin de mapper toute la gamme FP32 [-3.4e38, 3.4e38] dans INT8. Nous devons juste trouver un moyen de mapper la plage de données des paramètres réels du modèle dans INT8.

Les méthodes courantes de compression/mappage incluent la quantification symétrique et la quantification asymétrique, qui sont toutes deux des mappages linéaires.

Ce dont nous discuterons ensuite est la méthode de quantification de FP32 à INT8.

Quantification symétrique

Dans la quantification symétrique, la plage de la valeur à virgule flottante d'origine est mappée sur une plage symétrique centrée sur zéro dans l'espace de quantification, avec zéro comme point médian de la plage avant et après quantification.

Cela signifie que le zéro d'origine dans l'espace à virgule flottante est exactement zéro après avoir été mappé à l'espace quantifié.


Un exemple typique de quantification symétrique est la quantification maximale absolue (absmax).

Étant donné une liste de valeurs, nous prenons la valeur absolue la plus élevée (α) comme plage pour effectuer une cartographie linéaire.


[-127, 127] représente la plage restreinte et la plage non restreinte est [-128, 127], selon la méthode de quantification

Puisqu’il s’agit d’une application linéaire centrée en zéro, la formule est simple.

Calculez d’abord le(s) facteur(s) d’échelle à l’aide de la formule suivante :

- b est le nombre d'octets que nous voulons quantifier (8)

- α est la valeur absolue la plus élevée

Nous utilisons ensuite s pour quantifier l'entrée x :


Comme le montre la figure ci-dessus, la valeur absolue maximale α est de 10,8. Lors du mappage de FP32 à INT8, la formule suivante est obtenue :


Si vous souhaitez restaurer les valeurs originales du FP32, vous pouvez également utiliser le(s) facteur(s) d'échelle précédemment calculé(s) pour la quantification inverse.


Quantifiez d'abord, puis déquantifiez pour restaurer la valeur d'origine. L'ensemble du processus est le suivant :


Vous pouvez voir que certaines valeurs, telles que 3,08 et 3,02, sont toutes deux égales à 36 lorsqu'elles sont quantifiées en INT8. Ainsi, une fois déquantifiés en FP32, ils perdent un peu de précision et ne sont plus distinguables.

Cette différence entre la valeur originale et la valeur quantifiée inverse est appelée erreur de quantification. Généralement, moins le résultat de la quantification comporte de bits, plus l'erreur est grande.


quantification asymétrique

Contrairement à la quantification symétrique, la quantification asymétrique n’est pas une symétrie centrée sur zéro. Au lieu de cela, il mappe les valeurs minimales (β) et maximales (α) de la plage à virgule flottante aux valeurs minimales et maximales de la plage quantifiée, respectivement.

La méthode que nous explorons ici est appelée quantification du point zéro.


Remarquez comment la position de 0 a changé. C'est pourquoi on parle de quantification asymétrique. Dans la plage [-7,59, 10,8], les valeurs maximales et minimales sont à des distances différentes de 0.

En raison du décalage de la position du point zéro, nous devons calculer le point zéro dans la plage INT8 pour effectuer un mappage linéaire. Comme précédemment, nous devons également calculer le(s) facteur(s) d'échelle, mais en utilisant la différence dans la plage INT8 [-128, 127].


C'est un peu compliqué car le point zéro (z) doit être calculé dans la plage INT8 pour déplacer les poids.

Comme précédemment, remplissons la formule :


Afin de déquantifier la valeur quantifiée de INT8 à FP32, nous devons utiliser le ou les facteurs d'échelle précédemment calculés et le point zéro (z).

Sinon, la déquantification est simple :


Lorsqu’on met côte à côte quantifications symétrique et asymétrique, on voit rapidement la différence entre les deux méthodes :


Dans l'image ci-dessus, nous pouvons voir la caractéristique du centre zéro de la quantification symétrique et le décalage de la quantification asymétrique.

Mappage et découpage de plage (Clipping)

Dans l'exemple précédent, nous avons exploré comment mapper une plage de valeurs dans un vecteur donné à une représentation à bits faibles. Bien que cela puisse cartographier toute la plage des valeurs vectorielles, cela présente un inconvénient majeur, à savoir les valeurs aberrantes.

Imaginez que vous ayez un vecteur contenant les valeurs suivantes :


Une valeur beaucoup plus grande que toutes les autres peut être considérée comme une valeur aberrante. Si nous mappons toute la gamme de vecteurs, toutes les petites valeurs seront mappées sur la même représentation d'ordre inférieur et perdront leur caractère distinctif :


Il s’agit de la méthode absmax utilisée auparavant.La même chose se produit avec une quantification asymétrique sans écrêtage

Au lieu de cela, nous pouvons choisir de découper certaines valeurs. L'écrêtage fait référence à la définition d'une plage dynamique différente des valeurs d'origine afin que toutes les valeurs aberrantes soient définies sur la même valeur.

Dans l'exemple ci-dessous, nous définissons manuellement la plage dynamique sur [-5, 5], et toutes les valeurs en dehors de cette plage seront mappées à -127 ou 127, quelle que soit leur valeur réelle :


Le principal avantage de cette approche est que l’erreur de quantification pour les valeurs non aberrantes est considérablement réduite. Cependant, cela entraînera une augmentation de l’erreur de quantification pour les valeurs aberrantes.

Étalonnage

Dans l'exemple ci-dessus, nous définissons aléatoirement la plage dynamique sur [-5, 5], mais la décision doit être prise via un processus de « calibrage » pour trouver une plage appropriée qui englobe autant de valeurs que possible tout en minimisant l'erreur de quantification.

L'exécution spécifique des étapes d'étalonnage est différente pour différents types de paramètres.

Pondérations (et biais)

Nous pouvons considérer les poids et les biais d'un grand modèle de langage (LLM) comme des valeurs statiques car ils sont connus avant d'exécuter le modèle. Par exemple, le fichier d'environ 20 Go de Llama 3 se compose principalement de ses pondérations et de ses biais.

Étant donné que le nombre de variables de biais (millions) est nettement inférieur aux poids (milliards), les biais conservent généralement une plus grande précision (comme INT16), tandis que les principaux travaux sur la quantification se concentrent sur les poids.

Pour les poids statiques connus, les techniques d'étalonnage pour sélectionner la plage comprennent :

- Sélectionnez manuellement les centiles de la plage d'entrée

- Optimiser l'erreur quadratique moyenne (MSE) entre les poids d'origine et les poids quantifiés

- Minimiser l'entropie entre la valeur originale et la valeur quantifiée (divergence KL)


Le choix d’un percentile, par exemple, entraîne un comportement de découpage similaire à celui que nous avons vu précédemment.

valeur d'activation

Les entrées constamment mises à jour dans un grand modèle de langage sont souvent appelées activations.


On les appelle valeurs d'activation car elles passent généralement par une fonction d'activation, telle que sigmoïde ou relu.

Contrairement aux poids, les activations changent avec les données d'entrée lors de l'inférence et sont donc difficiles à quantifier avec précision.

Étant donné que ces valeurs sont mises à jour après chaque couche cachée, leurs valeurs spécifiques ne sont pas connues pendant la phase d'inférence jusqu'à ce que les données d'entrée traversent le modèle.


En général, il existe deux méthodes de calage des poids et des activations, appliquées à différentes étapes du modèle :

- Quantification post-formation (PTQ)

- Comme son nom l'indique, il s'agit d'une quantification après entraînement

- Formation prenant en compte la quantification (QAT)

- Quantification pendant l'entraînement/mise au point

Partie 3 : Quantification post-formation (PTQ)

La quantification post-formation (PTQ) est l'une des techniques de quantification les plus populaires. Il quantifie les paramètres du modèle (y compris les poids et les valeurs d'activation) une fois la formation du modèle terminée.

La quantification des poids peut utiliser une quantification symétrique ou une quantification asymétrique.

Cependant, la quantification des valeurs d’activation nécessite une étape d’inférence pour obtenir leur distribution sous-jacente, puisque l’on ne connaît pas leur étendue à l’avance.

Il existe deux formes de quantification des valeurs d'activation :

- quantification dynamique

- quantification statique

quantification dynamique

Une fois que les données ont traversé la couche cachée, leurs valeurs d'activation sont collectées et la valeur maximale (α) et la valeur minimale (β) de chaque couche sont comparées :


La distribution de ces activations est ensuite utilisée pour calculer les valeurs de point zéro (z) et de facteur d'échelle (s) requises pour la sortie quantifiée :


Ce processus se répète chaque fois que les données traversent une nouvelle couche réseau. Par conséquent, chaque couche possède ses propres valeurs z et s indépendantes, utilisant ainsi un schéma de quantification différent.

quantification statique

Contrairement à la quantification dynamique, la quantification statique ne calcule pas le point zéro (z) et le(s) facteur(s) d'échelle lors de l'inférence, mais calcule ces valeurs avant l'inférence.

Pour trouver ces valeurs, nous utilisons un ensemble de données d'étalonnage et l'introduisons dans le modèle pour collecter ces distributions sous-jacentes des valeurs d'activation.


Une fois ces distributions collectées, les valeurs s et z requises pour la quantification lors de l'inférence peuvent être calculées.

Au moment de l'inférence réel, les valeurs s et z ne sont pas recalculées mais utilisées globalement sur toutes les activations pour les quantifier.

Dans l'ensemble, la quantification dynamique, qui calcule les valeurs s et z pour chaque couche cachée, a tendance à être plus précise. Cependant, cela peut augmenter le temps de calcul puisque ces valeurs doivent être calculées à chaque instant d'inférence.

En revanche, la quantification statique, bien qu'elle ne soit pas aussi précise que la quantification dynamique, est plus rapide car elle connaît déjà à l'avance les valeurs s et z utilisées pour la quantification.

Champ quantitatif 4 bits

La quantification en dessous de 8 bits a toujours été un défi car l'erreur de quantification augmente avec chaque bit perdu. Heureusement, il existe plusieurs façons astucieuses de réduire le nombre de bits à 6, 4 ou même 2 bits (bien que réduire le nombre de bits en dessous de 4 bits ne soit généralement pas recommandé).

Nous explorerons deux méthodes courantes sur HuggingFace :

- GPTQ (le modèle complet fonctionne sur GPU)

- GGUF (décharge éventuellement les couches vers le CPU)

GPTQ

GPTQ peut être considéré comme l’une des méthodes de quantification 4 bits les plus connues dans les applications pratiques.

Il utilise une quantification asymétrique et la traite couche par couche, traitant chaque couche indépendamment avant de passer à la couche suivante :


Dans ce processus de quantification couche par couche, il convertit d’abord les poids des couches en matrices hessiennes inverses. La matrice de Hesse inverse est la dérivée seconde de la fonction de perte du modèle et représente la sensibilité de la sortie du modèle à chaque changement de poids.

En termes simples, cela montre essentiellement l'importance (importance inverse) des poids dans chaque couche.

Des poids de valeur plus petits dans la matrice hessienne sont plus importants car de petits changements dans ces poids peuvent entraîner des changements significatifs dans les performances du modèle.


Dans la matrice de Hesse inverse, les valeurs inférieures représentent des poids plus « importants »

Ensuite, nous quantifions et déquantifions la première ligne de la matrice de poids :


Ce processus nous permet de calculer l'erreur de quantification (q), que nous pouvons pondérer à l'aide de la valeur hessienne inverse précédemment calculée (h_1).

Essentiellement, nous créons une erreur quantifiée pondérée basée sur l’importance des poids :


Ensuite, nous redistribuons cette erreur de quantification pondérée aux autres poids de la ligne. Cela permet de maintenir la fonctionnalité globale et la sortie du réseau.

Par exemple, si nous faisons cela pour le deuxième poids (c'est-à-dire x_2=0,3), nous multiplions l'erreur de quantification (q) par l'inverse du Hessien du deuxième poids (h_2) et y ajoutons :


Continuez ensuite la même opération pour le troisième poids d'une ligne donnée :


Ce processus de redistribution de l'erreur de quantification pondérée q est répété jusqu'à ce que toutes les valeurs aient été quantifiées.

Cette méthode fonctionne car les poids sont généralement liés les uns aux autres. Par conséquent, lorsqu'un poids présente une erreur de quantification, le poids associé sera mis à jour en conséquence via le Hessian inverse.

GGUF

Bien que GPTQ soit une bonne méthode de quantification pour exécuter l'intégralité du grand modèle de langage (LLM) sur le GPU, s'il n'y a pas de conditions matérielles correspondantes, n'importe quelle couche du LLM peut également être déchargée sur le CPU via GGUF.

Cela équivaut à exécuter le modèle sur le CPU et le GPU en même temps pour compenser le manque de mémoire vidéo (VRAM).

La méthode de quantification GGUF est fréquemment mise à jour et dépend du nombre spécifique de bits de quantification, mais le principe de base est le suivant.

Premièrement, les poids d'une couche donnée sont divisés en « super-blocs », chacun contenant un ensemble de « sous-blocs ». A partir de ces "sous-blocs" on calcule le(s) facteur(s) d'échelle et la valeur alpha :


Pour quantifier un "sous-bloc" donné, vous pouvez utiliser la quantification absmax mentionnée précédemment, en multipliant le poids donné par le facteur d'échelle (s_sub) :


Le facteur d'échelle s_sub est calculé à l'aide des informations du « sous-bloc », mais quantifié à l'aide des informations s_super du « super-bloc » :


En résumé, cette quantification bloc par bloc utilise le facteur d'échelle du « super bloc » (s_super) pour quantifier le facteur d'échelle du « sous-bloc » (s_sub).

Le niveau de quantification de chaque facteur d'échelle peut être différent, et les facteurs d'échelle de « super-bloc » ont généralement une précision plus élevée que les facteurs d'échelle de « sous-bloc ».

Pour illustrer cela, explorons plusieurs niveaux de quantification (2 bits, 4 bits et 6 bits) :


Selon le type de quantification, une valeur minimale supplémentaire (m) est également nécessaire pour ajuster le point zéro, celles-ci sont quantifiées ainsi que le(s) facteur(s) d'échelle.

Partie 4 : Formation de sensibilisation quantitative (QAT)

La troisième partie décrit comment quantifier le modèle après entraînement. L’inconvénient de cette méthode est qu’elle ne prend pas en compte le processus de formation lui-même.

C’est là que la formation de sensibilisation quantitative (QAT) s’avère utile. Contrairement à la quantification post-formation (PTQ), l'objectif du QAT est d'apprendre le processus de quantification pendant la formation.


QAT a tendance à être plus précis que PTQ car la quantification est déjà prise en compte lors du processus de formation. Voici comment cela fonctionne:

Au cours du processus de formation, une quantification dite « fausse » est introduite. Par exemple, quantifiez d'abord les poids dans INT4, puis déquantifiez-les dans FP32 :


Ce processus permet au modèle de prendre en compte l'erreur de quantification lors du calcul des pertes et de la mise à jour des poids pendant la phase d'entraînement.

Comme le montre la figure ci-dessous, QAT tente d'explorer la valeur de perte dans le cas de minima « larges » afin de réduire les erreurs de quantification, car les minima « étroits » conduisent souvent à des erreurs de quantification plus importantes.


En supposant que la quantification n'est pas prise en compte lors de la rétropropagation, le processus de descente de gradient sélectionnera le poids ayant la plus petite valeur de perte. Cependant, s'il s'agit d'un minimum « étroit », cela introduira des erreurs de quantification plus importantes.

En revanche, si l’on considère la quantification, un poids de mise à jour différent sera choisi dans les minima « larges », avec une erreur de quantification beaucoup plus faible.


Par conséquent, bien que la méthode PTQ ait une faible valeur de perte à haute précision (par exemple FP32), QAT a également une faible valeur de perte à faible précision (par exemple INT4), ce que nous recherchons.

Ère 1 bit : BitNet

Nous avons vu précédemment que réduire la précision de quantification à 4 bits est déjà assez faible, mais que se passerait-il si nous la réduisions davantage ?

C'est là qu'intervient BitNet, il représente les poids d'un modèle sous la forme d'un seul bit, soit -1 ou 1, et le fait en injectant le processus de quantification directement dans l'architecture du Transformer.

L'architecture Transformer est la base de la plupart des LLM et consiste en des calculs impliquant des couches linéaires :


Ces couches linéaires sont généralement représentées avec une plus grande précision, comme FP16, et c'est là que se trouvent la plupart des poids.

BitNet remplace ces couches linéaires par des couches BitLinear :


Les couches BitLinear fonctionnent de la même manière que les couches linéaires normales, multipliant les poids par les valeurs d'activation pour calculer la sortie.

Mais la différence est que la couche BitLinear n'utilise que 1 bit pour représenter le poids du modèle et utilise INT8 pour représenter la valeur d'activation :


Les couches BitLinear, comme l'entraînement sensible à la quantification (QAT), effectuent une sorte de « fausse » quantification pendant l'entraînement pour analyser l'effet de quantification des poids et des activations :


Comprenons BitLinear étape par étape.

quantification du poids

Pendant l'entraînement, les poids sont stockés sous la forme INT8 puis quantifiés sur 1 bit à l'aide d'une stratégie de base appelée fonction signum.

Essentiellement, il déplace la distribution des poids pour qu'elle soit centrée sur 0, puis attribue toutes les valeurs inférieures à 0 à -1 et toutes les valeurs supérieures à 0 à 1 :


De plus, il garde la trace d’une valeur β (valeur absolue moyenne), que nous utiliserons plus tard dans le processus de quantification inverse.

Quantification d'activation

Pour quantifier les activations, BitLinear permet à la méthode de la valeur maximale absolue (absmax) de convertir les activations de FP16 en INT8 car elles nécessitent une multiplication matricielle (×) avec une plus grande précision.


De plus, il garde la trace d’une valeur α (valeur absolue maximale), que nous utiliserons plus tard dans le processus de déquantification.

quantification inverse

Nous gardons une trace de α (la valeur absolue maximale des activations) et β (la valeur absolue moyenne des poids), ce qui nous aidera à déquantifier les activations jusqu'au FP16.

Les activations de sortie sont redimensionnées en utilisant {α, γ} pour les déquantifier à la précision d'origine :


Ce processus est relativement simple et permet de représenter le modèle avec seulement deux valeurs, -1 ou 1.

Avec cette approche, les auteurs ont observé qu'à mesure que la taille du modèle augmente, l'écart de performances entre la formation 1 bit et la formation FP16 devient de plus en plus petit.

Cependant, cela ne s'applique qu'aux modèles plus grands (paramètres >30B), l'écart entre les modèles plus petits reste important.

Tous les LLM sont en 1,58 bits

Pour améliorer les problèmes d'évolutivité mentionnés précédemment, BitNet 1.58b a été introduit.

Dans cette nouvelle approche, chaque poids du modèle peut non seulement être -1 ou 1, mais peut également prendre la valeur 0, faisant de chaque variable un ternaire.

Fait intéressant, le simple fait d’ajouter 0 est une opération simple qui améliore considérablement BitNet et accélère le processus de calcul.

0 puissance

Pourquoi l’ajout de 0 constitue-t-il une amélioration significative ?

Cela a à voir avec la multiplication matricielle !

Tout d’abord, explorons le fonctionnement de base de la multiplication matricielle.

Lors du calcul de la sortie, nous multiplions la matrice de poids par le vecteur d'entrée. Voici une visualisation de la multiplication de la première ligne de la première couche de la matrice de poids :


Cette multiplication implique deux actions, multiplier un seul poids avec l'entrée puis les additionner tous.

En revanche, BitNet 1.58b parvient à éviter l'acte de multiplication, puisque les poids à trois valeurs vous indiquent essentiellement ce qui suit :

- 1 : je souhaite ajouter cette valeur

- 0 : je ne veux pas de cette valeur

- -1 : je veux soustraire cette valeur

Donc si vos poids sont quantifiés à 1,58 bits, il vous suffit d'effectuer l'addition :


Non seulement cela accélère considérablement les calculs, mais cela permet également le filtrage des fonctionnalités.

Définir un poids donné sur 0 équivaut à ignorer l'entrée, plutôt que d'ajouter ou de soustraire la valeur d'entrée comme 1 bit.

Quantifier

Pour effectuer la quantification du poids, BitNet 1.58b utilise la quantification de la valeur absolue moyenne (absmean), une variante de la quantification de la valeur absolue maximale (absmax) que nous avons vue auparavant.

Il compresse simplement la distribution des poids et utilise la moyenne absolue (α) pour quantifier les valeurs. Arrondissez-les ensuite à -1, 0 ou 1 :


Par rapport à BitNet, la quantification d'activation est la même à un aspect près : au lieu de mettre à l'échelle les activations sur la plage [0, 2ᵇ⁻¹], nous utilisons la méthode de la valeur absolue maximale pour mettre à l'échelle [-2ᵇ⁻¹, 2ᵇ⁻¹] .

Pour résumer, la quantification 1,58 bits implique principalement deux techniques :

- Ajoutez 0 pour créer une représentation à trois valeurs [-1, 0, 1]

- Quantification moyenne absolue des poids

L'article BitNet conclut : "13B BitNet b1.58 est plus efficace que 3B FP16 LLM en termes de latence, d'utilisation de la mémoire et de consommation d'énergie."


Adresse papier : https://arxiv.org/abs/2402.17764

Avec seulement 1,58 bits efficaces en termes de calcul, nous obtenons un modèle léger.

Les références:

https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-quantization