Article original : How Transformer Models Work for Language Processing

Si vous avez déjà utilisé Google Traduction, parcouru un résumé automatique ou demandé de l'aide à un chatbot, vous avez certainement vu les Transformers à l'œuvre. Ils sont considérés comme les architectes des plus grandes avancées actuelles dans le traitement du langage naturel (NLP).

Tout a commencé avec les réseaux de neurones récurrents (RNN), qui lisent le texte étape par étape. Les RNN fonctionnaient, mais ils avaient du mal avec les phrases longues car le contexte ancien se perdait souvent. Les LSTM (Long Short-Term Memory) ont amélioré la mémoire, mais traitaient toujours les mots en séquence, ce qui était lent et difficile à mettre à l'échelle.

La percée est venue avec l'attention : au lieu de se déplacer mot par mot, les modèles pouvaient directement « porter leur attention » sur les parties les plus pertinentes d'une phrase, quel que soit leur emplacement. En 2017, l'article Attention Is All You Need a introduit le Transformer, qui a remplacé la récurrence par l'attention et le traitement parallèle. Cela a rendu les modèles plus rapides, plus précis et capables d'apprendre à partir de quantités massives de texte.

Dans ce guide, vous apprendrez comment fonctionnent les Transformers, vous en construirez une version simple étape par étape et vous verrez comment appliquer des modèles pré-entraînés pour des tâches réelles. À la fin, vous comprendrez mieux les Transformers et pourquoi ils ont changé la donne.

Table des matières

Prérequis

Avant de plonger, il est utile de maîtriser quelques bases :

  • Python et PyTorch : Vous devez savoir écrire des scripts Python simples. Une familiarité avec les tenseurs et les modules PyTorch facilitera la compréhension du code.

  • Bases des réseaux de neurones : Une compréhension des embeddings, des couches feedforward et des boucles d'entraînement est utile, bien que non requise.

  • Bases de l'algèbre linéaire : Les concepts tels que les vecteurs, les produits scalaires et les matrices sont au cœur du fonctionnement de l'attention.

Si vous débutez dans l'un de ces domaines, vous pouvez tout de même suivre, mais ce bagage vous aidera à assimiler les idées plus rapidement.

Comprendre l'Attention depuis la base

Imaginez lire une phrase puis vous concentrer instinctivement sur les mots qui ont le plus de sens pour la suite. C'est précisément ce que le mécanisme d'attention fait pour les machines. Il donne aux modèles la capacité de mettre en évidence les parties du texte qui comptent le plus, exactement au moment où elles sont nécessaires.

Le mécanisme fonctionne en attribuant à chaque jeton (token) trois rôles : une Requête (Query), une Clé (Key) et une Valeur (Value). Pensez-y comme à une session de questions-réponses. La Requête représente ce qu'un mot recherche, les Clés sont ce que les autres mots proposent, et les Valeurs sont les informations qu'ils apportent. En comparant une requête avec toutes les clés, le modèle détermine quels mots doivent influencer la décision actuelle et rassemble leurs valeurs dans les bonnes proportions.

Par exemple, vous avez le mot « banque » dans une phrase. Son sens change selon les mots environnants. Si les termes proches incluent « rivière » ou « eau », l'attention renforce ces connexions et interprète « banque » comme un bord de l'eau. Si, au contraire, le contexte est « prêt » ou « argent », l'attention se déplace et « banque » devient financier. Cette approche par liaison est ce qui rend l'attention si précise : le modèle n'a pas besoin de tout mémoriser de manière linéaire, il connecte simplement les bons points au bon moment.

En coulisses, on appelle cela l'attention par produit scalaire mis à l'échelle (scaled dot-product attention). Les vecteurs Query et Key sont multipliés pour mesurer la similitude, mis à l'échelle pour éviter les valeurs extrêmes, et passés par une fonction softmax pour produire des poids. Ces poids décident ensuite de la contribution de chaque Valeur à la représentation finale.

