Vai al contenuto principale

Salesforce XGen-7B: un tutorial passo dopo passo su come usare e mettere a punto XGen-7B

La maggior parte degli LLM open source ha un grande limite: una breve lunghezza del contesto. Dato che la lunghezza del contesto è essenzialmente la “memoria” degli LLM, questo problema va affrontato subito. È esattamente ciò che fa l’LLM XGen 7B di Salesforce: offre un impressionante contesto da 8k token. Questo articolo è un tutorial su come usarlo e metterlo a punto.
· 15 min leggi

Scopri con l'IA

Al momento, questi sei sono tra gli LLM open source più in voga:

  1. LLaMA2
  2. BLOOM
  3. Falcon 180B
  4. OPT-175B
  5. GPT-Neox
  6. Vicuna 13-B

E hanno tutti lo stesso svantaggio: una lunghezza del contesto molto breve, fino a soli 2048 token. Rispetto a modelli proprietari come GPT-3.5 e GPT-4 che offrono contesti fino a 32k token (50 pagine di testo!), sembra che gli LLM open source partano svantaggiati.

La lunghezza del contesto è essenzialmente la “memoria” degli LLM. Una finestra di 2048 token significa che il modello può ricordare solo 2048 token della conversazione alla volta. Questo influisce in modo significativo sulle prestazioni in compiti in cui un ampio contesto è cruciale, come sintesi, traduzione, generazione di codice, ecc.

Per affrontare questo problema critico, Salesforce ha annunciato il modello XGen-7B con una lunghezza del contesto di ben 8k token (4 volte più lunga rispetto ad altri LLM simili). Questo articolo illustra le caratteristiche chiave del modello e mostra come usarlo e metterlo a punto su un dataset di esempio.

Perché scegliere XGen 7B?

Per la maggior parte delle persone, statistiche come la lunghezza del contesto non significano molto finché non si traducono in benefici concreti. Ecco quindi alcune delle sue principali caratteristiche e l’impatto che possono avere sui tuoi progetti:

Compatto ma potente

Nonostante le dimensioni relativamente ridotte, con 7 miliardi di parametri, XGen rende ben oltre le aspettative: offre prestazioni paragonabili o superiori a quelle di modelli molto più grandi. Questa efficienza è rivoluzionaria per sviluppatori e ricercatori, consentendo di eseguire e distribuire applicazioni di IA all’avanguardia direttamente su macchine locali di fascia alta senza ricorrere a vaste risorse cloud. Questo equilibrio tra dimensioni e prestazioni rende XGen particolarmente interessante per un’ampia platea di utenti, dalle piccole startup ai ricercatori accademici.

Varianti di modello versatili

Per rispondere a esigenze diverse, XGen offre tre versioni, ognuna adatta ad applicazioni specifiche:

  • XGen-7B-4K-base: Con una sequenza di 4k token, è adatto a compiti che richiedono contesti di dimensioni moderate. È concesso in licenza Apache 2.0.
  • XGen-7B-8K-base: È il modello di punta con una sequenza di 8k token, progettato per compiti complessi che beneficiano dell’analisi di ampi blocchi di testo. Come il precedente, è disponibile con licenza Apache 2.0, quindi può essere usato per quasi qualsiasi scopo.
  • XGen-7B-{4K,8K}-inst: Messo a punto su dati pubblici di tipo istruzionale, è specializzato per applicazioni interattive e didattiche, disponibile per uso non commerciale. Questa variante è ideale per strumenti educativi, bot interattivi e altre applicazioni in cui guida o istruzioni sono importanti.

Prestazioni elevate nei benchmark

La vera misura della forza del modello si riflette nei benchmark. XGen risulta in cima in una serie eterogenea di benchmark come MMLU, HumanEval e così via, se confrontato con modelli di dimensioni simili. Per un’analisi approfondita, il post di annuncio offre una panoramica completa dei risultati di XGen sui benchmark.

Ottimizzazione per compiti con sequenze lunghe

