Come convertire qualsiasi testo in un grafico di concetti

Come trasformare qualsiasi testo in un grafico di concetti

Immagine generata dall'autore utilizzando il progetto condiviso in questo articolo.

Qualche mese fa, la domanda e risposta basata sulla conoscenza (KBQA) era una novità. Ora KBQA con la generazione potenziata del recupero (RAG) è un gioco da ragazzi per ogni appassionato di intelligenza artificiale. È affascinante vedere come il campo delle possibilità nell’NLP si sia espanso così rapidamente grazie ai LLM (Language Model). E migliora ogni giorno di più.

Nel mio ultimo articolo ho condiviso un approccio RAG ricorsivo per implementare la domanda e risposta con ragionamento multi-hop per rispondere a query complesse basate su un ampio corpus di testo.

L’Agente di Ricerca: Affrontare la Sfida di Rispondere a Domande Basate su un Ampio Corpus di Testo

Ho creato un Agente di Ricerca Autonomo che può rispondere a domande difficili con capacità di ragionamento multi-hop profonde

towardsdatascience.com

Molte persone lo hanno provato ed hanno inviato i loro feedback. Grazie a tutti per i vostri feedback. Ho raccolto questi contributi e ho apportato alcune migliorie al codice per affrontare alcuni dei problemi con l’implementazione originale. Ho intenzione di scrivere un articolo separato al riguardo.

In questo articolo, voglio condividere un’altra idea che potrebbe aiutare a creare un super agente di ricerca quando combinata con RAG ricorsivo. L’idea è emersa dai miei esperimenti con RAG ricorsivo con LLM più piccoli, e alcune altre idee che ho letto su VoAGI – in particolare una, la Knowledge-Graph Augmented Generation.

Abstract

Un Grafo di Conoscenza (KG), o qualsiasi Grafo, è composto da Nodi e Archi. Ogni nodo del KG rappresenta un concetto e ogni arco è una relazione tra una coppia di tali concetti. In questo articolo, condividerò un metodo per convertire qualsiasi corpus di testo in un Grafo di Concetti. Utilizzo il termine ‘Grafo di Concetti’ (GC) in modo intercambiabile con il termine KG per descrivere meglio ciò che sto demostrando qui.

Tutti i componenti che ho utilizzato in questa implementazione possono essere configurati localmente, quindi questo progetto può essere eseguito facilmente su una macchina personale. Ho adottato un approccio senza GPT perché credo nei modelli open source più piccoli. Sto utilizzando i fantastici Mistral 7B Openorca instruct e Zephyr models. Questi modelli possono essere configurati in locale con Ollama.

I database come Neo4j semplificano la memorizzazione e il recupero dei dati grafici. Qui sto utilizzando Pandas Dataframes in memoria e la libreria Python NetworkX, per mantenere le cose semplici.

Il nostro obiettivo qui è convertire qualsiasi corpus di testo in un Grafo di Concetti (GC) e visualizzarlo come la bellissima immagine di copertina di questo articolo. Potremo persino interagire con il grafo di rete spostando nodi e archi, ingrandendo e riducendo lo zoom e modificando la fisica del grafo secondo il nostro desiderio. Ecco il link della pagina di Github che mostra il risultato di ciò che stiamo costruendo.

https://rahulnyk.github.io/knowledge_graph/

Ma prima, esploriamo l’idea fondamentale dei KG e perché ne abbiamo bisogno. Se sei già familiare con questo concetto, sentiti libero di saltare alla sezione successiva.

Grafo di Conoscenza

Considera il seguente testo.

Mary aveva un piccolo agnello,Hai già sentito questa storia prima;Ma sapevi che lei ha condiviso il suo piatto,E ne ha avuto un po’ di più!

(Spero che i bambini non stiano leggendo questo 😝)

Ecco una possibile rappresentazione del testo come un KG.

Diagramma creato dall'autore utilizzando draw.io

L’articolo seguente di IBM spiega in modo appropriato il concetto fondamentale di Knowledge Graph.

Cos’è un Knowledge Graph? | IBM

www.ibm.com

Quoting an excerpt from the article to summarise the idea:

Un knowledge graph, noto anche come rete semantica, rappresenta una rete di entità del mondo reale – ovvero oggetti, eventi, situazioni o concetti – e illustra la relazione tra di loro. Queste informazioni sono solitamente archiviate in un database a grafo e visualizzate come struttura a grafo, da qui il termine knowledge “graph”.

Perché Knowledge Graph?

I knowledge graph sono utili in vari modi. Possiamo eseguire algoritmi di grafo e calcolare le centralità per ogni nodo, per capire quanto sia importante un concetto (nodo) per il lavoro svolto. Possiamo analizzare insiemi di concetti collegati e disconnessi, o calcolare comunità di concetti per una comprensione approfondita della materia. Possiamo comprendere i collegamenti tra concetti apparentemente disconnessi.

