LangChain 101 Parte 2c. Affinare LLMs con PEFT, LORA e RL

LangChain 101 Parte 2c. Ottimizzare gli LLM con PEFT, LORA e RL

Per comprendere meglio questo articolo, consulta la parte precedente in cui discuto dei grandi modelli di linguaggio:

LangChain 101: Parte 2ab. Tutto ciò che devi sapere sui Modelli (Large Language)

Questa è la parte 2ab del corso LangChain 101. È vivamente consigliato consultare la prima parte per comprendere…

pub.towardsai.net

Se sei interessato a LangChain e ai grandi modelli di linguaggio, visita la prima parte della serie:

LangChain 101: Parte 1. Creazione di un’app di Domande e Risposte Semplice

In questo articolo, ti presenterò le basi di LangChain, un framework per la creazione di applicazioni con…

pub.towardsai.net

Segui l’autore per non perderti la prossima parte 🙂

Nell’apprendimento automatico e nella scienza dei dati, un’incognita che effettua previsioni viene spesso chiamata modello. Esistono modelli diversi, e uno di questi è un modello di linguaggio. I modelli di linguaggio esistevano da qualche tempo, ma non erano così popolari come sono diventati una volta apparso ChatGPT. Uno dei motivi è che il modello GPT-1 era stato addestrato su una piccola quantità di dati. Con l’aumentare dei numeri dopo GPT, aumentava anche la quantità di dati, il che ha portato all’apparizione di Grandi Modelli di Linguaggio, o LLM, come vengono più spesso chiamati.

Raf Fine-tunaggio del Modello

Il fine-tunaggio del modello, noto anche come trasferimento di apprendimento, è una tecnica di apprendimento automatico utilizzata per migliorare le prestazioni di un modello preesistente su un compito specifico addestrandolo ulteriormente su nuovi dati correlati a quel compito. Il fine-tunaggio è comunemente impiegato in scenari in cui un modello pre-addestrato ha appreso rappresentazioni di valore di un dominio generale (nel nostro caso, il linguaggio naturale) ed è adattato per ottenere buoni risultati su un compito più specifico e ristretto.

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

Ho sentito molte domande: vale la pena fare il fine-tunaggio di un grande modello di linguaggio? Perché non utilizzare le prompt — sembrano essere ok. Posso utilizzare i vectorstore al loro posto? E altre domande relative all’argomento…

Pensa alla seguente situazione: devi recarti dal dentista. Chi preferiresti:

  • Una persona che si comporta come un medico (prompt: “Immagina di essere un dentista…”)
  • Una persona che ha letto la letteratura riguardante la cura dentale (utilizzo di vectorstore)
  • Un dottore addestrato per svolgere operazioni dentali (modello fine-tunato)

Il pubblico con cui ho parlato ha sicuramente scelto l’ultima opzione (PyData and Data Science meetups)

PEFT – Il Fine-tunaggio dei Parametri Efficiente

PEFT, o Fine-tunaggio dei Parametri Efficiente, è un metodo che migliora le prestazioni dei modelli di linguaggio pre-addestrati senza effettuare il fine-tunaggio di tutti i parametri del modello. Ciò lo rende un modo molto più efficiente ed economico di effettuare il fine-tunaggio dei LLM, specialmente per i modelli grandi con centinaia di miliardi o trilioni di parametri.

Il PEFT funziona congelando alcuni degli strati del modello pre-addestrato e effettuando il fine-tunaggio solo degli ultimi strati specifici per il compito da svolgere. Questo si basa sull’osservazione che gli strati inferiori dei LLM tendono ad essere più generici e meno specifici del compito, mentre gli strati superiori sono più specializzati per il compito per cui è stato addestrato il LLM. Classico trasferimento di apprendimento.

Ecco un esempio di come PEFT può essere utilizzato per ottimizzare un LLM per un compito di classificazione del testo:

  1. Congelare i primi strati del LLM pre-addestrato.
  2. Ottimizzare i livelli non congelati del LLM su un dataset più piccolo di testo etichettato.
  3. Il modello viene ottimizzato e può essere testato su dati non visti in precedenza.

