Ottimizzare un modello Instruct su dati di testo non elaborati |  di Jon Flynn |  Marzo 2024

 | Intelligenza-Artificiale

Perfeziona un chatbot moderno con dati di conversazione minimi per meno di $ 10

Immagine dell'autore

Far sì che un chatbot moderno mantenga le sue capacità sui tuoi dati rimane un compito complesso. Le dimensioni delle finestre di contesto stanno aumentando rapidamente con prodotti leader come Gemini 1.5 Pro e il grande balzo di Claude 3 verso una capacità di 1 milione di token. Tuttavia, un’azienda come The Guardian, dove lavoro attualmente, dispone di innumerevoli repository di codici contenenti centinaia di milioni di token di dati.

IL recentemente annunciato Devin di Cognition Labs probabilmente utilizza tecniche RAG intelligenti per completare le sue attività, ma fare affidamento sull'inserimento di tutte le informazioni nella finestra di contesto può essere problematico. Il consenso nella comunità sembra essere che GPT-4 128k possa mantenere ottime prestazioni fino a circa 60.000 token, il che non è molto. Anche in questo caso, mantenere le ottime prestazioni richiede suggerimenti migliori e più complicati man mano che la quantità di token aumenta. A causa di queste limitazioni, sembra probabile che i modelli più capaci nel prossimo futuro utilizzeranno una combinazione di buoni suggerimenti, RAG e messa a punto. Ad esempio, per uno strumento di assistenza al codice, il codice più recente potrebbe essere recuperato tramite una pipeline RAG. Un modello ottimizzato potrebbe quindi analizzare e ragionare su questo codice in modo più efficace rispetto a un modello non ottimizzato, evidenziando eventuali casi limite e rischi da cui potrebbe aver imparato altrove. Inoltre, il modello perfezionato adotterà le convenzioni di codifica e le migliori pratiche dell'organizzazione, consentendole di fornire una guida più approfondita ai dipendenti.

Ho trovato risorse online limitate su chatbot ad alte prestazioni ottimizzati su set di dati più piccoli. Invece, la maggior parte delle ricerche introduce modelli come BioMistralche raggiungono il successo utilizzando grandi set di dati da 3 miliardi di token, richiedendo budget e competenze significativi.

Questo esperimento cerca di scoprire un approccio più leggero che naviga tra i vincoli di una finestra di contesto di 128K e le complessità di un modello messo a punto su miliardi di token, forse più nell'ambito di decine di milioni di token. Per un test su scala più piccola, metterò a punto quello di Mistral 7B Istruire il modello v0.2 SU Il repository di gestione del frontend del Guardian (il set di dati è di 1,6 milioni di token).

L'obiettivo di questo articolo era creare un set riproducibile di istruzioni per la messa a punto del modello economicamente vantaggioso utilizzando hardware facilmente accessibile. L'accento è stato posto sulla facilità d'uso, riducendo al minimo tentativi ed errori e massimizzando l'uso di dati di testo grezzi rispetto ai dati di conversazione etichettati. Si spera che qualsiasi sviluppatore di software, con zero esperienza nell'ingegneria del deep learning, possa imparare il notebook e addestrare il proprio modello con facilità.

Illustrerò i dati utilizzati, evidenzierò i migliori iperparametri e i relativi risultati, quindi concluderò con una spiegazione tecnica sulla loro efficacia.

A100 40GB

Ho utilizzato una Nvidia A100 da 40 GB di Colab per tutti gli allenamenti tranne una corsa in cui ho utilizzato un H100 da 80 GB.

Pigrizia

Ho utilizzato la libreria Unsloth per un allenamento più rapido ed efficiente in termini di memoria. Questo post sul blog fornisce un buon riepilogo su come Biblioteca indolente funziona sotto il cofano e mostra i parametri di riferimento per l'aumento della velocità di allenamento e il risparmio di memoria.

Differenze nell'approccio formativo all'avvio dei modelli perfezionati dell'arte

Esempi moderni di messa a punto per insegnare a un modello una nuova conoscenza specifica del dominio includono BioMistral E xFinanza. xFinance continua il pre-training del modello base Llama 7B, ovvero la versione non istruita. Utilizza LoRA. Il modello viene inizialmente addestrato su oltre 216.626 documenti, per un totale di 236 milioni di token. Viene poi ulteriormente perfezionato su 25.000 campioni di dati conversazionali basati sulla finanza. Similmente alla formazione standard dei chatbot, questo approccio inizia con la formazione su dati di testo grezzi, privi di token di istruzione o elementi di conversazione strutturati, per poi passare alla formazione su dati esclusivamente di conversazione. BioMistral adotta un approccio simile, anche se, cosa interessante, inizia a perfezionare il modello Mistral 7B Instruct v0.2.

