Paithon Book Paithon Book
Esegui il codice

Fatti come archi: i knowledge graph#

Nel maggio del 2012 Google annuncia una modifica al motore di ricerca con uno slogan che vale più della modifica: things, not strings, cose e non stringhe. Fino a quel momento cercare «Torino» significava chiedere le pagine che contenevano quella sequenza di sei caratteri. Da lì in avanti il motore prova a sapere che Torino è una città, che sta in Italia, che ha un fiume, un sindaco e una squadra di calcio, e che «Torino» può anche essere quella squadra.

L’idea non era nuova: la stessa struttura era già comparsa tre volte. Negli anni Sessanta con le reti semantiche di Ross Quillian, schemi in cui i concetti sono puntini e le linee fra loro dicono «è un», «ha un», «si trova in». Dal 1984 con Cyc, il progetto in cui squadre di persone scrivevano a mano, un fatto per volta, le ovvietà che tutti sanno e nessuno scrive («la pioggia bagna», «chi dorme ha gli occhi chiusi»). E nel 2001 con il web semantico proposto da Tim Berners-Lee, che voleva pagine leggibili non solo dalle persone ma anche dai programmi. Anche i grafi di fatti estratti in modo automatico da Wikipedia esistevano già da qualche anno (DBpedia e YAGO sono del 2007). Nuovo era metterne uno dietro un motore di ricerca usato ogni giorno da centinaia di milioni di persone.

Fin qui i grafi avevano nodi tutti della stessa specie e archi che volevano dire tutti la stessa cosa: utenti, atomi, articoli. Un knowledge graph toglie quella comodità.

Una tripla è un fatto#

Un knowledge graph è un grafo in cui ogni arco porta scritto sopra che cosa lega le due cose che collega: «si trova in», «è capitale di», «ha diretto». L’unità elementare è una frasetta di tre parole:

(Torino, si-trova-in, Piemonte) · (Torino, attraversata-da, Po) · (Po, sfocia-in, Adriatico)

Soggetto, relazione, oggetto, in quest’ordine: «Piemonte si-trova-in Torino» sarebbe un altro arco, e falso. La frasetta si chiama tripla, e migliaia di triple messe insieme formano un grafo in cui i nodi sono cose (persone, luoghi, film, proteine, prodotti) e gli archi sono fatti. Le cose si chiamano entità, e la parola vuol dire soltanto questo. Nodi di specie diverse, archi di specie diverse: un grafo eterogeneo.

Sopra le triple sta di solito un regolamento: Torino è una città, una città è un luogo abitato, un luogo abitato è un luogo; e «sindaco-di» parte da una persona e arriva a un luogo abitato. Serve a buttare fuori le triple che sgarrano (nessuno è sindaco di un fiume) e a leggere fatti che nessuno ha scritto: se Torino è una città allora è un luogo, e quell’arco non c’è bisogno di scriverlo.

C’è poi una differenza che sembra filosofica e invece decide come si progetta tutto il resto. In un knowledge graph, un arco che non c’è vuol dire «non lo so», non «è falso». Nessuno ha scritto tutti i fatti veri del mondo, e nessuno mai lo farà: l’assenza di (Torino, gemellata-con, Salt Lake City) non è una smentita, è un silenzio.

Sembra un dettaglio da logici, e invece decide come si addestra un modello che impari a indovinare i fatti mancanti, cioè gli archi veri che nessuno ha ancora scritto. Per imparare a distinguere il vero dal falso a un modello servono esempi delle due specie; qui gli esempi di fatti veri abbondano, e di fatti falsi non ce n’è nemmeno uno, perché nessuno si mette a scrivere le cose che non sono successe.

Un knowledge graph è un insieme di triple \(\mathcal{G} \subseteq \mathcal{E} \times \mathcal{R} \times \mathcal{E}\), dove \(\mathcal{E}\) sono le entità e \(\mathcal{R}\) i tipi di relazione. È un multigrafo diretto etichettato: fra due entità possono correre più archi con relazioni diverse, e la direzione conta (\(r\) e la sua inversa sono relazioni distinte).

