Rendendo LLMs ancora più accessibili con bitsandbytes, quantizzazione a 4 bit e QLoRA

'Rendendo LLMs più accessibili con bitsandbytes e QLoRA, quantizzazione a 4 bit.'

LLM sono noti per essere grandi e eseguirli o addestrarli su hardware consumer è una grande sfida per gli utenti e l’accessibilità. Il nostro post sul blog LLM.int8 ha mostrato come le tecniche nel paper LLM.int8 sono state integrate nei transformers utilizzando la libreria bitsandbytes. Mentre ci sforziamo di rendere i modelli ancora più accessibili a tutti, abbiamo deciso di collaborare nuovamente con bitsandbytes per consentire agli utenti di eseguire modelli con una precisione a 4 bit. Ciò include la maggior parte dei modelli HF, in qualsiasi modalità (testo, visione, multimodale, ecc.). Gli utenti possono anche addestrare adattatori su modelli a 4 bit utilizzando gli strumenti dell’ecosistema Hugging Face. Questo è un nuovo metodo introdotto oggi nel paper QLoRA di Dettmers et al. L’abstract del paper è il seguente:

Presentiamo QLoRA, un approccio di fine-tuning efficiente che riduce l’utilizzo della memoria sufficientemente da permettere di eseguire il fine-tuning di un modello a 65B parametri su una singola GPU da 48GB preservando al contempo le prestazioni del task di fine-tuning a 16 bit. QLoRA propagazione del gradiente attraverso un modello di linguaggio preaddestrato congelato con una quantizzazione a 4 bit in Adattatori a Basso Rango~(LoRA). La nostra migliore famiglia di modelli, che chiamiamo Guanaco, supera tutti i modelli precedentemente rilasciati pubblicamente nel benchmark Vicuna, raggiungendo il 99.3% del livello di performance di ChatGPT richiedendo solo 24 ore di fine-tuning su una singola GPU. QLoRA introduce una serie di innovazioni per risparmiare memoria senza sacrificare le prestazioni: (a) NormalFloat a 4 bit (NF4), un nuovo tipo di dato che è teoricamente ottimale per pesi distribuiti normalmente (b) doppia quantizzazione per ridurre l’occupazione media della memoria quantizzando le costanti di quantizzazione, e (c) ottimizzatori a pagine per gestire picchi di memoria. Utilizziamo QLoRA per il fine-tuning di oltre 1,000 modelli, fornendo un’analisi dettagliata del follow-up delle istruzioni e delle prestazioni dei chatbot su 8 dataset di istruzioni, diversi tipi di modelli (LLaMA, T5) e scale di modelli che sarebbero impraticabili da eseguire con il fine-tuning regolare (ad esempio, modelli a 33B e 65B parametri). I nostri risultati mostrano che il fine-tuning di QLoRA su un piccolo dataset di alta qualità porta a risultati all’avanguardia, anche utilizzando modelli più piccoli rispetto al precedente SoTA. Forniamo un’analisi dettagliata delle prestazioni dei chatbot basata sia su valutazioni umane che su GPT-4 mostrando che le valutazioni di GPT-4 sono un’alternativa economica e ragionevole alla valutazione umana. Inoltre, scopriamo che i benchmark attuali dei chatbot non sono affidabili per valutare accuratamente i livelli di performance dei chatbot. Un’analisi selezionata dimostra dove Guanaco fallisce rispetto a ChatGPT. Rilasciamo tutti i nostri modelli e codice, compresi i kernel CUDA per il training a 4 bit.

Risorse

Questo post sul blog e il suo rilascio sono accompagnati da diverse risorse per iniziare con i modelli a 4 bit e QLoRA:

  • Articolo originale
  • Notebook di utilizzo di base di Google Colab – Questo notebook mostra come utilizzare i modelli a 4 bit nell’inferenza con tutte le loro varianti e come eseguire GPT-neo-X (un modello a 20B parametri) su un’istanza gratuita di Google Colab 🤯
  • Notebook di fine-tuning di Google Colab – Questo notebook mostra come eseguire il fine-tuning di un modello a 4 bit su un task secondario utilizzando l’ecosistema Hugging Face. Mostriamo che è possibile eseguire il fine-tuning di GPT-neo-X 20B su un’istanza di Google Colab!
  • Repository originale per replicare i risultati del paper
  • Guanaco 33b playground – o controlla la sezione playground qui sotto

Introduzione

Se non sei familiare con le precisioni dei modelli e i tipi di dati più comuni (float16, float32, bfloat16, int8), ti consigliamo di leggere attentamente l’introduzione nel nostro primo post sul blog che spiega in dettaglio questi concetti in termini semplici con visualizzazioni.

