Cursus
Combien de fois avez-vous vu une valeur de perte NaN pendant l'entraînement d'un réseau de neurones profond ?
Après des heures d'entraînement, la courbe de perte semble saine, puis elle s'envole soudainement vers l'infini. La cause la plus fréquente : l'explosion des gradients — des valeurs de gradient qui deviennent si grandes pendant la rétropropagation que les mises à jour des paramètres deviennent instables et que le modèle se désagrège. Le phénomène touche surtout les réseaux récurrents, mais on l'observe aussi dans les transformers et les réseaux feedforward profonds.
Le gradient clipping résout ce problème en limitant l'amplitude des gradients avant qu'ils n'atteignent l'optimiseur. C'est une ligne à ajouter à votre boucle d'entraînement pour borner les mises à jour, sans toucher à l'architecture du modèle.
Dans cet article, je vous présente l'intuition derrière le gradient clipping, ses deux principales méthodes, comment choisir un seuil, et comment l'implémenter avec PyTorch et TensorFlow.
Mais qu'est-ce que la perte en data science, au juste ? Lisez notre billet Loss Function in Machine Learning pour en savoir plus.
Qu'est-ce que le gradient clipping ?
Le gradient clipping est une technique qui limite l'amplitude des gradients pendant l'entraînement afin d'éviter des mises à jour de paramètres instables.
Quand un gradient devient trop grand, l'optimiseur fait un pas gigantesque dans l'espace des paramètres et projette les poids dans une région où la perte explose. Le clipping limite cette amplitude avant qu'elle ne fasse des dégâts.
Il est important de noter que le gradient clipping n'affecte pas l'architecture du modèle. Vous n'ajoutez pas de couches et ne changez pas les fonctions d'activation. Il modifie uniquement le processus d'entraînement en interceptant les gradients entre la rétropropagation et l'étape d'optimisation.
C'est donc simple à tester et facile à retirer. Comme vous le verrez, cela tient en une ligne de code.
Comment fonctionne le gradient clipping
Le mécanisme est simple. L'opération de clipping se place entre la propagation arrière et l'étape de l'optimiseur, et suit les quatre étapes suivantes à chaque itération.
- Calculer les gradients : exécuter la passe avant, calculer la perte, puis lancer la rétropropagation. Rien ne change ici : les gradients circulent comme d'habitude dans le réseau.
- Vérifier l'amplitude des gradients : mesurer leur taille. Selon la méthode, on regarde les valeurs individuelles ou la norme globale sur tous les paramètres.
- Réduire les gradients s'ils dépassent un seuil : si l'amplitude dépasse la limite fixée, on rééchantillonne à la baisse. Sinon, on les laisse tels quels.
- Mettre à jour les paramètres du modèle : transmettre les gradients rognés à l'optimiseur et appliquer la mise à jour des poids.
La plupart du temps, vos gradients restent en deçà du seuil et l'entraînement se déroule comme sans clipping. En cas de pic, le clipping l'intercepte avant la réaction de l'optimiseur.
Et c'est tout.
Méthodes courantes de gradient clipping
Il existe deux façons de rogner les gradients, qui diffèrent par ce que vous mesurez et par ce que vous mettez à l'échelle.
Clipping par valeur
Le clipping par valeur borne individuellement chaque élément du gradient.
Vous choisissez un intervalle, par exemple [-1.0, 1.0], et toute valeur en dehors est ramenée à la borne la plus proche. Un gradient de 2.5 devient 1.0. Un gradient de -2.5 devient -1.0. Les valeurs déjà comprises dans l'intervalle sont inchangées.