Sopra le triple sta di solito uno schema (o ontologia): una gerarchia di tipi (Città è un LuogoAbitato è un Luogo) e i vincoli di dominio e codominio di ogni relazione (sindaco-di va da una Persona a un LuogoAbitato). Lo schema serve a due cose molto pratiche: validare ciò che entra e permettere l’inferenza per ereditarietà, cioè dedurre triple non scritte da quelle scritte.

La proprietà semantica decisiva è l’assunzione di mondo aperto: la mancanza di una tripla non è la sua negazione. Ne discende che il problema naturale su un knowledge graph, la link prediction, non è una classificazione binaria ordinaria: dispone di soli esempi positivi, e gli insiemi di addestramento e di valutazione vanno costruiti di conseguenza. La valutazione standard lo fa così. Per ogni tripla di test \((h, r, t)\) si sostituisce la coda con ciascuna entità \(e \in \mathcal{E}\), si ordinano i candidati per punteggio \(f(h, r, e)\) e si registra la posizione \(\mathrm{rank}\) della coda vera; lo stesso si fa con la testa. Su un insieme \(\mathcal{T}\) di interrogazioni si riportano la media dei reciproci, \(\mathrm{MRR} = \frac{1}{|\mathcal{T}|}\sum_{q \in \mathcal{T}} 1/\mathrm{rank}_q\), e la frazione \(\text{Hits@}k\) di interrogazioni con \(\mathrm{rank}_q \le k\) (di solito \(k\) vale 1, 3 o 10); per entrambe, più alto è meglio. L’impostazione filtrata toglie dalla graduatoria le altre entità che formano triple vere già note, perché un modello che mette al primo posto un’altra risposta giusta non va punito [BUGDuran+13]. Il protocollo ha anche una storia da conoscere: nei banchi FB15k e WN18 molte triple di test erano l’inversa di una tripla d’addestramento, tanto che una regola banale, che rovescia le triple note, metteva la risposta giusta al primo posto nel 95% dei casi su WN18 e nel 66% su FB15k, alla pari con i modelli migliori di allora, e le versioni ripulite FB15k-237 e WN18RR sono nate per toglierla [DMSR18, TC15].

Un’ultima trappola riguarda i pareggi. Un modello che dà lo stesso punteggio a molte entità mette la risposta vera al primo posto se i pari merito si risolvono a suo favore, quindi il rango va calcolato dichiarando dove la si colloca fra i pari (in testa, in coda o a caso). Sun e colleghi hanno trovato modelli che su FB15k-237 assegnavano alla tripla vera lo stesso punteggio di centinaia di candidate, e dovevano a questo una parte del vantaggio pubblicato [SVS+20].

Costruirlo è il lavoro#

Il grafo non arriva già fatto: costruirlo è la parte più costosa del lavoro, e i modelli che vi si applicano ne sono la parte più piccola. Il percorso da un mucchio di testi a un grafo di fatti passa per quattro gradini.

Il primo gradino è trovare i nomi: individuare nel testo i pezzi che nominano una cosa. Si chiama riconoscimento delle entità nominate, e lo tratta la sezione POS tagging ed entità.

Il secondo è capire quale cosa. Trovato «Torino» in una frase non si sa ancora se sia la città, la squadra, il comune omonimo in un altro paese o la persona con quel cognome; a deciderlo è il resto della frase, perché «Torino ha battuto la Juve» e «Torino è bagnata dal Po» parlano di due nodi diversi. Agganciare un nome al nodo giusto si chiama collegamento delle entità.