Per ulteriori informazioni, ti consigliamo di leggere i fondamenti della rappresentazione in virgola mobile attraverso questo documento wikibook.

Il recente paper QLoRA esplora diversi tipi di dati, Float a 4 bit e NormalFloat a 4 bit. Discuteremo qui il tipo di dato Float a 4 bit poiché è più facile da comprendere.

FP8 e FP4 rappresentano rispettivamente la precisione in virgola mobile a 8 bit e a 4 bit. Fanno parte della famiglia dei minifloats di valori in virgola mobile (tra le altre precisioni, la famiglia dei minifloats include anche bfloat16 e float16).

Diamo prima un’occhiata a come rappresentare i valori in virgola mobile nel formato FP8, quindi capire come appare il formato FP4.

Formato FP8

Come discusso nel nostro precedente post sul blog, un floating point contiene n-bit, con ogni bit che ricade in una specifica categoria responsabile di rappresentare una componente del numero (segno, mantissa ed esponente). Questi rappresentano quanto segue.

Il formato FP8 (floating point 8) è stato introdotto per la prima volta nel paper “FP8 per il Deep Learning” con due diverse codifiche FP8: E4M3 (4-bit di esponente e 3-bit di mantissa) e E5M2 (5-bit di esponente e 2-bit di mantissa).

Sebbene la precisione sia notevolmente ridotta riducendo il numero di bit da 32 a 8, entrambe le versioni possono essere utilizzate in una varietà di situazioni. Attualmente è possibile utilizzare la libreria Transformer Engine che è anche integrata nell’ecosistema HF tramite accelerate.

I potenziali punti mobili che possono essere rappresentati nel formato E4M3 sono compresi nell’intervallo da -448 a 448, mentre nel formato E5M2, con l’aumento del numero di bit dell’esponente, l’intervallo aumenta a -57344 a 57344, ma con una perdita di precisione poiché il numero di possibili rappresentazioni rimane costante. È stato dimostrato empiricamente che E4M3 è più adatto per il passaggio in avanti, e la seconda versione è più adatta per il calcolo all’indietro.

Precisione FP4 in poche parole

Il bit di segno rappresenta il segno (+/-), i bit dell’esponente rappresentano una base due elevata alla potenza dell’intero rappresentato dai bit (ad esempio, 2^{010} = 2^{2} = 4 ), e la frazione o mantissa è la somma delle potenze di meno due che sono “attive” per ogni bit che è “1”. Se un bit è “0”, la frazione rimane invariata per quella potenza di 2^-i in cui i è la posizione del bit nella sequenza di bit. Ad esempio, per i bit della mantissa 1010 abbiamo (0 + 2^-1 + 0 + 2^-3) = (0.5 + 0.125) = 0.625 . Per ottenere un valore, si aggiunge 1 alla frazione e si moltiplicano tutti i risultati insieme, ad esempio, con 2 bit di esponente e un bit di mantissa le rappresentazioni 1101 sarebbero:

-1 * 2^(2) * (1 + 2^-1) = -1 * 4 * 1.5 = -6

Per FP4 non c’è un formato fisso e quindi è possibile provare combinazioni di diverse combinazioni di mantissa/esponente. In generale, 3 bit dell’esponente funzionano un po’ meglio nella maggior parte dei casi. Ma a volte 2 bit dell’esponente e un bit della mantissa producono una migliore performance.

QLoRA paper, un nuovo modo di democratizzare i modelli di transformer grandi quantizzati

In poche parole, QLoRA riduce l’uso della memoria per il fine-tuning di LLM senza compromettere le prestazioni rispetto al fine-tuning del modello standard a 16 bit. Questo metodo consente il fine-tuning del modello da 33B su una singola GPU da 24GB e il fine-tuning del modello da 65B su una singola GPU da 46GB.

Nello specifico, QLoRA utilizza una quantizzazione a 4 bit per comprimere un modello di linguaggio preaddestrato. I parametri di LM vengono quindi congelati e un numero relativamente piccolo di parametri addestrabili viene aggiunto al modello sotto forma di Adattatori a Basso Rango. Durante il fine-tuning, QLoRA propaga all’indietro i gradienti attraverso il modello di linguaggio preaddestrato quantizzato a 4 bit congelato verso gli Adattatori a Basso Rango. Solo i livelli LoRA vengono aggiornati durante l’addestramento. Leggi di più su LoRA nell’articolo originale di LoRA.