En pratique, ce calcul est rapide et efficace car il se produit en parallèle sur tous les mots de la séquence. Cette capacité à se concentrer et à traiter plusieurs relations à la fois est ce qui permet aux transformers de capturer des dépendances à longue portée et de s'adapter à des ensembles de données massifs.

Maintenant que nous avons vu le mécanisme de l'attention, passons à la façon dont cette idée se développe pour former l'architecture complète du transformer.

Un regard à l'intérieur du Transformer

Si l'attention est l'idée clé, le transformer est le plan qui la met en action. À haut niveau, l'architecture suit une configuration encodeur-décodeur : l'encodeur traite la séquence d'entrée et le décodeur génère la sortie. Tous deux sont constitués de couches répétées, chacune contenant quelques éléments essentiels :

  • Auto-attention multi-têtes (Multi-head self-attention) : Le modèle utilise plusieurs « têtes » pour examiner les relations entre les mots sous différents angles. Une tête peut capturer la syntaxe, une autre la sémantique, et ensemble elles donnent au modèle une compréhension plus riche et plus détaillée.

  • Réseaux Feedforward : Après que l'attention a mis en évidence les connexions utiles, ces petits réseaux de neurones transforment et affinent l'information. Ils introduisent de la non-linéarité et permettent au modèle de représenter des motifs plus complexes.

  • Connexions résiduelles : Les données sont autorisées à « sauter » par-dessus les couches, ce qui empêche la perte d'informations importantes. Cela aide également le réseau à s'entraîner plus rapidement et de manière plus fiable.

  • Normalisation de couche (Layer normalization) : L'entraînement de modèles très profonds peut rendre les données instables. La normalisation maintient les valeurs équilibrées pour que chaque couche contribue de manière stable, aidant le modèle à apprendre de façon cohérente.

  • Encodage positionnel (Positional encoding) : Puisque les transformers examinent tous les jetons en parallèle, ils ont besoin d'un indice sur l'ordre. Les signaux positionnels agissent comme une chronologie, indiquant au modèle quel mot vient en premier et lequel vient après.

La beauté de cette conception réside dans la façon dont toutes ces parties collaborent. L'attention trouve les relations, les couches feedforward les développent, les résidus et la normalisation stabilisent l'apprentissage, et l'encodage positionnel ancre le tout dans la séquence. Le résultat est un modèle à la fois très précis et efficace, c'est pourquoi les transformers servent désormais de base à presque tous les modèles de langage modernes.

Maintenant que nous avons expliqué la structure, l'étape suivante consiste à mettre ces pièces en pratique en détaillant comment un mini transformer est construit couche par couche.

Comment construire un mini Transformer étape par étape

Pour vraiment comprendre comment fonctionne un transformer, construisons une version petite mais fonctionnelle de son encodeur, en commençant par les blocs de base, en les empilant en couches, puis en entraînant le modèle sur une tâche simple pour le voir concrètement en action.

Comment représenter le texte avec les Embeddings et l'Encodage Positionnel

Avant qu'un modèle puisse travailler avec du texte, il a besoin d'une représentation numérique. Chaque mot ou jeton est d'abord mappé dans un vecteur dense appelé embedding. Les vecteurs denses permettent au modèle de capturer le sens dans un espace continu, où les mots similaires se retrouvent proches les uns des autres. Par exemple, « chien » et « chat » seront naturellement plus proches l'un de l'autre que « chien » et « voiture ».

Cependant, les embeddings seuls ne disent rien au modèle sur l'ordre. Les Transformers traitent tous les jetons en parallèle, donc sans information supplémentaire, ils traiteraient « le chat s'assit » de la même manière que « s'assit le chat ». Pour corriger cela, on ajoute des encodages positionnels, qui injectent des informations de séquence directement dans les embeddings. Cela donne à chaque jeton à la fois son sens et sa place dans la phrase.