Exemple de clipping par valeur
Son atout : la simplicité. Aucuns calculs au-delà d'une opération min/max, et c'est très rapide.
Mais l'inconvénient est réel : rogner des valeurs individuelles modifie la direction du vecteur gradient. Si une composante est rognée et pas les autres, le vecteur mis à jour ne pointe plus exactement là où la rétropropagation l'indiquait. L'optimiseur avance alors dans une direction légèrement erronée.
C'est pourquoi le clipping par valeur est moins fréquent en pratique.
Clipping par norme
Le clipping par norme met à l'échelle l'ensemble du vecteur gradient quand son amplitude globale dépasse un seuil.
Au lieu de regarder des valeurs individuelles, on calcule la norme de tous les gradients combinés (généralement la norme L2) et on la compare à une valeur maximale. Si la norme est inférieure au seuil, rien ne se passe. Si elle le dépasse, chaque gradient est multiplié par le même facteur d'échelle afin de ramener la norme à la limite.

Exemple de clipping par norme
L'avantage : la direction est préservée. Comme chaque composante est réduite du même facteur, le vecteur gradient garde sa direction d'origine. Vous raccourcissez le pas, sans le dévier.
C'est pour cela que le clipping par norme est devenu la norme. Les fonctions clip_grad_norm_ de PyTorch et clipnorm de TensorFlow implémentent cette méthode, et la plupart des pipelines modernes l'utilisent par défaut.
Explosion vs disparition des gradients
L'explosion et la disparition des gradients sont deux problèmes fréquents en deep learning, mais un seul est résolu par le gradient clipping.
Explosion des gradients
L'explosion survient lorsque les valeurs de gradient deviennent trop grandes pendant la rétropropagation.
On l'observe souvent dans les réseaux profonds ou récurrents, où les gradients sont multipliés à travers de nombreuses couches ou étapes temporelles. Si ces multiplications composent dans le mauvais sens, la norme du gradient explose. L'optimiseur effectue alors une mise à jour massive, les poids atteignent des valeurs extrêmes, et la perte devient souvent NaN ou Inf.
Concrètement, vous verrez des pics soudains de perte ou un modèle qui diverge sans crier gare.
Disparition des gradients
La disparition est le problème inverse : les valeurs de gradient tendent vers zéro en remontant dans le réseau.
Des gradients trop petits entraînent des mises à jour minuscules. Les premières couches cessent d'apprendre, les couches profondes apprennent lentement, et l'entraînement s'enlise. La courbe de perte se stabilise et n'évolue plus, même après de nombreux epochs.
C'est la raison pour laquelle les RNN avaient du mal avec les longues séquences avant l'arrivée des LSTM et GRU.
Où intervient le gradient clipping
Le gradient clipping traite l'explosion des gradients, pas leur disparition.
Le clipping réduit les gradients trop grands, mais ne change rien s'ils sont trop faibles. Pour la disparition, misez sur une meilleure initialisation des poids, des connexions résiduelles, la normalisation par lots, ou des architectures conçues pour préserver le flux de gradient.
Clipping par norme : explications
Le clipping par norme est généralement ce que les lecteurs cherchent lorsqu'ils parlent de gradient clipping.
Le processus se déroule en trois temps : calculez d'abord la norme de l'ensemble des gradients. Comparez ensuite cette norme au seuil choisi. Enfin, reéchelonnez les gradients si la norme est trop grande.
La norme utilisée est généralement L2 : on met au carré chaque valeur de gradient, on somme, puis on prend la racine carrée. Si vous avez des gradients g_1, g_2, ..., g_n sur tous les paramètres du modèle, la norme L2 est :