Il terzo, e in pratica il più costoso, è il gemello del secondo: capire che «F.C. Juventus», «Juventus Football Club» e «la Juve» sono un nodo solo, e che due schede prodotto con nomi diversi descrivono lo stesso oggetto. Si chiama risoluzione delle entità, è il problema di togliere i doppioni su una scala enorme, ed è la voce su cui chi mantiene un knowledge graph spende gran parte del proprio lavoro.

L’ultimo gradino è l’estrazione di relazioni: dedurre dal testo che fra due entità esiste un certo legame. Oggi la si affida spesso a un grande modello di linguaggio, con i problemi di affidabilità che la sezione sui limiti dei modelli di linguaggio ha già discusso: un modello che inventa una tripla plausibile e falsa la inserisce nel grafo con la stessa sicurezza con cui inserisce quelle vere.

Entità come punti, relazioni come frecce#

Un grafo di fatti si può interrogare come un database, e per molte domande è la cosa giusta. Ma per prevedere i fatti mancanti serve trasformarlo in numeri, e qui succede una cosa che suonerà familiare.

Nel capitolo sul linguaggio ogni parola era diventata una fila di numeri, cioè un punto su una mappa, come una città, e le parole di significato simile finivano vicine. Avevano un senso anche gli spostamenti: il passo che porta da «uomo» a «donna» porta più o meno anche da «re» a «regina».

Su un grafo di fatti quello spostamento diventa la regola. Ogni entità è un punto, ogni relazione è una freccia, sempre la stessa per tutte le coppie che lega, e per ogni fatto vero partire dal soggetto e seguire la freccia deve portare vicino all’oggetto: da «Roma», con «capitale-di», si atterra vicino a «Italia»; la stessa freccia, da «Parigi», porta vicino a «Francia». Prevedere un fatto mancante diventa un calcolo: prendi «Lisbona», applica la freccia «capitale-di», guarda quale entità è più vicina al punto in cui sei arrivato.

Per sistemare punti e frecce bisogna poter dire al modello «questo sì e quest’altro no», e qui si paga il debito degli esempi falsi che non esistono: i «no» non ce li ha nessuno, e ce li fabbrichiamo guastando i fatti veri. Da (Roma, capitale-di, Italia), sostituendo una delle due estremità con un’entità pescata a caso, esce (Roma, capitale-di, Portogallo), che quasi certamente è falsa. Chiediamo che il fatto vero cada più vicino del suo gemello guastato, e non per un pelo: di uno scarto fissato in partenza.

Una scorciatoia, però, il modello la trova da solo: allargare la mappa. Se tutti i punti si allontanano fra loro, il pelo di vantaggio che il fatto vero aveva già diventa da sé lo scarto richiesto, senza che una freccia sia stata puntata meglio. Per questo, a ogni passata, i punti vengono rimessi tutti alla stessa distanza dal centro.

Alcuni fatti una freccia non li sa raccontare. Una freccia porta da un punto a un punto e basta, mentre «ha-recitato-in» lega un attore a decine di film: il modello se la cava ammucchiando quei film nello stesso punto, dove diventano indistinguibili. Altre relazioni valgono nei due sensi: l’Italia «confina-con» la Francia, e la Francia con l’Italia. La stessa freccia dovrebbe portare di là e riportare indietro, e l’unica che ci riesce è quella lunga zero, che lascia i due paesi nello stesso punto. Altre ancora si ereditano lungo la catena: se sei antenato di mio nonno sei antenato anche mio. La stessa freccia deve valere tanto per un passo quanto per due, ma una che sposta di tre, fatta due volte, sposta di sei: di nuovo regge soltanto la freccia lunga zero. Incatenare frecce diverse, invece, funziona benissimo: «fratello-di» seguita da «madre-di» dà «zio-di», e basta sommare le due frecce. Il conto non torna soltanto quando la relazione da incatenare è sempre la stessa.

