CBOW un progenitore degli LLM – Costruiamone uno da zero Parte 1

·

6 min

Paper originale

Questo articolo è stato scritto al 100% da un umano

C’è stato un tempo non molto lontano dove gli LLM non esistevano. Era il 2013 quando Google faceva nascere un nuovo pacchetto Word2Vec che usava un nuovo modello chiamato CBOW, Continuous Bag of Words.
Cos’è un CBOW? è un modello capace di predire una parola basandosi sul contesto, ovvero sulle parole che le stanno attorno. Vi ricorda qualcosa?
Scrivo questo articolo forse un po’ anacronistico perchè a mio avviso è il miglior modo per apprendere come funzionano gli LLM moderni, capirne l’evoluzione e la struttura.
Come funziona un CBOW? Per capirlo proviamo a costruirne uno.

Partiamo dalle basi: token, vettori ed embedding.

Prima di iniziare capiamo meglio cosa fa’ un modello testuale predittivo. Un LLM è in grado di formulare frasi, rispondere a domande e creare del testo in base al concetto di probabilità.
Ad es. se chiediamo “Cosa mangia il gatto?” il modello potrebbe rispondere “Il topo”. Come ha recuperato questa risposta? Il modello è andato a cercare nel suo “vocabolario” la risposta più probabile data questa domanda.
Come fa’ a sapere qual è la risposta più probabile? L’ ha “imparato” durante la fase di training dove ha letto per molte volte in molti testi che il gatto mangia il topo.

Tutto chiaro, ma nella pratica come posso dire che questa risposta è più probabile di un’ altra? Ora inizo a spiegarlo.

Cos’ è un Token?

Prendiamo la frase:

“Il gatto mangia il topo”

Per far sì che questa frase sia capibile da una macchina bisogna per prima cosa renderla matematica ovvero trasformarla in numeri; e qui entrano in gioco i token che scorporano la frase in tanti piccoli elementi ad es.

[Il] [gatto] [mangia] [il] [topo]

In questo caso ogni parola è un token. Manteniamo questa logica per semplicità, nella realtà la suddivisione in token può variare in base alla parola che stiamo analizzando (per chi è interessato questo processo si chiama tokenization).

Ora che abbiamo i nostri token il sistema deve trasformarli in qualcosa di numerico e per fare ciò utilizza i vettori, quindi:

[Il] = [0.2, 0.8]
[gatto] = [0.3, 0.8]
[mangia] = [0.21, 0.75]
….

Quando il nostro modello legge la nostra frase non vedrà delle parole ma una serie di numeri (una serie di vettori). Questo gli permetterà (lo vedremo in seguito) di effettuare calcoli matematici per capire quale parola del vocabolario(quale vettore) è più probabile.
In questo esempio il vettore ha solo 2 numeri, ma nella realtà sono molti di più.

Ma come si calcolano i vettori? Come posso dire che “gatto” è uguale a [0.1, -0.5]?

Il materiale che serve per costruire il nostro modello

  • Vocabolario
  • Dataset di contenuti

Iniziamo a costruire il nostro CBOW come fosse un mobile dell’Ikea. Apriamo la scatola e prepariamo tutto il materiale che serve per montarlo.
La prima cosa di cui abbiamo bisogno è un “vocabolario”. Un insieme di parole da tenere in memoria per poi poterle trasformare nei nostri vettori,molto simile al nostro vaocabolario di italiano. Per semplificare prenderemo un vocabolario ridotto di X parole. Sono abbastanza per analizzare frasi come:
“Il gatto mangia il topo”
“Il cane mangia l’osso”
“il cane non miagola”
“il cane gioca con la palla”

etc….

Il secondo pezzo che serve, sono dei contenuti e delle frasi che servono per far “allenare” il nostro modello. Le frasi devono contenere le parole del nostro vocabolario.

Si inizia a lavorare