Formule du clipping par norme
Une fois la norme obtenue, vous la comparez à votre seuil c. Si ||g|| <= c, les gradients passent inchangés. Si ||g|| > c, chaque gradient est multiplié par le facteur d'échelle c / ||g||. La nouvelle norme est alors exactement égale à c.
C'est crucial car chaque composante est réduite du même facteur. Les proportions relatives restent inchangées : le vecteur conserve sa direction. Vous raccourcissez le pas de l'optimiseur, sans changer sa destination.
Cette propriété qui préserve la direction fait du clipping par norme le choix par défaut. Le clipping par valeur peut tordre le vecteur gradient. Le clipping par norme n'en change que la longueur.
Les fonctions clip_grad_norm_ de PyTorch et clipnorm de TensorFlow font exactement cela. Quand quelqu'un dit « j'utilise le gradient clipping », il s'agit presque toujours d'un clipping par norme.
Choisir un seuil de gradient clipping
Le seuil est un hyperparamètre : il n'existe pas de valeur universelle valable pour tous les modèles.
S'il est trop élevé, le clipping ne s'activera presque jamais. Vos gradients restent sous la limite et le filet de sécurité ne capte rien. L'entraînement se déroule comme si le clipping n'était pas là, et vous verrez encore des pics de perte quand les gradients explosent.
S'il est trop faible, vous rognez trop agressivement. Chaque lot voit ses gradients réduits, ce qui rend les mises à jour plus petites que nécessaire. L'apprentissage ralentit et la convergence prend plus de temps, parfois beaucoup plus.
Un point de départ courant est 1.0, efficace pour de nombreuses architectures. Des valeurs entre 0.5 et 5.0 couvrent la plupart des cas pratiques.
Le mieux est de surveiller les normes de gradient pendant l'entraînement. Journalisez la norme non rognée à chaque étape et observez la distribution. Si la plupart des normes gravitent autour de 0.3 avec des pics occasionnels à 50, fixez le seuil au-dessus de la zone typique mais bien en dessous des pics — 2.0 ou 3.0 seraient raisonnables ici.
Traitez-le comme n'importe quel hyperparamètre : commencez à 1.0, observez, puis ajustez selon le comportement à l'entraînement.
Gradient clipping dans les réseaux de neurones récurrents
Les RNN sont le terrain où le gradient clipping s'est imposé en premier.
La raison tient à la propagation des gradients dans le temps. La rétropropagation dans le temps multiplie les mêmes matrices de poids sur de nombreuses étapes temporelles, et ces multiplications répétées peuvent produire des valeurs gigantesques. Les longues séquences aggravent le problème.
Les LSTM et GRU ont atténué le phénomène grâce aux mécanismes de portes, sans toutefois l'éliminer. Ces architectures bénéficient toujours du clipping, notamment sur de longues séquences ou avec des taux d'apprentissage élevés.
Pour entraîner des RNN, le clipping par norme avec un seuil entre 1.0 et 5.0 est la valeur par défaut la plus courante. Si vous utilisez nn.LSTM ou nn.GRU de PyTorch et que votre perte explose en cours d'entraînement, ajouter clip_grad_norm_ est généralement le premier réflexe.
Gradient clipping dans le deep learning moderne
Le gradient clipping n'a pas disparu avec l'arrivée des transformers.
Les grands modèles de langue comme GPT et BERT l'utilisent en pré-entraînement comme en fine-tuning. Idem pour les vision transformers, les modèles de diffusion et la plupart des architectures profondes à plusieurs centaines de couches. Les optimiseurs Adam et AdamW, très répandus, sont souvent associés à un clipping par norme avec des seuils proches de 1.0.
La raison reste la même que pour les RNN : les réseaux profonds multiplient les gradients au fil des couches, et de grands batchs combinés à des taux d'apprentissage élevés peuvent engendrer des pics occasionnels. Le clipping gère ces pics sans perturber les étapes normales.
La plupart des implémentations de référence intègrent le clipping par défaut. Le Trainer de Hugging Face, PyTorch Lightning et DeepSpeed l'exposent comme un paramètre standard. Si vous entraînez un modèle un tant soit peu ambitieux, le clipping fait presque sûrement partie du pipeline.
C'est une ligne de code, un coût quasi nul, et des heures d'entraînement épargnées de plantages. Voilà pourquoi la pratique perdure.
Gradient clipping avec PyTorch
PyTorch gère le gradient clipping avec une seule fonction utilitaire : torch.nn.utils.clip_grad_norm_.
L'appel au clipping se place entre loss.backward() et optimizer.step(). La rétropropagation calcule d'abord les gradients, le clipping les réduit si besoin, puis l'optimiseur applique la mise à jour. Placé ailleurs, cela ne fonctionnera pas.
Voici un script complet et exécutable qui entraîne un petit MLP sur des données de régression synthétiques avec le gradient clipping activé :
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
torch.manual_seed(42)
# Synthetic regression data
n_samples = 1000
n_features = 20
inputs = torch.randn(n_samples, n_features)
targets = (inputs.sum(dim=1, keepdim=True) * 2.0 + torch.randn(n_samples, 1) * 0.1)
dataset = TensorDataset(inputs, targets)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# Small feedforward network
model = nn.Sequential(
nn.Linear(n_features, 64),
nn.ReLU(),
nn.Linear(64, 64),
nn.ReLU(),
nn.Linear(64, 1),
)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.MSELoss()
# Training loop with gradient clipping
n_epochs = 5
max_grad_norm = 1.0
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch_inputs, batch_targets in dataloader:
optimizer.zero_grad()
predictions = model(batch_inputs)
loss = loss_fn(predictions, batch_targets)
loss.backward()
# Gradient clipping
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=max_grad_norm)
optimizer.step()
epoch_loss += loss.item()
print(f"Epoch {epoch + 1}: loss = {epoch_loss / len(dataloader):.4f}")

