Wiki IA
Deep Learning

Transformers

L'architecture révolutionnaire derrière les LLM

Les Transformers ont révolutionné le Deep Learning depuis leur introduction en 2017. Ils sont au cœur de GPT, BERT, Claude, et de tous les modèles de langage modernes.

"Attention Is All You Need"

Article fondateur de Vaswani et al. (Google, 2017) qui a tout changé.

Avant : RNN/LSTM dominaient le NLP Après : Les Transformers règnent en maîtres

Pourquoi le succès ?

RNN/LSTMTransformer
Traitement séquentielTraitement parallèle
Dépendances longues difficilesAttention globale
Lent à entraînerRapide (GPU)
Contexte limitéContexte étendu

Le mécanisme d'attention

L'attention permet à chaque élément de "regarder" tous les autres éléments de la séquence.

Intuition

"Le chat qui dormait sur le canapé s'est réveillé"

Pour comprendre "s'est réveillé", le modèle doit savoir que :
- Le sujet est "chat" (pas "canapé")
- "qui dormait" donne le contexte

L'attention crée des connexions directes entre les mots pertinents.

Self-Attention

Chaque mot génère trois vecteurs :

  • Query (Q) : "Que cherche ce mot ?"
  • Key (K) : "Quelles infos ce mot contient-il ?"
  • Value (V) : "Quelle valeur transmettre ?"
            Attention
Q₁ ←──────────────────────→ K₁, K₂, K₃, K₄
    scores = Q₁ · [K₁,K₂,K₃,K₄]
    weights = softmax(scores)
    output₁ = weights · [V₁,V₂,V₃,V₄]

Formule

Attention(Q, K, V) = softmax(Q · Kᵀ / √dₖ) · V

- Q · Kᵀ : similarité entre queries et keys
- √dₖ : normalisation (dₖ = dimension des keys)
- softmax : convertit en probabilités
- × V : moyenne pondérée des values

Exemple simplifié

Phrase : "Le chat dort"

         Le    chat   dort
Le     [0.1   0.6    0.3 ]  ← Le regarde surtout "chat"
chat   [0.2   0.5    0.3 ]
dort   [0.1   0.7    0.2 ]  ← "dort" attend "chat" (sujet)

Matrice d'attention (après softmax)

Multi-Head Attention

Au lieu d'une seule attention, on en fait plusieurs en parallèle.

┌─────────────────────────────────────────────────┐
│            MULTI-HEAD ATTENTION                  │
├─────────────────────────────────────────────────┤
│                                                  │
│   ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐       │
│   │Head 1│  │Head 2│  │Head 3│  │Head 4│       │
│   │syntax│  │semant│  │coref │  │ ...  │       │
│   └──┬───┘  └──┬───┘  └──┬───┘  └──┬───┘       │
│      └─────────┴─────────┴─────────┘            │
│                    │                             │
│               Concatenate                        │
│                    │                             │
│              Linear (Wₒ)                         │
│                    ↓                             │
│                 Output                           │
│                                                  │
└─────────────────────────────────────────────────┘

Chaque "tête" peut capturer un type de relation différent :

  • Syntaxe
  • Sémantique
  • Coréférence
  • Position relative
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        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, Q, K, V, mask=None):
        batch_size = Q.size(0)

        # Projections linéaires
        Q = self.W_q(Q).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(K).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(V).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)

        # 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, -1e9)
        attn = torch.softmax(scores, dim=-1)
        context = torch.matmul(attn, V)

        # Concatenate et projection finale
        context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.num_heads * self.d_k)
        return self.W_o(context)

Architecture complète

Encoder-Decoder original

┌──────────────────────────────────────────────────────────────┐
│                      TRANSFORMER                              │
├────────────────────────┬─────────────────────────────────────┤
│       ENCODER          │           DECODER                   │
│                        │                                     │
│   ┌────────────────┐   │   ┌────────────────┐               │
│   │ Multi-Head     │   │   │ Masked Multi-  │               │
│   │ Self-Attention │   │   │ Head Attention │               │
│   └───────┬────────┘   │   └───────┬────────┘               │
│           │            │           │                         │
│   ┌───────┴────────┐   │   ┌───────┴────────┐               │
│   │ Add & Norm     │   │   │ Add & Norm     │               │
│   └───────┬────────┘   │   └───────┬────────┘               │
│           │            │           │                         │
│   ┌───────┴────────┐   │   ┌───────┴────────┐               │
│   │ Feed Forward   │   │   │ Cross-Attention│←── Encoder    │
│   └───────┬────────┘   │   └───────┬────────┘    output     │
│           │            │           │                         │
│   ┌───────┴────────┐   │   ┌───────┴────────┐               │
│   │ Add & Norm     │   │   │ Add & Norm     │               │
│   └───────┬────────┘   │   └───────┬────────┘               │
│           │            │           │                         │
│         × N            │   ┌───────┴────────┐               │
│                        │   │ Feed Forward   │               │
│                        │   └───────┬────────┘               │
│                        │           │                         │
│                        │   ┌───────┴────────┐               │
│                        │   │ Add & Norm     │               │
│                        │   └───────┬────────┘               │
│                        │           │                         │
│                        │         × N                         │
└────────────────────────┴─────────────────────────────────────┘

Composants clés

Positional Encoding

