Batch Normalization
La batch normalization (BatchNorm ou BN) est une technique de deep learning qui normalise les activations de chaque couche d’un réseau de neurones en les centrant (moyenne nulle) et en les réduisant (écart-type unitaire) sur chaque mini-batch, puis en appliquant une transformation affine apprise.
Introduite par Ioffe et Szegedy chez Google en 2015, la batch normalization est l’une des innovations les plus importantes du deep learning moderne. Avant BatchNorm, entraîner des réseaux profonds était un exercice de funambulisme : le moindre mauvais choix de learning rate ou d’initialisation des poids pouvait faire diverger l’entraînement. BatchNorm a changé la donne en rendant l’entraînement plus stable, plus rapide et moins sensible aux hyperparamètres. Le papier original a été cité plus de 50 000 fois, et BatchNorm est aujourd’hui un composant standard de quasiment toute architecture de CNN.
- Auteurs
- Sergey Ioffe, Christian Szegedy (Google, 2015)
- Principe
- Normaliser les activations sur le mini-batch, puis appliquer une transformation affine apprise (γ, β)
- Bénéfices
- Convergence plus rapide, learning rate plus élevé, léger effet régularisant
- Placement
- Après la couche linéaire/convolutive, avant ou après l’activation
- Implémentation
- PyTorch :
nn.BatchNorm2d()| Keras :layers.BatchNormalization() - Alternative pour Transformers
- Layer Normalization
Comment fonctionne la batch normalization
L’algorithme en 4 étapes
Pour chaque mini-batch pendant l’entraînement, BatchNorm applique les opérations suivantes sur les activations d’une couche :
1. Calcul de la moyenne du batch. Pour chaque feature (ou chaque canal dans un CNN), calculer la moyenne des valeurs sur tous les exemples du mini-batch : μ_B = (1/m) × Σ xᵢ.
2. Calcul de la variance du batch. Calculer la variance des valeurs sur le mini-batch : σ²_B = (1/m) × Σ (xᵢ – μ_B)².
3. Normalisation. Centrer et réduire chaque valeur : x̂ᵢ = (xᵢ – μ_B) / √(σ²_B + ε), où ε est une petite constante (typiquement 1e-5) pour éviter la division par zéro.
4. Transformation affine (scale and shift). Appliquer deux paramètres appris, γ (gamma, le facteur d’échelle) et β (beta, le décalage) : yᵢ = γ × x̂ᵢ + β. Ces paramètres permettent au réseau de « défaire » la normalisation si c’est optimal. Sans eux, BatchNorm imposerait une distribution centrée réduite à chaque couche, ce qui pourrait limiter l’expressivité du réseau.
Entraînement vs inférence
Pendant l’entraînement, la moyenne et la variance sont calculées sur chaque mini-batch. Pendant l’inférence, on ne dispose pas forcément d’un batch (on peut prédire un seul exemple). BatchNorm utilise alors une moyenne mobile (running mean) et une variance mobile (running variance) accumulées pendant l’entraînement.
model.eval() en PyTorch avant l’inférence. Sans cet appel, BatchNorm continue d’utiliser les statistiques du batch courant (qui peut être un seul exemple), produisant des résultats instables. C’est l’une des erreurs les plus fréquentes en production.
Spécificité dans les CNN
Dans un CNN, BatchNorm est appliqué par canal : chaque feature map (canal) est normalisée indépendamment sur toutes les positions spatiales (H × W) et tous les exemples du batch (N). Concrètement, pour une couche convolutive avec C canaux, BatchNorm apprend 2C paramètres (un γ et un β par canal). C’est nn.BatchNorm2d(num_features=C) en PyTorch.
Pourquoi ça marche
Le mécanisme exact par lequel BatchNorm améliore l’entraînement fait encore débat dans la communauté scientifique. L’explication originale (réduction de l' »internal covariate shift ») a été contestée par des recherches ultérieures. Voici les trois théories principales.
Théorie originale : réduction du covariate shift interne
L’hypothèse initiale d’Ioffe et Szegedy : pendant l’entraînement, les paramètres de chaque couche changent, modifiant la distribution des entrées de la couche suivante. Ce « covariate shift interne » force chaque couche à constamment se réadapter à de nouvelles distributions, ralentissant la convergence. BatchNorm stabilise ces distributions.
Cependant, des expériences ont montré qu’ajouter du bruit explicite (qui augmente le covariate shift) après BatchNorm ne dégrade pas significativement les performances. Cela suggère que la réduction du covariate shift n’est pas l’explication principale.
Théorie dominante : lissage de la surface de loss
Des recherches plus récentes montrent que BatchNorm lisse la surface de la loss function, rendant le paysage d’optimisation plus « plat » et plus prévisible. Cela permet à l’optimizer de faire des pas plus grands (learning rate plus élevé) sans risquer de « tomber » dans un mauvais minimum. C’est l’explication la plus largement acceptée aujourd’hui.
Théorie complémentaire : découplage norme/direction
BatchNorm découple la norme (magnitude) et la direction des vecteurs de poids. La normalisation gère la magnitude, tandis que le réseau apprend la direction. Ce découplage facilite l’optimisation en réduisant les interactions entre ces deux aspects.
Avantages concrets
Convergence plus rapide. BatchNorm permet d’utiliser des learning rates plus élevés sans divergence. L’entraînement converge en moins d’epochs, ce qui réduit le temps et le coût de calcul. Des accélérations de 2 à 5× sont courantes par rapport à un réseau sans BatchNorm.
Moins sensible à l’initialisation. Sans BatchNorm, une mauvaise initialisation des poids (trop grande ou trop petite) peut faire diverger ou stagner l’entraînement. BatchNorm absorbe ces variations en normalisant les activations, rendant le réseau beaucoup plus tolérant à l’initialisation.
Effet régularisant. Le bruit statistique introduit par le calcul de la moyenne et de la variance sur un mini-batch (et non sur l’ensemble du dataset) agit comme un léger régulariseur. De nombreuses architectures modernes utilisent moins de dropout quand BatchNorm est présent, car les deux techniques ont un effet partiellement redondant.
Lutte contre le vanishing/exploding gradient. En normalisant les activations, BatchNorm maintient les gradients dans des plages exploitables pendant la rétropropagation, ce qui est particulièrement important pour les réseaux profonds (20+ couches).
Les variantes de normalisation
BatchNorm a inspiré toute une famille de techniques de normalisation, chacune adaptée à un contexte spécifique.
| Technique | Normalise sur | Dépend du batch ? | Usage principal |
|---|---|---|---|
| Batch Norm | N × H × W (par canal) | Oui | CNN, réseaux feedforward |
| Layer Norm | C × H × W (par exemple) | Non | Transformers, RNN, LLM |
| Instance Norm | H × W (par canal, par exemple) | Non | Style transfer, génération d’images |
| Group Norm | Groupes de canaux (par exemple) | Non | Détection d’objets (petits batchs), segmentation |
Layer Normalization (LN). Normalise toutes les features d’un seul exemple (indépendamment du batch). C’est le standard pour les Transformers et les LLM, car ces architectures fonctionnent souvent avec des tailles de batch variables ou des séquences de longueurs différentes. Layer Norm n’a pas besoin d’accumuler des statistiques de batch, ce qui simplifie l’inférence.
Instance Normalization (IN). Normalise chaque canal de chaque exemple indépendamment (sur H × W seulement). Utilisé principalement en style transfer et en génération d’images, où les statistiques de style (contraste, luminosité) doivent être traitées séparément pour chaque image et chaque canal.
Group Normalization (GN). Divise les canaux en groupes et normalise chaque groupe indépendamment, par exemple. C’est un compromis entre Layer Norm (tous les canaux ensemble) et Instance Norm (chaque canal séparément). GN est particulièrement utile quand la taille du batch est trop petite pour que BatchNorm fonctionne correctement (détection d’objets sur GPU avec peu de mémoire).
Implémentation pratique
# PyTorch : CNN avec BatchNorm
import torch.nn as nn
class ConvBlock(nn.Module):
def __init__(self, in_ch, out_ch):
super().__init__()
self.block = nn.Sequential(
nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),
nn.BatchNorm2d(out_ch), # BatchNorm après Conv
nn.ReLU(inplace=True), # Activation après BatchNorm
)
def forward(self, x):
return self.block(x)
# PyTorch : Transformer avec LayerNorm
class TransformerBlock(nn.Module):
def __init__(self, d_model, nhead):
super().__init__()
self.attn = nn.MultiheadAttention(d_model, nhead)
self.norm1 = nn.LayerNorm(d_model) # Layer Norm, pas Batch Norm
self.ffn = nn.Sequential(
nn.Linear(d_model, 4 * d_model),
nn.GELU(),
nn.Linear(4 * d_model, d_model),
)
self.norm2 = nn.LayerNorm(d_model)
def forward(self, x):
x = x + self.attn(self.norm1(x), self.norm1(x), self.norm1(x))[0]
x = x + self.ffn(self.norm2(x))
return x
Limites de la batch normalization
Dépendance à la taille du batch. BatchNorm calcule les statistiques sur le mini-batch. Avec un batch de taille 1, la variance est zéro et BatchNorm ne peut rien normaliser. Avec des batchs de 2 à 4, les statistiques sont très bruitées. En pratique, BatchNorm nécessite des batchs d’au moins 16, idéalement 32+. C’est un problème pour les tâches qui consomment beaucoup de mémoire GPU (segmentation 3D, vidéo haute résolution).
Comportement différent train/inférence. Le fait que BatchNorm utilise des statistiques de batch en entraînement et des moyennes mobiles en inférence crée une asymétrie qui peut causer des écarts de performance. Si la distribution des données de production diffère de celle de l’entraînement, les running statistics accumulées peuvent être inadaptées.
Interaction complexe avec le dropout. BatchNorm et dropout peuvent interférer : le dropout modifie les activations (en mettant des neurones à zéro), ce qui biaise les statistiques de batch calculées par BatchNorm. En pratique, on place le dropout après BatchNorm, ou on utilise l’un ou l’autre mais rarement les deux sur la même couche.
Pas adapté aux Transformers. Les Transformers travaillent avec des séquences de longueurs variables et des tailles de batch parfois petites. Layer Normalization est le choix standard pour ces architectures, car elle normalise chaque exemple indépendamment du batch.
BatchNorm dans les architectures emblématiques
ResNet. L’architecture ResNet (2015) a été l’une des premières à utiliser massivement BatchNorm dans chaque bloc résiduel. Le pattern Conv → BN → ReLU est répété des dizaines de fois (34, 50, 101, voire 152 couches). BatchNorm est un facteur clé qui a permis d’entraîner des réseaux aussi profonds sans explosion de gradient. Sans BatchNorm, ResNet-152 serait quasiment impossible à entraîner.
YOLO et la détection d’objets. Toutes les versions de YOLO (de YOLOv2 à YOLO26) intègrent BatchNorm dans chaque bloc convolutif. La stabilité apportée par BatchNorm est cruciale pour les modèles de détection temps réel qui doivent fonctionner sur des images très variées (éclairage, résolution, contenu).
EfficientNet. L’architecture EfficientNet utilise BatchNorm dans ses blocs MBConv (Mobile Inverted Bottleneck). La combinaison BatchNorm + Swish activation + squeeze-and-excitation est au cœur de l’efficacité de cette famille de modèles qui domine les benchmarks de classification d’images à iso-calcul.
Modèles génératifs (GAN). Les GAN utilisent BatchNorm dans le générateur pour stabiliser l’entraînement (notoirement instable). Certaines variantes comme Spectral Normalization complètent ou remplacent BatchNorm dans le discriminateur pour éviter le mode collapse.
U-Net (segmentation médicale). L’architecture U-Net, standard en segmentation d’images médicales, utilise BatchNorm dans chaque bloc encodeur et décodeur. Pour les images médicales haute résolution où la mémoire GPU limite la taille du batch, Group Norm est parfois substitué à BatchNorm pour maintenir la stabilité.
Erreurs fréquentes
Oublier model.eval() à l’inférence. Sans ce basculement, BatchNorm utilise les statistiques du batch courant au lieu des running statistics. Avec un seul exemple en inférence, cela produit des résultats aberrants.
Placer BatchNorm après l’activation. Le débat « BN avant ou après ReLU » existe toujours, mais la pratique dominante (et celle de l’article original) place BatchNorm entre la couche linéaire/convolutive et l’activation : Conv → BN → ReLU. Certaines architectures font l’inverse avec succès, mais commencez par la convention standard.
Utiliser BatchNorm avec des batchs trop petits. Un batch de 2 ou 4 produit des statistiques de normalisation très bruitées. Passez à Group Norm ou Layer Norm si votre mémoire GPU ne permet pas des batchs de 16+.
Appliquer BatchNorm aux Transformers. Utilisez Layer Norm pour les Transformers. BatchNorm est conçu pour les CNN et les réseaux feedforward.
Questions fréquentes sur la batch normalization
Quelle est la différence entre batch normalization et layer normalization ?
BatchNorm normalise chaque feature (canal) sur l’ensemble du mini-batch (tous les exemples). Layer Norm normalise chaque exemple sur l’ensemble de ses features (tous les canaux). BatchNorm dépend de la taille du batch et nécessite un comportement différent train/inférence. Layer Norm est indépendante du batch et fonctionne identiquement en train et inférence. BatchNorm est le standard pour les CNN ; Layer Norm est le standard pour les Transformers et les LLM.
BatchNorm remplace-t-il le dropout ?
Pas complètement, mais il réduit le besoin de dropout. L’effet régularisant de BatchNorm (dû au bruit des statistiques mini-batch) est réel mais modeste. Pour les architectures CNN modernes (ResNet, EfficientNet), BatchNorm seul suffit souvent, et le dropout n’est appliqué que dans les couches fully connected finales. Pour les Transformers, dropout et Layer Norm cohabitent. En pratique, testez avec et sans dropout et comparez les résultats de validation.
Où placer la batch normalization dans le réseau ?
La convention la plus courante est : couche linéaire/convolutive → BatchNorm → activation (ReLU). C’est l’ordre de l’article original et celui utilisé dans ResNet et la majorité des architectures modernes. L’ordre inverse (Conv → ReLU → BN) existe et fonctionne aussi dans certains cas, mais commencez par la convention standard. Ne placez pas BatchNorm sur la couche de sortie du réseau.
BatchNorm fonctionne-t-il avec des petits batchs ?
Mal. Avec des batchs de 1 à 4, les statistiques de normalisation sont trop bruitées pour être fiables. Si votre taille de batch est contrainte (mémoire GPU limitée, images haute résolution), utilisez Group Normalization (indépendante du batch, fonctionne bien avec 32 groupes) ou Layer Normalization. Certaines techniques comme Synchronized BatchNorm (qui calcule les statistiques sur plusieurs GPU) peuvent aussi aider en distribué.
Pourquoi les Transformers utilisent Layer Norm au lieu de BatchNorm ?
Trois raisons principales. D’abord, les Transformers traitent des séquences de longueurs variables, ce qui rend les statistiques de batch incohérentes (les positions après la fin d’une séquence courte sont du padding, pas des données réelles). Ensuite, les tailles de batch des Transformers sont souvent petites (surtout pour les LLM avec des séquences longues), ce qui dégrade BatchNorm. Enfin, Layer Norm normalise chaque token indépendamment, ce qui est plus naturel pour les modèles séquentiels où chaque position a sa propre sémantique. Layer Norm est aussi plus simple en inférence (pas de running statistics à gérer).