Nell'articolo dedicato agli embedding abbiamo visto che il primo compito di un modello linguistico è trasformare il testo in numeri. Ogni token viene associato a un vettore di migliaia di valori reali: nel caso di Llama 3.1 8B, ciascun embedding ha 4.096 componenti.
Questa rappresentazione è tutt'altro che casuale. Durante il pre-addestramento, il modello modifica progressivamente gli embedding in modo che token utilizzati in contesti simili occupino regioni vicine dello spazio vettoriale. È per questo motivo che parole semanticamente affini finiscono per avere rappresentazioni simili: la loro vicinanza geometrica riflette la somiglianza statistica dei contesti in cui sono apparse.
Fin qui il meccanismo è relativamente semplice. Tuttavia, appena si passa dal singolo token al linguaggio reale emerge un limite evidente: l'embedding di un token è statico.
Dopo che il tokenizzatore ha convertito il testo in identificativi di token, il modello recupera per ciascun identificativo la riga corrispondente nella matrice degli embedding. A parità di token ID, il vettore iniziale recuperato è sempre lo stesso.
Se il token "ape" compare cento volte in cento testi diversi, il modello parte ogni volta esattamente dalla stessa rappresentazione iniziale.
Questo non significa che il modello attribuisca sempre lo stesso significato alla parola, significa soltanto che il punto di partenza è invariabile.
Ed è qui che nasce il problema.
Consideriamo due frasi.
L'ape produce miele.
e
La nostra startup è un'ape: piccola, efficiente e instancabile.
Nel primo caso "ape" indica l'insetto. Nel secondo è una metafora utilizzata per descrivere un'organizzazione.
Per un lettore umano la differenza è immediata: il significato della parola emerge automaticamente dal resto della frase; per il modello, invece, entrambe le elaborazioni iniziano dallo stesso embedding.
La domanda diventa allora inevitabile: come può un modello produrre rappresentazioni diverse se parte sempre dallo stesso vettore?
La risposta costituisce il cuore dell'architettura transformer: l'embedding non è il punto di arrivo della rappresentazione di un token, ma soltanto il punto di partenza.
Il significato nasce dal contesto
Nel linguaggio naturale il significato di una parola non dipende soltanto dalla parola stessa, ma da ciò che la circonda.
Molte parole sono ambigue, altre assumono sfumature differenti a seconda della frase, altre ancora cambiano completamente significato quando vengono usate in senso figurato.
La lingua è, per sua natura, contestuale, e questo vale non solo per le parole polisemiche come "banco", "rete" o "penna", ma praticamente per qualsiasi termine. Pensiamo alla parola "freddo".
In
Il metallo è freddo.
descrive una temperatura.
In
Ha risposto con tono freddo.
descrive invece un atteggiamento.
Poiché lo stesso parametro di embedding viene utilizzato in tutti i contesti in cui compare quel token, il vettore iniziale deve risultare utile per impieghi anche molto diversi. Non codifica quindi, da solo, il significato specifico assunto nella frase corrente. È una rappresentazione estremamente utile, ma inevitabilmente perde le informazioni specifiche del contesto corrente.
Per comprendere davvero una frase il modello deve quindi costruire una rappresentazione diversa, valida soltanto per quella particolare sequenza.
Questa nuova rappresentazione viene spesso chiamata embedding contestualizzato oppure contextualized representation.
È importante distinguere bene questi due concetti.
L'embedding statico appartiene al vocabolario del modello. Esiste indipendentemente dal testo che stiamo elaborando.
La rappresentazione contestualizzata, invece, esiste soltanto durante l'elaborazione della sequenza. Se la stessa parola compare in due frasi diverse, il modello produrrà due rappresentazioni differenti.
In altre parole, il token rimane lo stesso, ma cambia il modo in cui viene rappresentato.
La self-attention come meccanismo di aggiornamento
Come costruisce il modello questa nuova rappresentazione?
L'idea alla base della self-attention è sorprendentemente semplice.
Per ogni token della sequenza il modello osserva anche tutti gli altri token disponibili e cerca di capire quali siano realmente rilevanti.
Non tutti contribuiscono allo stesso modo.
Se stiamo elaborando la frase
Dopo aver raccolto nettare dai fiori, l’ape torna all’alveare.
parole precedenti come “nettare”, “fiori” e “alveare” potrebbero contribuire a rendere la rappresentazione di “ape” coerente con il senso dell’insetto.
Il modello effettua proprio questa operazione.
La self-attention permette al modello di combinare le informazioni disponibili assegnando a ciascuna un peso diverso. Le informazioni considerate più rilevanti esercitano un’influenza maggiore; quelle meno rilevanti contribuiscono in misura minore.
Il risultato non sostituisce l'embedding originario nella matrice del vocabolario, ma è una nuova rappresentazione, costruita dinamicamente durante l’esecuzione del modello e dipendente dal contesto corrente.
Quando una sequenza viene elaborata in un unico passaggio, le rappresentazioni delle diverse posizioni possono essere calcolate in parallelo, nel rispetto della maschera di attenzione. Durante la generazione autoregressiva, invece, il modello aggiunge una nuova posizione alla volta.
Ogni posizione può utilizzare le informazioni provenienti dalle posizioni consentite dalla maschera e può, a sua volta, contribuire alla rappresentazione delle posizioni successive. In un decoder causale, infatti, l’informazione fluisce soltanto dal passato verso il futuro.
Il termine self-attention deriva proprio da questo comportamento: l'attenzione viene calcolata all'interno della stessa sequenza.
Nei transformer decoder, come Llama, questa osservazione è limitata dai vincoli della generazione autoregressiva. Durante la generazione di testo un token può utilizzare soltanto sé stesso e i token precedenti, mai quelli futuri. Questa restrizione viene implementata mediante la cosiddetta causal mask, che impedisce matematicamente al modello di "guardare avanti".
L'idea generale, però, rimane la stessa: ogni token costruisce la propria rappresentazione osservando il contesto disponibile.
Un'analogia utile
Una buona analogia consiste nell'immaginare una riunione.
Ogni partecipante entra nella sala con il proprio bagaglio di conoscenze. Quello corrisponde, grossolanamente, all'embedding statico.
Durante la discussione, però, nessuno mantiene esattamente la stessa prospettiva con cui era entrato: le osservazioni degli altri modificano gradualmente la comprensione di ciascuno.
Al termine della riunione ogni partecipante possiede ancora la propria identità iniziale, ma anche una nuova comprensione costruita grazie alle informazioni ricevute dagli altri.
Il transformer realizza qualcosa di analogo.
Ogni token parte da una rappresentazione stabile, osserva gli altri token e costruisce una nuova rappresentazione che incorpora soltanto le informazioni ritenute utili.
Naturalmente questa analogia non deve essere presa alla lettera; il modello non "capisce", non "riflette" e non possiede intenzioni.
Esegue semplicemente una sequenza di operazioni di algebra lineare che, una volta apprese durante l'addestramento, producono rappresentazioni estremamente efficaci.
L'impressione di comprensione emerge dal risultato del calcolo, non dall'esistenza di un processo cognitivo interno.
Query, Key e Value: come il modello decide a cosa prestare attenzione
Finora abbiamo descritto il comportamento del modello in termini intuitivi.
L'idea della self-attention è intuitiva: ogni token osserva il contesto e aggiorna la propria rappresentazione. Rimane però una domanda fondamentale: come stabilisce il modello quali token siano davvero rilevanti?
La risposta non consiste in una regola grammaticale né in un insieme di istruzioni scritte dai progettisti. Il transformer non contiene un parser sintattico nascosto e non gli viene insegnato esplicitamente che un verbo deve guardare il suo soggetto o che un aggettivo modifica un sostantivo. Tutto questo emerge durante l'addestramento.
Per rendere possibile questo comportamento, ogni embedding viene trasformato in tre vettori distinti, ciascuno con una funzione diversa. Questi vettori sono chiamati Query (Q), Key (K) e Value (V).
È importante chiarire subito un punto. Query, Key e Value non rappresentano tre "tipi" di significato della parola. Sono tre proiezioni lineari dello stesso embedding, ottenute moltiplicandolo per tre matrici di pesi differenti, apprese durante l'addestramento.
Formalmente:
[
Q = XW_Q,\qquad
K = XW_K,\qquad
V = XW_V
]
dove (X) è la rappresentazione del token in ingresso al layer e (W_Q), (W_K) e (W_V) sono matrici di parametri che il modello ha imparato durante il training.
La cosa interessante è che questi tre vettori assumono ruoli completamente diversi nel calcolo dell'attenzione.
Una metafora utile
Immaginiamo di dover organizzare una conferenza scientifica.
Ogni partecipante arriva con tre caratteristiche.
Da una parte possiede alcune competenze: intelligenza artificiale, matematica, biologia, economia.
Dall'altra ha interessi specifici: vuole parlare di reti neurali, di teoria dell'informazione o di modelli linguistici.
Infine, possiede anche un patrimonio di conoscenze che può condividere con gli altri.
Queste tre dimensioni corrispondono abbastanza bene ai tre vettori del transformer.
La Query rappresenta ciò che il token sta cercando.
La Key rappresenta il tipo di informazione che quel token è in grado di offrire.
Il Value rappresenta invece il contenuto che verrà effettivamente trasmesso, se il token verrà ritenuto rilevante.
Questa distinzione è fondamentale.
Il modello separa deliberatamente due problemi diversi:
- capire chi vale la pena ascoltare;
- decidere quale informazione ricevere da quel token.
Se utilizzasse un unico vettore per entrambe le operazioni, queste due decisioni rimarrebbero inevitabilmente intrecciate, riducendo la flessibilità del meccanismo di attenzione.
Il ruolo della Query
La Query può essere interpretata come una descrizione del contesto informativo che il token sta cercando. Non rappresenta una domanda formulata in linguaggio naturale, ma un vettore numerico costruito in modo che il prodotto scalare con le Key degli altri token indichi quanto essi siano rilevanti.
Pensiamo al token "ape" nella frase
L'ape produce miele.
Il modello potrebbe costruire una Query che, nello spazio vettoriale appreso durante l'addestramento, tende a essere compatibile con rappresentazioni di verbi che descrivono azioni o con sostantivi collegati al comportamento dell'insetto.
Naturalmente non esiste una singola dimensione che significhi "cerco un verbo". Lo spazio vettoriale è distribuito e ogni informazione è codificata attraverso l'interazione di molte componenti contemporaneamente.
Il ruolo della Key
Ogni token produce anche una Key.
Se la Query descrive ciò che il token sta cercando, la Key descrive il tipo di informazione che quel token può mettere a disposizione degli altri.
Quando il modello confronta una Query con una Key non sta confrontando due significati lessicali, ma sta valutando la compatibilità tra una richiesta informativa e un'offerta informativa.
Più il prodotto scalare tra Query e Key è elevato, maggiore sarà l'attenzione che il primo token dedicherà al secondo.
Questa è probabilmente la parte meno intuitiva della self-attention.
Non stiamo misurando quanto due parole siano semanticamente simili ma stiamo misurando quanto un token possa essere utile a un altro nel contesto corrente.
Due parole molto diverse possono quindi ricevere un punteggio di attenzione elevato se il modello ha imparato che una fornisce informazioni importanti per interpretare l'altra.
Il ruolo del Value
Una volta individuati i token rilevanti rimane ancora un passaggio.
Quale informazione deve essere trasferita?
Qui entra in gioco il Value.
Il Value contiene il contenuto che verrà combinato nella nuova rappresentazione del token.
La separazione tra Key e Value permette al modello di utilizzare un criterio per decidere da chi ricevere informazione e un criterio diverso per rappresentare che cosa ricevere.
È una distinzione sottile ma estremamente potente.
Due token potrebbero risultare ugualmente rilevanti rispetto alla stessa Query pur fornendo contenuti molto diversi.
Il meccanismo dell'attenzione consente di mantenere separate queste due dimensioni.
Dal confronto tra vettori ai pesi di attenzione
Una volta costruiti Query, Key e Value per tutti i token della sequenza, il modello può finalmente stabilire come distribuire la propria attenzione.
Il primo passo consiste nel confrontare ogni Query con tutte le Key, mediante il prodotto scalare.
Il prodotto scalare restituisce un numero che misura quanto due vettori siano allineati nello spazio.
Più il valore è elevato, maggiore è la compatibilità tra Query e Key.
Se la sequenza contiene (n) token, il risultato non è un singolo numero ma una matrice quadrata (n \times n), dove ogni riga rappresenta un token che osserva il contesto; ogni colonna rappresenta un token potenzialmente osservato.
L'elemento nella posizione ((i,j)) indica quanto il token (i) dovrebbe prestare attenzione al token (j).
È importante sottolineare che questa matrice non descrive relazioni grammaticali esplicite. Non contiene soggetti, verbi o complementi.
Contiene soltanto punteggi di compatibilità appresi statisticamente durante il training.
Perché è necessario lo scaling
A questo punto emerge un problema matematico.
Quando la dimensionalità dei vettori cresce, il prodotto scalare tende ad assumere valori sempre più grandi.
Se questi numeri venissero utilizzati direttamente nel passo successivo, la funzione Softmax produrrebbe distribuzioni estremamente sbilanciate, rendendo l'addestramento instabile.
Per questo motivo il transformer divide ogni punteggio per
[
\sqrt{d_k}
]
dove (d_k) rappresenta la dimensione delle Key.
Questa operazione prende il nome di scaling.
La divisione per (\sqrt{d_k}) non cambia l’ordinamento dei punteggi grezzi, ma ne riduce la scala e rende meno satura la Softmax, modificando quindi quanto la distribuzione finale risulti concentrata.
Serve semplicemente a mantenere i valori in un intervallo numericamente favorevole all'ottimizzazione.
È uno di quei dettagli apparentemente secondari che, in realtà, rendono possibile l'addestramento stabile di modelli molto profondi.
La funzione Softmax
Dopo lo scaling, i punteggi vengono trasformati in (una specie di) probabilità mediante la funzione Softmax. In realtà, la funzione Softmax trasforma ogni riga in una distribuzione di pesi non negativi la cui somma è uno. Questi pesi possono essere letti come quote relative di attenzione, ma non sono probabilità calibrate di una relazione linguistica.
Questo passaggio ha un significato intuitivo molto semplice: il modello non vuole sapere soltanto quale token sia il più rilevante, ma vuole anche stabilire quanto ogni token debba contribuire alla rappresentazione finale.
La Softmax trasforma quindi ogni riga della matrice di compatibilità in una distribuzione di probabilità.
Tutti i pesi risultano compresi tra zero e uno, e la loro somma è sempre uguale a uno.
Questo permette di interpretare ogni valore come la frazione di attenzione assegnata a ciascun token. È importante osservare che la Softmax non produce una scelta binaria; il modello non decide semplicemente di ascoltare oppure ignorare un token.
Distribuisce invece la propria attenzione lungo un continuum:
alcuni token riceveranno un peso molto elevato;
altri contribuiranno solo marginalmente;
altri ancora avranno un'influenza praticamente trascurabile.
La nuova rappresentazione del token
L'ultimo passaggio consiste nel combinare i Value utilizzando i pesi appena calcolati.
Ogni Value viene moltiplicato per il proprio coefficiente di attenzione e, successivamente, tutti questi contributi vengono sommati.
Il risultato è un nuovo vettore che rappresenta il token nel contesto corrente. Questo è il momento in cui nasce la rappresentazione contestualizzata.
L'embedding iniziale non viene modificato. Rimane una componente della rappresentazione, ma viene arricchito dalle informazioni provenienti dagli altri token ritenuti rilevanti.
Dal punto di vista matematico il procedimento è sorprendentemente compatto. Dal punto di vista concettuale, invece, rappresenta il cuore dell'intera architettura transformer. Ogni token diventa una sintesi pesata del proprio significato originario e delle informazioni che il contesto mette a disposizione.
Ed è proprio questa capacità di costruire rappresentazioni dinamiche, diverse a ogni frase, che consente ai transformer di superare il limite fondamentale degli embedding statici.
Nel prossimo passo vedremo come questa idea venga ulteriormente estesa mediante la Multi-Head Attention, uno dei principali motivi per cui i transformer riescono a catturare contemporaneamente relazioni sintattiche, semantiche e contestuali di natura molto diversa.
Oltre la teoria: Multi-Head Attention e Grouped-Query Attention
Finora abbiamo descritto il funzionamento della self-attention come se esistesse un solo meccanismo di osservazione. Ogni token costruisce la propria Query, la confronta con le Key degli altri token e utilizza i Value per aggiornare la propria rappresentazione. Dal punto di vista concettuale è corretto, ma i transformer moderni fanno un passo ulteriore.
La lingua è un sistema estremamente ricco di relazioni. In una stessa frase convivono dipendenze sintattiche, relazioni semantiche, accordi grammaticali, riferimenti anaforici, legami tra soggetto e verbo, modificatori, espressioni idiomatiche e dipendenze che possono estendersi per decine o centinaia di token. È difficile immaginare che un'unica rappresentazione di Query, Key e Value riesca a catturare contemporaneamente tutti questi aspetti.
Per questo motivo i transformer utilizzano la Multi-Head Attention.
Perché servono più teste
L'idea è semplice: invece di calcolare una sola attenzione, il modello ne calcola molte in parallelo.
Ogni testa dispone delle proprie matrici (W_Q), (W_K) e (W_V), completamente indipendenti da quelle delle altre teste. Di conseguenza, la stessa rappresentazione in ingresso viene proiettata in sottospazi differenti dello spazio vettoriale.
È importante chiarire un punto che spesso viene semplificato nelle introduzioni ai transformer.
Non bisogna immaginare che l'embedding di 4096 dimensioni venga semplicemente suddiviso in trentadue blocchi da 128 dimensioni, assegnandone uno a ciascuna testa. In realtà ogni testa riceve come input l'intera rappresentazione del token e costruisce la propria proiezione lineare. Le 128 dimensioni su cui lavora ciascuna testa sono quindi un sottospazio appreso durante l'addestramento, non una porzione fissa dell'embedding originale.
Questa distinzione è importante perché spiega perché teste diverse possano apprendere prospettive molto differenti pur partendo dalla stessa informazione iniziale.
Una specializzazione che emerge durante l'addestramento
Nessun progettista assegna un compito specifico alle varie teste. Durante il training il modello riceve soltanto l'obiettivo di prevedere il token successivo. È l'ottimizzazione dei parametri a portare spontaneamente alcune teste a sviluppare comportamenti specializzati.
Negli ultimi anni numerosi studi di interpretabilità hanno osservato che alcune teste sembrano concentrarsi su particolari tipi di relazioni. Alcune collegano frequentemente soggetti e verbi, altre sembrano seguire riferimenti pronominali, altre ancora prestano particolare attenzione ai token immediatamente precedenti oppure ai segni di punteggiatura.
Bisogna però essere prudenti nell'interpretare questi risultati.
Non tutte le teste mostrano una funzione facilmente identificabile, e soprattutto la loro specializzazione non è una proprietà garantita dell'architettura. È un comportamento osservato empiricamente in molti modelli, ma può variare da un'architettura all'altra e persino tra diverse istanze dello stesso modello addestrate con semi casuali differenti.
Più che parlare di "teste grammaticali" o "teste semantiche", è quindi più corretto dire che le diverse teste imparano a distribuire il lavoro in modi che risultano utili all'ottimizzazione complessiva del modello.
Come vengono combinati i risultati
Ogni testa esegue il proprio calcolo di attenzione in maniera completamente indipendente. Alla fine produce, per ciascun token, un vettore della stessa dimensione della testa, ad esempio 128 componenti.
Questi vettori vengono poi concatenati e sottoposti a un'ulteriore trasformazione lineare, spesso indicata come matrice (W_O), che li riporta nella dimensione dello spazio nascosto del modello.
Questa trasformazione finale è spesso trascurata nelle spiegazioni introduttive, ma svolge un ruolo importante. Permette infatti al modello di combinare le informazioni provenienti dalle diverse teste e di costruire una rappresentazione unificata che verrà utilizzata dal layer successivo.
Di conseguenza, la Multi-Head Attention non produce semplicemente trentadue punti di vista separati. Produce una nuova rappresentazione nella quale le informazioni raccolte dalle varie teste vengono fuse in modo appreso durante il training.
Un'attenzione ripetuta molte volte
Il layer di attenzione non compare però una sola volta nel transformer.
Llama 3.1 8B, ad esempio, contiene 32 blocchi transformer sovrapposti. Ogni blocco riceve la rappresentazione prodotta dal blocco precedente e la raffina ulteriormente. Questo significa che la contestualizzazione non avviene in un unico passaggio, ma che le rappresentazioni vengono progressivamente arricchite.
Nei primi layer il modello tende spesso a catturare relazioni più locali, più sintattiche; nei layer intermedi emergono rappresentazioni semantiche più sofisticate; negli strati più profondi l'informazione proveniente da tutta la sequenza viene progressivamente integrata. Questa descrizione è necessariamente semplificata, ma riflette una tendenza osservata in molti studi di interpretabilità.
L'idea importante è che nessun layer possiede, da solo, una comprensione completa della frase. La rappresentazione evolve gradualmente attraversando l'intera profondità del modello.
Conclusione
In questo articolo abbiamo visto come un transformer riesca a superare il limite degli embedding statici costruendo rappresentazioni contestualizzate attraverso il meccanismo di self-attention. Query, Key e Value permettono al modello di identificare quali informazioni siano rilevanti per ogni token, mentre la Multi-Head Attention consente di osservare la stessa sequenza da prospettive differenti. È questo processo, ripetuto lungo tutti i layer del transformer, a rendere possibile una rappresentazione dinamica del significato, molto più ricca del semplice embedding iniziale.
Ma questa non è tutta la storia. La self-attention presenta anche limiti importanti, sia teorici sia pratici. Inoltre, nei modelli moderni, il suo funzionamento è stato modificato per ridurre drasticamente il consumo di memoria senza perdere precisione. Nella prossima puntata vedremo come nasce la Grouped-Query Attention, come funziona la KV Cache e, soprattutto, quali sono i limiti intrinseci del meccanismo di attenzione e perché, da solo, non basta a spiegare le capacità dei moderni LLM.
Bibliografia
- Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., & Polosukhin, I. (2017). Attention Is All You Need. Advances in Neural Information Processing Systems (NeurIPS 30).
https://arxiv.org/abs/1706.03762 - Dao, T. (2023). FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning. arXiv:2307.08691.
https://arxiv.org/abs/2307.08691 - Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F., & Sanghai, S. (2023). GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. EMNLP 2023.
https://arxiv.org/abs/2305.13245 - Elhage, N., Nanda, N., Olsson, C., Henighan, T., Joseph, N., Mann, B., Askell, A., Bai, Y., et al. (2021). A Mathematical Framework for Transformer Circuits. Anthropic.
https://transformer-circuits.pub/2021/framework/ - Anthropic. (2025). Tracing the Thoughts of a Large Language Model.
https://www.anthropic.com/research/tracing-thoughts-language-model - Dubey, A., Jauhri, A., Pandey, A., et al. (Llama Team). (2024). The Llama 3 Herd of Models. arXiv:2407.21783.
https://arxiv.org/abs/2407.21783