LoRa – L’Adattamento a Basso Rango di Cui Tutti Parlano

LoRa, o Adattamento a Basso Rango, è una tecnica di ottimizzazione che permette di adattare grandi modelli linguistici (LLM) a compiti o domini specifici senza addestrare tutti i parametri del modello. LoRa non modifica in modo fondamentale l’architettura del trasformatore corrente. LoRa congela i pesi del modello pre-addestrato e inserisce matrici decomposizione raggiungibili tramite allenamento in ciascun livello dell’architettura Transformer.

LORA funziona adattando i pesi di un modello di trasformatore pre-addestrato a un compito o a un dominio specifico decomponendo la differenza tra i pesi pre-addestrati originali e i pesi desiderati dopo l’ottimizzazione in due matrici più piccole di basso rango. Queste due matrici vengono poi ottimizzate anziché l’intero set di parametri del modello. Ciò può ridurre il numero di parametri allenabili di 10000 volte, pur ottenendo prestazioni paragonabili all’ottimizzazione completa dei parametri. Durante l’ottimizzazione, LORA aggiorna i pesi degli strati di incorporamento e proiezione a basso rango, come di consueto per le scienze dei dati, minimizzando la funzione di perdita.

Ora, qual è la differenza tra PEFT e LoRa? PEFT è un metodo che utilizza varie tecniche, tra cui LoRa, per ottimizzare in modo efficiente grandi modelli linguistici.

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

Questo approccio ha diversi vantaggi:

  1. È più efficiente in termini di tempo rispetto all’ottimizzazione completa dei parametri, soprattutto per i grandi modelli di trasformatore.
  2. È più efficiente in termini di memoria, consentendo di ottimizzare i modelli su dispositivi con memoria limitata.
  3. È un’ottimizzazione più controllata, poiché le matrici a basso rango codificano conoscenze o vincoli specifici.

Apprendimento per Rinforzo

L’apprendimento per rinforzo (RL) è un altro modo per ottimizzare i modelli. Richiede due copie del modello originale. Una copia è il modello attivo, addestrato per eseguire il compito desiderato. L’altra copia è il modello di riferimento, utilizzato per generare logit (l’output non normalizzato del modello) che vincolano l’addestramento del modello attivo.

Come Genera Testo un LLM?

Questo articolo non tratta di trasformatori o di come vengono addestrati i grandi modelli linguistici. Invece, ci concentreremo sull’utilizzo…

pub.towardsai.net

Il requisito di avere due copie del modello può essere una sfida, specialmente per i modelli di grandi dimensioni in termini di GPU. Tuttavia, questo vincolo è necessario per evitare che il modello attivo si discosti troppo dal suo comportamento originale, poiché gli algoritmi RL possono portare a modelli che generano output inaspettati o dannosi.

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

Vediamo insieme il processo di ottimizzazione:

  1. Il modello di riferimento si inizializza con i parametri del modello di linguaggio pre-addestrato.
  2. Il modello attivo inizia ad allenarsi utilizzando il reinforcement learning.
  3. Ad ogni passaggio di ottimizzazione, vengono calcolati i logit sia del modello attivo che del modello di riferimento (log-probs).
  4. Successivamente viene calcolata la funzione di perdita utilizzando i logit sia del modello attivo che del modello di riferimento (metrica KL).
  5. I parametri del modello attivo vengono quindi aggiornati utilizzando i gradienti della funzione di perdita o l’ottimizzazione della politica proximal.

Tempo di Codice!

Il codice completo è disponibile su GitHub.

Inizieremo importando peft e preparandolo per il fine-tuning.

from peft import prepare_model_for_kbit_trainingpretrained_model.gradient_checkpointing_enable()model = prepare_model_for_kbit_training(pretrained_model)

