In questo post presenterò un paradigma recentemente sviluppato presso Anaplan per estrarre informazioni temporali da testi in linguaggio naturale, come parte di un progetto NLQ (query in linguaggio naturale). Anche se mi concentrerò sull'estrazione del tempo, il paradigma è versatile e applicabile per analizzare vari testi non strutturati ed estrarre diversi modelli di informazioni. Ciò include il riconoscimento di entità denominate, la conversione da testo a SQL, l'estrazione di quantità e altro ancora.
Il nucleo del paradigma sta nella costruzione di una pipeline flessibile, che fornisce la massima flessibilità, facilitando la messa a punto di un modello per estrarre il significato da qualsiasi espressione immaginabile nel linguaggio. Si basa su un modello di deep learning (trasformatori), ma per noi ha raggiunto una precisione del 99,98%, cosa relativamente rara per i metodi ML. Inoltre, non utilizza LLM (modelli linguistici di grandi dimensioni), infatti richiede un modello di trasformatore minimo. Ciò produce un modello ML compatto e adattabile, che mostra la precisione dei sistemi basati su regole.
Per coloro che cercano tempo, valore numerico o estrazione di numeri di telefono, Facebook Pacchetto anatroccolo offre una soluzione basata su regole. Tuttavia, se Duckling non soddisfa le tue esigenze o sei ansioso di esplorare un nuovo paradigma ML, continua a leggere.
Gli LLM possono catturarne il significato?
Gli LLM, nonostante le loro capacità, devono affrontare sfide nell'analizzare tali frasi ed estrarne il significato in modo completo. Consideriamo l’espressione “le prime 15 settimane dell’anno scorso”. Per convertirlo in un intervallo di date è necessario che il modello determini l'anno corrente, ne sottragga uno e calcoli la posizione della quindicesima settimana mentre si adegua agli anni bisestili. I modelli linguistici non sono stati costruiti per questo tipo di calcolo.
Nella mia esperienza, i LLM possono produrre con precisione l'intervallo di date corretto circa il 90-95% delle volte, ma hanno difficoltà con il restante 5-10%, indipendentemente dalle tecniche di suggerimento utilizzate. Per non parlare del fatto che gli LLM richiedono molte risorse e sono lenti.
Per fortuna, seguendo tre principi, i trasformatori compatti possono svolgere con successo il compito
- Separare l'estrazione delle informazioni dalla deduzione logica.
- Genera automaticamente un set di dati utilizzando modelli strutturati.
- Vincolare l'IA generativa alla struttura richiesta.
In questo post tratterò i primi due, così come ho trattato il terzo un post precedente.
Separare l'estrazione delle informazioni dalla deduzione logica
Il primo principio è garantire che il ruolo del modello linguistico sia quello di estrarre informazioni dal testo libero, piuttosto che fare qualsiasi deduzione logica: le deduzioni logiche possono essere facilmente implementate nel codice.
Considera la frase: “Quanti film sono usciti due anni fa?” Il compito del modello linguistico dovrebbe essere quello di identificare che l'anno rilevante è: this_year - 2
senza calcolare l'anno corrente (il che significa che non è necessario conoscere l'anno corrente). Il suo obiettivo è analizzare il significato e strutturare il linguaggio non strutturato. Una volta estratta la formula, possiamo implementarne il calcolo nel codice.
Affinché ciò funzioni, introduciamo uno Structured Time Language (STL) in grado di esprimere elementi temporali. Ad esempio, “nel 2020” si traduce in “TIME.year==2020” e “tra tre mesi” diventa “ADESSO.mese==3”. Sebbene l'intero linguaggio STL non sia dettagliato qui, dovrebbe essere relativamente intuitivo: puoi fare riferimento ad attributi come anno, trimestre e mese per un tempo assoluto o relativo ad ADESSO. La traduzione di “le ultime 12 settimane dell'anno scorso” è “NOW.year==-1 AND TIME.week>=-12”
Rimuovendo qualsiasi deduzione logica o calcolo dal compito, togliamo un enorme peso dal modello linguistico e gli permettiamo di concentrarsi sull’estrazione delle informazioni. Questa divisione del lavoro migliorerà significativamente la sua precisione. Una volta completato il processo di traduzione, è semplice sviluppare codice per un parser che legga il linguaggio strutturato e recuperi l'intervallo di date necessario.
Poiché si tratta di un compito di traduzione, dal linguaggio naturale a STL, abbiamo utilizzato un trasformatore codificatore-decodificatore. Abbiamo usato il Modello Bart di Hugging Faceche può essere facilmente ottimizzato per questo compito.
Ma come otteniamo i dati per addestrare il modello?
Genera automaticamente un set di dati utilizzando modelli strutturati
Poiché non esiste un set di dati di addestramento per questa attività di traduzione, dobbiamo generarlo noi stessi. Ciò è stato fatto seguendo questi passaggi:
Primo passo: Scrivere funzioni per mappare oggetti datetime sia in “linguaggio naturale” che in formato STL:
def since_year(datetime):
free_text = f“since {datetime.year}”
answer = f”TIME.year >= {datetime.year}”
return free_text, answerdef half_literal(datetime):
free_text = datetime.strftime(“%-d, %B %Y”)
answer = f”TIME.date >= {datetime}”
return free_text, answer
def until_quarter_year(datetime):
q = datetime.month//3
free_text = f”until Q{q}-{datetime.year}”
answer = f”TIME.year=={datetime.year} AND TIME.quarter=={q}”
Dato un oggetto datetime, queste funzioni restituiscono una tupla di testo libero e il relativo STL, ad esempio: “since 2020”, “TIME.year >= 2020”.
Passo due: campiona una funzione casuale e campiona una data casuale entro un intervallo specificato:
date = np.random.choice(pd.date_range('1970/1/1', '2040/12/31'))
ora inserisci il datetime nella funzione.
Passo tre: aggiungi il testo libero a una domanda casuale (possiamo facilmente generare domande in modo casuale o estrarle da un set di dati di domande, la loro qualità e significato non sono molto importanti).
Con questa pipeline, possiamo generare rapidamente migliaia di coppie testo-STL, ad esempio:
- “Qual è stata la crescita del PIL nel secondo trimestre del 2019?”, “TIME.quarter==2 AND TIME.year==2019”
- “Dal 2017, chi ha vinto più Oscar?”, “TIME.year>=2017”
- “Chi era il presidente il 3 maggio 2020?”, “TIME.date==2020/05/03”
Questo approccio garantisce flessibilità nell'aggiungere nuovi modelli senza sforzo. Se trovi un'espressione temporale che non è coperta da una di queste funzioni (ad esempio “In N anni”), puoi scrivere una funzione che genererà esempi per questo modello in pochi secondi.
In pratica, possiamo ottimizzare ulteriormente l'efficienza del codice. Invece di separare funzioni per ogni modello come “dal 2020” e “fino al 2020”, possiamo campionare casualmente parole connettive come “dal”, “fino a”, “il”, ecc. Questo gruppo iniziale di funzioni potrebbe richiedere del tempo per essere sviluppato. , ma puoi scalare rapidamente fino a centinaia di modelli. Successivamente, risolvere eventuali espressioni mancanti diventa banale, poiché la pipeline è già stabilita. Con poche iterazioni è possibile coprire quasi tutte le espressioni rilevanti.
Inoltre, non è necessario coprire tutte le espressioni: Poiché il modello del trasformatore che abbiamo utilizzato è pre-addestrato su un enorme corpus di testo, generalizzerà dai modelli forniti a quelli nuovi.
Infine, possiamo utilizzare un LLM per generare più esempi. Chiedi semplicemente a un LLM:
Hey, what's another way to write "What was the revenue until Aug 23"
E potrebbe tornare:
"How much did we make before August 2023".
Anche questo processo di aumento dei dati può essere automatizzato: inviando numerosi esempi a un LLM, aggiungendo così varietà al nostro set di dati. Dato che il ruolo del LLM è esclusivamente nella creazione di set di dati, le considerazioni sui costi e sulla velocità diventano irrilevanti.
Combinando la flessibilità di aggiungere nuovi modelli, la generalizzazione del modello pre-addestrato e l'aumento dei dati utilizzando un LLM, possiamo coprire efficacemente quasi tutte le espressioni.
Il principio finale di questo paradigma è vincolare l’intelligenza artificiale generativa a produrre solo query STL, garantendo l’aderenza alla struttura richiesta. È stato discusso il metodo per raggiungere questo obiettivo, nonché un metodo per ottimizzare il processo di tokenizzazione in un post precedente.
Aderendo a questi tre principi, abbiamo raggiunto un'impressionante precisione del 99,98% sul nostro set di dati di test. Inoltre, questo paradigma ci ha dato la flessibilità necessaria per affrontare rapidamente nuove espressioni temporali non supportate.
Riepilogo
I Large Language Models (LLM) non sono sempre la soluzione ottimale per le attività linguistiche. Con il giusto approccio, i modelli di trasformatori meno profondi possono estrarre in modo efficiente informazioni dal linguaggio naturale con elevata precisione e flessibilità, in tempi e costi ridotti.
I principi fondamentali da ricordare sono:
- Concentrare il modello solo sull'estrazione delle informazioni, evitando complesse deduzioni logiche. Ciò potrebbe richiedere la generazione di un linguaggio di mediazione e l'implementazione di un parser e di una deduzione logica nel codice.
- Stabilire una pipeline per la generazione di un set di dati e l'addestramento di un modello, in modo che l'aggiunta di nuove funzionalità (nuovi modelli linguistici) sia semplice e veloce. Questa pipeline può includere l'uso di un LLM, aggiungendo più varietà al set di dati.
- Confinare la generazione del modello ai vincoli di un linguaggio strutturato.
Mentre questo post si concentra sull'estrazione di elementi temporali, il paradigma si applica all'estrazione di qualsiasi informazione dal testo libero e alla sua strutturazione in vari formati. Con questo paradigma puoi ottenere la precisione di un motore basato su regole, con la flessibilità di un modello di machine learning.
Fonte: towardsdatascience.com