Architetture complesse: dai layer alla logica modulare
Perché “architetture complesse”?
Quando i problemi crescono di difficoltà (linguaggio naturale, visione, serie temporali multivariate), non basta una rete “piatta”. Serve costruire modelli componibili, con blocchi riutilizzabili, che separano le responsabilità: estrazione di feature, memorie a lungo raggio, ragionamento sequenziale, generazione. Questo modulo insegna come passare dai singoli layer a moduli più ricchi – e come assemblarli in pipeline robuste.
1) Layer base: mattoni fondamentali
I layer sono le unità minime di calcolo. Conoscerne comportamenti e limiti è cruciale per non “abusare” della profondità o scegliere attivazioni/normalizzazioni inadatte.
- Dense (fully connected): proiezioni lineari con attivazione non lineare (ReLU, GELU, SiLU). Ottimi come head finali o per integrare feature eterogenee.
- Convolutional (Conv): estraggono pattern locali con condivisione dei pesi. Varianti utili: depthwise separable, dilated, residual. Nati per immagini, efficaci anche su sequenze 1D.
- Ricorrenti (LSTM/GRU): gestiscono dipendenze temporali. Le LSTM eccellono su contesti lunghi; le GRU sono più leggere con prestazioni simili.
- Transformer block: stack di Multi-Head Self-Attention (MHSA) + Feed-Forward Network (FFN), con residual + LayerNorm. Cattura dipendenze lunghe in parallelo.
<!-- Esempio di “blocco” astratto -->Input → [Normalizzazione] → [Operazione principale] → [Dropout] → (+ Residual) → Output
Nota pratica: Normalizzazione prima del blocco (pre-norm) tende a stabilizzare il training di modelli molto profondi; il residuo riduce il rischio di vanishing gradient.
2) Dalla collezione di layer alla logica modulare
Un’architettura complessa non è solo “più layer”: è composizione. Si definiscono moduli con un’API chiara e testabile, che possono essere riutilizzati in punti diversi della rete.
- Blocchi ripetibili: es. “ConvBlock(k, s)” con Conv → Norm → Attivazione → Dropout; “TransformerBlock(h, d)” con MHSA → FFN → Residual/Norm.
- Percorsi paralleli (inception-like): più rami con kernel/attività diverse, poi concatenazione: migliore copertura di scale differenti.
- Skip/Residual multi-scala: collegamenti tra livelli lontani per preservare dettagli (U-Net in segmentazione, encoder–decoder in NLP).
- Conditioning: iniezione di segnali esterni (classe/tempo/contesto) nei blocchi tramite concatenazione, gating o attenzione condizionata.
<!-- Pseudocodice di un modulo riutilizzabile -->def TransformerBlock(x):x_norm = LayerNorm(x)x_attn = MultiHeadAttention(x_norm, x_norm)x = x + Dropout(x_attn) # residualy_norm = LayerNorm(x)y_ffn = FFN(y_norm)y = x + Dropout(y_ffn) # residualreturn y
3) Strutture moderne: encoder–decoder, attention, embedding
- Embedding: mappa token/ID in vettori densi. Fondamentali in NLP; analoghi per categorie in tabellari. Si può includere positional encoding (sinusoidale o learnable) per preservare l’ordine.
- Attention/MHSA: meccanismo che assegna pesi Query–Key–Value alle relazioni tra elementi. Multi-head = sotto-spazi diversi in parallelo.
- Encoder–Decoder:
- Encoder: comprime l’input in rappresentazioni contestualizzate (BERT-like).
- Decoder: genera output condizionato all’encoder (traduzione, riassunto) o in modo autoregressivo (GPT-like).
- Cross-attention: il decoder “guarda” l’encoder per ogni passo di generazione.
Scelte progettuali chiave
- Maschere di attenzione: causale (no “sbirciare” il futuro) per generazione; bidirezionale per comprensione.
- Label smoothing: regolarizza la classificazione su vocabolari grandi.
- Ottimizzazione: AdamW + scheduler con warmup lineare spesso accelera la convergenza.
4) Dataset sequenziali e input testuali
Il successo di un’architettura complessa dipende dalla corretta preparazione del dato.
- Tokenizzazione: BPE/WordPiece alleviano out-of-vocabulary e mantengono compattezza. Conservare special tokens (PAD, BOS, EOS, SEP).
- Padding & masking: batch di lunghezze uniformi, con maschere per ignorare il padding nell’attenzione e nella loss.
- Bilanciamento: shuffling, pesi di classe, sampling per evitare bias di frequenza.
- Serie temporali: finestre scorrevoli, lookback/horizon, normalizzazione per feature (z-score/min-max), gestione di “missing” (imputazione, maschere).
- Data leakage: attenti a non usare informazioni future in addestramento (split temporale rigoroso).
5) Pattern di addestramento stabili
- Inizializzazione & attivazioni: He (ReLU/SiLU), Xavier (tanh); evitare saturazioni; LayerNorm/BatchNorm dove appropriato.
- Regolarizzazione: dropout (attenzione e FFN), weight decay, early stopping, stochastic depth in reti profonde.
- Gradiente: clip del gradiente su RNN/Transformer (specie con sequenze lunghe); mixed precision per velocità/memoria.
- Curriculum & teacher forcing: per modelli autoregressivi; scheduled sampling per ridurre esposizione a distribuzioni diverse tra train/test.
6) Valutazione e metriche
- Classificazione: accuracy, F1 (macro/micro), AUC; matrici di confusione per classi sbilanciate.
- Generazione testo: perplexity, BLEU/ROUGE/METEOR; analisi qualitativa (allucinazioni, ripetizioni, coerenza).
- Serie temporali: MAE/MSE/RMSE, MAPE; backtesting a più orizzonti (rolling window).
7) Laboratorio: Progettare un piccolo encoder–decoder per generazione frasi
Obiettivo: costruire un modello che generi frasi di risposta data un’istruzione breve (mini traduzione o dialogo toy).
Dataset suggeriti
- Tatoeba o coppie frase–frase semplificate (es. “it → en” ridotto) oppure un dataset custom di prompt–risposta (1000–5000 esempi bastano per il prototipo).
Passi operativi
- Preprocessing: tokenizzazione subword (BPE/WordPiece), definizione vocabolario, aggiunta di BOS/EOS, padding/truncation; split train/val/test.
- Embedding & Positional Encoding: dimensione embed 128–256; posizionale sinusoidale o learnable.
- Encoder: 2–4 TransformerBlock con 4–8 teste, FFN 2–4× dimensione embed, dropout 0.1–0.2.
- Decoder: 2–4 blocchi con masked self-attention + cross-attention verso l’encoder; tie embeddings opzionale.
- Loss & training: cross-entropy con label smoothing 0.1; AdamW (lr 3e−4) + warmup; early stopping via perdita di validazione.
- Decoding: greedy per debug; poi beam search (k=3–5) o top-k/top-p per qualità/varietà.
- Valutazione: BLEU/ROUGE su test; rassegna qualitativa di buone/cattive generazioni per guidare i miglioramenti.
<!-- Pseudocodice di montaggio (stile Keras/PyTorch-agnostico) -->src = Input(shape=(T_src,))tgt = Input(shape=(T_tgt,))src_emb = TokenEmbedding(V, d)(src) + PositionalEncoding(T_src, d)tgt_emb = TokenEmbedding(V, d)(tgt) + PositionalEncoding(T_tgt, d)enc = src_embfor _ in range(N_enc):enc = TransformerBlock(d, heads=H, ffn=4*d, dropout=0.1)(enc)dec = tgt_embfor _ in range(N_dec):dec = MaskedSelfAttentionBlock(d, heads=H, dropout=0.1)(dec)dec = CrossAttentionBlock(d, heads=H, context=enc, dropout=0.1)(dec)dec = FeedForwardBlock(d, ffn=4*d, dropout=0.1)(dec)logits = Dense(V)(dec) # head linguisticamodel = Model([src, tgt], logits)
Estensioni opzionali: weight tying embedding/output, shared encoder per multi-task, riduzione complessità con local attention per sequenze lunghe.
8) Errori comuni & best practice
- Maschere mancanti: senza causal mask il decoder “vede il futuro” e impara scorciatoie.
- Padding non mascherato: il modello impara a “predire” zeri: sempre applicare la mask del padding in attenzione e loss.
- Learning rate inadeguato: troppo alto → divergenza; usare warmup e scheduler.
- Overfitting precoce: aumentare dropout/weight decay, usare early stopping, più dati/augment.
- Leakage temporale: nei dati sequenziali rispettare la cronologia nei split e nelle finestre.
9) Checklist rapida di design
- Definisci chiaramente input/output e loro natura (immagini, testo, serie).
- Scegli i moduli (Conv/RNN/Transformer) in base a località vs lunga dipendenza.
- Applica normalizzazione, residual, dropout in ogni blocco profondo.
- Stabilisci metriche coerenti con il task (F1/BLEU/MAE) e un protocollo di validazione.
- Automatizza il training (checkpoint, early stopping, logging) e prova più semi.

Nessun commento:
Posta un commento