import torch
import torch.nn as nn
import math

class Embeddings(nn.Module):
    def __init__(self, vocab_size, d_model):
        super().__init__()
        self.emb = nn.Embedding(vocab_size, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.emb(x) * math.sqrt(self.d_model)

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)
        div_term = torch.exp(torch.arange(0, d_model, 2) * -(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)]

De ce code, nous pouvons voir :

  • Embeddings transforme les jetons en vecteurs que le modèle peut traiter.

  • PositionalEncoding injecte l'ordre de la séquence pour que le modèle sache qui vient avant et qui vient après.

À l'intérieur d'une couche d'encodeur

Avec des jetons désormais représentés comme des vecteurs signifiants respectant l'ordre, l'étape suivante est de les traiter via l'encodeur. Chaque couche d'encodeur suit une recette claire :

  1. Appliquer l'attention multi-têtes pour trouver les relations entre les jetons.

  2. Ajouter des connexions résiduelles et une normalisation de couche pour maintenir la stabilité de l'entraînement.

  3. Passer les résultats par un réseau feedforward pour affiner la représentation.

  4. Normaliser à nouveau pour la cohérence.

Cette conception permet au modèle de capturer les connexions en parallèle tout en maintenant la stabilité à mesure que les couches s'empilent.

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        assert d_model % num_heads == 0
        self.d_k = d_model // num_heads
        self.num_heads = num_heads
        self.qkv_linear = nn.Linear(d_model, d_model * 3)
        self.out_linear = nn.Linear(d_model, d_model)

    def forward(self, x):
        batch_size, seq_len, _ = x.size()
        qkv = self.qkv_linear(x).view(batch_size, seq_len, self.num_heads, 3 * self.d_k)
        q, k, v = qkv.chunk(3, dim=-1)
        scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k)
        attn = torch.softmax(scores, dim=-1)
        context = torch.matmul(attn, v).transpose(1, 2).reshape(batch_size, seq_len, -1)
        return self.out_linear(context)

class FeedForward(nn.Module):
    def __init__(self, d_model, hidden_dim):
        super().__init__()
        self.ff = nn.Sequential(
            nn.Linear(d_model, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, d_model)
        )

    def forward(self, x):
        return self.ff(x)

class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, hidden_dim, dropout=0.1):
        super().__init__()
        self.attn = MultiHeadAttention(d_model, num_heads)
        self.ff = FeedForward(d_model, hidden_dim)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        x = self.norm1(x + self.dropout(self.attn(x)))
        x = self.norm2(x + self.dropout(self.ff(x)))
        return x

Ici,

  • L'attention multi-têtes trouve les relations utiles entre les jetons en parallèle.

  • Les couches feedforward affinent l'information.

  • Les connexions résiduelles (x + ...) stabilisent l'apprentissage et empêchent la perte d'informations.

  • La normalisation de couche assure une mise à l'échelle cohérente à travers le réseau.

Empiler les couches de l'encodeur

Une couche d'encodeur est puissante, mais en empiler plusieurs crée des représentations plus riches. Avec chaque couche supplémentaire, le modèle peut construire des caractéristiques plus abstraites, en partant des relations entre les mots locaux pour progresser vers des concepts de plus haut niveau, tels que la structure des phrases ou les rôles sémantiques. Après l'empilement, une normalisation finale lisse les sorties, les préparant pour les tâches en aval.

class MiniTransformer(nn.Module):
    def __init__(self, vocab_size, d_model=128, num_heads=4, 
                 ff_hidden=256, num_layers=2, max_len=5000):
        super().__init__()
        self.embedding = Embeddings(vocab_size, d_model)
        self.positional = PositionalEncoding(d_model, max_len)
        self.layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, ff_hidden) 
            for _ in range(num_layers)
        ])
        self.norm = nn.LayerNorm(d_model)

    def forward(self, x):
        x = self.embedding(x)
        x = self.positional(x)
        for layer in self.layers:
            x = layer(x)
        return self.norm(x)

