Introduzione: L'Architettura che ha Cambiato Tutto
Il Transformer, introdotto nel paper "Attention Is All You Need" (Vaswani et al., 2017), ha rivoluzionato il deep learning eliminando completamente la ricorrenza delle RNN. Al suo posto, il meccanismo di self-attention permette a ogni elemento della sequenza di "guardare" direttamente tutti gli altri elementi, catturando dipendenze a lungo termine senza il bottleneck del vanishing gradient.
Dalla sua introduzione, il Transformer e diventato l'architettura dominante non solo nel NLP (BERT, GPT, T5) ma anche nella computer vision (Vision Transformer), nell'audio (Whisper) e nella generazione di immagini (DALL-E, Stable Diffusion). Comprendere questa architettura e fondamentale per chiunque lavori nel deep learning moderno.
Cosa Imparerai
- Self-Attention: come ogni token "guarda" gli altri nella sequenza
- Query, Key, Value: la meccanica dell'attention
- Multi-Head Attention: catturare pattern diversi simultaneamente
- Positional Encoding: come il Transformer conosce l'ordine della sequenza
- Architettura Encoder-Decoder completa
- BERT vs GPT: encoder-only vs decoder-only
- Implementazione pratica con Hugging Face Transformers
Self-Attention: Il Cuore del Transformer
Il self-attention (o intra-attention) permette a ogni posizione nella sequenza di calcolare un peso di attenzione rispetto a tutte le altre posizioni. Questo significa che per comprendere la parola "banca" in una frase, il modello può direttamente guardare se nel contesto ci sono parole come "fiume" (banca del fiume) o "denaro" (istituto bancario).
Il meccanismo si basa su tre vettori calcolati per ogni token:
- Query (Q): rappresenta "cosa sto cercando" - la domanda che ogni token pone agli altri
- Key (K): rappresenta "cosa offro" - l'etichetta con cui ogni token si presenta
- Value (V): rappresenta "il mio contenuto" - l'informazione effettiva da trasmettere
L'attention score tra due token e il prodotto scalare tra la Query del primo e la Key del secondo, normalizzato per la radice quadrata della dimensione. Dopo un softmax, questi score pesano i Value per produrre l'output.
import torch
import torch.nn as nn
import math
class ScaledDotProductAttention(nn.Module):
"""Scaled Dot-Product Attention: Attention(Q, K, V)"""
def __init__(self, d_k):
super().__init__()
self.scale = math.sqrt(d_k)
def forward(self, query, key, value, mask=None):
# query, key, value: (batch, seq_len, d_k)
scores = torch.matmul(query, key.transpose(-2, -1)) / self.scale
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
attention_weights = torch.softmax(scores, dim=-1)
output = torch.matmul(attention_weights, value)
return output, attention_weights
# Esempio
batch_size, seq_len, d_model = 2, 10, 64
Q = torch.randn(batch_size, seq_len, d_model)
K = torch.randn(batch_size, seq_len, d_model)
V = torch.randn(batch_size, seq_len, d_model)
attention = ScaledDotProductAttention(d_k=d_model)
output, weights = attention(Q, K, V)
print(f"Output: {output.shape}") # [2, 10, 64]
print(f"Weights: {weights.shape}") # [2, 10, 10]
Multi-Head Attention
Un singolo meccanismo di attention cattura un solo tipo di relazione tra i token. La Multi-Head Attention esegue l'attention in parallelo con diverse proiezioni lineari (teste), permettendo al modello di catturare simultaneamente relazioni sintattiche, semantiche, posizionali e di coreference.
Ogni testa opera su una sottodimensione dello spazio di embedding: se d_model=512 e abbiamo 8 teste, ogni testa lavora su d_k=64 dimensioni. I risultati vengono concatenati e proiettati attraverso una trasformazione lineare finale.
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
assert d_model % num_heads == 0
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model)
def forward(self, query, key, value, mask=None):
batch_size = query.size(0)
# Proiezioni lineari e split in heads
Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# Scaled dot-product attention
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
attn = torch.softmax(scores, dim=-1)
context = torch.matmul(attn, V)
# Concatena heads e proiezione finale
context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
return self.W_o(context)
mha = MultiHeadAttention(d_model=512, num_heads=8)
x = torch.randn(4, 20, 512) # batch=4, seq=20, dim=512
output = mha(x, x, x)
print(f"MHA output: {output.shape}") # [4, 20, 512]
Positional Encoding
A differenza delle RNN che elaborano i token sequenzialmente, il Transformer processa tutti i token in parallelo. Senza informazione sulla posizione, il modello tratta la sequenza come un insieme non ordinato. Il positional encoding aggiunge informazione sulla posizione di ogni token nell'embedding.
Il paper originale usa funzioni sinusoidali con frequenze diverse per ogni dimensione. Questo schema ha il vantaggio di generalizzare a sequenze più lunghe di quelle viste durante il training, poichè le funzioni seno e coseno sono periodiche.
perchè il Transformer e Migliore delle RNN
Tre vantaggi chiave: (1) Parallelizzazione - tutti i token vengono processati simultaneamente, sfruttando al massimo le GPU. (2) Dipendenze a lungo termine - ogni token può "guardare" direttamente qualsiasi altro token, senza propagazione sequenziale. (3) Scalabilità - l'architettura scala efficacemente a miliardi di parametri (GPT-3: 175B, GPT-4: ~1.8T stimati), cosa impossibile con le RNN.
Architettura Encoder-Decoder
Il Transformer originale ha un'architettura encoder-decoder:
- Encoder: 6 layer identici, ciascuno con Multi-Head Self-Attention + Feed-Forward Network, separati da Layer Normalization e residual connections. Processa l'input completo
- Decoder: 6 layer identici con Masked Self-Attention (per non guardare token futuri), Cross-Attention (per guardare l'output dell'encoder) e Feed-Forward Network. Genera l'output auto-regressivamente
BERT vs GPT: Due Filosofie
BERT (Encoder-Only)
BERT (Bidirectional Encoder Representations from Transformers) usa solo l'encoder. Durante il pre-training, maschera casualmente il 15% dei token e li predice (Masked Language Modeling), imparando rappresentazioni bidirezionali. Eccelle in task di comprensione: classificazione, NER, question answering.
GPT (Decoder-Only)
GPT (Generative Pre-trained Transformer) usa solo il decoder con masked attention. Pre-addestrato a predire il token successivo (Causal Language Modeling), eccelle nella generazione di testo. GPT-3 e GPT-4 hanno dimostrato capacità emergenti con l'aumentare della scala.
from transformers import pipeline, AutoTokenizer, AutoModel
# Sentiment analysis con pipeline Hugging Face
classifier = pipeline("sentiment-analysis")
result = classifier("This movie was absolutely fantastic!")
print(result) # [{'label': 'POSITIVE', 'score': 0.9998}]
# Text generation con GPT-2
generator = pipeline("text-generation", model="gpt2")
text = generator("Deep learning is", max_length=50, num_return_sequences=1)
print(text[0]['generated_text'])
# BERT embeddings per downstream tasks
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")
inputs = tokenizer("The transformer architecture is revolutionary",
return_tensors="pt")
outputs = model(**inputs)
# outputs.last_hidden_state: (1, seq_len, 768)
cls_embedding = outputs.last_hidden_state[:, 0, :] # CLS token
print(f"CLS embedding: {cls_embedding.shape}") # [1, 768]
Vision Transformer (ViT) e Oltre
Il successo dei Transformer nel NLP ha ispirato la loro applicazione in altri domini. Il Vision Transformer (ViT) divide un'immagine in patch (tipicamente 16x16), le tratta come token e applica l'architettura Transformer standard. Sorprendentemente, ViT raggiunge performance competitive con le CNN su grandi dataset, e le supera quando pre-addestrato su dataset massivi.
Oggi i Transformer sono alla base di: modelli linguistici (GPT-4, Claude, Llama), generazione immagini (DALL-E, Stable Diffusion), riconoscimento vocale (Whisper), robotica (RT-2) e modelli multimodali (GPT-4V, Gemini). L'architettura si e dimostrata essere un fondamento universale per l'intelligenza artificiale moderna.
Prossimi Passi nella Serie
- Nel prossimo articolo esploreremo le GAN (Generative Adversarial Networks)
- Vedremo come due reti in competizione generano dati sintetici realistici
- Analizzeremo DCGAN, StyleGAN e le sfide del training adversariale







