# Bitsandbytes

La biblioteca [bitsandbytes](https://github.com/bitsandbytes-foundation/bitsandbytes) ofrece herramientas de cuantización para LLMs a través de un envoltorio ligero de Python alrededor de funciones de aceleradores de hardware. Permite trabajar con modelos grandes utilizando recursos computacionales limitados al reducir su huella de memoria.

En su núcleo, bitsandbytes ofrece:

- **Capas lineales cuantizadas**: capas `Linear8bitLt` y `Linear4bit` que reemplazan las capas lineales estándar de PyTorch por alternativas cuantizadas eficientes en memoria
- **Optimized Optimizers**: 8-bit versions of common optimizers through its `optim` module, enabling training of large models with reduced memory requirements
- **Multiplicación de matrices**: Operaciones de multiplicación de matrices optimizadas que aprovechan el formato cuantizado

bitsandbytes ofrece dos funciones principales de cuantización:

1. **LLM.int8()** - Un método de cuantización de 8 bits que hace que la inferencia sea más accesible sin una degradación significativa del rendimiento. A diferencia de la cuantización ingenua, [LLM.int8()](https://hf.co/papers/2208.07339) preserva dinámicamente una mayor precisión para los cálculos críticos, evitando la pérdida de información en las partes sensibles del modelo.

2. **QLoRA** - Una técnica de cuantización de 4 bits que comprime los modelos aún más manteniendo su capacidad de entrenamiento mediante la inserción de un pequeño conjunto de pesos de adaptación de bajo rango (LoRA) entrenables.

> **Nota:** Para una experiencia de cuantización más amigable, puedes utilizar el [espacio de la comunidad](https://huggingface.co/spaces/bnb-community/bnb-my-repo) de `bitsandbytes`.

Ejecute el siguiente comando para instalar bitsandbytes.

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

Para compilar desde el código fuente, siga las instrucciones de la [guía de instalación de bitsandbytes](https://huggingface.co/docs/bitsandbytes/main/en/installation).

## Compatibilidad con el hardware

bitsandbytes es compatible con GPUs de NVIDIA para versiones de CUDA 11.8 - 13.0, Intel XPU, Intel Gaudi (HPU) y CPU. Existe un esfuerzo en curso para dar soporte a plataformas adicionales. Si te interesa proporcionar comentarios o realizar pruebas, consulta el [repositorio de bitsandbytes](https://github.com/bitsandbytes-foundation/bitsandbytes) para obtener más información.

### GPUs de NVIDIA (CUDA)

Este backend es compatible con las plataformas Linux x86-64, Linux aarch64 y Windows.

| Característica | Requisito mínimo de hardware |
|---------|-------------------------------|
| Optimizadores de 8 bits | GPUs NVIDIA Pascal (serie GTX 10X0, P100) o más recientes * |
| LLM.int8() | GPUs NVIDIA Turing (serie RTX 20X0, T4) o más recientes |
| Cuantización NF4/FP4 | GPUs NVIDIA Pascal (serie GTX 10X0, P100) o más recientes * |

### GPUs de Intel (XPU)

Este backend se admite en las plataformas Linux x86-64 y Windows x86-64.

### Intel Gaudi (HPU)

Este backend es compatible con Linux x86-64 para Gaudi2 y Gaudi3.

### CPU

Este backend se admite en las plataformas Linux x86-64, Linux aarch64 y Windows x86-64.

## Ejemplos de cuantización

Cuantice un modelo pasando una [BitsAndBytesConfig](/docs/transformers/main/es/main_classes/quantization#transformers.BitsAndBytesConfig) a [from_pretrained()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.from_pretrained). Esto funciona para cualquier modelo de cualquier modalidad, siempre que admita [Accelerate](https://huggingface.co/docs/accelerate/index) y contenga capas [torch.nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html).

Cuantizar un modelo en 8 bits reduce a la mitad el uso de memoria, y para modelos grandes, establezca `device_map="auto"` para distribuir eficientemente los pesos entre todas las GPUs 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
)
```

Por defecto, todos los demás módulos, como [torch.nn.LayerNorm](https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html), se configuran con el dtype de torch predeterminado. Puede cambiar el tipo de datos de estos módulos con el parámetro `dtype`. Establecer `dtype="auto"` carga el modelo con el tipo de datos definido en el archivo `config.json` del modelo.

```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
```

Una vez que un modelo está cuantizado a 8 bits, no se pueden subir los pesos cuantizados al Hub a menos que se esté utilizando la última versión de Transformers y bitsandbytes. Si se tienen las últimas versiones, se puede subir el modelo de 8 bits al Hub con [push_to_hub()](/docs/transformers/main/es/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). Primero se sube el archivo de configuración de cuantización config.json, seguido de los pesos del modelo cuantizado.

```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")
```

Cuantizar un modelo en 4 bits reduce el uso de memoria en 4 veces, y para modelos grandes, establezca `device_map="auto"` para distribuir eficientemente los pesos entre todas las 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
)
```

Por defecto, todos los demás módulos, como [torch.nn.LayerNorm](https://pytorch.org/docs/stable/generated/torch.nn.LayerNorm.html), se convierten a `torch.float16`. Puede cambiar el tipo de datos de estos módulos con el parámetro `dtype`. Establecer `dtype="auto"` carga el modelo en el tipo de datos definido en el archivo `config.json` del modelo.

```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
```

Asegúrate de tener la última versión de bitsandbytes para poder serializar modelos de 4 bits y subirlos al Hub con [push_to_hub()](/docs/transformers/main/es/main_classes/model#transformers.utils.PushToHubMixin.push_to_hub). Utiliza [save_pretrained()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.save_pretrained) para guardar el modelo de 4 bits localmente.

```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]
> El entrenamiento en 8 y 4 bits solo se admite para entrenar parámetros *extra*.

Comprueba tu huella de memoria con `get_memory_footprint`.

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

Cargue modelos cuantizados con [from_pretrained()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.from_pretrained) sin un `quantization_config`.

```py
from transformers import AutoModelForCausalLM, AutoTokenizer

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

## LLM.int8

Esta sección explora algunas de las características específicas de la cuantización de 8 bits, como el offloading, los umbrales de valores atípicos, el omitir la conversión de módulos y el finetuning.

### Descarga

Los modelos de 8 bits pueden descargar los pesos entre la CPU y la GPU para que quepan en memoria modelos muy grandes. Los pesos que se envían a la CPU se almacenan en **float32** y no se convierten a 8 bits. Por ejemplo, habilite la descarga para [bigscience/bloom-1b7](https://huggingface.co/bigscience/bloom-1b7) mediante [BitsAndBytesConfig](/docs/transformers/main/es/main_classes/quantization#transformers.BitsAndBytesConfig).

```py
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(llm_int8_enable_fp32_cpu_offload=True)
```

Diseña un mapa de dispositivos personalizado para que todo quepa en tu GPU, excepto `lm_head`, que se despacha a la CPU.

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

Ahora carga tu modelo con el `device_map` y el `quantization_config` personalizados.

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

### Umbral de valores atípicos

Un "outlier" es un valor de estado oculto que supera cierto umbral, y estos valores se calculan en fp16. Si bien los valores suelen tener una distribución normal ([-3.5, 3.5]), esta distribución puede ser muy diferente en modelos grandes ([-60, 6] o [6, 60]). La cuantización de 8 bits funciona bien para valores ~5, pero más allá de eso, hay un penalización significativa en el rendimiento. Un valor de umbral predeterminado adecuado es 6, pero puede ser necesario un umbral más bajo para modelos más inestables (modelos pequeños o finetuning).

Para encontrar el mejor umbral para tu modelo, experimenta con el parámetro `llm_int8_threshold` en [BitsAndBytesConfig](/docs/transformers/main/es/main_classes/quantization#transformers.BitsAndBytesConfig). Por ejemplo, establecer el umbral en `0.0` acelera significativamente la inferencia, a costa de una posible pérdida de precisión.

```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,
)
```

### Omitir la conversión de módulos

Para algunos modelos, como Jukebox, no es necesario cuantizar cada módulo a 8 bits, ya que esto puede causar inestabilidad. En el caso de Jukebox, hay varios módulos `lm_head` que deben omitirse mediante el parámetro `llm_int8_skip_modules` en [BitsAndBytesConfig](/docs/transformers/main/es/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,
)
```

### Ajuste fino

La biblioteca [PEFT](https://github.com/huggingface/peft) permite el ajuste fino de modelos grandes como [flan-t5-large](https://huggingface.co/google/flan-t5-large) y [facebook/opt-6.7b](https://huggingface.co/facebook/opt-6.7b) con cuantización de 8 bits. No es necesario pasar el parámetro `device_map` para el entrenamiento, ya que carga automáticamente el modelo en una GPU. Sin embargo, aún puedes personalizar el mapa de dispositivos con el parámetro `device_map` (`device_map="auto"` solo debe usarse para inferencia).

## QLoRA

Esta sección explora algunas de las características específicas de la cuantización de 4 bits, como el cambio del tipo de datos de cálculo, el tipo de datos Normal Float 4 (NF4) y la cuantización anidada.

### Tipo de datos de cálculo

Cambie el tipo de datos de float32 (el valor predeterminado) a bf16 en [BitsAndBytesConfig](/docs/transformers/main/es/main_classes/quantization#transformers.BitsAndBytesConfig) para acelerar el cálculo.

```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 es un tipo de datos de 4 bits del artículo [QLoRA](https://hf.co/papers/2305.14314), adaptado para pesos inicializados desde una distribución normal. Debe utilizar NF4 para entrenar modelos base de 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)
```

Para la inferencia, el `bnb_4bit_quant_type` no tiene un gran impacto en el rendimiento. Sin embargo, para mantener la coherencia con los pesos del modelo, debe usar los valores de `bnb_4bit_compute_dtype` y `dtype`.

### Cuantización anidada

La cuantización anidada puede ahorrar memoria adicional sin un coste de rendimiento extra. Esta característica realiza una segunda cuantización de los pesos ya cuantizados para ahorrar 0,4 bits/parámetro adicionales. Por ejemplo, con cuantización anidada, puedes hacer un ajuste fino de un modelo [Llama-13b](https://huggingface.co/meta-llama/Llama-2-13b) en una GPU NVIDIA T4 de 16 GB con una longitud de secuencia de 1024, un tamaño de lote de 1 y habilitando la acumulación de gradientes con 4 pasos.

```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)
```

## Descomprimir modelos de bitsandbytes

Una vez cuantizado, puedes [dequantize()](/docs/transformers/main/es/main_classes/model#transformers.PreTrainedModel.dequantize) un modelo a la precisión original, aunque esto puede provocar cierta pérdida de calidad. Asegúrate de tener suficiente memoria de GPU para cargar el modelo decuantizado.

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

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

## Recursos

Obtenga más información sobre los detalles de la cuantización de 8 bits en [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).

Prueba la cuantización de 4 bits en este [cuaderno](https://colab.research.google.com/drive/1ge2F1QSK8Q7h0hn3YKuBCOAS0bK8E0wf) y conoce más detalles en [Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA](https://huggingface.co/blog/4bit-transformers-bitsandbytes).