Dans cette partie :

  • L'embedding + l'encodage positionnel préparent l'entrée.

  • Plusieurs couches d'encodeur sont appliquées en séquence.

  • Une normalisation finale produit la représentation affinée.

Extension pour la prédiction

Jusqu'à présent, notre encodeur construit des représentations solides des séquences d'entrée, mais il ne fait pas de prédictions. Pour le mettre au travail, nous ajoutons une simple tête de prédiction. Dans ce cas, le modèle examinera une séquence de nombres et prédira le suivant.

Nous réutilisons l'encodeur pour traiter la séquence, puis extrayons la représentation du dernier jeton. Ce vecteur capture le contexte de tout ce qui a été vu auparavant. Une couche linéaire finale le convertit en logits de vocabulaire, produisant la supposition du modèle pour le prochain élément de la séquence.

class MiniTransformerPredictor(MiniTransformer):
    def __init__(self, vocab_size, d_model=128, num_heads=4, 
                 ff_hidden=256, num_layers=2):
        super().__init__(vocab_size, d_model, num_heads, ff_hidden, num_layers)
        self.fc_out = nn.Linear(d_model, vocab_size)

    def forward(self, x):
        x = super().forward(x)        # [batch, seq_len, d_model]
        x = x[:, -1, :]               # garde la représentation du dernier jeton
        return self.fc_out(x)         # prédit le prochain jeton

Ce qui se passe ici :

  • L'encodeur de base reste inchangé.

  • Nous ne prenons que la représentation du dernier jeton, car elle porte le contexte.

  • Une couche linéaire finale produit les logits du vocabulaire pour la classification.

Allons maintenant un peu plus loin.

Entraînement sur un jeu de données factice

Pour donner vie à notre mini Transformer, donnons-lui une tâche très simple : apprendre à compter. Au lieu de l'entraîner sur des jeux de données massifs, nous lui donnerons de courtes séquences de nombres [1,2,3,4,5] et lui demanderons de prédire le nombre suivant (6). C'est un bon moyen de voir comment le modèle apprend des motifs séquentiels.

import torch.optim as optim
# ---- Données factices : séquences de comptage ----
vocab_size = 20
model = MiniTransformerPredictor(vocab_size)

optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()

# exemples d'entraînement : [1,2,3,4,5] -> 6 , [2,3,4,5,6] -> 7 , etc.
train_data = [
    (torch.tensor([i, i+1, i+2, i+3, i+4]), torch.tensor(i+5))
    for i in range(1, 11)
]

# ---- Boucle d'entraînement ----
for epoch in range(200):
    total_loss = 0
    for seq, target in train_data:
        seq = seq.unsqueeze(0)  # taille de lot 1
        optimizer.zero_grad()
        output = model(seq)
        loss = criterion(output, target.unsqueeze(0))
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    if epoch % 50 == 0:
        print(f"Époque {epoch}, Perte : {total_loss:.4f}")

# ---- Test de prédiction ----
test_seq = torch.tensor([[1, 2, 3, 4, 5]])
pred = model(test_seq).argmax(dim=1).item()
print("Prédiction pour [1,2,3,4,5] :", pred)

Après un peu d'entraînement, le modèle devrait prédire correctement 6 comme nombre suivant. À partir de cette petite expérience, nous voyons comment les pièces s'assemblent :

  • Les embeddings et les encodages positionnels transforment les nombres en vecteurs apprenables.

  • Les couches d'attention détectent les relations séquentielles.

  • Les couches d'encodeur empilées affinent l'information étape par étape.

  • Enfin, le modèle convertit tout en une prédiction.

La tâche est un peu triviale par rapport au NLP réel, mais elle montre magnifiquement comment les transformers peuvent apprendre des motifs structurés, ce qui est le même principe qu'ils appliquent pour manipuler du texte, traduire ou résumer.