Imposteremo i parametri di LoraConfig e utilizzeremo il metodo get_peft_model per creare un PeftModel:

  • r: Il rango delle matrici con rango basso rappresenta la differenza tra i pesi pre-addestrati originali e i pesi sintonizzati desiderati. Un valore maggiore di r consente a LORA di apprendere relazioni più complesse tra i parametri, ma sarà anche più computazionalmente costoso.
  • lora_alpha: Un iperparametro che controlla il compromesso tra la funzione di perdita per il compito successivo e la funzione di perdita per preservare i pesi pre-addestrati originali. Un valore maggiore di lora_alpha darà maggior peso alla funzione di perdita per proteggere i pesi pre-addestrati iniziali.
  • target_modules: Una lista dei nomi dei moduli nel modello che devono essere sintonizzati con LORA.
  • lora_dropout: Il tasso di dropout da applicare alle matrici con rango basso durante l’allenamento.
  • bias: Il tipo di bias da utilizzare nelle matrici con rango basso. Le opzioni valide sono “none”, “shared” e “individual”.
  • task_type: Il tipo di compito per cui il modello viene sintonizzato. Le opzioni valide sono “CAUSAL_LM” e “CLASSIFICATION”.
from peft import LoraConfig, get_peft_modelconfig = LoraConfig(    r=16,    lora_alpha=32,    target_modules=["query_key_value"],    lora_dropout=0.05,    bias="none",    task_type="CAUSAL_LM",)model = get_peft_model(model, config)

Ora è il momento di creare la classe Trainer:

  • data_collator: Una funzione utilizzata per aggregare i dati di addestramento in batch.
  • per_device_train_batch_size: La dimensione del batch per GPU.
  • gradient_accumulation_steps: Il numero di passaggi per accumulare i gradienti prima di aggiornare i parametri del modello. Ciò può essere utilizzato per ridurre l’utilizzo della memoria e migliorare la velocità di addestramento.
  • warmup_ratio: La proporzione dei passaggi di addestramento dedicati al warmup del tasso di apprendimento lineare.
  • fp16: Se utilizzare la precisione di virgola mobile a 16 bit (FP16) nell’addestramento. Questo può migliorare la velocità di addestramento e ridurre l’utilizzo della memoria.
  • logging_steps: Il numero di passaggi di addestramento tra gli aggiornamenti di registrazione.
  • output_dir: La directory in cui verranno salvati il modello addestrato e altri artefatti di addestramento.
  • optim: L’ottimizzatore da utilizzare per addestrare il modello. Le opzioni valide sono “adamw”, “sgd” e “paged_adamw_8bit”.
  • lr_scheduler_type: Il tipo di scheduler del tasso di apprendimento da utilizzare. Le opzioni valide sono “cosine”, “linear” e “constant”.
trainer = transformers.Trainer(    model=model,    train_dataset=train_dataset,    # eval_dataset=val_dataset,    args=transformers.TrainingArguments(        num_train_epochs=10,        per_device_train_batch_size=8,        gradient_accumulation_steps=4,        warmup_ratio=0.05,        max_steps=40,        learning_rate=2.5e-4,        fp16=True,        logging_steps=1,        output_dir="outputs",        optim="paged_adamw_8bit",        lr_scheduler_type="cosine",    ),    data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),)

Tutto quello che ci resta è iniziare l’addestramento:

trainer.train()

Ora possiamo usarlo subito con input_ids tokenizzati o salvarlo per un uso successivo:

trained_model = (    trainer.model.module se hasattr(trainer.model, "module") else trainer.model)  # Gestisci l'addestramento distribuito/parallelo# Usa modeltrained_model.generate(input_ids)# Salva modeltrained_model.save_pretrained("outputs")

Promemoria: il codice completo è disponibile su GitHub.

Questa è la fine della parte 2c. La prossima parte (de) sarà dedicata all’affinamento dei modelli utilizzando il feedback umano.

LangChain 101: Parte 1. Costruzione di un’applicazione di domande e risposte semplice

In questo articolo ti presenterò le basi di LangChain, un framework per la costruzione di applicazioni con modelli di lingua estesi…

pub.towardsai.net

LangChain 101: Parte 2ab. Tutto ciò che devi sapere sui modelli (di linguaggio) estesi

pub.towardsai.net

<p_applaudi a="" articoli="" e="" informato="" la="" mi="" motiva="" nuovi="" p="" parte.