Sortie PyTorch
La fonction clip_grad_norm_ prend deux arguments principaux :
-
parameters: les paramètres du modèle dont vous souhaitez rogner les gradients. Passezmodel.parameters()pour couvrir tout le modèle. -
max_norm: le seuil de norme des gradients. Une valeur de1.0est un bon point de départ.
Un argument optionnel norm_type vaut 2.0 par défaut (norme L2). Vous aurez rarement besoin de le modifier.
Le soulignement final dans clip_grad_norm_ indique une opération in situ. La fonction modifie directement les gradients dans l'attribut .grad de chaque paramètre, sans que vous ayez à gérer la valeur de retour. Elle renvoie la norme totale des gradients avant clipping, pratique pour la journalisation.
Pour rogner par valeur plutôt que par norme, PyTorch propose torch.nn.utils.clip_grad_value_ :
torch.nn.utils.clip_grad_value_(model.parameters(), clip_value=0.5)
Mais comme expliqué plus haut, vous l'utiliserez rarement (voire jamais).
Et voilà : deux lignes ajoutées à votre boucle d'entraînement.
Gradient clipping avec TensorFlow
TensorFlow gère le clipping au niveau de l'optimiseur plutôt que via un appel de fonction séparé.
Lorsque vous créez un optimiseur, vous transmettez clipnorm ou clipvalue en argument. L'optimiseur applique le clipping en interne à chaque étape, sans que vous ayez à modifier votre boucle d'entraînement.
Voici un exemple complet avec l'API Keras sur des données de régression synthétiques :
import numpy as np
import tensorflow as tf
tf.random.set_seed(42)
np.random.seed(42)
# Synthetic regression data
n_samples = 1000
n_features = 20
x_train = np.random.randn(n_samples, n_features).astype(np.float32)
y_train = (x_train.sum(axis=1, keepdims=True) * 2.0
+ np.random.randn(n_samples, 1).astype(np.float32) * 0.1)
# Small feedforward network
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation="relu", input_shape=(n_features,)),
tf.keras.layers.Dense(64, activation="relu"),
tf.keras.layers.Dense(1),
])
# Optimizer with gradient clipping by norm
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3, clipnorm=1.0)
model.compile(optimizer=optimizer, loss="mse")
model.fit(x_train, y_train, epochs=5, batch_size=32)