À présent, vous avez vu comment un transformer peut être construit et même entraîné sur une petite tâche factice. Mais en pratique, personne ne part de zéro. L'entraînement de transformers à pleine échelle nécessite des quantités énormes de données et de puissance de calcul, c'est pourquoi la plupart des développeurs s'appuient sur des modèles pré-entraînés.

Explorons maintenant comment Hugging Face facilite l'utilisation de cette puissance pour appliquer des transformers à des tâches de langage réelles avec seulement quelques lignes de code.

De zéro au pré-entraîné : comment utiliser Hugging Face

Lorsqu'il s'agit d'applications réelles, nous ne construisons ni n'entraînons généralement pas de modèles de toutes pièces. Les transformers à grande échelle sont entraînés sur des jeux de données massifs à l'aide de ressources informatiques énormes. Au lieu de cela, nous profitons de modèles pré-entraînés et les adaptons à nos besoins.

C'est là qu'interviennent les Transformers de Hugging Face. Ils fournissent des milliers de modèles pré-entraînés et des outils comme des tokenizers qui préparent le texte sous la forme que les transformers comprennent. En quelques lignes de code, vous pouvez charger un modèle puissant et l'appliquer immédiatement à des tâches.

Voici quelques exemples rapides d'utilisation des Transformers de Hugging Face :

Embeddings avec BERT : Produit des représentations numériques de phrases utiles pour le clustering, la recherche sémantique ou pour alimenter d'autres modèles.

from transformers import AutoTokenizer, AutoModel
import torch

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")

inputs = tokenizer("Transformers are amazing!", return_tensors="pt")
outputs = model(**inputs)
embeddings = outputs.last_hidden_state.mean(dim=1)  # embedding de la phrase
print(embeddings.shape)

Analyse de sentiment : Classifie le texte comme positif, négatif ou neutre — précieux pour analyser les retours clients, les avis ou les réseaux sociaux.

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
print(classifier("I love learning about transformers!"))

Résumé automatique : Condense de longs passages en résumés plus courts, utile pour examiner des articles, des rapports ou de la documentation.

from transformers import pipeline

summarizer = pipeline("summarization", model="facebook/bart-large-cnn")

article = """Transformers have transformed natural language processing. 
They allow models to understand context across entire documents, 
process words in parallel, and scale to very large datasets. 
Because of this, they now power applications such as translation, 
automatic summarization, and conversational assistants used every day."""

summary = summarizer(article, max_length=40, min_length=20, do_sample=False)
print(summary[0]['summary_text'])

Traduction : Convertit le texte entre les langues, facilitant la communication mondiale et les applications multilingues.

translator = pipeline("translation_en_to_fr")
print(translator("Transformers are changing the world of AI"))

Hugging Face rend les transformers pré-entraînés accessibles via des interfaces simples. Cela nous permet d'expérimenter rapidement des tâches telles que l'analyse de sentiment, le résumé et la traduction, tout en restant concentrés sur la compréhension du fonctionnement de ces modèles.

Maintenant que nous avons vu comment les transformers sont utilisés dans Hugging Face, voyons ce qui les attend à l'avenir.

Quelle est la suite pour les Transformers ?

Les Transformers entrent dans une nouvelle phase définie par la vitesse, l'efficacité et la polyvalence. Les benchmarks de la dernière génération de modèles montrent comment ces systèmes deviennent plus rapides, plus rentables et plus performants à travers diverses tâches.

