RNN (Recurrent Neural Network)
Un RNN (Recurrent Neural Network, ou réseau de neurones récurrent) est une architecture de deep learning conçue pour traiter des données séquentielles (texte, signaux temporels, audio). Sa particularité : une boucle de rétroaction qui permet au réseau de conserver une « mémoire » des entrées précédentes, chaque étape recevant à la fois l’entrée courante et l’état caché de l’étape précédente.
- Type
- Réseau de neurones récurrent (séquentiel)
- Origines
- Jordan (1986), Elman (1990). Fondements : Werbos (1974, BPTT)
- Variantes clés
- LSTM (1997), GRU (2014), BiRNN, Stacked RNN
- Données
- Texte, séries temporelles, audio, signaux, séquences
- Frameworks
- PyTorch, TensorFlow/Keras, JAX
- Problème principal
- Vanishing gradient (gradient qui s’évanouit)
- Successeur dominant
- Transformer (2017, pour le NLP)
Pourquoi les RNN existent
Les réseaux de neurones feedforward classiques (y compris les CNN) traitent chaque entrée indépendamment. Si vous leur présentez le mot « banque », ils ne savent pas si vous parlez d’un établissement financier ou du bord d’une rivière, car ils n’ont pas accès aux mots précédents.
Les données du monde réel sont souvent séquentielles : le sens d’un mot dépend de ceux qui le précèdent, le cours d’une action dépend de son historique, une note musicale dépend de la mélodie en cours. Traiter ces données nécessite un modèle capable de « se souvenir » du passé.
Le RNN résout ce problème par un mécanisme simple : à chaque étape temporelle t, le réseau reçoit l’entrée xₜ ET l’état caché hₜ₋₁ de l’étape précédente. Le nouvel état caché hₜ est calculé puis transmis à l’étape suivante. Cette boucle crée une chaîne de mémoire qui traverse toute la séquence.
Comment fonctionne un RNN
L’architecture de base
Un RNN vanilla (simple) applique la même opération à chaque position de la séquence :
hₜ = tanh(Wₕₕ · hₜ₋₁ + Wₓₕ · xₜ + b)
Où :
hₜ est l’état caché à l’étape t (la « mémoire » du réseau)
xₜ est l’entrée à l’étape t
Wₕₕ sont les poids récurrents (état caché vers état caché)
Wₓₕ sont les poids d’entrée (entrée vers état caché)
tanh est la fonction d’activation (borne les valeurs entre -1 et 1)
Le point crucial : les mêmes poids (Wₕₕ, Wₓₕ) sont partagés à travers toutes les étapes temporelles. C’est le partage de poids qui permet au RNN de généraliser sur des séquences de longueur variable, et c’est ce qui le rend compact.
La sortie à chaque étape peut être calculée à partir de l’état caché :
yₜ = Wₕᵧ · hₜ + bᵧ
Les modes de fonctionnement
Selon la tâche, un RNN peut fonctionner dans différentes configurations :
Many-to-one : une séquence en entrée, une seule sortie. Exemple : analyse de sentiment (un texte → positif/négatif).
Many-to-many (même longueur) : une séquence en entrée, une séquence de même longueur en sortie. Exemple : POS tagging (chaque mot → son tag grammatical).
Many-to-many (longueur différente) : architecture encodeur-décodeur. L’encodeur compresse la séquence d’entrée en un vecteur, le décodeur génère la séquence de sortie. Exemple : traduction automatique (phrase en français → phrase en anglais).
One-to-many : une seule entrée, une séquence en sortie. Exemple : génération de description à partir d’une image (image → texte).
Le problème du vanishing gradient
C’est la faiblesse fondamentale du RNN vanilla. Lors de la rétropropagation à travers le temps (Backpropagation Through Time, BPTT), le gradient doit traverser autant d’étapes qu’il y a de positions dans la séquence. À chaque étape, le gradient est multiplié par la matrice de poids Wₕₕ et par la dérivée de la fonction d’activation.
Si ces multiplicateurs sont systématiquement inférieurs à 1, le gradient s’évanouit exponentiellement (vanishing gradient) : après 20 à 30 étapes, il est tellement proche de zéro que le réseau ne peut plus apprendre les dépendances à long terme. Si les multiplicateurs sont supérieurs à 1, le gradient explose (exploding gradient), rendant l’entraînement instable.
Concrètement, un RNN vanilla est incapable d’apprendre qu’un sujet au début d’une phrase (mot 3) détermine l’accord du verbe en fin de phrase (mot 25). Les informations lointaines sont simplement « oubliées » par le gradient.
LSTM et GRU : les solutions au vanishing gradient
LSTM (Long Short-Term Memory)
Inventé par Hochreiter et Schmidhuber en 1997, le LSTM remplace la cellule simple du RNN par un mécanisme de portes (gates) qui contrôle le flux d’information :
Forget gate : décide quelle information de l’état cellulaire passé doit être oubliée.
Input gate : décide quelle nouvelle information doit être stockée dans l’état cellulaire.
Output gate : décide quelle partie de l’état cellulaire doit être exposée comme état caché.
La clé du LSTM est l’état cellulaire (cell state), un « tapis roulant » d’information qui traverse toute la séquence avec seulement des opérations additives. Le gradient peut circuler le long de ce tapis sans être multiplié à répétition, ce qui atténue considérablement le vanishing gradient.
Le LSTM est devenu le standard des RNN pendant près de 20 ans, avant l’arrivée des Transformers.
GRU (Gated Recurrent Unit)
Introduit par Cho et al. en 2014, le GRU est une simplification du LSTM. Il fusionne l’état cellulaire et l’état caché en un seul vecteur, et réduit trois portes à deux :
Reset gate : contrôle combien de l’état passé est pris en compte pour calculer le nouvel état candidat.
Update gate : contrôle combien de l’ancien état est conservé vs remplacé par le nouvel état candidat.
Le GRU a moins de paramètres que le LSTM (environ 25% de moins), s’entraîne plus vite, et produit souvent des résultats comparables. C’est un bon choix quand la mémoire ou la vitesse sont contraintes.
| Critère | RNN vanilla | LSTM | GRU |
|---|---|---|---|
| Portes | Aucune | 3 (forget, input, output) | 2 (reset, update) |
| État cellulaire séparé | Non | Oui | Non |
| Paramètres (pour dim h) | ~h² | ~4h² | ~3h² |
| Dépendances longues | Très limitées (~10-20 pas) | Bonnes (~100-500 pas) | Bonnes (~100-500 pas) |
| Vitesse d’entraînement | Rapide | Lent | Modéré |
| Usage | Rare (pédagogique) | Standard historique | Alternative plus légère |
Variantes architecturales
RNN bidirectionnel (BiRNN)
Un BiRNN (ou BiLSTM, BiGRU) utilise deux RNN en parallèle : l’un traite la séquence de gauche à droite, l’autre de droite à gauche. Les deux états cachés sont concaténés à chaque position, donnant au réseau accès au contexte passé ET futur.
C’est essentiel pour des tâches comme la reconnaissance d’entités nommées ou le POS tagging, où le sens d’un mot dépend de son contexte dans les deux directions. BERT a généralisé cette idée aux Transformers avec l’attention bidirectionnelle.
RNN empilé (Stacked RNN)
On peut empiler plusieurs couches de RNN : la séquence d’états cachés d’une couche sert d’entrée à la couche suivante. Un RNN empilé à 2-4 couches capture des patterns plus abstraits qu’une seule couche. Au-delà de 4 couches, les gains diminuent et l’entraînement devient difficile.
RNN + Attention
Le mécanisme d’attention (Bahdanau et al., 2014) a été inventé pour les RNN avant d’être généralisé dans les Transformers. Au lieu de compresser toute la séquence d’entrée dans un seul vecteur (le bottleneck de l’encodeur-décodeur), l’attention permet au décodeur de « regarder » directement toutes les positions de l’encodeur, en attribuant un poids à chacune.
L’ajout de l’attention aux LSTM a été la dernière grande avancée des RNN avant que les Transformers ne les remplacent pour le NLP.
Implémentation avec PyTorch
import torch
import torch.nn as nn
class SentimentRNN(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim,
n_layers=2, bidirectional=True, dropout=0.3):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
self.rnn = nn.LSTM(
embed_dim, hidden_dim,
num_layers=n_layers,
bidirectional=bidirectional,
dropout=dropout if n_layers > 1 else 0,
batch_first=True
)
direction_factor = 2 if bidirectional else 1
self.fc = nn.Linear(hidden_dim * direction_factor, output_dim)
self.dropout = nn.Dropout(dropout)
def forward(self, text):
# text shape: (batch, seq_len)
embedded = self.dropout(self.embedding(text))
# embedded: (batch, seq_len, embed_dim)
output, (hidden, cell) = self.rnn(embedded)
# output: (batch, seq_len, hidden_dim * directions)
# Concaténer le dernier hidden state des deux directions
if self.rnn.bidirectional:
hidden = torch.cat((hidden[-2], hidden[-1]), dim=1)
else:
hidden = hidden[-1]
# Classification
return self.fc(self.dropout(hidden))
# Instanciation
model = SentimentRNN(
vocab_size=25000, embed_dim=100, hidden_dim=256,
output_dim=1, n_layers=2, bidirectional=True
)
print(f"Paramètres : {sum(p.numel() for p in model.parameters()):,}")
batch_first=True dans PyTorch pour avoir les dimensions (batch, séquence, features) et non (séquence, batch, features). C’est plus intuitif et compatible avec le reste de l’écosystème. Ajoutez aussi pack_padded_sequence pour éviter que le RNN ne traite les tokens de padding.
RNN vs Transformer : où en est-on ?
Depuis le papier « Attention Is All You Need » (Vaswani et al., 2017), les Transformers ont progressivement remplacé les RNN dans la majorité des tâches de NLP. Les raisons sont multiples.
| Critère | RNN (LSTM/GRU) | Transformer |
|---|---|---|
| Parallélisation | Séquentielle (pas par pas) | Totalement parallèle |
| Dépendances longues | Limitées (malgré LSTM) | Illimitées (attention globale) |
| Scalabilité | Limitée | Excellente (scaling laws) |
| Complexité mémoire | O(1) par step | O(n²) (attention) |
| Latence inférence (streaming) | Faible (incrémental) | Plus élevée (attention sur toute la séquence) |
| Empreinte mémoire | Faible | Élevée |
| Performance NLP | Bonne | Supérieure |
| Performance séries temporelles | Compétitive | Variable |
Verdict : quand utiliser un RNN
Les Transformers dominent le NLP et la plupart des tâches séquentielles à grande échelle. Mais les RNN (LSTM/GRU) conservent des niches où ils restent pertinents :
Déploiement on-device et edge : les RNN consomment beaucoup moins de mémoire et de calcul qu’un Transformer. Pour un modèle embarqué sur smartphone ou IoT, un petit LSTM peut être le bon choix.
Streaming et temps réel : un RNN traite les données token par token, sans attendre la fin de la séquence. C’est naturel pour la reconnaissance vocale en direct, le monitoring IoT ou le traitement de flux financiers.
Séries temporelles courtes à moyennes : pour la prévision de séries temporelles avec des séquences de quelques dizaines à quelques centaines de pas, les LSTM restent compétitifs et bien plus simples à mettre en œuvre qu’un Transformer.
Contraintes de données : les Transformers ont besoin de beaucoup de données pour bien généraliser (pas de biais inductif séquentiel fort). Un LSTM peut fonctionner correctement avec des datasets modestes.
Pour le NLP à grande échelle (traduction, génération de texte, chatbots), les Transformers et les LLM sont le choix évident. Ne partez pas sur un RNN pour ces tâches.
Nouvelles architectures récurrentes
Le concept de récurrence n’est pas mort : de nouvelles architectures récurrentes tentent de combiner l’efficacité des RNN avec les performances des Transformers.
State Space Models (SSM) : Mamba (Gu & Dao, 2023) est un modèle séquentiel basé sur des équations d’espace d’état qui capture les dépendances longues comme un Transformer, mais avec une complexité linéaire en longueur de séquence (vs O(n²) pour l’attention). C’est une des architectures les plus prometteuses pour le post-Transformer.
RWKV : un modèle hybride qui combine attention et récurrence, entraînable comme un Transformer (parallèle) mais utilisable comme un RNN à l’inférence (séquentiel). Il offre le meilleur des deux mondes pour certains cas.
Liquid Neural Networks (LNN) : inspirés des systèmes biologiques, les LNN utilisent des équations différentielles continues pour modéliser la dynamique temporelle. Ils montrent un potentiel intéressant pour les données bruitées et non stationnaires, et une meilleure généralisation hors distribution.
Cas d’usage des RNN
Prévision de séries temporelles : prédiction de ventes, de consommation énergétique, de trafic réseau. Les LSTM et GRU restent des baselines solides, surtout quand les données sont limitées.
Reconnaissance vocale : les systèmes de speech-to-text historiques utilisaient des BiLSTM avec CTC (Connectionist Temporal Classification). Les architectures récentes migrent vers des Transformers, mais les LSTM restent présents dans les systèmes embarqués.
Génération de musique et de texte : les RNN caractère par caractère ont été parmi les premiers modèles génératifs de texte (le célèbre blog post de Karpathy « The Unreasonable Effectiveness of Recurrent Neural Networks », 2015).
Détection d’anomalies : les LSTM apprennent le comportement « normal » d’une séquence (logs serveur, signaux capteurs) et signalent les déviations. L’inférence incrémentale rend cette approche naturelle pour le monitoring en temps réel.
Modélisation cognitive et neurosciences : les RNN sont utilisés comme modèles du cerveau pour étudier la mémoire de travail, la prise de décision et l’apprentissage séquentiel. Des travaux récents (Nature, 2025) montrent que des RNN de seulement 1 à 4 neurones surpassent les modèles cognitifs classiques pour prédire les choix humains.
Bonnes pratiques
Utilisez LSTM ou GRU, jamais un RNN vanilla. Le RNN simple est un outil pédagogique, pas un outil de production. Le vanishing gradient le rend inutilisable pour toute séquence de plus de 10-20 pas.
Appliquez le gradient clipping. torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) est obligatoire pour stabiliser l’entraînement des RNN.
Normalisez vos données d’entrée. Pour les séries temporelles, standardisez (moyenne 0, écart-type 1). Pour le texte, utilisez des embeddings pré-entraînés (GloVe, Word2Vec) ou des embeddings apprenables.
Utilisez le bidirectionnel quand la séquence complète est disponible (classification, tagging). Ne l’utilisez pas pour la génération (le modèle ne doit pas voir le futur).
Empilez 2-3 couches maximum. Au-delà, les gains sont marginaux et l’entraînement se dégrade. Ajoutez du dropout entre les couches.
Évaluez si un Transformer serait plus adapté. Si votre dataset est volumineux, vos séquences longues (> 500 tokens) et que vous avez les ressources GPU, un Transformer sera presque toujours supérieur.
Questions fréquentes sur les RNN
Quelle est la différence entre un RNN et un LSTM ?
Le LSTM est un type de RNN. Le RNN vanilla utilise une cellule simple qui souffre du vanishing gradient et ne peut pas retenir l’information sur plus de 10-20 pas. Le LSTM ajoute un mécanisme de portes (forget, input, output) et un état cellulaire qui permettent de retenir l’information sur des centaines de pas. En pratique, quand on dit « RNN », on parle souvent d’un LSTM ou d’un GRU plutôt que du RNN vanilla original.
Les RNN sont-ils obsolètes face aux Transformers ?
Pour le NLP à grande échelle (chatbots, traduction, résumé), oui, les Transformers et les LLM ont remplacé les RNN. Mais les RNN restent pertinents pour le déploiement embarqué (smartphone, IoT), le traitement en temps réel (streaming), les séries temporelles courtes et les contextes où les données sont limitées. De plus, de nouvelles architectures récurrentes comme Mamba et RWKV tentent de combiner les avantages des deux approches.
Pourquoi le vanishing gradient est-il un problème pour les RNN ?
Lors de la rétropropagation à travers le temps, le gradient est multiplié à chaque étape par la matrice de poids et la dérivée de l’activation. Si ces multiplicateurs sont < 1, le gradient décroît exponentiellement : après 20-30 étapes, il est quasi nul. Le réseau ne peut donc pas apprendre les dépendances entre des éléments éloignés dans la séquence. Le LSTM résout partiellement ce problème grâce à un "autoroute" (l'état cellulaire) où le gradient peut circuler sans multiplication répétée.
Quand choisir un GRU plutôt qu’un LSTM ?
Choisissez un GRU quand la mémoire ou le temps de calcul sont contraints (déploiement mobile, edge), quand vos séquences sont modérément longues, ou comme premier modèle avant de tester un LSTM. Le GRU a ~25% de paramètres en moins et s’entraîne plus vite. En termes de performance, les différences sont généralement faibles : testez les deux et gardez le meilleur sur votre jeu de validation.
Comment choisir entre un RNN et un Transformer pour ma tâche ?
Posez-vous trois questions. (1) Avez-vous beaucoup de données ? Si oui, Transformer. (2) Vos séquences sont-elles longues (> 500 tokens) ? Si oui, Transformer. (3) Devez-vous déployer sur un appareil à ressources limitées ou en streaming temps réel ? Si oui, RNN (LSTM/GRU). Pour les séries temporelles courtes avec peu de données, un LSTM reste souvent le choix le plus pragmatique et le plus simple à mettre en œuvre.