Ce qui nous mènera ensuite aux transformers.
Les CNN sont très efficaces pour les données spatiales (images). Mais ils ont une limite fondamentale :
ils n'ont pas de mémoire.
Un CNN traite chaque entrée de manière indépendante. Il ne sait pas ce qui s'est passé avant.
Or beaucoup de données du monde réel sont séquentielles, l'ordre compte :
Le problème : comment donner de la mémoire à un réseau de neurones ?
La solution : les Recurrent Neural Networks (RNN)
sequences de réseaux feed forward ou la sortie d'un FF est réinjectée dans le réseaux suivant
Recurrent Neural Networks : enchaîner les couches pour utiliser la sortie de la couche N-1 comme entrée de la couche N avec en plus un nouvel échantillon.
>
À chaque pas de temps t, la cellule RNN fait un calcul simple :
h(t) = tanh( W · h(t-1) + U · x(t) + b )
Où :
Exemple concret : imaginons un RNN qui lit une phrase mot par mot.
| Temps | Entrée x(t) | Le réseau combine... | État caché h(t) |
|---|---|---|---|
| t=1 | "le" | "le" + état initial (zéros) | mémoire de "le" |
| t=2 | "chat" | "chat" + mémoire de "le" | mémoire de "le chat" |
| t=3 | "mange" | "mange" + mémoire de "le chat" | mémoire de "le chat mange" |
À chaque étape, le réseau accumule du contexte. C'est sa mémoire.
En fait on a un seul réseau récurrent avec des poids partagés à chaque pas de temps.
Les CNN extraient des features spatiales, les RNN modélisent la séquence temporelle.
note: le RNN a été entraîné sur des correspondances (image, description) (ex: dataset COCO avec 300k+ images annotées)
Un filtre CNN ne voit qu'une petite zone de l'image (3x3, 5x5...). Même en empilant des couches, le champ réceptif reste limité.
En ajoutant un RNN après les couches convolutives, on balaye les feature maps (ligne par ligne, colonne par colonne) et chaque position accumule du contexte sur ce qui précède → un pixel peut "savoir" ce qui se passe à l'autre bout de l'image.
Exemple : en segmentation sémantique, pour savoir si un pixel est du "ciel" ou un "mur bleu", il faut du contexte global (y a-t-il un sol en bas ? des arbres ?). Le CNN seul voit trop local, le RNN propage ce contexte spatial.
Cette approche a été largement remplacée par les mécanismes d'attention (transformers de vision), qui capturent le contexte global sans balayage séquentiel.
Avantages :
Inconvénients :
Les RNN sont puissants pour capturer des relations séquentielles complexes dans les données, mais ils peuvent être difficiles à entraîner et souffrent de problèmes comme l'explosion ou la disparition du gradient.
Les variantes comme les LSTM et les GRU ont été développées pour atténuer ces problèmes et améliorer les performances sur des tâches séquentielles complexes.
Depuis 2024, pour tout ce qui est audio et NLP, les RNNs ont été remplacés par les Transformers.
Un article très populaire à l'époque sur l'efficacité des RNNs :
The Unreasonable Effectiveness of Recurrent Neural Networks https://karpathy.github.io/2015/05/21/rnn-effectiveness/
"The concept of attention is the most interesting recent architectural innovation in neural networks."
Une ou plusieurs variables évoluant dans le temps : prix, quotation, température, humidité.
Exemple : Air Passengers (1949-1960)
Ce dataset classique montre le nombre mensuel de passagers aériens internationaux. On y observe clairement :
C'est exactement le type de données que les RNN savent modéliser : une structure temporelle avec des patterns qui se répètent et évoluent.
Dataset : https://www.kaggle.com/datasets/rakannimer/air-passengers
Réf : https://sthalles.github.io/a-visual-guide-to-time-series-decomposition/
Réf : https://keras.io/api/layers/recurrent_layers/
Les couches RNN de Keras se regroupent en 3 catégories :
La brique fondamentale. Un seul état caché h(t), pas de mécanisme de mémoire long terme.
model.add(keras.layers.SimpleRNN(units=64, activation='tanh'))
Limité par le vanishing gradient → ne fonctionne pas bien sur les longues séquences.
Long Short-Term Memory — résout le vanishing gradient grâce à un cell state et 3 portes (forget, input, output).
model.add(keras.layers.LSTM(units=128, return_sequences=True, dropout=0.2))
recurrent_dropout)Gated Recurrent Unit — version simplifiée du LSTM. 2 portes au lieu de 3, pas de cell state séparé.
model.add(keras.layers.GRU(units=128, return_sequences=True))
Traite la séquence dans les deux sens (passé → futur et futur → passé), puis concatène les sorties.
model.add(keras.layers.Bidirectional(keras.layers.LSTM(64)))
Utile quand le contexte futur compte (NLP, speech). Inutile pour la prédiction de séries temporelles (on ne connaît pas le futur).
Applique une même couche (ex: Dense) indépendamment à chaque pas de temps.
model.add(keras.layers.TimeDistributed(keras.layers.Dense(10)))
Utile quand on veut une sortie à chaque pas de temps (sequence-to-sequence) : traduction, tagging, segmentation temporelle.
Combine convolution + LSTM dans une seule couche. L'entrée est une séquence de grilles spatiales (vidéo, météo, etc.).
model.add(keras.layers.ConvLSTM2D(filters=32, kernel_size=(3, 3)))
On l'a vu : le RNN simple souffre du vanishing gradient sur les longues séquences.
Concrètement, dans la phrase :
"J'ai grandi en France, j'ai voyagé dans de nombreux pays, j'ai appris plusieurs langues et je parle couramment le ..."
Le RNN doit se souvenir de "France" (très loin en arrière) pour prédire "français". Mais les gradients se dégradent à chaque pas de temps et l'information de "France" a disparu quand on arrive à la fin.
La solution : il faut un mécanisme qui permette à l'information de circuler sur de longues distances sans se dégrader.
C'est exactement ce que font les LSTM.
Long Short-Term Memory : le nom semble contradictoire, mais il résume bien l'idée :
L'idée clé :
Le cell state (Ct) est le cœur de l'architecture LSTM. C'est ce qui différencie fondamentalement un LSTM d'un RNN simple.
On peut le voir comme une autoroute qui traverse toute la séquence. L'information circule dessus de manière linéaire (additions et multiplications), sans passer par des fonctions d'activation qui écraseraient le gradient.
Pourquoi ça résout le vanishing gradient :
Les portes (gates) sont les bretelles d'accès à cette autoroute. Elles décident quelle information monte sur l'autoroute, laquelle en sort, et laquelle est évacuée.
Prenons une analogie : le LSTM est un étudiant qui prend des notes pendant un cours.
Entrée : x(t) et h(t-1) → fonction sigmoid → valeurs entre 0 et 1
Exemple : le sujet du cours change → on "oublie" les informations du chapitre précédent qui ne sont plus pertinentes.
Deux opérations en parallèle :
Le produit des deux donne ce qui sera effectivement ajouté au cell state.
Exemple : le prof dit quelque chose d'important → on décide de le noter.
Entrée : x(t) et h(t-1) → sigmoid → multipliée par tanh(cell state)
On ne révèle pas tout ce qu'on sait, seulement ce qui est pertinent pour la question posée.
Exemple : on nous demande la date d'un événement → on extrait cette info de nos notes sans tout réciter.
Le cell state est mis à jour en deux temps :
Étape 1 — Oublier : on multiplie l'ancien cell state par la sortie de la Forget Gate.
C(t) = f(t) × C(t-1)
Ce qui doit être oublié est mis à zéro.
Étape 2 — Ajouter : on ajoute les nouvelles informations filtrées par l'Input Gate.
C(t) = f(t) × C(t-1) + i(t) × C̃(t)
Où C̃(t) est la mémoire candidate (sortie du tanh).
Le hidden state (sortie de la cellule) est ensuite calculé :
h(t) = o(t) × tanh(C(t))
C'est ce hidden state qui est transmis à la cellule suivante et utilisé pour la prédiction.
| Composant | Rôle | Fonction d'activation |
|---|---|---|
| Forget Gate (f) | Décide quoi oublier du cell state | sigmoid (0 à 1) |
| Input Gate (i) | Décide quoi ajouter au cell state | sigmoid (filtre) + tanh (candidates) |
| Output Gate (o) | Décide quoi exposer en sortie | sigmoid |
| Cell state (C) | Mémoire à long terme (l'autoroute) | mis à jour linéairement |
| Hidden state (h) | Sortie de la cellule / mémoire court terme | tanh |
Gated Recurrent Units (GRU) : une version simplifiée du LSTM. L'idée est la même (des portes pour contrôler le flux d'information), mais avec une architecture plus légère.
Simplification principale : la GRU fusionne le cell state et le hidden state en un seul vecteur, et combine les portes Forget et Input en une seule Update Gate.
Deux portes seulement :
| Critère | LSTM | GRU |
|---|---|---|
| Complexité du problème | Meilleur pour les séquences longues et les dépendances à long terme | Plus efficace pour les problèmes plus simples et les dépendances plus courtes |
| Ressources informatiques | Nécessite plus de ressources et de mémoire | Moins de paramètres, plus efficace computationnellement |
| Quantité de données | Performant avec de grandes quantités de données | Bon résultat avec des ensembles de données plus petits |
| Vitesse d'entraînement | Entraînement plus long | Plus rapide à entraîner |
En pratique : commencer par GRU (plus rapide à itérer), puis passer à LSTM si les performances ne sont pas suffisantes.
Construction de RNNs de prédiction de séries temporelles sur le dataset SunSpot
https://github.com/SkatAI/deeplearning/blob/master/notebooks/RNN_hands_on_claude_sunspots.ipynb
Appliquer les modèles RNN/LSTM/GRU sur d'autres datasets :