QLoRA ha un tipo di dato di archiviazione (di solito NormalFloat a 4 bit) per i pesi del modello di base e un tipo di dato di calcolo (BrainFloat a 16 bit) utilizzato per eseguire i calcoli. QLoRA dequantizza i pesi dal tipo di dato di archiviazione al tipo di dato di calcolo per eseguire i passaggi in avanti e all’indietro, ma calcola solo i gradienti dei pesi per i parametri LoRA che utilizzano bfloat a 16 bit. I pesi vengono decompressi solo quando sono necessari, quindi l’uso della memoria rimane basso durante l’addestramento e l’inferenza.

QLoRA viene dimostrato essere equivalente ai metodi di fine-tuning a 16 bit in una vasta gamma di esperimenti. Inoltre, i modelli Guanaco, che utilizzano il fine-tuning di QLoRA per i modelli LLaMA sul dataset OpenAssistant (OASST1), sono sistemi di chatbot all’avanguardia e si avvicinano a ChatGPT nel benchmark di Vicuna. Questa è una dimostrazione aggiuntiva del potere del fine-tuning di QLoRA.

Per una lettura più dettagliata, ti consigliamo di leggere l’articolo QLoRA .

Come utilizzarlo in transformers?

In questa sezione ti presentiamo l’integrazione di transformers di questo metodo, come utilizzarlo e quali modelli possono essere effettivamente quantizzati.

Iniziare

Come avvio rapido, carica un modello in 4 bit (al momento della stesura di questo testo) installando accelerate e transformers da origine e assicurati di avere installata l’ultima versione della libreria 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

Avvio rapido

Il modo di base per caricare un modello in 4 bit è passare l’argomento load_in_4bit=True quando si chiama il metodo from_pretrained fornendo una mappa dei dispositivi (passare "auto" per ottenere una mappa dei dispositivi che verrà automaticamente inferita).

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("facebook/opt-350m", load_in_4bit=True, device_map="auto")
...

Questo è tutto ciò di cui hai bisogno!

Come regola generale, consigliamo agli utenti di non impostare manualmente un dispositivo una volta che il modello è stato caricato con device_map . Quindi qualsiasi chiamata di assegnazione del dispositivo al modello, o a qualsiasi sottomodulo del modello dovrebbe essere evitata dopo quella riga, a meno che tu non sappia cosa stai facendo.

Tieni presente che il caricamento di un modello quantizzato convertirà automaticamente gli altri sottomoduli del modello in float16 dtype. È possibile modificare questo comportamento (ad esempio se si desidera avere le norme del livello in float32 ) passando torch_dtype=dtype al metodo from_pretrained.

Utilizzo avanzato

Puoi sperimentare con diverse varianti di quantizzazione a 4 bit come NF4 (float 4 normalizzato (predefinito)) o quantizzazione FP4 pura. Sulla base di considerazioni teoriche e risultati empirici dell’articolo, consigliamo di utilizzare la quantizzazione NF4 per una migliore performance.

Altre opzioni includono bnb_4bit_use_double_quant che utilizza una seconda quantizzazione dopo la prima per risparmiare ulteriori 0,4 bit per parametro. E infine, il tipo di calcolo. Mentre bitsandbytes a 4 bit memorizza i pesi a 4 bit, il calcolo avviene ancora a 16 o 32 bit e qui può essere scelta qualsiasi combinazione (float16, bfloat16, float32, ecc).

La moltiplicazione della matrice e l’addestramento saranno più veloci se si utilizza un dtype di calcolo a 16 bit (torch.float32 predefinito). È possibile sfruttare la recente BitsAndBytesConfig di transformers per modificare questi parametri. Un esempio per caricare un modello a 4 bit utilizzando la quantizzazione NF4 di seguito con doppia quantizzazione con il dtype di calcolo bfloat16 per un addestramento più veloce:

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)

Cambiare il dtype di calcolo

Come indicato sopra, è possibile anche cambiare il dtype di calcolo del modello quantizzato semplicemente modificando l’argomento bnb_4bit_compute_dtype in BitsAndBytesConfig .

import torch
from transformers import BitsAndBytesConfig

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

Quantizzazione nidificata

Per abilitare la quantizzazione nidificata, è possibile utilizzare l’argomento bnb_4bit_use_double_quant in BitsAndBytesConfig . Ciò abiliterà una seconda quantizzazione dopo la prima per risparmiare ulteriori 0,4 bit per parametro. Utilizziamo anche questa funzionalità nel notebook di Google colab per l’addestramento.

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)