Da quei guai è nata una lunga discendenza di modelli che al posto della freccia mettono un’altra mossa, e ognuno rimedia a un caso e ne rompe un altro. La più riuscita è la rotazione: invece di spostare il punto, lo si fa girare attorno al centro. Due quarti di giro fanno mezzo giro, quindi le catene di relazioni diverse si compongono come prima; e mezzo giro fatto due volte riporta al punto di partenza, che è proprio quello che chiede «confina-con». Nemmeno la rotazione, però, regge l’ereditarietà lungo la catena, perché un giro che fatto due volte deve dare sé stesso è il giro nullo. Per quella servono modelli in cui un’entità diventa una scatola capace di contenerne altre, la scatola «città» dentro la scatola «luogo»: un modo molto più naturale di dire «è un caso particolare di».

C’è infine una via del tutto diversa: portare su un grafo di fatti il passaparola fra vicini. Qui gli archi non sono tutti uguali, e un bigliettino che arriva lungo un «è nato a» non va letto come uno che arriva lungo un «ha diretto»: serve una ricetta di riscrittura per ogni tipo di arco, e con mille tipi ne servirebbero mille, che per non pagarle tutte si preparano mescolando poche ricette di base. In cambio la fila di numeri di un’entità si calcola da quel che le sta intorno, invece di impararla a memoria. Con un limite: se l’entità non porta con sé niente di proprio, il punto di partenza resta imparato a memoria come prima, e di un’entità appena arrivata non si calcola niente.

Un avviso di notazione, perché l’alfabeto cambia: nelle formule di TransE \(\mathbf{h}\), \(\mathbf{r}\) e \(\mathbf{t}\) sono la testa, la relazione e la coda di una tripla. Gli stati nascosti del message passing tornano con R-GCN, e si riconoscono dal pedice del nodo e dall’apice dello strato (\(\mathbf{h}_v^{(l)}\)).

TransE [BUGDuran+13] rappresenta ogni entità con un vettore \(\mathbf{e} \in \mathbb{R}^d\) e ogni relazione con un vettore \(\mathbf{r} \in \mathbb{R}^d\) interpretato come traslazione, e chiede che per ogni tripla vera \((h, r, t)\) valga

\[ \mathbf{h} + \mathbf{r} \approx \mathbf{t} . \]

La funzione di punteggio è la distanza cambiata di segno, \(f(h,r,t) = -\lVert \mathbf{h} + \mathbf{r} - \mathbf{t} \rVert\), in modo che un punteggio alto significhi tripla plausibile, e si addestra con una margin ranking loss che chiede alle triple vere di stare a distanza minore delle triple false di almeno un margine \(\gamma\):