Molto bene, ora abbiamo vocabolario e frasi, ma è ancora tutto scritto in lettere e parole, il primo lavoro da fare è quello di trasformare le parole in vettori per farle capire alla macchina.
Ma come li calcoliamo?
Inizialmente lo facciamo in modo completamente casuale.
Strano vero? Questo perché non ci interessa lo “stato iniziale”, questi vettori andranno poi modificati e aggiustati durante la fase di training. In questa fase potremmo associare qualsiasi numero(vettore) alle nostre parole.

Possiamo scrivere un piccolo script python per associare ad ogni parola un vettore casuale.

Quindi ora siamo pronti?
No non ancora manca ancora un pezzettino, quello che definiamo come “punteggi”. Cosa sono e cosa servono?
Abbiamo detto che ad ogni parola viene associato un vettore che la identifica, oltre a questo però ad ogni parola viene associato anche un altro vettore, un vettore punteggio.

Facciamo un esempio così si capisce meglio:
Prendiamo la parola “gatto”. Abbiamo associato a “gatto” un vettore che la identifica: [0.3, 0.8]. Ora associamo a “gatto” anche un punteggio che sarà anche lui un vettore di 2 dimensioni ad es. [0.2,-0.9]. E così dobbiamo fare per tutte le parole del nostro vocabolario. Come vengono calcolati i punteggi? Anche in questo caso in modo casuale, verranno poi ricalibrati durante il training come vengono ricalibrate le parole.

Ultimo step da fare è unire tutti i punteggi delle varie parole in un’ unica matrice. Se il nostro vocabolario ha 2 parole, oltre a “gatto” abbiamo la parola “mangia” che ha punteggio [0.1, 0.7]. Uniamo i 2 vettori in una matrice 2X2 in questo modo:

[[0.2, 0.1]
[-0.9, 0.7]]

La fase più bella, quella del training

Abbiamo tolto tutti i pezzi dallo scatolone li abbiamo divisi ognuno al proprio posto, abbiamo vocabolario, frasi e punteggi, ora siamo pronti all’azione. Possiamo iniziare con il training del nostro primo modello.

Come funziona il training?

Per iniziare facciamo leggere al nostro modello le nostre frasi con un pezzetto mancante, ad es.
“Il gatto mangia il ___”.
Il modello dovrà indovinare qual è la parola mancante e lo farà confrontando i vari vettori. Essendo i vettori creati in maniera completamente casuale, inizialmente quasi sicuramente sbaglierà. Quando confronterà la sua risposta con la parola corretta andrà a ricalibrare i vettori in modo da ridurre l’errore.

Spieghiamolo meglio con degli esempi:

il modello legge la nostra frase “Il gatto mangia il ___” e la tokenizza.
Una volta letta crea una “previsione” della parola mancante. Ovviamente lo fa’ a modo suo, quindi non in lettere e parole, ma in vettore. Crea un “vettore previsione”. Come? Facendo la media dei vettori della frase. Ad es:

il = [0.2, 0.6]
gatto = [0.3, 0.8]
mangia = [0.4, -0.6]
il = [0.2, 0.6]


Fa una semplice media. Per il primo valore (0.2+0.3+0.4+0.2)/4 = 0.275 mentre per il secondo valore (0.6+0.8-0.6+0.6)/4 = 0.35.
Quindi il “vettore previsione” sarà:
[0.275, 0.35]
Abbiamo il “vettore previsione” come lo confrontiamo con il “vocabolario” per capire quale parola è più probabile? Usando la matrice dei punteggi.
Andiamo a fare il prodotto scalare tra il vettore_previsione e il vettore_punteggio di ogni parola:

risultato['parola'] = [vettore_previsione] x [vettore_punteggio]

Quindi:

risultato['gatto'] = [0.275, 0.35] x [0.2,-0.9] = −0.26
risultato['mangia'] = [0.275, 0.35] x [0.1, 0.7] = 0.2725
risultato['topo'] = [0.275, 0.35] x [0.3, 0.5] = 0.2575

In questo caso risponderebbe(sbagliando) “mangia”. Nel prossimo articolo vedremo come da questo errore “impari” e migliori il modello.