Possiamo anche utilizzare i knowledge graph per implementare la Graph Retrieval Augmented Generation (GRAG o GAG) e chattare con i nostri documenti. Ciò può darci risultati molto migliori rispetto alla semplice versione di RAG, che presenta diverse lacune. Ad esempio, trovare il contesto più rilevante per la query con una semplice ricerca di similarità semantica non è sempre efficace. Soprattutto quando la query non fornisce abbastanza contesto sul suo vero intento, o quando il contesto è frammentato in un corpus di testo ampio.

Ad esempio, considera questa query –

Dimmi dell’albero genealogico di José Arcadio Buendía nel libro ‘Cent’anni di solitudine’.

Il libro documenta 7 generazioni di José Arcadio Buendía con metà dei personaggi chiamati José Arcadio Buendía. Sarebbe una sfida, seppur possibile, rispondere alla query utilizzando una semplice pipeline di RAG.

Un’altra lacuna di RAG è che non può dirti cosa chiedere. Molto spesso, fare la domanda giusta è più importante che ottenere le risposte.

La Graph Augmented Generation (GAG) può compensare queste lacune di RAG fino a un certo punto. Meglio ancora, possiamo combinare e costruire una pipeline di Graph Augmented Retrieval Augmented Generation per ottenere il meglio dei due mondi.

Ora sappiamo che i grafici sono interessanti, possono essere estremamente utili e anche belli da vedere.

Creazione del grafico dei concetti

Se dovessi chiedere a GPT come creare un grafico di conoscenza da un determinato testo, potrebbe suggerire un processo simile al seguente.

  1. Estrai concetti ed entità dal corpo di lavoro. Questi sono i nodi.
  2. Estrai le relazioni tra i concetti. Questi sono gli archi.
  3. Popola i nodi (concetti) e gli archi (relazioni) in una struttura dati a grafo o in un database a grafo.
  4. Visualizza, per una gratificazione artistica se nient’altro.

I passaggi 3 e 4 sembrano comprensibili. Ma come si ottengono i passaggi 1 e 2?

Ecco un diagramma di flusso del metodo che ho ideato per estrarre un grafico di concetti da un qualsiasi corpus di testo. È simile al metodo descritto sopra, ma con alcune piccole differenze.

Diagramma creato dall'autore usando draw.io
  1. Suddividi il corpus di testo in parti. Assegna un chunk_id a ciascuna di queste parti.
  2. Per ogni parte di testo, estrai concetti e le relative relazioni semantiche utilizzando un LLM. Assegniamo a questa relazione un peso W1. Ci possono essere diverse relazioni tra la stessa coppia di concetti. Ogni relazione rappresenta un arco tra una coppia di concetti.
  3. Considera che i concetti che si trovano nella stessa parte di testo sono anche correlati per la loro vicinanza contestuale. Assegniamo a questa relazione un peso W2. Nota che la stessa coppia di concetti può comparire in più parti di testo.
  4. Raggruppa le coppie simili, somma i loro pesi e concatena le loro relazioni. Ora abbiamo un solo arco tra due concetti distinti. L’arco ha un certo peso e una lista di relazioni come nome.

Puoi vedere l’implementazione di questo metodo come codice Python nel repository GitHub che condivido in questo articolo. Iniziamo brevemente a esplorare le principali idee dell’implementazione nelle prossime sezioni.

Per dimostrare il metodo qui, sto utilizzando il seguente articolo di revisione pubblicato su PubMed/Cureus nei termini della licenza di attribuzione Creative Commons. Il merito va agli autori alla fine di questo articolo.

Opportunità dell’India di Affrontare le Sfide delle Risorse Umane nel Settore Sanitario

Gli indicatori di salute dell’India sono migliorati nel tempo, ma continuano a rimanere indietro rispetto a quelli delle nazioni paritarie. …

www.cureus.com

Il Mistral e il Prompt

Il passaggio 1 nel diagramma di flusso sopra è facile. Langchain fornisce una moltitudine di splitter di testo che possiamo utilizzare per suddividere il nostro testo in blocchi.

Il passaggio 2 è dove inizia il vero divertimento. Per estrarre i concetti e le loro relazioni, sto utilizzando il modello Mistral 7B. Prima di convergere sulla variante del modello più adatta al nostro scopo, ho sperimentato le seguenti:

Mistral InstructMistral OpenOrca, e Zephyr (versione Hugging Face derivata da Mistral)

Ho utilizzato la versione quantizzata a 4 bit di questi modelli – in modo che il mio Mac non inizi a odiarmi – ospitata localmente con Ollama.

Ollama

Avvia e appassionati con modelli di lingua grandi, localmente.

ollama.ai