Rischiando di ripetermi, ribadisco che XGen è altamente ottimizzato per compiti che richiedono ampie finestre di contesto. Questa capacità è fondamentale per applicazioni come la sintesi dettagliata di documenti, dove comprendere l’intero testo è importante per generare riassunti accurati. Allo stesso modo, nel question answering complesso e nella generazione di contenuti lunghi, la capacità di XGen di elaborare grandi quantità di informazioni produce output più coerenti e contestualmente pertinenti.

Dettagli sul training di Salesforce XGen 7B

Come ottiene XGen questi risultati impressionanti? Ovviamente, la risposta sta nei metodi di training e ottimizzazione utilizzati dai ricercatori di Salesforce AI.

La strategia di training di XGen consiste in due fasi. Nella fase 1, un modello nuovo viene addestrato su 1,37 trilioni di token, che comprendono un mix di dati in linguaggio naturale e codice.

image2.png

Nella seconda fase, sono stati utilizzati ulteriori 55 miliardi di token di codice per migliorare la generazione di codice:

image1.png

Il training è stato eseguito usando una libreria interna chiamata JaxFormer, progettata specificamente per un training efficiente di LLM con parallelizzazione sia dei dati sia del modello su hardware TPU-v4.

Prerequisiti e installazione di XGen 7B

Nonostante le dimensioni ridotte, XGen 7B è comunque piuttosto grande in termini di reti neurali. Se decidi di eseguirlo senza risorse cloud, servono macchine locali di fascia alta. Il requisito principale è una RAM sufficientemente ampia, ben oltre i 32 GB, poiché il modello pesa ~30 GB da scaricare da HuggingFace. Per le GPU, vale la regola “più grande è, meglio è”.

Se il tuo PC non ha queste specifiche, l’opzione più economica è Colab Pro, che offre 40 GB di RAM e 40 GB di vRAM GPU (A100). Per questo tutorial, sto usando Colab Pro:

image3.png

Dopo aver configurato una macchina compatibile, è il momento di installare e scaricare il modello. Se stai seguendo in locale, lo step 0 è creare un ambiente virtuale:

$ conda create -n xgen -y
$ conda activate xgen

Per scaricare il modello da HuggingFace, è necessario che torch con supporto GPU sia installato. Ecco il comando per installare tutte le librerie richieste:

$ pip install torch torchvision torchaudio transformers[torch]

Ci serviranno anche le seguenti librerie per la fase di fine-tuning più avanti:

$ pip install accelerate peft bitsandbytes trl datasets --upgrade

Non dimenticare di riavviare il kernel dopo l’installazione delle librerie.

Spiegherò ogni libreria quando arriveremo a quella sezione.