Sortie TensorFlow
Les deux arguments ne font pas la même chose :
-
clipnormrogne d'après la norme L2 de chaque tenseur de gradients. Si la norme dépasse le seuil, le tenseur est réduit proportionnellement. -
clipvaluerogne chaque élément de gradient individuellement. Toute valeur au-dessus du seuil est rabattue sur le seuil, et toute valeur au-dessous du seuil négatif est rabattue sur ce seuil négatif.
Pour passer du clipping par norme au clipping par valeur, il suffit de changer l'argument :
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3, clipvalue=0.5)
Les deux arguments fonctionnent avec tous les optimiseurs Keras : Adam, SGD, RMSprop, AdamW, etc. Il existe aussi un argument global_clipnorm qui rogne selon la norme calculée sur l'ensemble des gradients combinés, plutôt que par tenseur. Cela se rapproche davantage du comportement par défaut de PyTorch.
Si vous écrivez une boucle d'entraînement personnalisée avec tf.GradientTape, l'optimiseur gère toujours le clipping lors de l'appel à apply_gradients :
for epoch in range(5):
for batch_x, batch_y in zip(np.array_split(x_train, 32), np.array_split(y_train, 32)):
with tf.GradientTape() as tape:
predictions = model(batch_x, training=True)
loss = tf.reduce_mean(tf.square(predictions - batch_y))
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
C'est la différence entre les deux frameworks : PyTorch vous laisse contrôler le clipping dans la boucle, TensorFlow l'intègre à l'optimiseur. La logique sous-jacente reste identique.
Gradient clipping vs autres techniques de stabilisation
Le gradient clipping n'est pas la seule façon de stabiliser l'entraînement, et ce n'est pas toujours l'outil adéquat.
D'autres techniques traitent des problèmes voisins. Certaines évitent dès le départ que les gradients ne grossissent trop, d'autres empêchent leur disparition, et d'autres encore rendent la surface de perte plus facile à optimiser. Voici quelques approches complémentaires.
Batch normalization
La normalisation par lots normalise les activations au sein de chaque mini-batch pendant l'entraînement.
Elle maintient les sorties des couches dans un intervalle stable, ce qui rend les amplitudes de gradient plus prévisibles. Les réseaux entraînés avec batch norm tolèrent des taux d'apprentissage plus élevés, convergent plus vite et sont moins sensibles à l'initialisation des poids.
Mais la batch norm n'empêche pas directement les explosions de gradients. Elle réduit leur fréquence, pas leur effet lorsqu'elles surviennent. Beaucoup de modèles la combinent avec le gradient clipping pour cette raison.
Connexions résiduelles
Les connexions résiduelles ajoutent des raccourcis qui contournent une ou plusieurs couches, laissant les gradients circuler directement des couches tardives vers les couches précoces.
Elles résolvent le problème de disparition des gradients dans les réseaux profonds. Sans elles, entraîner des réseaux de plus de 20–30 couches devient ardu, car les gradients s'amenuisent en remontant. Avec elles, des réseaux de centaines de couches s'entraînent sans difficulté.
Les connexions résiduelles ciblent l'extrémité opposée du problème par rapport au clipping : le clipping gère des gradients trop grands, les résidus gèrent des gradients trop petits.
Initialisation soignée des poids
Les valeurs initiales des poids fixent l'amplitude de départ des activations et des gradients. Une mauvaise initialisation peut provoquer explosion ou disparition dès la première étape.
Les méthodes Xavier et He adaptent l'échelle initiale aux dimensions des couches, maintenant la variance des activations stable au démarrage et prévenant bon nombre de problèmes de gradient.
Une bonne initialisation diminue la probabilité d'avoir besoin du clipping, sans l'écarter complètement. Des pics peuvent survenir plus tard, notamment avec des taux d'apprentissage élevés ou des lots atypiques.
Comment ces techniques se complètent
Ces techniques ne s'excluent pas : elles sont complémentaires et adressent différentes facettes du même problème.
Un setup moderne typique combine une initialisation soignée, des connexions résiduelles dans l'architecture, une normalisation (batch ou layer) à l'intérieur du réseau, et le gradient clipping comme filet de sécurité pendant l'optimisation. Chacun cible un risque précis, et ensemble ils rendent l'entraînement des réseaux profonds plus robuste.
Conclusion
Le gradient clipping est l'un des correctifs les plus simples en deep learning, et il évite qu'une seule étape ne ruine des heures d'entraînement.
La bonne nouvelle : vous n'avez pas besoin de changer l'architecture ni de réécrire votre code. Une ligne sous PyTorch ou un argument sous TensorFlow suffit pour l'implémenter.
Il fonctionne idéalement dans un ensemble cohérent : associez-le à une initialisation soignée des poids, des connexions résiduelles et une normalisation par lots ou par couche, et vous disposerez d'un pipeline résilient aux instabilités.
Si votre perte explose, commencez par le clipping. Si elle disparaît, cherchez ailleurs. Et si vous entraînez un modèle plus qu'elementaire, ajoutez le clipping par défaut et n'y pensez plus.
Le gradient clipping n'est qu'un des nombreux termes que tout ingénieur en apprentissage automatique doit maîtriser. Pour apprendre les autres et être opérationnel en 2026, inscrivez-vous dès aujourd'hui au Machine Learning Engineer track.
Devenez un scientifique ML
FAQ sur le gradient clipping
Qu'est-ce que le gradient clipping en deep learning ?
Le gradient clipping est une technique qui limite la taille des gradients pendant l'entraînement d'un réseau de neurones afin d'empêcher des mises à jour instables des paramètres. Quand les gradients grossissent trop durant la rétropropagation, l'optimiseur fait d'immenses pas qui projettent les poids dans de mauvaises régions et font exploser la perte. Le clipping borne l'amplitude des gradients avant l'étape d'optimisation, de sorte que les mises à jour restent bornées même quand les gradients bruts font des pics.
Quand dois-je utiliser le gradient clipping ?
Utilisez le gradient clipping lorsque votre entraînement est instable, en particulier si vous observez des pics soudains de perte, des valeurs NaN ou une divergence après des heures de calcul. C'est une pratique standard pour les réseaux récurrents comme les LSTM et GRU, et pour toute architecture profonde entraînée avec des taux d'apprentissage élevés. Si votre courbe de perte est saine, vous pouvez vous en passer, mais l'ajouter comme filet de sécurité ne coûte rien.
Quelle est la différence entre clipping par valeur et par norme ?
Le clipping par valeur borne chaque élément du gradient individuellement, ce qui peut modifier la direction du vecteur gradient. Le clipping par norme met à l'échelle tout le vecteur lorsque son amplitude globale dépasse un seuil, en préservant la direction d'origine tout en raccourcissant le pas. Le clipping par norme est la référence en deep learning moderne car il ne déforme pas la direction de mise à jour.
Comment choisir un bon seuil de gradient clipping ?
Commencez à 1.0 et ajustez selon vos observations pendant l'entraînement. Journalisez vos normes de gradient non rognées sur les batches et examinez la distribution. Fixez le seuil au-dessus de la plage typique mais bien en dessous des pics à capturer. Trop haut, le clipping ne s'active jamais ; trop bas, vous ralentissez inutilement l'apprentissage.
Le gradient clipping corrige-t-il aussi la disparition des gradients ?
Non. Le gradient clipping traite uniquement l'explosion des gradients, lorsque les valeurs deviennent trop grandes. La disparition des gradients est le problème inverse, où les valeurs tendent vers zéro et l'apprentissage s'arrête pratiquement. Pour la disparition, utilisez une meilleure initialisation des poids, des connexions résiduelles, la normalisation par lots ou des architectures comme les LSTM et GRU.