Tutti questi modelli sono modelli sintonizzati con istruzioni con un prompt di sistema e un prompt utente. Fanno tutti un buon lavoro nel seguire le istruzioni e formattare la risposta in modo ordinato in JSON se lo diciamo loro.

Dopo alcuni tentativi, sono finalmente giunto al modello Zephyr con i seguenti prompt.

SYS_PROMPT = (    "Sei un creatore di grafici di rete che estrae termini e le loro relazioni da un contesto dato. "    "Ti viene fornito un frammento di contesto (delimitato da ```) Il tuo compito è estrarre l'ontologia "    "dei termini menzionati nel contesto. Questi termini dovrebbero rappresentare i concetti chiave secondo il contesto. \n"    "Pensiero 1: Mentre ti muovi attraverso ogni frase, pensa ai termini chiave menzionati in essa.\n"        "\tI termini possono includere oggetti, entità, luoghi, organizzazioni, persone, \n"        "\tcondizioni, acronimi, documenti, servizi, concetti, ecc.\n"        "\tI termini dovrebbero essere il più atomici possibile\n\n"    "Pensiero 2: Pensa a come questi termini possono avere una relazione uno a uno con altri termini.\n"        "\tI termini che vengono menzionati nella stessa frase o nello stesso paragrafo sono tipicamente correlati tra loro.\n"        "\tI termini possono essere correlati a molti altri termini\n\n"    "Pensiero 3: Trova la relazione tra ciascuna coppia di termini correlati. \n\n"    "Formatta il tuo output come una lista di json. Ogni elemento della lista contiene una coppia di termini"    "e la relazione tra di loro, come segue: \n"    "[\n"    "   {\n"    '       "node_1": "Un concetto dall\'ontologia estratta",\n'    '       "node_2": "Un concetto correlato dall\'ontologia estratta",\n'    '       "edge": "relazione tra i due concetti, node_1 e node_2 in una o due frasi"\n'    "   }, {...}\n"    "]")USER_PROMPT = f"context: ```{input}``` \n\n output: "

Se passiamo il nostro (non adatto) filastrocca con questo prompt, ecco il risultato.

[  {    "node_1": "Mary",    "node_2": "agnello",    "edge": "posseduto da"  },  {    "node_1": "piatto",    "node_2": "cibo",    "edge": "contenuto"  }, . . .]

Notice, che ha indovinato anche ‘cibo’ come concetto, che non è stato esplicitamente menzionato nel frammento di testo. Non è fantastico!

Se eseguiamo questo processo su ogni frammento di testo del nostro articolo di esempio e convertiamo il JSON in un dataframe di Pandas, ecco cosa appare.

Ogni riga rappresenta una relazione tra una coppia di concetti. Ogni riga è un collegamento tra due nodi nel nostro grafo e può esserci più di un collegamento o relazione tra la stessa coppia di concetti. Il conteggio nel dataframe precedente rappresenta il peso che ho arbitrariamente impostato su 4.

Vicinanza Contestuale

Assumo che i concetti che si verificano vicini l’uno all’altro nel corpus di testo siano correlati. Chiamiamo questa relazione ‘vicinanza contestuale’.

Per calcolare i collegamenti di vicinanza contestuale, fonderemo il dataframe in modo che node_1 e node_2 si combinino in una sola colonna. Poi creeremo un self-join di questo dataframe utilizzando chunk_id come chiave. Quindi i nodi che hanno lo stesso chunk_id si accoppieranno tra loro per formare una riga.

Ma questo significa anche che ogni concetto sarà accoppiato anche con se stesso. Questo è chiamato un self-loop, dove un collegamento inizia e termina sullo stesso nodo. Per eliminare questi self-loop, elimineremo ogni riga in cui node_1 è uguale a node_2 dal dataframe.

Alla fine, otterremo un dataframe molto simile al nostro dataframe originale.

La colonna conteggio qui rappresenta il numero di frammenti dove node_1 e node_2 occorrono insieme. La colonna chunk_id è una lista di tutti questi frammenti.

Quindi ora abbiamo due dataframe, uno con la relazione semantica e un altro con la relazione di vicinanza contestuale tra i concetti menzionati nel testo. Possiamo combinarli per formare il dataframe del nostro grafo di rete.

Aver costruito un grafo di concetti per il nostro testo è solo un punto di partenza. Il nostro obiettivo è visualizzare il grafo come l’immagine in evidenza all’inizio di questo articolo, e non siamo lontani dal raggiungere il nostro obiettivo.

Creazione di una Rete di Concetti

NetworkX è una libreria Python che semplifica enormemente la manipolazione di grafi. Se non sei ancora familiare con la libreria, clicca il loro logo qui sotto per saperne di più

Aggiungere il nostro dataframe a un grafo di NetworkX richiede solo poche righe di codice.

