Transformer : une révolution dans l’apprentissage profond
Applications hors LLM :
Entrée:
Sortie:
Idée :
On projette ces vecteurs vers trois espaces via des matrices de paramètres :
Pour un token :
\[ q = xW_Q,\quad k = xW_K,\quad v = xW_V \]
Pour une séquence \(X\) de longueur \(T\), on empile les vecteurs projetés :
Matrice des queries :
\[ Q = X W_Q \quad \text{avec } X \in \mathbb{R}^{T \times d_{\text{model}}} \] \[ Q \in \mathbb{R}^{T \times d_k} \]
Matrice des keys :
\[ K = X W_K \] \[ K \in \mathbb{R}^{T \times d_k} \]
Chaque ligne correspond au query (ou key) d’un token.
On définit la similarité entre le token i et le token j par :
\[ \text{Scores}_{i,j} = \frac{q_i k_j^\top}{\sqrt{d_k}} = \frac{x_i (W_Q W_K^\top) x_j^\top}{\sqrt{d_k}} \]
Sur toute la séquence, cela donne la matrice complète :
\[ \text{Scores} = \frac{QK^\top}{\sqrt{d_k}} \qquad \text{Scores} \in \mathbb{R}^{T \times T} \]
Définition : matrice d’attention
\[ A = \text{softmax}(\text{Scores}) \qquad A \in \mathbb{R}^{T \times T} \]
Exemple : « it » regarde « cat » (0.88), mais « cat » regarde peu « it » (0.38)
Dans tous les cas :
Si \(d_k = d_{model}\):
Si \(d_k < d_{model}\)
Pour un token i, la sortie est une combinaison pondérée des valeurs V :
\[ \text{output}_i = \sum_{j=1}^{T} A_{i,j} \, v_j \]
Sous forme matricielle:
\[ \text{Output}(Q,K,V)=\text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V \]
Motivation :
Têtes réelles de GPT-2 : chaque tête apprend un motif différent
Principe :
Formule :
\[ \text{MultiHead}(Q,K,V)=\text{Concat}(\text{head}_1,\dots,\text{head}_h)W^O \]
On note \(\text{head}_i = A_i X W_V^i\) la sortie de la tête \(i\), et \(W_O^i\) (\(d_v \times d_{model}\)) le \(i\)-ème bloc de lignes de \(W^O\) :
\[ \text{Concat}(\text{head}_1,\dots,\text{head}_h)W^O = \sum_{i=1}^{h} A_i X \, (W_V^i W_O^i) \]
Sans \(W^O\) (\(W^O = I\)) :
Entrée:
Sortie:
Bloc transformer (version simplifiée, sans normalisation):
Attention : mélange l’information entre les tokens \[ X_1 = X + \text{MultiHeadAttention}(X) \qquad X_1 \in \mathbb{R}^{T \times d_{model}} \]
FeedForward : appliqué à chaque token séparément, avec les mêmes poids pour tous les tokens \[ Y[t,:] = X_1[t,:] + FF(X_1[t,:]) \qquad t = 1, \dots, T \] On note simplement \(Y = X_1 + FF(X_1)\), avec \(FF\) appliqué ligne par ligne.
Voir le cours “Architectures profondes”, section “Connexions résiduelles”.
Pourquoi les résidus ?
Transformer original (2017), BERT :
\[ X_1 = \text{LN}\big(X + \text{MultiHeadAttention}(X)\big) \] \[ Y = \text{LN}\big(X_1 + FF(X_1)\big) \]
nn.TransformerEncoderLayer(..., norm_first=False) (défaut)GPT-2, LLaMA, la plupart des LLM actuels :
\[ X_1 = X + \text{MultiHeadAttention}\big(\text{LN}(X)\big) \] \[ Y = X_1 + FF\big(\text{LN}(X_1)\big) \]
nn.TransformerEncoderLayer(..., norm_first=True)Bilan : Post-LN écrase les couches du début, Pre-LN celles de la fin. En pratique, Pre-LN (souvent avec RMSNorm) est le choix par défaut.
But:
Transformer:
Par défaut:
Problème:
Idée:
Masque:
Remarque: On peut aussi définir le masque comme la valeur qu’il faut ajouter avant le softmax. Cela donne \(M_{i,j} = -\infty\).
Masque causal:
Modèle 1 couche
import torch
import torch.nn as nn
import math
def generate_causal_mask(size):
mask = torch.full((size, size), fill_value=True, dtype=torch.bool)
mask = torch.triu(mask, diagonal=1)
return mask
class SimpleLanguageModel(nn.Module):
def __init__(self, vocab_size, d_model, nhead, dropout=0.1):
super().__init__()
self.d_model = d_model
self.embedding = nn.Embedding(vocab_size, d_model)
self.decoder_layer = nn.TransformerEncoderLayer(d_model, nhead, batch_first=True)
self.fc_out = nn.Linear(d_model, vocab_size)
def forward(self, x):
T = x.size(1)
mask = generate_causal_mask(T).to(x.device)
emb = self.embedding(x) * math.sqrt(self.d_model)
output = self.decoder_layer(emb, src_mask = mask)
output = self.fc_out(output)
return output
Transformer:
Encodage positionnel:
Encodage historique: \[PE_{(pos,\,2i)} = \sin\!\left(\frac{pos}{10000^{\,2i/d_{\text{model}}}}\right)\] et \[PE_{(pos,\,2i+1)} = \cos\!\left(\frac{pos}{10000^{\,2i/d_{\text{model}}}}\right)\]
avec \(pos\) la position du token dans la séquence et \(i\) l’indice de la dimension
class PositionalEncoding(nn.Module):
def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
position = torch.arange(max_len).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))
pe = torch.zeros(max_len, 1, d_model)
pe[:, 0, 0::2] = torch.sin(position * div_term)
pe[:, 0, 1::2] = torch.cos(position * div_term)
self.register_buffer('pe', pe)
def forward(self, x: Tensor) -> Tensor:
"""
Arguments:
x: Tensor, shape ``[seq_len, batch_size, embedding_dim]``
"""
x = x + self.pe[:x.size(0)]
return self.dropout(x)Paramètres :
Données :
Exemple : en 2025, des modèles de Google DeepMind et d’OpenAI obtiennent un score de niveau médaille d’or aux Olympiades internationales de mathématiques, sur des problèmes nouveaux.
Durée des tâches (METR, 2025) : la durée (pour un humain) des tâches qu’un modèle réussit une fois sur deux double environ tous les 7 mois. https://metr.org/blog/2025-03-19-measuring-ai-ability-to-complete-long-tasks/
Chronologie :
Navier-Stokes : les équations de la mécanique des fluides. Une solution régulière peut-elle « exploser » (vitesse infinie) en temps fini ?
2021 : “On the Dangers of Stochastic Parrots: Can Language Models Be Too Big?”
Contrepoint : des représentations internes. Othello-GPT (2023) :
Limite qui demeure : les hallucinations. Un LLM peut affirmer avec assurance des choses fausses.
| Transformer (2017) | LLM actuels (Llama, Qwen, DeepSeek…) | |
|---|---|---|
| Architecture | encodeur-décodeur | décodeur seul, masque causal |
| Normalisation | Post-LN, LayerNorm | Pre-LN, RMSNorm |
| Position | sinusoïdale, ajoutée à l’entrée | RoPE : rotation de \(q\) et \(k\) selon la position, dans chaque couche |
| Attention | multi-head | GQA : plusieurs têtes partagent les mêmes \(K\) et \(V\) |
| FeedForward | ReLU, dense | SwiGLU, souvent un mélange d’experts |
La structure ne change pas : attention + FeedForward + chemin résiduel, répétés \(L\) fois.
Idée : remplacer le FeedForward par \(N\) FeedForward (les experts) et un routeur
Conséquence : paramètres totaux \(\gg\) paramètres actifs
La sécurité (refuser les demandes dangereuses, etc.) est apprise pendant les étapes 2 et 3.
Génération :