Il mio approccio combina sia il set di dati grezzi che il set di dati annotati nella stessa esecuzione del training poiché questo approccio ha prodotto i migliori risultati. Viene eseguita una sola corsa di allenamento.

Il trainer SFT di TRL

Ho usato il SFTtrainer dal trl biblioteca. Ho visto che era usato questo taccuino dimostrativo di Unsloth con buoni risultati. Questo è un wrapper sul trainer HuggingFace predefinito. Non sono riuscito a trovare molta documentazione su come SFTtrainer lo estende e il codice suggerisce modifiche minime. Sembra preparare il set di dati per l'addestramento autosupervisionato impostando etichette target identiche a input_ids (vedi queste righe di codice). Stabilisce l'obiettivo labels essere uguale a input_ids. Ecco un esempio di un taccuino fare la stessa cosa con il trainer HuggingFace predefinito. Questo si riduce semplicemente alla previsione del token successivo utilizzando il trainer predefinito fornito da HuggingFace, niente di speciale. L'unica differenza nell'addestramento tra i “dati di testo grezzi” e i dati di conversazione è l'aggiunta dei token di istruzione speciali “(INST)” e “(/INST)” che Mistral Instruct è stato addestrato a riconoscere. Fare riferimento alle uscite della cella in il notebook per vedere come appare il set di dati.

Il mio set di dati grezzi è costituito dalla wiki del repository, da un'istantanea del ramo principale di dicembre e dalle ultime 100 richieste pull inclusi commenti e modifiche al codice. L'ho suddiviso in blocchi in modo che ogni campione avesse un massimo di 8192 token.

Raschiare il wiki

Per questo ho semplicemente copiato e incollato ogni pagina in un file di testo

Raschiare la base di codice

Ho scritto uno script Python eseguito localmente e ho scritto tutti i file in un file di testo nel seguente formato:

- File: productSwitchTypes.ts
Content:
export type ProductSwitchType =
| 'to-recurring-contribution'
| 'recurring-contribution-to-supporter-plus';

export interface PreviewResponse {
amountPayableToday: number;
supporterPlusPurchaseAmount: number;
contributionRefundAmount: number;
nextPaymentDate: string;
checkChargeAmountBeforeUpdate: boolean;
}

- File: productTypes.ts
Content:
...
...
...

Recupero dei dati PR

La cella corrispondente nel taccuino Colab produrrà un output come questo per questo PR:

PR #2989: Create devcontainer.json
URL: https://github.com/octocat/Hello-World/pull/2989
Description: None
Created at: 2024-02-26T11:39:03Z
Merged at: None
File: .devcontainer/devcontainer.json, Status: added
Changes: @@ -0,0 +1,5 @@
+{
+ "image": "mcr.microsoft.com/devcontainers/universal:2",
+ "features": {
+ }
+}

Nonostante il titolo di questo articolo, ho utilizzato un po' di dati conversazionali etichettati, ma sono generati sinteticamente e facilmente. Ciò non corrisponde alla qualità dei set di dati attentamente curati, ma i dati sintetici stanno diventando comuni (ho letto da qualche parte che ammontavano a circa il 50% dei set di dati su HuggingFace). Anche se non porterà a prestazioni sorprendenti del chatbot, l'intuizione è che potrebbe aiutare a mitigare eventuali dimenticanze catastrofiche e cali di prestazioni, ed è anche un modo semplice per aumentare il nostro set di dati. Ho utilizzato 3 metodi per generare i dati sintetici:

  1. Per ogni pagina Wiki, ho utilizzato l'API GPT-4 Turbo per generare alcuni esempi di QA basati sul testo fornito. Ciò ha prodotto circa 300 coppie di QA.
  2. Per ogni pagina Wiki, ho creato un'istruzione o una domanda specifica. Ad esempio, sul 'Velocemente e memorizzando nella cache', l'istruzione potrebbe essere 'Spiegami come viene utilizzato Fastly in `manage-frontend`.' La risposta è quindi semplicemente il contenuto di quella pagina Wiki.
  3. Similmente al passaggio precedente, per ogni file nella codebase ho creato una domanda. Ad esempio: “Cosa significa package.json il file appare come nel file manage-frontend recupero?” Quindi antepongo a ciascun file di codice la data dell'istantanea della base di codice utilizzata per l'addestramento, ovvero: “A partire da dicembre 2023, il package.json il file appare così:

