# Bitsandbytes

La bibliothèque [bitsandbytes](https://github.com/bitsandbytes-foundation/bitsandbytes) fournit des outils de quantification pour les LLM via un wrapper Python léger autour des fonctions des accélérateurs matériels. Elle permet de travailler avec de grands modèles en disposant de ressources de calcul limitées, en réduisant leur empreinte mémoire.

Au cœur de bitsandbytes, on trouve :

- **Couches linéaires quantifiées** : les couches `Linear8bitLt` et `Linear4bit` qui remplacent les couches linéaires standard de PyTorch par des alternatives quantifiées plus économes en mémoire
- **Optimized Optimizers**: 8-bit versions of common optimizers through its `optim` module, enabling training of large models with reduced memory requirements
- **Multiplication de matrices** : Opérations de multiplication de matrices optimisées qui exploitent le format quantifié

bitsandbytes propose deux fonctionnalités principales de quantification :

1. **LLM.int8()** – Une méthode de quantification en 8 bits qui rend l'inférence plus accessible sans dégradation significative des performances. Contrairement à une quantification naïve, [LLM.int8()](https://hf.co/papers/2208.07339) conserve dynamiquement une précision plus élevée pour les calculs critiques, évitant ainsi la perte d'informations dans les parties sensibles du modèle.

2. **QLoRA** - Une technique de quantification sur 4 bits qui compresse encore davantage les modèles tout en conservant leur capacité d'entraînement, en insérant un petit ensemble de poids d'adaptation de faible rang (LoRA) entraînables.

> **Remarque :** Pour une expérience de quantification conviviale, vous pouvez utiliser l'[espace communautaire](https://huggingface.co/spaces/bnb-community/bnb-my-repo) `bitsandbytes`.

Exécutez la commande ci-dessous pour installer bitsandbytes.

```bash
pip install --upgrade transformers accelerate bitsandbytes
```

Pour compiler à partir du code source, suivez les instructions du [guide d'installation de bitsandbytes](https://huggingface.co/docs/bitsandbytes/main/en/installation).

## Compatibilité matérielle

bitsandbytes est pris en charge sur les GPU NVIDIA pour les versions CUDA 11.8 - 13.0, les XPU Intel, les Gaudi Intel (HPU) et le CPU. Des efforts sont en cours pour prendre en charge d'autres plateformes. Si vous souhaitez donner votre avis ou effectuer des tests, consultez le [dépôt bitsandbytes](https://github.com/bitsandbytes-foundation/bitsandbytes) pour plus d'informations.

### GPU NVIDIA (CUDA)

Ce backend est pris en charge sur les plateformes Linux x86-64, Linux aarch64 et Windows.

| Fonctionnalité | Exigence matérielle minimale |
|---------|-------------------------------|
| Optimiseurs 8 bits | GPU NVIDIA Pascal (série GTX 10X0, P100) ou plus récent * |
| LLM.int8() | GPU NVIDIA Turing (série RTX 20X0, T4) ou plus récent |
| Quantification NF4/FP4 | GPU NVIDIA Pascal (série GTX 10X0, P100) ou plus récent * |

### GPU Intel (XPU)

Ce backend est pris en charge sur les plateformes Linux x86-64 et Windows x86-64.

### Intel Gaudi (HPU)

Ce backend est pris en charge sur Linux x86-64 pour Gaudi2 et Gaudi3.

### CPU

Ce backend est pris en charge sur les plateformes Linux x86-64, Linux aarch64 et Windows x86-64.

## Exemples de quantification

Quantifiez un modèle en passant une [BitsAndBytesConfig](/docs/transformers/main/fr/main_classes/quantization#transformers.BitsAndBytesConfig) à [from_pretrained()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.from_pretrained). Cela fonctionne pour n'importe quel modèle de n'importe quelle modalité, à condition qu'il prenne en charge [Accelerate](https://huggingface.co/docs/accelerate/index) et qu'il contienne des couches [torch.nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html).

La quantification d’un modèle en 8 bits réduit de moitié l’empreinte mémoire, et pour les grands modèles, définissez `device_map="auto"` afin de répartir efficacement les poids sur toutes les GPU disponibles.

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

model_8bit = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-1b7", 
    device_map="auto",
    quantization_config=quantization_config
)
```

Par défaut, tous les autres modules, tels que [torch.nn.LayerNorm](https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html), sont définis sur le dtype torch par défaut. Vous pouvez modifier le type de données de ces modules à l'aide du paramètre `dtype`. La configuration `dtype="auto"` charge le modèle dans le type de données défini dans le fichier `config.json` du modèle.

```py
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

model_8bit = AutoModelForCausalLM.from_pretrained(
    "facebook/opt-350m", 
    device_map="auto",
    quantization_config=quantization_config, 
    dtype="auto"
)
model_8bit.model.decoder.layers[-1].final_layer_norm.weight.dtype
```

Une fois un modèle quantisé en 8 bits, il est impossible de publier les poids quantisés sur le Hub, sauf si vous utilisez les dernières versions de Transformers et bitsandbytes. Si vous disposez des versions les plus récentes, vous pouvez publier le modèle 8 bits sur le Hub à l'aide de [push_to_hub()](/docs/transformers/main/fr/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). Le fichier de configuration de quantization.json est d'abord publié, suivi des poids du modèle quantisé.

```py
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

model = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-560m", 
    device_map="auto",
    quantization_config=quantization_config
)

model.push_to_hub("bloom-560m-8bit")
```

La quantification d’un modèle en 4 bits réduit la consommation mémoire par 4, et pour les grands modèles, définissez `device_map="auto"` afin de répartir efficacement les poids sur l’ensemble des GPU disponibles.

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model_4bit = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-1b7",
    device_map="auto",
    quantization_config=quantization_config
)
```

Par défaut, tous les autres modules, tels que [torch.nn.LayerNorm](https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html), sont convertis en `torch.float16`. Vous pouvez modifier le type de données de ces modules à l'aide du paramètre `dtype`. La valeur `dtype="auto"` charge le modèle dans le type de données défini dans le fichier `config.json` du modèle.

```py
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model_4bit = AutoModelForCausalLM.from_pretrained(
    "facebook/opt-350m",
    device_map="auto",
    quantization_config=quantization_config, 
    dtype="auto"
)
model_4bit.model.decoder.layers[-1].final_layer_norm.weight.dtype
```

Assurez-vous de disposer de la dernière version de bitsandbytes afin de pouvoir sérialiser les modèles 4 bits et les pousser sur le Hub à l’aide de [push_to_hub()](/docs/transformers/main/fr/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). Utilisez [save_pretrained()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.save_pretrained) pour enregistrer le modèle 4 bits localement.

```py
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-560m", 
    device_map="auto",
    quantization_config=quantization_config
)

model.push_to_hub("bloom-560m-4bit")
```

> [!WARNING]
> L'entraînement en 8 et 4 bits n'est pris en charge que pour l'entraînement de paramètres *extra*.

Vérifiez votre empreinte mémoire avec `get_memory_footprint`.

```py
print(model.get_memory_footprint())
```

Charger des modèles quantifiés avec [from_pretrained()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.from_pretrained) sans `quantization_config`.

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("{your_username}/bloom-560m-8bit", device_map="auto")
```

## LLM.int8

Cette section explore certaines fonctionnalités spécifiques de la quantification 8 bits, telles que le déchargement, les seuils de valeurs aberrantes, le saut de la conversion de modules et l’ajustement fin.

### Offloading

Les modèles 8 bits peuvent décharger les poids entre le CPU et le GPU pour faire tenir des modèles très volumineux en mémoire. Les poids déchargés sur le CPU sont stockés en **float32** et ne sont pas convertis en 8 bits. Par exemple, activez le déchargement pour [bigscience/bloom-1b7](https://huggingface.co/bigscience/bloom-1b7) via [BitsAndBytesConfig](/docs/transformers/main/fr/main_classes/quantization#transformers.BitsAndBytesConfig).

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)
```

Concevez une carte de périphériques personnalisée pour tout placer sur votre GPU, à l’exception de `lm_head`, qui est affecté au CPU.

```py
device_map = {
    "transformer.word_embeddings": 0,
    "transformer.word_embeddings_layernorm": 0,
    "lm_head": "cpu",
    "transformer.h": 0,
    "transformer.ln_f": 0,
}
```

Chargez maintenant votre modèle avec le `device_map` et le `quantization_config` personnalisés.

```py
model_8bit = AutoModelForCausalLM.from_pretrained(
    "bigscience/bloom-1b7",
    dtype="auto",
    device_map=device_map,
    quantization_config=quantization_config,
)
```

### Seuil des valeurs aberrantes

Un « outlier » est une valeur d’état caché supérieure à un certain seuil, et ces valeurs sont calculées en fp16. Bien que les valeurs soient généralement distribuées normalement ([-3,5, 3,5]), cette distribution peut être très différente pour les grands modèles ([-60, 6] ou [6, 60]). La quantification 8 bits fonctionne bien pour des valeurs ~5, mais au-delà, il y a une pénalité de performance significative. Une valeur de seuil par défaut appropriée est 6, mais un seuil plus bas peut être nécessaire pour les modèles plus instables (petits modèles ou finetuning).

Pour trouver le meilleur seuil pour votre modèle, expérimentez avec le paramètre `llm_int8_threshold` dans [BitsAndBytesConfig](/docs/transformers/main/fr/main_classes/quantization#transformers.BitsAndBytesConfig). Par exemple, définir le seuil à `0.0` accélère considérablement l'inférence, au prix potentiel d'une légère perte de précision.

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

model_id = "bigscience/bloom-1b7"

quantization_config = BitsAndBytesConfig(
    llm_int8_threshold=0.0,
    llm_int8_enable_fp32_cpu_offload=True
)

model_8bit = AutoModelForCausalLM.from_pretrained(
    model_id,
    dtype="auto",
    device_map=device_map,
    quantization_config=quantization_config,
)
```

### Passer la conversion du module

Pour certains modèles, comme Jukebox, il n'est pas nécessaire de quantiser chaque module en 8 bits, car cela peut en réalité provoquer une instabilité. Avec Jukebox, plusieurs modules `lm_head` doivent être ignorés à l'aide du paramètre `llm_int8_skip_modules` dans [BitsAndBytesConfig](/docs/transformers/main/fr/main_classes/quantization#transformers.BitsAndBytesConfig).

```py
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

model_id = "bigscience/bloom-1b7"

quantization_config = BitsAndBytesConfig(
    llm_int8_skip_modules=["lm_head"],
)

model_8bit = AutoModelForCausalLM.from_pretrained(
    model_id,
    dtype="auto",
    device_map="auto",
    quantization_config=quantization_config,
)
```

### Affinage

La bibliothèque [PEFT](https://github.com/huggingface/peft) prend en charge l'ajustement fin de grands modèles tels que [flan-t5-large](https://huggingface.co/google/flan-t5-large) et [facebook/opt-6.7b](https://huggingface.co/facebook/opt-6.7b) avec une quantification 8 bits. Il n'est pas nécessaire de passer le paramètre `device_map` pour l'entraînement, car le modèle est automatiquement chargé sur un GPU. Toutefois, vous pouvez toujours personnaliser la carte des appareils à l'aide du paramètre `device_map` (`device_map="auto"` ne doit être utilisé que pour l'inférence).

## QLoRA

Cette section explore certaines fonctionnalités spécifiques de la quantification 4 bits, telles que le changement du type de données de calcul, le type de données Normal Float 4 (NF4) et la quantification imbriquée.

### Type de données de calcul

Changez le type de données de float32 (la valeur par défaut) en bf16 dans [BitsAndBytesConfig](/docs/transformers/main/fr/main_classes/quantization#transformers.BitsAndBytesConfig) pour accélérer les calculs.

```py
import torch
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
```

### Float 4 normal (NF4)

NF4 est un type de données sur 4 bits issu de l'article [QLoRA](https://hf.co/papers/2305.14314), adapté aux poids initialisés à partir d'une distribution normale. Vous devez utiliser NF4 pour l'entraînement de modèles de base sur 4 bits.

```py
from transformers import BitsAndBytesConfig

nf4_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
)

model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, dtype="auto", quantization_config=nf4_config)
```

Pour l’inférence, le `bnb_4bit_quant_type` n’a pas d’impact majeur sur les performances. Toutefois, pour rester cohérent avec les poids du modèle, vous devez utiliser les valeurs de `bnb_4bit_compute_dtype` et de `dtype`.

### Quantification imbriquée

La quantification imbriquée permet d’économiser de la mémoire supplémentaire sans surcoût en termes de performances. Cette fonctionnalité effectue une seconde quantification des poids déjà quantifiés afin d’économiser 0,4 bit/paramètre supplémentaires. Par exemple, avec la quantification imbriquée, vous pouvez effectuer un fine-tuning d’un modèle [Llama-13b](https://huggingface.co/meta-llama/Llama-2-13b) sur un GPU NVIDIA T4 de 16 Go avec une longueur de séquence de 1024, une taille de lot de 1 et l’accumulation de gradients activée sur 4 étapes.

```py
from transformers import BitsAndBytesConfig

double_quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
)

model_double_quant = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-13b-chat-hf", dtype="auto", quantization_config=double_quant_config)
```

## Déquantisation des modèles bitsandbytes

Une fois le modèle quantisé, vous pouvez le [dequantize()](/docs/transformers/main/fr/main_classes/model#transformers.PreTrainedModel.dequantize) pour revenir à la précision d'origine, mais cela peut entraîner une perte de qualité. Assurez-vous de disposer de suffisamment de mémoire GPU pour charger le modèle déquantisé.

```python
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m", BitsAndBytesConfig(load_in_4bit=True))
model.dequantize()
```

## Ressources

En savoir plus sur les détails de la quantification 8 bits dans [A Gentle Introduction to 8-bit Matrix Multiplication for transformers at scale using Hugging Face Transformers, Accelerate and bitsandbytes](https://huggingface.co/blog/hf-bitsandbytes-integration).

Essayez la quantification 4 bits dans ce [notebook](https://colab.research.google.com/drive/1ge2F1QSK8Q7h0hn3YKuBCOAS0bK8E0wf) et en apprenez plus sur ses détails dans [Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA](https://huggingface.co/blog/4bit-transformers-bitsandbytes).

