Diamo un’occhiata ad alcuni estratti di codice per il nostro piccolo esempio illustrativo. Trovi il codice completo nel file quaderno allegato e un implementazione più completa che utilizziamo nei seguenti articoli si trova nello stesso repository.

Cominciamo con come configuriamo un adattatore. Passiamo un riferimento al modulo da adattare, che ora chiameremo the adaptee. Memorizziamo un riferimento al suo originale forward metodo e lascia che adapteeIl metodo forward di ora punta a quello dell’adattatore forward implementazione del metodo.

class LoRAAdapter(nn.Module):
def __init__(self,
adaptee, # <- module to be adapted
r):
super().__init__()

self.r = r
self.adaptee = adaptee

# Store a pointer to the original forward implementation
# of the module to be adapted.
# Then point its forward method to this adapter module.
self.orig_forward = adaptee.forward
adaptee.forward = self.forward
(..)

Ora che abbiamo impostato i meccanismi dell’integrazione, inizializziamo anche i parametri delle nostre matrici di rango basso. Riconosciamo che inizializziamo una matrice con 0 e uno in modo casuale:

        (..)
# Adding the weight matrices directly to the adaptee,
# which makes is more practical to report the parameters,
# and to remove it later.
adaptee.lora_A = (nn.Parameter(torch.randn(adaptee.in_features, r)/
math.sqrt(adaptee.in_features)))
adaptee.lora_B = nn.Parameter(torch.zeros(r, adaptee.out_features))

E infine, ancora parte del LoRAAdapter classe, abbiamo il nostro forward metodo che chiama per primo il metodo adaptee‘S forward metodo con il nostro input x. Questo è il percorso originale eseguito nel modulo originale. Ma poi aggiungiamo anche quel risultato a quello del nostro ramo adattato, dove moltiplichiamo l’input con una matrice x con A E B.

def forward(self, x, *args, **kwargs):
return (
self.orig_forward(x, *args, **kwargs) +
x @ self.adaptee.lora_A @ self.adaptee.lora_B
)

Questa semplicità sembra elegante ai miei occhi.

Ci sono ulteriori dettagli che potrebbero essere interessanti, ma è meglio spiegarli insieme al codice. Li trovi in quaderno allegato:

  • Come congelare prima l’intero modello
  • Come sbloccare quindi il classificatore. Poiché è specifico per il nostro compito a valle e lo addestriamo completamente.
  • Come aggiungere adattatori; che sono tutti attivi, non congelati.
  • Revisione di come le dimensioni della matrice del modulo si riferiscono alle due matrici di rango inferiore A E B.
  • Quanto è più piccolo il numero di parametri quando si utilizza un valore piccolo per r?

Un piccolo estratto qui sotto mostra come sono i parametri del modulo originale output.dense non sono addestrati (contrassegnati con a 0 ), ma le sue matrici LoRA sono addestrabili (contrassegnate con a 1) e, ovviamente, il classificatore complessivo del modello (contrassegnato anche come addestrabile con a 1):

(..)
roberta.encoder.layer.11.attention.output.LayerNorm.bias 0 768
roberta.encoder.layer.11.intermediate.dense.weight 0 2359296
roberta.encoder.layer.11.intermediate.dense.bias 0 3072
roberta.encoder.layer.11.output.dense.weight 0 2359296
roberta.encoder.layer.11.output.dense.bias 0 768
roberta.encoder.layer.11.output.dense.lora_A 1 12288
roberta.encoder.layer.11.output.dense.lora_B 1 3072
roberta.encoder.layer.11.output.LayerNorm.weight 0 768
roberta.encoder.layer.11.output.LayerNorm.bias 0 768
classifier.dense.weight 1 589824
classifier.dense.bias 1 768
classifier.out_proj.weight 1 1536
classifier.out_proj.bias 1 2
(..)
Total parameters: 124,978,946, thereof learnable: 923,906 (0.7392%)

Dai un’occhiata a taccuino per più.

Inoltre, vedrai alcuni test nel file taccuino ciò dimostra che l’intera configurazione funziona meccanicamente.

Ma poi eseguiamo il nostro primo esperimento e inviamo i training job a SageMaker. Effettuiamo una messa a punto completa sul modello originale e quindi un training con LoRA abilitato come descritto qui.

Per il nostro test alleniamo RoBERTa Large (4) sul set di dati sst-2 (5) con r=2 adattare il query E output parametri su tutti i livelli. Noi usiamo 5e-5 E 4e-4 come tassi di apprendimento per il full-finetuning e il finetuning LoRA.

Questo è il risultato (più nel taccuino):

full-finetuning accuracy: 0.944
lora-finetuning accuracy: 0.933

Quindi è… fantastico, non così eccezionale? Che cos’è? Innanzitutto, mostra chiaramente che l’intera configurazione funziona a livello meccanico: è fantastico. E una precisione superiore al 90% dimostra che funziona bene.

Ma quanto bene? A cosa confrontiamo questi numeri? E quanto sono rappresentativi questi due percorsi di allenamento individuali? Siamo stati solo fortunati o sfortunati? I numeri LoRA sono migliori rispetto all’approccio tradizionale? Non è strano? Quanto bene abbiamo messo a punto l’approccio tradizionale?

Nessuno dei risultati sopra riportati è affidabile. Non sappiamo se l’utilizzo dei nostri iperparametri in una seconda esecuzione produrrebbe risultati simili. Inoltre, abbiamo utilizzato iperparametri selezionati con un’ipotesi semi-istruita.

Esiste, ovviamente, un modo migliore. Pertanto nel prossimo articolo applicheremo un approccio più serio alla selezione degli iperparametri e valuteremo le prestazioni in modo più sistematico:

  • Stabilire linee di base per i confronti
  • Cerca buoni iperparametri sia per le linee di base che per gli esperimenti
  • La cosa più importante: approfondire la nostra comprensione del metodo LoRA e dell’impatto delle decisioni di progettazione, allineando le nostre intuizioni in modo basato sui dati

Fino ad allora, spero che ti sia divertito leggendo questo articolo.

Grazie a Costantino Gonzalez, Compagna Speranza, Valerio Perrone E Elina Lesyk per aver fornito un prezioso feedback durante la stesura di questo articolo.

Tutte le immagini sono dell’autore se non diversamente specificato.

(1) Armen Aghajanyan, Luke Zettlemoyer, Sonal Gupta. La dimensionalità intrinseca spiega l’efficacia della messa a punto del modello linguistico, 2020

(2) Edward J. Hu, Yelong Shen, Phillip Wallis, Zeyuan Allen-Zhu, Yuanzhi Li, Shean Wang, Lu Wang, Weizhu Chen. LoRA: adattamento di basso rango di modelli linguistici di grandi dimensioni, 2021

(3) Renrui Zhang, Jiaming Han, Chris Liu, Peng Gao, Aojun Zhou, Xiangfei Hu, Shilin Yan, Pan Lu, Hongsheng Li, Yu Qiao. Adattatore LLaMA: messa a punto efficiente dei modelli linguistici con attenzione Zero-init, 2023

(4) Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Danqi Chen, Omer Levy, Mike Lewis, Luke Zettlemoyer, Veselin Stoyanov. RoBERTa: un approccio di preformazione BERT fortemente ottimizzato, 2019

(5) Richard Socher, Alex Perelygin, Jean Wu, Jason Chuang, Christopher D. Manning, Andrew Ng e Christopher Potts. Modelli profondi ricorsivi per la composizionalità semantica su un sentiment treebank, 2013

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *