LSTM (Long Short-Term Memory)
Un LSTM (Long Short-Term Memory) est une architecture de réseau de neurones récurrent conçue pour capturer les dépendances à long terme dans les données séquentielles. Il résout le problème du vanishing gradient grâce à un état cellulaire (cell state) et trois portes apprenables (forget, input, output) qui contrôlent le flux d’information à travers le temps.
- Type
- RNN à portes (gated recurrent network)
- Inventeurs
- Sepp Hochreiter et Jürgen Schmidhuber (1997)
- Complété par
- Forget gate (Gers, Schmidhuber, Cummins, 1999), Peephole (2000)
- Composants
- Cell state, forget gate, input gate, output gate
- Évolution récente
- xLSTM (Hochreiter et al., 2024, NeurIPS spotlight)
- Alternative simplifiée
- GRU (Cho et al., 2014)
- Successeur dominant
- Transformer (pour le NLP à grande échelle)
- Frameworks
- PyTorch (
nn.LSTM), TensorFlow/Keras, JAX
Le problème que le LSTM résout
Un RNN vanilla traite les séquences en transmettant un état caché d’une étape à la suivante. En théorie, cet état peut conserver l’information indéfiniment. En pratique, lors de la rétropropagation à travers le temps (BPTT), le gradient est multiplié à chaque pas temporel par la matrice de poids et la dérivée de l’activation. Après 20 à 30 pas, ce gradient s’évanouit (vanishing gradient) ou explose.
Conséquence directe : un RNN vanilla ne peut pas apprendre que le sujet d’une phrase (position 3) détermine l’accord du verbe (position 25). Les informations distantes sont mécaniquement oubliées.
Hochreiter et Schmidhuber ont identifié ce problème en 1991 (thèse de Hochreiter) et proposé la solution en 1997 : le Constant Error Carousel (CEC), rebaptisé « état cellulaire » (cell state). C’est un chemin additif où l’information peut traverser toute la séquence sans être multipliée à répétition, préservant le gradient.
Architecture détaillée d’une cellule LSTM
Une cellule LSTM maintient deux vecteurs qui circulent à travers le temps :
L’état cellulaire Cₜ (cell state) : la « mémoire long terme ». C’est un tapis roulant d’information qui traverse la séquence avec seulement des opérations additives et multiplicatives élément par élément. C’est là que réside la capacité de mémoire à long terme du LSTM.
L’état caché hₜ (hidden state) : la « mémoire court terme » et la sortie de la cellule. C’est le vecteur transmis à la couche suivante et/ou utilisé pour la prédiction.
Trois portes (gates) contrôlent le flux d’information entre ces deux vecteurs. Chaque porte est un mini-réseau de neurones (couche linéaire + sigmoïde) qui produit des valeurs entre 0 (bloquer) et 1 (laisser passer).
1. Forget gate (porte d’oubli)
Décide quelle information de l’état cellulaire passé doit être conservée ou oubliée.
fₜ = σ(Wf · [hₜ₋₁, xₜ] + bf)
La porte prend en entrée l’état caché précédent hₜ₋₁ et l’entrée courante xₜ, les passe à travers une sigmoïde, et produit un vecteur de valeurs entre 0 et 1. Ce vecteur est multiplié élément par élément avec l’état cellulaire précédent : une valeur de 0 efface complètement une information, une valeur de 1 la conserve intégralement.
2. Input gate (porte d’entrée)
Décide quelle nouvelle information doit être stockée dans l’état cellulaire.
iₜ = σ(Wi · [hₜ₋₁, xₜ] + bi)
C̃ₜ = tanh(Wc · [hₜ₋₁, xₜ] + bc)
Deux étapes : d’abord, la sigmoïde décide quelles valeurs mettre à jour (iₜ). Ensuite, une couche tanh crée un vecteur de nouvelles valeurs candidates (C̃ₜ). Le produit des deux est ajouté à l’état cellulaire.
Mise à jour de l’état cellulaire
Cₜ = fₜ ⊙ Cₜ₋₁ + iₜ ⊙ C̃ₜ
C’est l’équation centrale du LSTM. L’ancien état cellulaire est multiplié par la forget gate (oubli sélectif), puis on y ajoute les nouvelles informations filtrées par l’input gate. Le symbole ⊙ désigne la multiplication élément par élément (Hadamard product).
Le point crucial : cette mise à jour est additive. Le gradient peut circuler le long du chemin Cₜ₋₁ → Cₜ sans être multiplié par une matrice de poids, ce qui atténue considérablement le vanishing gradient.
3. Output gate (porte de sortie)
Décide quelle partie de l’état cellulaire est exposée comme état caché (sortie).
oₜ = σ(Wo · [hₜ₋₁, xₜ] + bo)
hₜ = oₜ ⊙ tanh(Cₜ)
L’état cellulaire est passé à travers tanh (borné entre -1 et 1), puis multiplié par la sortie de la porte output. Seule l’information pertinente pour la prédiction courante est exposée.
Variantes du LSTM
Peephole LSTM
Ajouté par Gers et Schmidhuber en 2000. Les connexions peephole permettent aux portes d’accéder directement à l’état cellulaire Cₜ₋₁ (et pas seulement à l’état caché hₜ₋₁). Cela aide le réseau à apprendre des timings précis. Peu utilisé en pratique car les gains sont marginaux dans la plupart des cas.
BiLSTM (Bidirectionnel)
Deux LSTM 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. Indispensable pour les tâches où le contexte complet est disponible (NER, POS tagging, classification de texte).
Stacked LSTM
Empiler 2 à 4 couches de LSTM permet de capturer des abstractions hiérarchiques. La séquence de sortie d’une couche sert d’entrée à la couche suivante. C’est la configuration standard pour les tâches complexes. Au-delà de 4 couches, les bénéfices diminuent.
xLSTM : le LSTM nouvelle génération
Publié à NeurIPS 2024 (spotlight) par Sepp Hochreiter et son équipe, xLSTM (Extended LSTM) pose une question audacieuse : que se passe-t-il si on modernise le LSTM avec les techniques des LLM actuels ?
Deux innovations principales :
sLSTM : un LSTM avec un gating exponentiel (au lieu de sigmoïde) et un nouveau mécanisme de mélange mémoire. Permet le suivi d’état (state tracking) que le LSTM classique ne peut pas faire.
mLSTM : remplace la mémoire scalaire par une mémoire matricielle avec une règle de mise à jour basée sur la covariance. Le point clé : le mLSTM est entièrement parallélisable à l’entraînement (comme un Transformer).
Les résultats sont prometteurs : xLSTM rivalise avec les Transformers et les State Space Models (Mamba) sur les benchmarks de modélisation du langage. L’équipe a entraîné un modèle xLSTM de 7 milliards de paramètres sur 2.3 trillions de tokens, démontrant que l’architecture LSTM peut scaler à l’échelle des LLM modernes.
LSTM vs GRU
Le GRU (Gated Recurrent Unit) est une simplification du LSTM introduite par Cho et al. en 2014.
| Critère | LSTM | GRU |
|---|---|---|
| Portes | 3 (forget, input, output) | 2 (reset, update) |
| État cellulaire séparé | Oui (Cₜ distinct de hₜ) | Non (un seul état caché) |
| Paramètres | 4 × (h² + h·d + h) | 3 × (h² + h·d + h) |
| Avantage mémoire | Meilleure mémoire long terme | ~25% moins de paramètres |
| Vitesse d’entraînement | Plus lent | Plus rapide |
| Performance | Souvent légèrement supérieure sur les longues séquences | Comparable sur les séquences courtes à moyennes |
| Cas d’usage | Tâches nécessitant une mémoire fine (traduction, musique) | Déploiement embarqué, prototypage rapide |
En pratique, la différence de performance est souvent minime. L’étude de Greff et al. (2015), qui a comparé systématiquement les variantes de LSTM, conclut que toutes les variantes testées produisent des résultats comparables. Testez les deux et gardez le meilleur sur votre jeu de validation.
Implémentation avec PyTorch
LSTM pour la prévision de séries temporelles
import torch
import torch.nn as nn
class TimeSeriesLSTM(nn.Module):
def __init__(self, input_dim, hidden_dim, num_layers, output_dim, dropout=0.2):
super().__init__()
self.lstm = nn.LSTM(
input_size=input_dim,
hidden_size=hidden_dim,
num_layers=num_layers,
batch_first=True,
dropout=dropout if num_layers > 1 else 0
)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
# x shape: (batch, seq_len, input_dim)
lstm_out, (h_n, c_n) = self.lstm(x)
# h_n shape: (num_layers, batch, hidden_dim)
# Utiliser le dernier état caché de la dernière couche
last_hidden = h_n[-1] # (batch, hidden_dim)
output = self.fc(last_hidden)
return output
# Prédire le prochain pas d'une série temporelle à 5 features
model = TimeSeriesLSTM(
input_dim=5, # 5 features par pas de temps
hidden_dim=128, # taille de l'état caché
num_layers=2, # 2 couches empilées
output_dim=1 # prédire une valeur
)
# Exemple d'utilisation
x = torch.randn(32, 60, 5) # batch=32, séquence=60 pas, 5 features
prediction = model(x)
print(f"Sortie : {prediction.shape}") # (32, 1)
BiLSTM pour la classification de texte
class TextBiLSTM(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes,
num_layers=2, dropout=0.3):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)
self.lstm = nn.LSTM(
embed_dim, hidden_dim,
num_layers=num_layers,
bidirectional=True,
batch_first=True,
dropout=dropout if num_layers > 1 else 0
)
# Bidirectionnel : hidden_dim * 2
self.classifier = nn.Sequential(
nn.Dropout(dropout),
nn.Linear(hidden_dim * 2, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout),
nn.Linear(hidden_dim, num_classes)
)
def forward(self, text):
embedded = self.embedding(text)
output, (h_n, c_n) = self.lstm(embedded)
# Concaténer les deux directions du dernier layer
forward_last = h_n[-2] # dernière couche, direction forward
backward_last = h_n[-1] # dernière couche, direction backward
hidden = torch.cat((forward_last, backward_last), dim=1)
return self.classifier(hidden)
model = TextBiLSTM(
vocab_size=30000, embed_dim=300, hidden_dim=256, num_classes=4
)
print(f"Paramètres : {sum(p.numel() for p in model.parameters()):,}")
Bonnes pratiques
Appliquez le gradient clipping. C’est obligatoire pour les LSTM. torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) empêche le gradient explosif et stabilise l’entraînement.
Initialisez la forget gate avec un biais positif. Une valeur de 1.0 pour le biais de la forget gate (au lieu de 0) pousse le réseau à retenir l’information par défaut au début de l’entraînement. Ce trick simple, suggéré par Jozefowicz et al. (2015), améliore significativement la convergence.
Utilisez pack_padded_sequence. Si vos séquences ont des longueurs variables, le padding gaspille du calcul. pack_padded_sequence / pad_packed_sequence dans PyTorch permet au LSTM de ne traiter que les tokens réels.
Dimensionnez l’état caché prudemment. 128 à 512 unités pour la plupart des tâches. Au-delà de 512, les rendements sont décroissants et le risque d’overfitting augmente. Ajoutez du dropout entre les couches (0.2 à 0.5).
Normalisez vos entrées. Pour les séries temporelles, standardisez chaque feature (moyenne 0, écart-type 1). Pour le texte, utilisez des embeddings pré-entraînés ou apprenables. Un LSTM sur des données non normalisées convergera mal.
Limitez la longueur des séquences. Même si le LSTM gère mieux les longues séquences que le RNN vanilla, il reste moins efficace qu’un Transformer au-delà de 500 à 1000 pas. Pour les très longues séquences, considérez un Transformer, Mamba ou xLSTM.
Cas d’usage
Prévision de séries temporelles : cours boursiers, consommation énergétique, trafic, météo. Le LSTM reste une baseline solide et souvent suffisante pour les séquences de quelques dizaines à quelques centaines de pas.
NLP pré-Transformer : traduction automatique (seq2seq + attention), analyse de sentiment, résumé de texte. Historiquement dominant, aujourd’hui largement remplacé par les Transformers pour les tâches à grande échelle.
Reconnaissance vocale : les systèmes CTC-LSTM (BiLSTM + Connectionist Temporal Classification) ont été l’état de l’art pendant des années. Google les a utilisés pour Google Voice en 2015, réduisant les erreurs de transcription de 49%.
Détection d’anomalies : le LSTM apprend le comportement « normal » d’un système (logs, capteurs, transactions) et alerte quand les données s’en écartent. Naturellement adapté au traitement incrémental en temps réel.
Génération de musique : les LSTM note par note ou accord par accord ont produit certains des premiers résultats convaincants en musique générée par IA, capturant les structures harmoniques et rythmiques sur des horizons temporels moyens.
Robotique et contrôle : les LSTM traitent les séquences de capteurs (accéléromètre, gyroscope, lidar) pour le contrôle de robots et la navigation, où le traitement en temps réel token par token est un avantage.
Limites du LSTM
Entraînement séquentiel : le LSTM traite les tokens un par un. Impossible de paralléliser le calcul sur la dimension temporelle pendant l’entraînement. C’est sa faiblesse structurelle majeure face aux Transformers, qui calculent l’attention sur toute la séquence en parallèle. Sur un GPU moderne, cette différence se traduit par un entraînement 5x à 10x plus lent sur de longues séquences.
Mémoire limitée malgré tout : même avec les portes et l’état cellulaire, un LSTM classique peine sur les séquences de plus de 500 à 1000 pas. La forget gate, en pratique, finit par éroder l’information sur de très longues distances. C’est un progrès immense par rapport au RNN vanilla (10-20 pas), mais insuffisant pour des tâches comme la modélisation de documents entiers.
Pas de mécanisme d’attention natif : le LSTM compresse toute la séquence d’entrée dans un vecteur d’état caché fixe. Pour les tâches encodeur-décodeur (traduction), cette compression est un goulot d’étranglement. L’ajout d’un mécanisme d’attention résout partiellement ce problème, mais les Transformers intègrent l’attention de manière plus naturelle et plus efficace.
Hyperparamètres sensibles : le nombre de couches, la taille de l’état caché, le learning rate, le gradient clipping, le dropout nécessitent tous un tuning soigneux. Un LSTM mal configuré peut être nettement inférieur à un modèle plus simple comme un XGBoost sur des features manuelles.
Interprétabilité limitée : les états cachés et cellulaires sont des vecteurs opaques. Comprendre ce que le LSTM a « retenu » d’une séquence est difficile, même si des techniques de visualisation des activations des portes existent.
Questions fréquentes sur le LSTM
Quelle est la différence entre le cell state et le hidden state dans un LSTM ?
L’état cellulaire (cell state, Cₜ) est la mémoire long terme : il traverse la séquence via un chemin additif, modifié uniquement par les forget et input gates. L’état caché (hidden state, hₜ) est la mémoire court terme et la sortie de la cellule : c’est une version filtrée de l’état cellulaire (via l’output gate et tanh), utilisée pour les prédictions et transmise comme entrée à l’étape suivante. L’état cellulaire retient l’information sur de longues distances ; l’état caché expose l’information pertinente à l’instant présent.
Pourquoi le LSTM résout-il le vanishing gradient ?
La clé est le chemin additif de l’état cellulaire : Cₜ = fₜ ⊙ Cₜ₋₁ + iₜ ⊙ C̃ₜ. Le gradient le long de ce chemin est multiplié par la forget gate fₜ (un nombre entre 0 et 1) à chaque pas, mais pas par une matrice de poids ni par la dérivée de tanh. Quand la forget gate est proche de 1, le gradient passe quasiment intact. C’est le « Constant Error Carousel » : l’erreur peut circuler à travers la séquence sans s’évanouir, permettant au réseau d’apprendre des dépendances à long terme.
Qu’est-ce que xLSTM et en quoi diffère-t-il du LSTM classique ?
xLSTM (Extended LSTM), publié à NeurIPS 2024 par l’équipe de Sepp Hochreiter, modernise le LSTM avec deux innovations majeures. Le gating exponentiel remplace la sigmoïde par une exponentielle normalisée, améliorant la dynamique d’apprentissage. Le mLSTM introduit une mémoire matricielle (au lieu de scalaire) entièrement parallélisable à l’entraînement, comme un Transformer. Un modèle xLSTM de 7B paramètres a été entraîné sur 2.3T tokens et rivalise avec les Transformers et Mamba en modélisation du langage.
Quand utiliser un LSTM plutôt qu’un Transformer ?
Utilisez un LSTM quand vos séquences sont courtes à moyennes (< 500 pas), quand vous avez peu de données, quand la mémoire et le calcul sont contraints (edge, mobile, IoT), ou quand vous traitez des flux en temps réel (le LSTM est incrémental, le Transformer attend la séquence complète). Pour le NLP à grande échelle, la traduction, les chatbots ou la génération de texte, les Transformers sont le choix standard. Pour les séries temporelles, le LSTM reste une baseline pragmatique et efficace.
Combien de couches et d’unités cachées choisir pour un LSTM ?
Pour la plupart des tâches, 2 couches avec 128 à 256 unités cachées est un bon point de départ. Les tâches complexes (traduction, synthèse vocale) peuvent bénéficier de 3-4 couches et 512 unités. Au-delà, les gains sont marginaux et le risque d’overfitting augmente. Utilisez le dropout (0.2 à 0.5) entre les couches. Augmentez progressivement la capacité en surveillant l’écart entre les performances d’entraînement et de validation.