\[ \mathcal{L} = \sum_{(h,r,t) \in \mathcal{G}} \; \sum_{(h',r,t') \in S'_{(h,r,t)}} \big[\, \gamma - f(h,r,t) + f(h',r,t') \,\big]_+ . \]

Le triple false non esistono in natura, per l’assunzione di mondo aperto: si fabbricano corrompendo quelle vere, ed è per questo che l’insieme dei negativi \(S'_{(h,r,t)}\) porta in pedice la tripla positiva da cui nasce, invece di essere un unico insieme globale: si sostituisce una sola delle due estremità con un’entità pescata a caso, mai tutt’e due. È l’equivalente, per i grafi, del negative sampling di word2vec [MSC+13], e la parentela non è casuale: entrambi trasformano un problema con soli positivi in un problema di discriminazione.

C’è poi un vincolo che sembra implementativo e non lo è: gli embedding delle entità vanno rinormalizzati a \(\lVert \mathbf{e} \rVert_2 = 1\), e nell’algoritmo del paper la riga sta all’inizio di ogni iterazione, non a fine addestramento. Senza, il modello ha una scappatoia banale, cioè far crescere le norme finché la loss scende senza che nessuna relazione sia stata imparata.

I limiti di una traslazione sono espressivi, non implementativi. Le relazioni uno-a-molti e molti-a-uno non sono rappresentabili: se \((h, r, t_1)\) e \((h, r, t_2)\) sono entrambe vere, TransE forza \(\mathbf{t}_1 \approx \mathbf{t}_2\), cioè fa collassare entità distinte. Le relazioni simmetriche (\(r(a,b) \Leftrightarrow r(b,a)\)) richiedono \(\mathbf{r} \approx -\mathbf{r}\), cioè \(\mathbf{r} \approx \mathbf{0}\), e con la relazione annullata collassano anche le due entità. Le relazioni riflessive finiscono allo stesso modo.

Il caso che manca chiede una precisazione, perché è il punto in cui il racconto corrente sbaglia bersaglio. Una traslazione compone benissimo: se dalla coppia \(r_1(a,b)\) e \(r_2(b,c)\) deve seguire \(r_3(a,c)\), basta porre \(\mathbf{r}_3 = \mathbf{r}_1 + \mathbf{r}_2\), ed è per questo che nella tassonomia diventata standard con RotatE [SDNT19] TransE è dato capace di composizione, di inversione e di antisimmetria, e incapace della sola simmetria. Quel che non regge è il caso particolare in cui le tre relazioni sono la stessa, cioè la transitività (antenato-di, parte-di, sottoclasse-di: la norma in qualunque grafo con un’ontologia). Lì servirebbero insieme \(\mathbf{a} + 2\mathbf{r} \approx \mathbf{c}\) e \(\mathbf{a} + \mathbf{r} \approx \mathbf{c}\), cioè ancora una volta \(\mathbf{r} \approx \mathbf{0}\).

Il seguito della famiglia sistema altre caselle, e conviene dire quali, perché non è la transitività. I modelli bilineari come DistMult [YYH+15] danno il punteggio \(f(h,r,t) = \sum_{k} h_k r_k t_k\), una forma bilineare con matrice diagonale \(\mathrm{diag}(\mathbf{r})\). Scambiando \(\mathbf{h}\) e \(\mathbf{t}\) il punteggio resta identico, quindi sono simmetrici per costruzione e perdono l’antisimmetria e l’inversione che TransE aveva. ComplEx [TWR+16] porta gli embedding in \(\mathbb{C}^d\) e usa \(f(h,r,t) = \mathrm{Re}\big(\sum_k h_k r_k \bar{t}_k\big)\): il coniugato \(\bar{t}_k\) rompe la simmetria, la parte immaginaria di \(\mathbf{r}\) dosa quanto la relazione è antisimmetrica, e l’inversa di una relazione si ottiene coniugandone il vettore. La composizione, in quella stessa tassonomia, resta fuori tanto da DistMult quanto da ComplEx. RotatE fa di ogni relazione una rotazione componente per componente, \(f(h,r,t) = -\lVert \mathbf{h} \odot \mathbf{r} - \mathbf{t} \rVert\), con \(\odot\) il prodotto elemento per elemento e \(r_k = e^{\mathrm{i}\theta_{r,k}}\): la simmetria corrisponde ad angoli \(\theta_{r,k} \in \{0, \pi\}\), l’inversa al coniugato, la composizione alla somma degli angoli, e le quattro proprietà stanno insieme. La transitività però resta fuori anche di lì, per lo stesso motivo algebrico: se una rotazione applicata due volte deve dare sé stessa, e ha modulo uno, allora è l’identità, e la relazione torna a non spostare niente. A reggere le gerarchie servono famiglie di altro tipo, che rappresentano un’entità non come un punto ma come un oggetto capace di contenerne un altro (ordini parziali, scatole, spazi iperbolici).

I parametri, con embedding di dimensione \(d\): TransE e DistMult tengono \(d(|\mathcal{E}| + |\mathcal{R}|)\) numeri reali; ComplEx il doppio, perché ogni componente è complessa; RotatE \(2d|\mathcal{E}| + d|\mathcal{R}|\), perché di una rotazione basta l’angolo. Il modello bilineare pieno, con una matrice \(d \times d\) per relazione di cui DistMult tiene la sola diagonale, ne tiene invece \(d|\mathcal{E}| + d^2|\mathcal{R}|\). E si addestrano in modi diversi: TransE e DistMult con la margin ranking loss di TransE, ComplEx con la perdita logistica su triple vere e corrotte, RotatE con un campionamento dei negativi che pesa ogni tripla corrotta secondo quanto il modello stesso la trova plausibile (self-adversarial), così che i negativi ormai facili smettano di contare.

Poi c’è la via del message passing. R-GCN [SKB+18] porta il message passing sui grafi eterogenei con una mossa diretta: una matrice di pesi per ogni tipo di relazione,

\[ \mathbf{h}_v^{(l+1)} = \sigma\!\Big( \mathbf{W}_0^{(l)} \mathbf{h}_v^{(l)} + \sum_{r \in \mathcal{R}} \sum_{u \in \mathcal{N}_v^{r}} \frac{1}{c_{v,r}} \mathbf{W}_r^{(l)} \mathbf{h}_u^{(l)} \Big), \]

dove \(\mathcal{N}_v^{r}\) sono i vicini di \(v\) raggiunti da archi di tipo \(r\) e \(c_{v,r}\) è una normalizzazione (tipicamente \(|\mathcal{N}_v^{r}|\)). Il problema evidente è il numero di parametri, che cresce con il numero di relazioni: un grafo con mille tipi di arco vorrebbe mille matrici. Si controlla imponendo che le \(\mathbf{W}_r\) siano combinazioni di poche matrici di base condivise, il che è una forma di condivisione dei pesi fra relazioni simili. La differenza rispetto a TransE è che qui l’embedding di un’entità si calcola dal suo vicinato invece di essere una riga di tabella: è la stessa differenza fra DeepWalk e le GNN vista nella sezione «Il mondo come grafo». Il vantaggio dell’induttività, però, arriva solo se i nodi portano feature proprie da cui partire: nel paper originale le entità non ne hanno, lo stato iniziale è a sua volta un embedding appreso per ciascuna entità, e senza quella riga di tabella un’entità mai vista resta fuori, esattamente come in TransE.

Rispondere navigando#

Riempire da sé i buchi che ha, prevedendo i fatti che nessuno ci ha scritto, è già qualcosa. Ma a che cosa serve, un grafo di fatti, quando la domanda arriva da fuori? A tre cose, e sono tre cose che un archivio di documenti non sa fare.

La prima è comporre. Se il grafo contiene «il regista di questo film è X» e «X è nato in questa città», la domanda «in che città è nato il regista di questo film» si risponde percorrendo due archi. Il modo usuale di rispondere a una domanda su un archivio di testi è invece cercare i brani più somiglianti alla domanda e passarli a un modello di linguaggio: è il retrieval denso della sezione su retrieval e RAG, dove i brani non si confrontano parola per parola, ma trasformando ciascuno in una fila di numeri e cercando le file più vicine. Se nessun documento contiene entrambi i fatti, la ricerca per somiglianza di solito non porta davanti al modello tutti e due i brani, perché ciascuno somiglia alla domanda solo a metà, e il modello non può metterli insieme. Recuperare in più passi, usando la prima risposta per guidare la ricerca successiva, rimedia in parte, ma ogni passo è un altro punto in cui il recupero può sbagliare.

Il secondo vantaggio è che il cammino è la spiegazione. Una ricerca per somiglianza restituisce tre paragrafi e una risposta, e per verificarla bisogna leggere i paragrafi. Una risposta ottenuta navigando restituisce la catena di fatti che l’ha prodotta, e ogni anello si può controllare da solo. In un dominio dove sbagliare costa (clinico, legale, finanziario) è una differenza di natura.

Il terzo vantaggio si dimentica spesso ed è forse il più pratico: le domande che chiedono di contare. «Quanti registi italiani hanno girato almeno tre film ambientati a Napoli» non è una domanda a cui un modello di linguaggio possa rispondere in modo affidabile, e nemmeno un sistema di ricerca per somiglianza: vuole un’interrogazione a un archivio ordinato, e una struttura su cui contare davvero.

Dare a un modello di linguaggio dei documenti pescati sul momento, invece di fidarsi di quel che ricorda, si chiama RAG, dalle iniziali di Retrieval-Augmented Generation, «generazione con recupero». Da qui l’idea, diffusa nei sistemi costruiti attorno ai modelli di linguaggio, di fare la stessa cosa con un grafo: GraphRAG. Nella forma più semplice, invece di brani di testo si recupera un sottografo, cioè il pezzetto di grafo attorno alle cose nominate nella domanda, e lo si mette davanti al modello insieme alla domanda. Le varianti differiscono per come si sceglie il pezzetto e per come lo si riscrive in frasi (un grafo va disteso in una fila di parole prima di poterlo dare a un modello che legge testo). Con lo stesso nome circola anche un’idea diversa: il grafo lo costruisce un modello di linguaggio a partire dai documenti, lo divide in comunità di entità e scrive un riassunto di ciascuna, per rispondere a domande che riguardano l’intera raccolta («quali sono i temi principali?») invece di un fatto preciso [ETC+24].

Quando conviene, e quando no#

L’onestà dovuta, perché su questo tema si sente molto entusiasmo.

Un knowledge graph è caro da costruire e caro da tenere aggiornato. Ogni fatto del mondo che cambia è un arco da correggere, e un grafo non manutenuto invecchia peggio di un archivio di documenti, perché sembra ancora autorevole mentre è già falso. La domanda da farsi prima di cominciare non è se sarebbe utile, ma chi lo aggiornerà fra due anni.

I grandi modelli di linguaggio, inoltre, hanno assorbito una parte del mestiere che si affidava ai grafi di fatti: molte domande fattuali ricevono oggi una risposta corretta senza che nessun grafo sia stato consultato. Quello che i modelli non danno, e che resta la ragione durevole di questa struttura, è di altro tipo. Il cammino che si può verificare anello per anello. La possibilità di contare. E la possibilità di dichiarare delle regole che il sistema non ha il permesso di violare: che il sindaco di un posto debba essere una persona e non un’altra città, che nessuno possa essere nato dopo essere morto. Sono garanzie, non conoscenza, ed è per le garanzie che si paga il prezzo di costruirlo.

Da ricordare

  • Un knowledge graph è un grafo di fatti: i nodi sono cose (persone, luoghi, film, prodotti) e ogni arco porta un’etichetta che è un verbo. L’unità minima è una frasetta di tre parole, la tripla: soggetto, relazione, oggetto. Nodi di specie diverse e archi di specie diverse: è un grafo eterogeneo, mentre quelli visti finora avevano nodi tutti della stessa specie.

  • Un arco che manca vuol dire «non lo so», non «è falso»: nessuno ha mai scritto tutti i fatti veri del mondo. Ne segue una conseguenza pratica fastidiosa: di esempi sbagliati non ce ne sono, e per addestrare un modello bisogna fabbricarseli guastando i fatti veri, cioè sostituendo una delle due estremità con una cosa pescata a caso.

  • Il lavoro vero è costruirlo: trovare i nomi nel testo, capire di quale Torino si parla, accorgersi che «la Juve» e «Juventus Football Club» sono lo stesso nodo, ed estrarre dalle frasi i legami fra le cose. I modelli che ci girano sopra sono la parte più piccola del lavoro.

  • Il modo più semplice di metterlo in numeri è fare di ogni cosa un punto e di ogni relazione una freccia sempre uguale: da «Roma», seguendo la freccia «capitale-di», si atterra vicino a «Italia». Funziona, ma una freccia porta in un solo punto, e quindi non può legare un attore a dieci film né reggere le relazioni che si ereditano lungo la catena (se sei antenato di mio nonno sei antenato mio): là la freccia dovrebbe valere sia un passo sia due, e l’unica freccia che lo fa è quella lunga zero. Da lì una lunga discendenza di modelli che sostituiscono la freccia con qualcosa di più flessibile (la migliore è una rotazione); quest’ultimo caso però nessuno di loro lo risolve, e servono entità fatte a scatola, che si contengono l’una nell’altra.

  • L’altra via è portare il passaparola delle sezioni precedenti su questo grafo, usando una ricetta di riscrittura diversa per ogni tipo di arco: così la fila di numeri di un’entità si calcola da quel che le sta intorno invece di impararla a memoria, purché l’entità porti con sé qualcosa di proprio da cui partire. Se non lo porta, il punto di partenza resta imparato a memoria come prima, e un’entità mai vista resta fuori.

  • Il vantaggio che resta, e per cui si paga la manutenzione, sta nel mettere insieme più fatti in catena, non nel sapere i fatti (per quello ci sono i modelli di linguaggio): mostrare il percorso che ha prodotto la risposta perché sia verificabile, rispondere a domande che chiedono di contare, e poter dichiarare regole che il sistema non può violare. E un grafo non aggiornato è peggio di nessun grafo, perché sembra ancora autorevole quando è già falso.

Da ricordare

  • Un knowledge graph è un multigrafo diretto etichettato di triple (soggetto, relazione, oggetto): nodi ed archi di tipi diversi, cioè un grafo eterogeneo, a differenza di tutti quelli visti finora nel capitolo.

  • Vale l’assunzione di mondo aperto: un arco che manca vuol dire «non lo so», non «è falso». Da qui il fatto che gli esempi negativi non esistano e si debbano fabbricare corrompendo le triple vere.

  • Costruirlo è il lavoro: riconoscimento delle entità, collegamento (quale Torino?), risoluzione (Juventus e la Juve sono un nodo solo), estrazione di relazioni. La parte modellistica viene dopo, ed è la più piccola.

  • TransE [BUGDuran+13] fa delle relazioni delle traslazioni (\(\mathbf{h}+\mathbf{r}\approx\mathbf{t}\)), cioè prende sul serio l’aritmetica delle analogie del capitolo sul linguaggio. Non regge le relazioni uno-a-molti, le simmetriche e le riflessive; la composizione invece la regge (\(\mathbf{r}_3 = \mathbf{r}_1 + \mathbf{r}_2\)), ed è il suo caso particolare, la transitività, a forzare \(\mathbf{r} \approx \mathbf{0}\). Da lì la discendenza (DistMult perde antisimmetria e inversione; ComplEx le recupera entrambe, ma la composizione resta fuori tanto da DistMult quanto da ComplEx; RotatE le tiene tutte e quattro), che però la transitività non la risolve: per le gerarchie servono rappresentazioni che contengono invece di spostare (ordini, scatole, spazi iperbolici).

  • R-GCN [SKB+18] porta il message passing sul grafo eterogeneo con una matrice di pesi per tipo di relazione, controllata con matrici di base condivise per non esplodere in parametri.

  • Il vantaggio durevole sta nel comporre più fatti, non nel saperli (per quello ci sono gli LLM): esibire il cammino come spiegazione e rispondere a domande aggregate. Il prezzo è la manutenzione, e un grafo non aggiornato è peggio di nessun grafo perché sembra ancora autorevole.

Un’entità mai vista, con R-GCN, resta fuori se non porta niente di proprio, e il problema è più generale: una rete addestrata guardando il grafo intero non sa che cosa fare dei nodi che arrivano dopo, né regge grafi da miliardi di archi. E i vicini, anche quando gli archi hanno un tipo solo, non contano tutti allo stesso modo, mentre la GCN li pesa soltanto secondo i gradi. Da queste due domande riparte la sezione su GraphSAGE e GAT.