Haciendo que los LLMs sean aún más accesibles con bitsandbytes, cuantización de 4 bits y QLoRA
Haciendo LLMs más accesibles con bitsandbytes, cuantización de 4 bits y QLoRA.
Se sabe que los LLM son grandes, y ejecutar o entrenarlos en hardware de consumo es un gran desafío para los usuarios y la accesibilidad. Nuestro artículo de blog LLM.int8 mostró cómo las técnicas en el documento LLM.int8 se integraron en los transformadores utilizando la biblioteca bitsandbytes
. Con el objetivo de hacer que los modelos sean aún más accesibles para todos, decidimos colaborar nuevamente con bitsandbytes para permitir a los usuarios ejecutar modelos con una precisión de 4 bits. Esto incluye la gran mayoría de los modelos de HF, en cualquier modalidad (texto, visión, multimodal, etc.). Los usuarios también pueden entrenar adaptadores sobre modelos de 4 bits aprovechando las herramientas del ecosistema de Hugging Face. Este es un nuevo método presentado hoy en el artículo QLoRA de Dettmers et al. El resumen del artículo es el siguiente:
Presentamos QLoRA, un enfoque eficiente de afinación fina que reduce el uso de memoria lo suficiente como para afinar un modelo de 65B parámetros en una sola GPU de 48GB mientras se mantiene el rendimiento completo de afinación fina de 16 bits. QLoRA propaga los gradientes a través de un modelo de lenguaje preentrenado cuantizado de 4 bits congelado en adaptadores de rango bajo~(LoRA). Nuestra mejor familia de modelos, a la que llamamos Guanaco, supera a todos los modelos previamente lanzados abiertamente en la prueba de referencia Vicuna, alcanzando el 99.3% del nivel de rendimiento de ChatGPT mientras solo requiere 24 horas de afinación fina en una sola GPU. QLoRA introduce varias innovaciones para ahorrar memoria sin sacrificar el rendimiento: (a) NormalFloat de 4 bits (NF4), un nuevo tipo de datos que es óptimo desde el punto de vista teórico de la información para pesos distribuidos normalmente (b) doble cuantización para reducir la huella de memoria promedio cuantizando las constantes de cuantización, y (c) optimizadores paginados para gestionar picos de memoria. Utilizamos QLoRA para afinar más de 1,000 modelos, proporcionando un análisis detallado del seguimiento de instrucciones y el rendimiento de chatbots en 8 conjuntos de datos de instrucciones, múltiples tipos de modelos (LLaMA, T5) y escalas de modelos que serían inviables de ejecutar con afinación fina regular (por ejemplo, modelos de 33B y 65B parámetros). Nuestros resultados muestran que la afinación fina de QLoRA en un pequeño conjunto de datos de alta calidad conduce a resultados de vanguardia, incluso cuando se utilizan modelos más pequeños que los del SoTA anterior. Proporcionamos un análisis detallado del rendimiento de chatbots basado en evaluaciones tanto humanas como de GPT-4 que demuestran que las evaluaciones de GPT-4 son una alternativa económica y razonable a la evaluación humana. Además, descubrimos que las pruebas actuales de chatbots no son confiables para evaluar con precisión los niveles de rendimiento de los chatbots. Un análisis selectivo demuestra dónde Guanaco falla en comparación con ChatGPT. Publicamos todos nuestros modelos y código, incluidos los núcleos CUDA para entrenamiento de 4 bits.
Recursos
Este artículo de blog y la publicación incluyen varios recursos para comenzar con modelos de 4 bits y QLoRA:
- Documento original
- Notebook básico de uso de Google Colab: este notebook muestra cómo usar modelos de 4 bits en inferencia con todas sus variantes y cómo ejecutar GPT-neo-X (un modelo de 20B parámetros) en una instancia gratuita de Google Colab 🤯
- Notebook de afinación fina de Google Colab: este notebook muestra cómo afinar un modelo de 4 bits en una tarea secundaria utilizando el ecosistema de Hugging Face. ¡Mostramos que es posible afinar GPT-neo-X 20B en una instancia de Google Colab!
- Repositorio original para replicar los resultados del artículo
- Área de juegos de Guanaco 33b: o consulte la sección de juegos a continuación
Introducción
Si no está familiarizado con las precisiones del modelo y los tipos de datos más comunes (float16, float32, bfloat16, int8), le recomendamos que lea detenidamente la introducción en nuestro primer artículo de blog que explica estos conceptos en términos simples con visualizaciones.
Para obtener más información, recomendamos leer los fundamentos de la representación de punto flotante a través de este documento de wikilibros.
- Presentando la integración de BERTopic con el Hugging Face Hub
- Presentamos el Contenedor de Inferencia LLM de Hugging Face para Am...
- Hugging Face seleccionada para el Programa de Apoyo Mejorado de la ...
El reciente artículo QLoRA explora diferentes tipos de datos, como el float de 4 bits y el NormalFloat de 4 bits. Aquí discutiremos el tipo de datos float de 4 bits, ya que es más fácil de entender.
FP8 y FP4 representan los puntos flotantes de precisión de 8 y 4 bits, respectivamente. Forman parte de la familia de minipuntos flotantes (entre otras precisiones, la familia de minipuntos flotantes también incluye bfloat16 y float16).
Primero veamos cómo se representan los valores de punto flotante en formato FP8 y luego comprendamos cómo se ve el formato FP4.
Formato FP8
Como se discutió en nuestra publicación anterior, un punto flotante contiene n-bits, y cada bit cae en una categoría específica que se encarga de representar una componente del número (signo, mantisa y exponente). Estos representan lo siguiente.
El formato FP8 (punto flotante 8) fue presentado por primera vez en el artículo “FP8 para Deep Learning” con dos codificaciones diferentes de FP8: E4M3 (exponente de 4 bits y mantisa de 3 bits) y E5M2 (exponente de 5 bits y mantisa de 2 bits).
Aunque la precisión se reduce sustancialmente al reducir el número de bits de 32 a 8, ambas versiones se pueden utilizar en una variedad de situaciones. Actualmente se puede utilizar la biblioteca Transformer Engine, que también está integrada con el ecosistema de HF a través de accelerate.
Los puntos flotantes potenciales que se pueden representar en el formato E4M3 están en el rango de -448 a 448, mientras que en el formato E5M2, a medida que aumenta el número de bits del exponente, el rango aumenta a -57344 a 57344, pero con una pérdida de precisión porque el número de representaciones posibles permanece constante. Se ha demostrado empíricamente que el formato E4M3 es el más adecuado para el paso hacia adelante, y la segunda versión es la más adecuada para el cálculo hacia atrás.
Precisión FP4 en pocas palabras
El bit de signo representa el signo (+/-), los bits del exponente son una base dos elevada a la potencia del entero representado por los bits (por ejemplo, 2^{010} = 2^{2} = 4
), y la fracción o mantisa es la suma de las potencias de menos dos que están “activas” para cada bit que es “1”. Si un bit es “0”, la fracción permanece sin cambios para esa potencia de 2^-i
donde i es la posición del bit en la secuencia de bits. Por ejemplo, para los bits de mantisa 1010 tenemos (0 + 2^-1 + 0 + 2^-3) = (0.5 + 0.125) = 0.625
. Para obtener un valor, se suma 1 a la fracción y se multiplican todos los resultados juntos, por ejemplo, con 2 bits de exponente y un bit de mantisa, las representaciones 1101 serían:
-1 * 2^(2) * (1 + 2^-1) = -1 * 4 * 1.5 = -6
Para FP4 no hay un formato fijo y, como tal, se pueden probar combinaciones de diferentes combinaciones de mantisa/exponente. En general, 3 bits de exponente funcionan un poco mejor en la mayoría de los casos. Pero a veces, 2 bits de exponente y un bit de mantisa ofrecen un mejor rendimiento.
Artículo QLoRA, una nueva forma de democratizar los modelos de transformadores cuantizados grandes
En pocas palabras, QLoRA reduce el uso de memoria del ajuste fino de LLM sin comprometer el rendimiento en comparación con el ajuste fino del modelo estándar de 16 bits. Este método permite el ajuste fino del modelo de 33B en una sola GPU de 24GB y el ajuste fino del modelo de 65B en una sola GPU de 46GB.
Más específicamente, QLoRA utiliza una cuantización de 4 bits para comprimir un modelo de lenguaje preentrenado. Los parámetros de LM se congelan y se agregan un número relativamente pequeño de parámetros entrenables al modelo en forma de adaptadores de rango bajo. Durante el ajuste fino, QLoRA propaga los gradientes a través del modelo de lenguaje preentrenado cuantizado de 4 bits congelado hacia los adaptadores de rango bajo. Las capas LoRA son los únicos parámetros que se actualizan durante el entrenamiento. Obtenga más información sobre LoRA en el artículo original de LoRA.
QLoRA tiene un tipo de dato de almacenamiento (normalmente NormalFloat de 4 bits) para los pesos del modelo base y un tipo de dato de cálculo (BrainFloat de 16 bits) utilizado para realizar cálculos. QLoRA descuantiza los pesos del tipo de datos de almacenamiento al tipo de datos de cálculo para realizar los pasos hacia adelante y hacia atrás, pero solo calcula los gradientes de peso para los parámetros LoRA que utilizan bfloat de 16 bits. Los pesos se descomprimen solo cuando se necesitan, por lo tanto, el uso de memoria se mantiene bajo durante el entrenamiento y la inferencia.
Se ha demostrado que el ajuste fino de QLoRA coincide con los métodos de ajuste fino de 16 bits en una amplia gama de experimentos. Además, los modelos Guanaco, que utilizan el ajuste fino de QLoRA para los modelos LLaMA en el conjunto de datos OpenAssistant (OASST1), son sistemas de chatbot de última generación y están cerca de ChatGPT en la prueba Vicuna. Esto es una demostración adicional del poder del ajuste fino de QLoRA.
Para una lectura más detallada, te recomendamos leer el artículo QLoRA .
¿Cómo usarlo en transformers?
En esta sección, vamos a presentar la integración de transformers de este método, cómo usarlo y qué modelos se pueden cuantizar de manera efectiva.
Comenzando
Como inicio rápido, carga un modelo en 4 bits (en el momento de escribir esto) instalando accelerate y transformers desde la fuente, y asegúrate de haber instalado la última versión de la biblioteca bitsandbytes (0.39.0).
pip install -q -U bitsandbytes
pip install -q -U git+https://github.com/huggingface/transformers.git
pip install -q -U git+https://github.com/huggingface/peft.git
pip install -q -U git+https://github.com/huggingface/accelerate.git
Inicio rápido
La forma básica de cargar un modelo en 4 bits es pasar el argumento load_in_4bit=True
al llamar al método from_pretrained
y proporcionar un mapa de dispositivos (pasa "auto"
para obtener un mapa de dispositivos que se inferirá automáticamente).
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_4bit=True, device_map="auto")
...
¡Eso es todo lo que necesitas!
Como regla general, recomendamos a los usuarios no establecer manualmente un dispositivo una vez que el modelo se haya cargado con device_map
. Por lo tanto, cualquier llamada de asignación de dispositivo al modelo, o a cualquier submódulo del modelo, debe evitarse después de esa línea, a menos que sepas lo que estás haciendo.
Ten en cuenta que cargar un modelo cuantizado automáticamente convertirá otros submódulos del modelo a float16
. Puedes cambiar este comportamiento (si, por ejemplo, quieres tener las normas de capa en float32
) pasando torch_dtype=dtype
al método from_pretrained
.
Uso avanzado
Puedes experimentar con diferentes variantes de cuantización de 4 bits, como NF4 (4 bits de punto flotante normalizados (valor predeterminado)) o cuantización pura de FP4. Basado en consideraciones teóricas y resultados empíricos del artículo, recomendamos utilizar la cuantización NF4 para un mejor rendimiento.
Otras opciones incluyen bnb_4bit_use_double_quant
, que utiliza una segunda cuantización después de la primera para ahorrar 0.4 bits adicionales por parámetro. Y finalmente, el tipo de cálculo. Mientras que bitsandbytes de 4 bits almacena los pesos en 4 bits, el cálculo aún se realiza en 16 o 32 bits y aquí se puede elegir cualquier combinación (float16, bfloat16, float32, etc).
La multiplicación de matrices y el entrenamiento serán más rápidos si se utiliza un tipo de cálculo de 16 bits (torch.float32 por defecto). Deberías aprovechar la reciente BitsAndBytesConfig
de transformers para cambiar estos parámetros. Un ejemplo para cargar un modelo en 4 bits utilizando la cuantización NF4 a continuación con doble cuantización con el tipo de cálculo bfloat16 para un entrenamiento más rápido:
from transformers import BitsAndBytesConfig
nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
model_nf4 = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=nf4_config)
Cambiando el tipo de cálculo
Como se mencionó anteriormente, también puedes cambiar el tipo de cálculo del modelo cuantizado cambiando simplemente el argumento bnb_4bit_compute_dtype
en BitsAndBytesConfig
.
import torch
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
Cuantización anidada
Para habilitar la cuantización anidada, puedes usar el argumento bnb_4bit_use_double_quant
en BitsAndBytesConfig
. Esto habilitará una segunda cuantización después de la primera para ahorrar 0.4 bits adicionales por parámetro. También utilizamos esta función en el cuaderno de entrenamiento de Google Colab.
from transformers import BitsAndBytesConfig
double_quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
)
model_double_quant = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=double_quant_config)
Y, como se mencionó al principio de la sección, todos estos componentes son componibles. Puedes combinar todos estos parámetros juntos para encontrar el caso de uso óptimo para ti. Una regla general es: usa la doble cuantificación si tienes problemas con la memoria, usa NF4 para una mayor precisión y usa un tipo de datos de 16 bits para un ajuste fino más rápido. Por ejemplo, en la demostración de inferencia, utilizamos cuantificación anidada, tipo de cálculo bfloat16 y cuantificación NF4 para ajustar completamente gpt-neo-x-20b (40GB) en 4 bits en una sola GPU de 16GB.
Preguntas frecuentes
En esta sección, también abordaremos algunas preguntas frecuentes que cualquiera podría tener con respecto a esta integración.
¿La cuantificación FP4 tiene algún requisito de hardware?
Ten en cuenta que este método solo es compatible con GPUs, por lo tanto, no es posible cuantizar modelos en 4 bits en una CPU. Entre las GPUs, no debería haber ningún requisito de hardware para este método, por lo tanto, cualquier GPU se puede utilizar para ejecutar la cuantificación de 4 bits siempre que tengas CUDA>=11.2 instalado. También ten en cuenta que la computación no se realiza en 4 bits, los pesos y las activaciones se comprimen a ese formato y la computación se mantiene en el tipo de datos deseado o nativo.
¿Cuáles son los modelos compatibles?
De manera similar a la integración de LLM.int8 presentada en esta publicación de blog, la integración depende en gran medida de la biblioteca “accelerate”. Por lo tanto, cualquier modelo que admita la carga de aceleración (es decir, el argumento “device_map” al llamar a “from_pretrained”) se puede cuantizar en 4 bits. También ten en cuenta que esto es completamente agnóstico a las modalidades, siempre que los modelos se puedan cargar con el argumento “device_map”, es posible cuantizarlos.
Para los modelos de texto, en el momento de escribir esto, esto incluiría las arquitecturas más utilizadas como Llama, OPT, GPT-Neo, GPT-NeoX para modelos de texto, Blip2 para modelos multimodales, y así sucesivamente.
En el momento de escribir esto, los modelos que admiten “accelerate” son:
[
'bigbird_pegasus', 'blip_2', 'bloom', 'bridgetower', 'codegen', 'deit', 'esm',
'gpt2', 'gpt_bigcode', 'gpt_neo', 'gpt_neox', 'gpt_neox_japanese', 'gptj', 'gptsan_japanese',
'lilt', 'llama', 'longformer', 'longt5', 'luke', 'm2m_100', 'mbart', 'mega', 'mt5', 'nllb_moe',
'open_llama', 'opt', 'owlvit', 'plbart', 'roberta', 'roberta_prelayernorm', 'rwkv', 'switch_transformers',
't5', 'vilt', 'vit', 'vit_hybrid', 'whisper', 'xglm', 'xlm_roberta'
]
Ten en cuenta que si tu modelo favorito no está ahí, puedes abrir una solicitud de extracción o plantear un problema en transformers para agregar el soporte de carga de aceleración para esa arquitectura.
¿Podemos entrenar modelos de 4 bits/8 bits?
No es posible realizar entrenamiento puro de 4 bits en estos modelos. Sin embargo, puedes entrenar estos modelos aprovechando métodos de ajuste fino de parámetros eficientes (PEFT) y entrenar, por ejemplo, adaptadores sobre ellos. Eso es lo que se hace en el artículo y es oficialmente compatible con la biblioteca PEFT de Hugging Face. También proporcionamos un cuaderno de entrenamiento y recomendamos a los usuarios que consulten el repositorio QLoRA si están interesados en replicar los resultados del artículo.
¿Qué otras consecuencias hay?
Esta integración puede abrir varias consecuencias positivas para la comunidad y la investigación en IA, ya que puede afectar múltiples casos de uso y posibles aplicaciones. En RLHF (Aprendizaje por Reforzamiento con Retroalimentación Humana), es posible cargar un único modelo base, en 4 bits, y entrenar múltiples adaptadores sobre él, uno para el modelado de recompensas y otro para el entrenamiento de la política de valor. Pronto se realizará una publicación de blog y un anuncio más detallado sobre este caso de uso.
También hemos realizado algunos benchmarks sobre el impacto de este método de cuantización en el entrenamiento de modelos grandes en hardware de consumo. Hemos realizado varios experimentos para ajustar finamente 2 arquitecturas diferentes, Llama 7B (15GB en fp16) y Llama 13B (27GB en fp16) en un NVIDIA T4 (16GB) y aquí están los resultados
Hemos utilizado el reciente SFTTrainer
de la biblioteca TRL, y el script de benchmarking se puede encontrar aquí
Playground
Prueba el modelo Guananco mencionado en el artículo en el área de juegos o directamente a continuación
Agradecimientos
El equipo de HF desea agradecer a todas las personas involucradas en este proyecto de la Universidad de Washington, y por ponerlo a disposición de la comunidad.
Los autores también quieren agradecer a Pedro Cuenca por revisar amablemente el blogpost, a Olivier Dehaene y Omar Sanseviero por su rápido y sólido apoyo para la integración de los artefactos del artículo en el HF Hub.