Ora, eseguiamo il modello per la prima volta con questo snippet.

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("Salesforce/xgen-7b-8k-base", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained("Salesforce/xgen-7b-8k-base", torch_dtype=torch.bfloat16)

inputs = tokenizer("DataCamp is one he ...", return_tensors="pt")
sample = model.generate(**inputs, max_length=128)

print(tokenizer.decode(sample[0]))

La classe AutoTokenizer carica l’auto-tokenizer per il modello di lunghezza 4098 xgen-7b-4k-base. La classe AutoModelForCausalLM serve per caricare modelli di generazione di testo.

Specifichiamo il prompt come inputs e lo passiamo a model.generate impostando una lunghezza massima di 128 token. Il codice sopra impiegherà un po’ al primo avvio perché deve scaricare il modello.

Ecco l’output che ho ottenuto alla fine:

DataCamp is one of the world’s leading providers of data science courses and training...

L’inizio della risposta è discreto, ma peggiora gradualmente verso la fine. Dobbiamo metterlo a punto per ottenere prestazioni migliori.

Fine-tuning di Salesforce XGen 7B

Gli LLM non sono come i modelli di sklearn: non puoi semplicemente regolare gli iperparametri in poche righe di codice. Quindi, metteremo a punto XGen 7B in vari passaggi. Ti suggerisco di affrontare ogni step con calma: ci saranno molti dettagli.

Nota che il flusso di lavoro che descriverò di seguito funziona per molti LLM su HuggingFace, a patto di avere potenza di calcolo sufficiente.

Iniziamo.

1. Installazione

Abbiamo già coperto questo passaggio in precedenza. Facciamo quindi una rapida rassegna delle librerie installate e del perché ci servono:

  • torch: libreria PyTorch per tensori e reti neurali; abilita l’accelerazione GPU.
  • transformers: libreria di Hugging Face per modelli NLP pre-addestrati.
  • datasets: per un caricamento e una gestione dei dati semplice con i dataset di HuggingFace.
  • accelerate: libreria ufficiale HuggingFace per semplificare il training distribuito degli LLM.
  • peft: un pacchetto per mettere a punto una piccola frazione dei parametri degli LLM e accelerare il training.
  • bitsandbytes: libreria di ottimizzazione per LLM in termini di memoria ed efficienza computazionale.
  • trl: tecniche per il fine-tuning di modelli di grandi dimensioni tramite RLHF (reinforcement learning con feedback umano).

Spiegheremo i vantaggi di ciascuna libreria quando le useremo.

2. Importare i moduli necessari

import os
import torch

from datasets import load_dataset
from transformers import (
   AutoModelForCausalLM,
   AutoTokenizer,
   BitsAndBytesConfig,
   TrainingArguments,
   pipeline,
)

from peft import LoraConfig
from trl import SFTTrainer

Ecco una panoramica delle nuove classi e funzioni che importiamo:

  • BitsAndBytesConfig: configurazione per ottimizzare i parametri del modello con tecniche “bits and bytes”, migliorando efficienza di memoria e calcolo.
  • TrainingArguments: specifica i parametri di training (ad es. learning rate, batch size) per il fine-tuning.
  • pipeline: semplifica l’applicazione dei modelli a compiti come la generazione di testo.
  • LoraConfig: configurazione per applicare LoRA (Low-Rank Adaptation), un metodo di fine-tuning efficiente in termini di parametri che adatta un piccolo set di pesi.
  • SFTTrainer: classe trainer per il Supervised Fine-Tuning (SFT), che facilita il training con feedback umano o dataset etichettati.

3. Definire le configurazioni per modello base e modello messo a punto

# Model from HF
base_model = "Salesforce/xgen-7b-8k-base"

# New instruction dataset
guanaco_dataset = "mlabonne/guanaco-llama2-1k"

# Fine-tuned model
new_model = "xgen-7b-8k-tuned"

Per il dataset, useremo il Guanaco LLaMA2, che contiene 1000 coppie istruzione-risposta per mettere a punto LLM su compiti interattivi e istruzionali (pensa ai chatbot).

4. Caricare i dati

dataset = load_dataset(guanaco_dataset, split="train")

Per caricare i dati da HuggingFace, usiamo la funzione load_dataset specificando percorso e split del dataset. Possiamo visualizzare esempi del dataset convertendolo in formato testuale e indicizzando una coppia istruzione-risposta a caso:

>>> dataset["text"][89]

<s>[INST] In England, what vegetable is referred to as a rocket? [/INST] The species name for "rocket" is "Eruca vesicaria", and it's also sometimes called "eruca".
However, other countries have different names for it:
* Arugula - America
* Garden Rocket or Rocket - Britain, Australia, South Africa, Ireland, New Zealand

Other names include "ruchetta", "rucola", "rucoli", "rugula", "colewoort", and "roquette".

The word transferred from Latin to Italian to English, which might explain the variants with similar pronunciation. </s>

5. Definire i parametri di quantizzazione

La quantizzazione è una tecnica potente usata nel machine learning per ridurre il numero di bit necessari a rappresentare i dati. Si ottiene approssimando i dati originali con un numero minore di bit, ottenendo una rappresentazione più compatta.

La quantizzazione può ridurre l’impronta di memoria di un modello, migliorare l’efficienza computazionale e talvolta persino migliorare l’accuratezza.

compute_dtype = torch.float16

quant_config = BitsAndBytesConfig(
   load_in_4bit=True,
   bnb_4bit_quant_type="nf4",
   bnb_4bit_compute_dtype=compute_dta

Per prima cosa impostiamo il tipo di dato per ogni tensore con compute_dtype a float16. Poi, usando BitsAndBytesConfig, definiamo i seguenti parametri di quantizzazione:

  • load_in_4bit=True: specifica che i dati in input saranno quantizzati a 4 bit.
  • bnb_4bit_compute_dtype=compute_dtype: specifica il tipo di dato da usare per i calcoli, impostato a float16 come definito sopra.
  • bnb_4bit_quant_type="nf4": specifica il tipo di quantizzazione a 4 bit, in questo caso "nf4".

nf4 si riferisce a un tipo specifico di quantizzazione non uniforme a 4 bit. La quantizzazione non uniforme può talvolta essere migliore di quella uniforme.

6. Definire il modello e i suoi parametri

model = AutoModelForCausalLM.from_pretrained(
   base_model,
   quantization_config=quant_config,
   device_map="auto"
)

Questo passaggio è simile al nostro download iniziale di XGen, ma questa volta passiamo i parametri di quantizzazione a quantization_config e impostiamo device_map su auto in modo che venga usata automaticamente la GPU.

7. Caricare il tokenizer

tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

Dopo aver caricato il tokenizer, configuriamo i parametri dei token di padding. Nell’NLP, i token di padding sono simboli speciali senza significato, aggiunti a ciascun input affinché tutte le sequenze abbiano la stessa lunghezza. Token di dimensione fissa sono un requisito per molte architetture di modello in NLP.

tokenizer.pad_token = tokenizer.eos_token imposta il token di padding del tokenizer uguale al token di fine frase (EOS). È una pratica comune, perché consente al modello di distinguere tra fine frase e padding. tokenizer.padding_side = "right" specifica che il padding va aggiunto a destra delle sequenze di input.

8. Parametri PEFT

peft_params = LoraConfig(
   lora_alpha=16,
   lora_dropout=0.1,
   r=64,
   bias="none",
   task_type="CAUSAL_LM",
)

Gli LLM pre-addestrati richiedono enormi quantità di dati e risorse di calcolo per il fine-tuning. Con il Parameter-Efficient Fine-Tuning (PEFT), possiamo mettere a punto solo una frazione dei parametri totali del modello, riducendo in modo significativo i tempi di esecuzione. Puoi approfondire questa tecnica nella documentazione ufficiale.

La classe LoraConfig imposta le configurazioni del metodo Low-Rank Adaptation. LoRA è uno specifico tipo di parametrizzazione usata nel PEFT. In generale, lo snippet sopra controlla l’intensità dell’adattamento dei layer LoRA, il numero di parametri addestrabili e altri aspetti dei layer.

9. Impostare i parametri di training

training_params = TrainingArguments(
   output_dir="./results",
   num_train_epochs=1,
   per_device_train_batch_size=1,
   gradient_accumulation_steps=1,
   optim="paged_adamw_32bit",
   learning_rate=2e-4,
   weight_decay=0.001,
   fp16=False,
   bf16=False,
   max_grad_norm=0.3,
   max_steps=-1,
   warmup_ratio=0.03,
   group_by_length=True,
   lr_scheduler_type="constant",
)

Oltre a tutto ciò che abbiamo definito, il fine-tuning di XGen richiede circa una dozzina di altri parametri di training. Includono parametri noti come learning rate, scheduler, numero di epoche, ottimizzatori, e alcuni nuovi come warmup_ratio, fp16, bf16, weight_decay, ecc.

Per restare focalizzati, non tratteremo nel dettaglio cosa fa ciascun parametro: rimando a questo ottimo articolo sul fine-tuning di LLaMA2 che li spiega.

10. Finalmente, mettiamolo a punto!

Per mettere a punto un modello PEFT, useremo la classe SFTTrainer (Supervised fine-tuning) della libreria trl, un passaggio chiave nell’RLHF.

trainer = SFTTrainer(
   model=model,
   train_dataset=dataset,
   peft_config=peft_params,
   dataset_text_field="text",
   max_seq_length=None,
   tokenizer=tokenizer,
   args=training_params,
   packing=False,
)

Per inizializzare il trainer, gli forniamo il modello, il dataset di training, i parametri PEFT, i parametri di training e il tokenizer. Per avviare il processo di fine-tuning, basta chiamare .train():

trainer.train()

In base ai parametri di training (soprattutto il numero di epoche), l’addestramento può durare da 15 minuti a diverse ore.

11. Valutazione

Una volta terminato il training, possiamo finalmente testare il nostro modello messo a punto:

prompt = "Who wrote Python?"
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)

result = pipe(f"<s>[INST] {prompt} [/INST]")
print(result[0]['generated_text'])

Prima di passare il prompt al model messo a punto, passiamo model e tokenizer a una pipeline. La funzione pipeline carica i modelli pre-addestrati, pre-elabora l’input usando il tokenizer e applica (se presenti) passaggi di post-processing personalizzati al testo generato.

Sopra, eseguiamo la pipeline con un prompt formattato appositamente e racchiuso in <s>[INST] {prompt} [/INST], esattamente come le istruzioni usate durante il training. Ecco il risultato:

<s>[INST] Who wrote Python? [/INST] Python was created by Guido van Rossum, a Dutch computer programmer. He started working on the language in the late 1980s and released the first version in 1991. </s>

Python is a high-level, general-purpose programming language that is widely used in various fields, including data science, machine learning, and web development. It is known for its readability, flexibility, and ease of use, making it a popular choice for beginners and experienced developers alike. </s>

Python is an open-source language, meaning that anyone can access and modify the source code, making it a popular choice for developers who want to contribute to the community. </s>...

12. Salvare il modello e il tokenizer

Quando siamo soddisfatti del nostro modello, possiamo finalmente salvarlo:

trainer.model.save_pretrained(new_model)
trainer.tokenizer.save_pretrained(new_model)

Puoi ricaricarlo usando di nuovo la classe AutoModelForCausalLM:

fine_tuned_xgen = AutoModelForCausalLM.from_pretrained(new_model, ...)

Conclusione

Iniziare con Large Language Models (LLM) come XGen 7B di Salesforce è semplice, ma personalizzarli per esigenze specifiche è più complesso. La nostra esperienza di fine-tuning del modello XGen 7B su un piccolo dataset istruzionale evidenzia la sfida. Adattare il modello a vari compiti richiede l’accesso a dataset pertinenti (disponibili tramite la libreria datasets di Hugging Face) e risorse computazionali in grado di gestire l’addestramento di un modello con 7 miliardi di parametri su tali dataset.

Il processo di fine-tuning può essere riassunto nei seguenti passaggi:

  1. Installazione delle librerie
  2. Importazione dei moduli necessari
  3. Definizione delle configurazioni globali
  4. Caricamento di un dataset per il fine-tuning
  5. Definizione dei parametri di quantizzazione con bitsandbytes
  6. Definizione del modello e dei suoi parametri iniziali tramite transformers
  7. Caricamento di un tokenizer adatto al modello
  8. Definizione dei parametri PEFT con LoRA come layer tramite LoraConfig
  9. Impostazione dei parametri di training con transformers
  10. Fine-tuning del modello con SFTTrainer di trl
  11. Test/valutazione del modello con prompt di esempio
  12. Salvataggio del modello e del tokenizer per usi futuri

Se alcuni concetti o snippet di codice ti risultano ancora poco familiari, ti consiglio queste ottime risorse:

Grazie per la lettura!

Bexruz (Bex) Tuychiev

Autore

Bexruz (Bex) Tuychiev

Sono un creator di contenuti sulla data science con oltre 2 anni di esperienza e uno dei più seguiti su Medium. Mi piace scrivere articoli dettagliati su AI e ML con un pizzico di sarcasmo, perché bisogna pur fare qualcosa per renderli un po’ meno noiosi. Ho pubblicato oltre 130 articoli e un corso su DataCamp, con un altro in arrivo. I miei contenuti sono stati visti da oltre 5 milioni di persone, 20.000 delle quali sono diventate follower sia su Medium che su LinkedIn. 

Argomenti

Correlato