G = nx.Graph()## Aggiungi nodi al grafofor node in nodes:    G.add_node(str(node))## Aggiungi collegamenti al grafofor index, row in dfg.iterrows():    G.add_edge(        str(row["node_1"]),        str(row["node_2"]),        title=row["edge"],        weight=row['count']    )

Qui possiamo iniziare a sfruttare la potenza del Graph Network. NetworkX offre una miriade di algoritmi di rete già pronti per essere utilizzati. Ecco un link alla lista degli algoritmi che possiamo eseguire sul nostro grafo.

Algoritmi – Documentazione NetworkX 3.2.1

Modifica descrizione

networkx.org

In questo caso, utilizzo un algoritmo di rilevamento delle comunità per aggiungere colori ai nodi. Le comunità sono gruppi di nodi che sono più strettamente collegati tra loro rispetto al resto del grafo. Le comunità dei concetti possono darci un’idea generale degli argomenti ampi trattati nel testo.

L’algoritmo Girvan Newman ha rilevato 17 comunità di concetti nell’articolo di revisione con cui stiamo lavorando. Ecco una di queste comunità.

[  'tecnologia digitale',   'EVIN',   'dispositivi medici',   'sistemi di gestione delle informazioni di formazione online',   'tecnologia indossabile e tracciabile']

Questo ci dà immediatamente un’idea del tema ampio delle tecnologie sanitarie discusse nella revisione e ci permette di porci domande che poi possiamo rispondere con il nostro RAG Pipeline. Non è fantastico?

Calcoliamo anche il grado di ciascun concetto nel nostro grafo. Il grado di un nodo è il numero totale di archi con cui è connesso. Quindi nel nostro caso, maggiore è il grado di un concetto, più centrale è per il tema del nostro testo. Utilizzeremo il grado come dimensione del nodo nella nostra visualizzazione.

Visualizzazione del Grafico

La visualizzazione è la parte più divertente di questo esercizio. Ha una certa qualità che ti dà una gratificazione artistica.

Sto usando la libreria PiVis per creare grafici interattivi. Pyvis è una libreria di Python per la visualizzazione di reti. Ecco un articolo di VoAGI che dimostra la semplicità e la potenza della libreria

Pyvis: Visualizza Grafici di Rete Interattivi in Python

Tutto ciò che serve è qualche riga di codice

towardsdatascience.com

Pyvis ha un aiutante integrato di NetworkX per tradurre il nostro grafo di NetworkX in oggetti PyVis. Quindi non abbiamo bisogno di ulteriore codifica… Yay!!

Ricorda, abbiamo già calcolato i pesi di ciascun arco per lo spessore dell’arco, le comunità dei nodi per il loro colore e il grado di ciascun nodo come la loro dimensione.

Quindi, con tutti questi extra, ecco il nostro grafo.

Gif generato dall'autore utilizzando il progetto discusso in questo articolo.

Link al grafico interattivo: https://rahulnyk.github.io/knowledge_graph/

Possiamo ingrandire, ridurre e spostare nodi e archi come desideriamo. Abbiamo anche un pannello di scorrimento in fondo alla pagina per modificare la fisica del grafico. Vediamo come il grafico può aiutarci a porre le domande giuste e capire meglio il soggetto!

Possiamo inoltre discutere come il nostro grafico può aiutarci a costruire Graph Augmented Retrieval e come ciò può aiutarci a costruire un miglior RAG pipeline. Ma penso che sia meglio lasciarlo per un altro giorno. Abbiamo già raggiunto il nostro obiettivo per questo articolo!

Repo di GitHub

GitHub – rahulnyk/knowledge_graph: Converti qualsiasi testo in un grafico delle conoscenze. Questo può essere utilizzato per …

Converti qualsiasi testo in un grafico delle conoscenze. Questo può essere utilizzato per la generazione con integrazione grafica o per la base di QnA basato su Knowledge Graph…

github.com

Contributi e suggerimenti sono i benvenuti

Ho utilizzato l’articolo seguente per la dimostrazione del mio codice.

Saxena S G, Godfrey T (11 giugno 2023) Opportunità dell’India per affrontare le sfide delle risorse umane nel settore sanitario. Cureus 15(6): e40274. DOI 10.7759/cureus.40274

Sono grato agli autori per il meraviglioso lavoro e per averlo rilasciato con licenza Creative Commons Attribution.

Riguardo a me

Sono un appassionato di architettura (non i palazzi… quello della tecnologia). In passato ho lavorato con la modellazione di semiconduttori, la progettazione di circuiti digitali, la modellazione di interfacce elettroniche e l’Internet delle cose. Attualmente, sto lavorando con l’interoperabilità dei dati e le architetture del data warehouse per la salute e il benessere, presso Walmart Health and Wellness.