I dati del QA sono stati esportati in un file JSONL, come molti tokenizzatori è consigliato il seguente formato avere una funzione chiamata apply_chat_template che contiene l'elenco all'interno del file messages proprietà in ogni riga. Di seguito è riportato un formato di esempio:

{"messages":({"role":"user","content":"What is the capital of France?"},{"role":"assistant","content":"The capital of France is Paris."})}
{"messages":({"role":"user","content":"What is the capital of England?"},{"role":"assistant","content":"The capital of England is London."})}

Sto utilizzando il 10% di questi dati di conversazione per il set di dati di convalida.

Sweep iperparametrici

Ho utilizzato una ricerca manuale. La mia intuizione era che il rango LoRA, la dimensione del batch e il tasso di apprendimento avrebbero influenzato maggiormente le prestazioni del modello. Ho quindi iniziato con un'ampia gamma di questi iperparametri e poi ho ristretto in modo iterativo lo spazio di ricerca in base alle prestazioni degli sweep iniziali. Un tasso di apprendimento di 2e-5 è apparso ottimale, che sembra essere lo standard per la messa a punto di Mistral. BioMistral ha continuato a perfezionare il modello di istruzione v0.2 con 0 riscaldamento, uno scheduler coseno e un tasso di apprendimento di 2e-5. Aumentando il grado e riducendo la dimensione del batch, la perdita di valutazione è migliorata. Tuttavia, è importante notare che la semplice riduzione delle dimensioni del batch di valutazione può naturalmente migliorare la perdita di convalida dovuta al minor numero di campioni convalidati contemporaneamente, quindi è sempre bene controllare manualmente il modello dopo aver completato l'addestramento!

Gli sweep nell'immagine seguente utilizzano tutti un rango di 512 o 768, con alfa diversi; 1x, 1,5x o 2x il grado. Le dimensioni dei batch sono 1, 2 o 4. Puoi vedere gli iperparametri finali che ho utilizzato Qui.

Una volta trovati gli iperparametri ottimali, ho eseguito nuovamente l'addestramento per includere tutti i dati e sfruttare al meglio i pochi dati a disposizione, come è prassi comune. Queste corse sono annotate da All-Data tag alla fine del nome dello sweep.

Ogni scansione è durata meno di 3 ore, solo poche sterline in Colab. Tutti i controlli probabilmente mi costano tra £ 40 e £ 50.

Nota: Ho incluso accidentalmente i miei dati di convalida di domande e risposte nei miei dati di testo non elaborati (ho dimenticato di averli copiati e incollati in uno dei miei file di testo 🙃). Tuttavia, la riesecuzione di un paio di scansioni senza questo ha confermato che gli iperparametri selezionati rimangono robusti e la perdita di convalida non era molto più elevata, con l'esecuzione ottimale che ha avuto una perdita di valutazione di circa 0,12. Questo valore è ancora molto basso e indica prestazioni quasi perfette, ma non è così. Pertanto la strategia di valutazione necessita di qualche indagine e miglioramento.

Le mie aspettative su questo esperimento erano basse. Con risorse online limitate su progetti di scala e configurazione simili, ho pensato che ci fossero ovvie ragioni tecniche per questo. La mia ipotesi era che ci fossero molte dimenticanze catastrofiche, allucinazioni casuali e un calo significativo delle prestazioni, anche se pensavo che forse avrebbe potuto rispondere a una semplice domanda come “Che stack tecnologico fa?” manage-frontend utilizzo?”.

Questo taccuino include un'app Gradio per sperimentare con il tuo chatbot.

I risultati sono stati migliori del previsto:

La seguente risposta a una domanda riguardante il “cambio di prodotto” è impressionante, data la mancanza di riferimenti al linguaggio naturale nelle descrizioni Wiki o PR. La maggior parte dei nomi delle variabili e dei condizionali sono corretti qui:

Una domanda come la seguente non ha riferimenti al linguaggio naturale e in realtà richiede di scavare nel codice per rendersi conto che non consentiamo il passaggio a Paypal, solo carta e DD. Ha quasi capito bene.

Può richiamare perfettamente del codice quando richiesto esplicitamente:

Che dire delle informazioni contrastanti all'interno del nostro set di dati?

Parte della Wiki è obsoleta (esempio), inclusi riferimenti alla nostra vecchia piattaforma CI TeamCity e alla nostra vecchia soluzione di routing che utilizzava Reach Router. Dopo aver chiesto informazioni al chatbot, ha risposto correttamente, ma è importante notare che questi sono più comuni e il modello pre-addestrato potrebbe essere più propenso a suggerirli:

Fonte: towardsdatascience.com

Lascia un commento

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