Benchmarks de performance actuels : vitesse, efficacité et précision

  • Vitesse d'inférence (jetons par seconde) : Des modèles comme Llama 4 Scout (2 600 jetons/sec) et Llama 3.3 70B (2 500 jetons/sec) démontrent la rapidité avec laquelle le texte peut désormais être produit. Dans les systèmes conversationnels, le temps jusqu'au premier jeton (TTFT) est essentiel pour des interactions fluides, Nova Micro et Llama 3.1 8B fournissant des réponses en moins de 0,3 seconde.

  • Efficacité et coût (par million de jetons) : Gemma 3 27B atteint des coûts d'entrée de 0,10 $ par million de jetons et des coûts de sortie de 0,30 $ par million de jetons, rendant les systèmes d'IA avancés beaucoup plus abordables à déployer à grande échelle.

  • Précision et capacité : Sur le benchmark AIME pour les mathématiques de compétition, GPT-5 a obtenu 94,6 %, légèrement devant Grok 4 à 93 %. Pour le benchmark GPQA, qui évalue le raisonnement scientifique avancé en biologie, physique et chimie, GPT-5 mène également avec 88,4 % contre 88 % pour Grok 4. Sur SWE-Bench, qui mesure la capacité à résoudre des problèmes de code GitHub réels, GPT-5 a atteint 74,9 %, démontrant une forte performance dans les tâches de codage appliqué.

L'avenir des architectures Transformer

  • Mélange d'experts (Mixture of Experts - MoE) : Les modèles MoE répartissent leurs paramètres sur plusieurs sous-réseaux experts, n'en activant qu'une fraction pour chaque entrée. Cette conception combine échelle et efficacité. Mixtral 8x7B, par exemple, possède environ 47 milliards de paramètres au total, avec 13 milliards actifs pendant l'inférence, et supporte une longueur de contexte de 32 768 jetons. DeepSeek V2.5 pousse cette approche plus loin avec 238 milliards de paramètres au total et 16 milliards actifs par jeton, offrant une longueur de contexte allant jusqu'à 128 000 jetons. Jamba 1.5 Large repousse encore les limites avec 398 milliards de paramètres et 94 milliards actifs, ainsi qu'une longueur de contexte de 256 000 jetons, lui permettant de gérer facilement des livres entiers ou des bases de code complètes.

  • Mémoire et contexte long : Les innovations dans l'attention permettent aux transformers de gérer des entrées beaucoup plus longues, ouvrant la voie à des applications telles que l'analyse de documents juridiques, le résumé de livres et le débogage de vastes bases de code.

  • Co-conception matériel et logiciel : Des frameworks comme BetterTransformer de PyTorch et TensorRT de Nvidia offrent des accélérations de 2x à 11x, tandis que les GPU comme le H100 de Nvidia disposent de « moteurs Transformer » dédiés pour accélérer les opérations de base.

Ensemble, ces avancées pointent vers un avenir où les transformers sont plus rapides, plus efficaces et capables de supporter des applications plus riches — de la traduction instantanée aux assistants contextuels — à des échelles autrefois inaccessibles.

Synthèse

Les Transformers sont devenus un élément central de la construction des systèmes de langage. Au fil du temps, les idées d'attention, d'efficacité et d'entraînement à grande échelle ont façonné des modèles capables de comprendre le texte, de résoudre des problèmes et de soutenir des applications pratiques dans de nombreux domaines.

Voici quelques idées clés à retenir :

  • L'attention aide les modèles à se concentrer sur les informations les plus pertinentes.

  • Les Transformers combinent des blocs de construction simples tels que l'attention, les réseaux feedforward, la normalisation et l'encodage positionnel.

  • Les modèles pré-entraînés et les bibliothèques largement utilisées permettent d'appliquer ces méthodes avec une configuration minimale.

  • Les benchmarks récents soulignent les progrès en termes de vitesse, de coût et de précision, montrant comment ces modèles deviennent plus adaptables à l'usage réel.

Si vous souhaitez explorer davantage les transformers, essayez d'expérimenter avec de petits modèles, de reproduire des benchmarks ou de les appliquer à un projet qui vous tient à cœur. La meilleure façon de comprendre leur impact n'est pas seulement de lire à leur sujet, mais de les mettre en action.