Les Transformers n'ont pas de notion d'ordre (contrairement aux RNN). On ajoute des encodages positionnels.

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1).float()
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))

        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        self.register_buffer('pe', pe.unsqueeze(0))

    def forward(self, x):
        return x + self.pe[:, :x.size(1)]

Feed Forward Network

Deux couches linéaires avec activation :

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff):
        super().__init__()
        self.linear1 = nn.Linear(d_model, d_ff)
        self.linear2 = nn.Linear(d_ff, d_model)
        self.gelu = nn.GELU()

    def forward(self, x):
        return self.linear2(self.gelu(self.linear1(x)))

Layer Normalization

nn.LayerNorm(d_model)

Connexions résiduelles

# Add & Norm
output = layer_norm(x + sublayer(x))

Variantes d'architecture

Encoder-only (BERT)

Bidirectionnel, voit tout le contexte.

[CLS] Le chat dort [SEP]
  ↓    ↓    ↓    ↓    ↓
┌─────────────────────────┐
│       ENCODER × N       │
└─────────────────────────┘
  ↓    ↓    ↓    ↓    ↓
Représentations contextuelles

Utilisations : Classification, NER, Q&A extractif

Decoder-only (GPT, Claude)

Autorégressif, ne voit que le passé (masque causal).

Le → chat → dort → [NEXT]
↓      ↓      ↓      ↓
┌──────────────────────────┐
│   DECODER × N (masked)   │
└──────────────────────────┘

                   Prédiction

Utilisations : Génération de texte, LLM

Encoder-Decoder (T5, BART)

Pour les tâches de séquence à séquence.

Utilisations : Traduction, résumé

Masques d'attention

Padding mask

Ignore les tokens de padding.

Séquence : [Le, chat, dort, <PAD>, <PAD>]
Mask :     [1,  1,    1,    0,     0    ]

Causal mask (GPT)

Empêche de voir le futur.

         Le  chat dort
Le      [1    0    0  ]
chat    [1    1    0  ]
dort    [1    1    1  ]
def causal_mask(size):
    mask = torch.triu(torch.ones(size, size), diagonal=1)
    return mask == 0  # True = peut voir

Modèles célèbres

BERT (2018)

Bidirectional Encoder Representations from Transformers

  • Encoder-only, bidirectionnel
  • Pré-entraîné avec Masked Language Model (MLM)
  • Base : 110M paramètres

GPT (2018-2023)

Generative Pre-trained Transformer

VersionParamètresContexte
GPT-1117M512
GPT-21.5B1024
GPT-3175B2048
GPT-4~1T?128k

Autres modèles notables

  • T5 : Text-to-Text, encoder-decoder
  • RoBERTa : BERT optimisé
  • ALBERT : BERT allégé
  • LLaMA : Meta, open-source
  • Mistral : Français, efficace
  • Claude : Anthropic

Vision Transformer (ViT)

Applique les Transformers aux images.

Image 224×224

Découpage en patches 16×16

14×14 = 196 patches

Flatten + Linear projection

[CLS] + 196 patch embeddings + Position

┌─────────────────────────┐
│   TRANSFORMER ENCODER   │
└─────────────────────────┘

Classification via [CLS]

Scaling Laws

Plus c'est gros, mieux c'est (jusqu'à un certain point).

Performance ∝ (Paramètres)^α × (Données)^β × (Compute)^γ

Règle de Chinchilla :
Tokens d'entraînement ≈ 20 × Paramètres

Optimisations modernes

Flash Attention

Attention optimisée pour GPU, réduit la mémoire.

from flash_attn import flash_attn_func

Grouped Query Attention (GQA)

Partage les Key/Value entre groupes de têtes.

Rotary Position Embedding (RoPE)

Encodage positionnel rotatif pour meilleure extrapolation.

Mixture of Experts (MoE)

Active seulement une partie des paramètres.

Input → Router → Expert 1  ← Sélectionné
              → Expert 2
              → Expert 3  ← Sélectionné
              → Expert 4

Implémentation simplifiée

import torch
import torch.nn as nn
import math

class TransformerBlock(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.attention = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = FeedForward(d_model, d_ff)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # Self-attention avec connexion résiduelle
        attn_output = self.attention(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_output))

        # Feed-forward avec connexion résiduelle
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))

        return x

class GPTModel(nn.Module):
    def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_len):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_len)
        self.layers = nn.ModuleList([
            TransformerBlock(d_model, num_heads, d_ff)
            for _ in range(num_layers)
        ])
        self.norm = nn.LayerNorm(d_model)
        self.output = nn.Linear(d_model, vocab_size)

    def forward(self, x):
        seq_len = x.size(1)
        mask = causal_mask(seq_len).to(x.device)

        x = self.embedding(x)
        x = self.pos_encoding(x)

        for layer in self.layers:
            x = layer(x, mask)

        x = self.norm(x)
        return self.output(x)

Résumé

TRANSFORMER = Attention + Feed Forward + Residual + LayerNorm

Clés du succès :
├── Parallélisation (vs RNN séquentiel)
├── Attention globale (contexte long)
├── Scaling (plus de paramètres = meilleur)
└── Pré-entraînement + Fine-tuning

Variantes :
├── Encoder-only (BERT) : compréhension
├── Decoder-only (GPT) : génération
└── Encoder-Decoder (T5) : seq2seq

On this page