E naturalmente, come indicato all’inizio della sezione, tutti questi componenti sono componibili. Puoi combinare tutti questi parametri insieme per trovare il caso d’uso ottimale per te. Una regola generale è: usa la doppia quantizzazione se hai problemi di memoria, usa NF4 per una maggiore precisione e usa un tipo di dati a 16 bit per un addestramento più veloce. Ad esempio, nella demo di inferenza, utilizziamo la quantizzazione nidificata, il tipo di calcolo bfloat16 e la quantizzazione NF4 per adattare completamente gpt-neo-x-20b (40 GB) in un singolo GPU da 16 GB.

Domande comuni

In questa sezione, affronteremo anche alcune domande comuni che chiunque potrebbe avere riguardo a questa integrazione.

La quantizzazione FP4 ha qualche requisito hardware?

Si noti che questo metodo è compatibile solo con le GPU, quindi non è possibile quantizzare modelli in 4 bit su una CPU. Tra le GPU, non dovrebbero esserci requisiti hardware per questo metodo, quindi qualsiasi GPU potrebbe essere utilizzata per eseguire la quantizzazione a 4 bit purché si abbia CUDA>=11.2 installato. Tieni anche presente che il calcolo non viene eseguito in 4 bit, i pesi e le attivazioni vengono compressi in quel formato e il calcolo viene comunque mantenuto nel tipo di dati desiderato o nativo.

Quali modelli sono supportati?

Allo stesso modo dell’integrazione di LLM.int8 presentata in questo post del blog, l’integrazione si basa pesantemente sulla libreria accelerate. Pertanto, qualsiasi modello che supporta il caricamento di accelerate (cioè l’argomento device_map durante la chiamata a from_pretrained) può essere quantizzato in 4 bit. Si noti inoltre che ciò è totalmente agnostico alle modalità, purché i modelli possano essere caricati con l’argomento device_map, è possibile quantizzarli.

Per i modelli di testo, al momento della stesura di questo testo, ciò includerebbe le architetture più utilizzate come Llama, OPT, GPT-Neo, GPT-NeoX per i modelli di testo, Blip2 per i modelli multimodali, e così via.

Al momento della stesura di questo testo, i modelli che supportano accelerate sono:

[
    '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'
]  

Si noti che se il tuo modello preferito non è presente, puoi aprire una Pull Request o sollevare un problema in transformers per aggiungere il supporto al caricamento di accelerate per quell’architettura.

Possiamo addestrare modelli a 4 bit/8 bit?

Non è possibile eseguire un addestramento puro a 4 bit su questi modelli. Tuttavia, è possibile addestrare questi modelli sfruttando metodi di addestramento efficienti dei parametri (PEFT) e addestrare ad esempio adattatori su di essi. Questo è ciò che viene fatto nel documento e viene ufficialmente supportato dalla libreria PEFT di Hugging Face. Forniamo anche un notebook di addestramento e consigliamo agli utenti di consultare il repository QLoRA se sono interessati a replicare i risultati del documento.

Quali altre conseguenze ci sono?

Questa integrazione può aprire diverse conseguenze positive per la comunità e la ricerca sull’IA poiché può influire su molti casi d’uso e possibili applicazioni. In RLHF (Reinforcement Learning with Human Feedback) è possibile caricare un singolo modello di base, a 4 bit, e addestrare più adattatori su di esso, uno per la modellazione del premio e un altro per l’addestramento della politica di valore. Presto verrà pubblicato un post del blog e un annuncio più dettagliato su questo caso d’uso.

Abbiamo anche effettuato alcuni benchmark sull’impatto di questo metodo di quantizzazione sull’addestramento di modelli complessi su hardware per consumatori. Abbiamo eseguito diversi esperimenti sul fine-tuning di 2 diverse architetture, Llama 7B (15GB in fp16) e Llama 13B (27GB in fp16) su un NVIDIA T4 (16GB) e questi sono i risultati

Abbiamo utilizzato il recente SFTTrainer dalla libreria TRL, e lo script di benchmarking può essere trovato qui

Playground

Prova il modello Guananco citato nel paper sul playground o direttamente qui sotto

Ringraziamenti

Il team HF desidera ringraziare tutte le persone coinvolte in questo progetto presso l’Università di Washington, e per aver reso tutto questo disponibile alla comunità.

Gli autori desiderano inoltre ringraziare Pedro Cuenca per la gentile recensione del post del blog, Olivier Dehaene e Omar Sanseviero per il loro rapido e forte supporto per l’integrazione degli artefatti del paper sull’HF Hub.