Fonction torch.nn.BatchNorm2d de PyTorch

PyTorch torch.nn 参考手册Manuel de référence torch.nn de PyTorch


torch.nn.BatchNorm2dIl s'agit d'un module de PyTorch pour la normalisation par lots en deux dimensions.

La normalisation par lots accélère l'entraînement et stabilise la convergence en normalisant l'entrée d'une couche, et est l'une des techniques les plus couramment utilisées dans les réseaux de neurones profonds modernes.

Définition de fonction

torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

Description des paramètres :

  • num_features(int) : Nombre de canaux d'entrée C.
  • eps(float) : Valeur ajoutée au dénominateur pour la stabilité numérique. La valeur par défaut est 1e-5.
  • momentum(float) : Utilisé pour calculer la moyenne et la variance glissantes. La valeur par défaut est 0.1.
  • affine(bool) : Indique s'il faut utiliser des paramètres affines apprenables (gamma et beta). La valeur par défaut est True.
  • track_running_stats(bool) : Indique s'il faut suivre les statistiques glissantes. La valeur par défaut est True.

Attributs :

  • weight(Tensor) : Paramètre d'échelle apprenable gamma, de forme (num_features,).
  • bias(Tensor) : Paramètre de décalage apprenable beta, de forme (num_features,).
  • running_mean(Tensor) : Moyenne glissante, non mise à jour pendant l'entraînement.
  • running_var(Tensor) : Variance glissante, non mise à jour pendant l'entraînement.

Principe mathématique

La normalisation par lots normalise chaque canal indépendamment :

y = (x - E[x]) / sqrt(Var[x] + eps) * gamma + beta

Ici, gamma et beta sont des paramètres apprenables qui permettent au réseau de restaurer sa capacité d'expression.


Exemples d'utilisation

Exemple 1 : Utilisation de base

Utilisation de la normalisation par lots après une couche de convolution :

Exemple

import torch
import torch.nn as nn

# Créer une couche de normalisation par lots : 32 canaux
bn = nn.BatchNorm2d(num_features=32)

# Afficher les paramètres
print("gamma (poids) :", bn.weight.shape)
print("beta (biais) :", bn.bias.shape)
print("running_mean:", bn.running_mean.shape)
print("running_var:", bn.running_var.shape)

# Créer l'entrée : batch=4, canaux=32, hauteur=16, largeur=16
input_tensor = torch.randn(4, 32, 16, 16)

# Passe avant
output = bn(input_tensor)

print("nMoyenne d'entrée (par canal) :", input_tensor.mean(dim=(0, 2, 3))[:5].tolist())
print("Moyenne de sortie (par canal) :", output.mean(dim=(0, 2, 3))[:5].tolist())
print("nForme de l'entrée :", input_tensor.shape)
print("Forme de sortie :", output.shape)

Le résultat de sortie est:

gamma (weight): torch.Size([32])
beta (bias): torch.Size([32])
running_mean: torch.Size([32])
running_var: torch.Size([32])

输入均值 (按通道): tensor([ 0.0234,  0.0456, -0.0123, -0.0345,  0.0567])
输出均值 (按通道): tensor([ 0.,  0.,  0.,  0.,  0.])

输入形状: torch.Size([4, 32, 16, 16])
输出形状: torch.Size([4, 32, 16, 16])

Pendant l'entraînement, la sortie est normalisée pour avoir une moyenne de 0 et une variance de 1 (suivie d'une transformation gamma et beta).

Exemple 2 : mode entraînement vs mode évaluation

La normalisation par lots se comporte différemment pendant l'entraînement et l'évaluation :

Exemple

import torch
import torch.nn as nn

bn = nn.BatchNorm2d(num_features=16)

# Mode entraînement
bn.train()
print("Mode entraînement - nécessite un gradient :", bn.weight.requires_grad)

# Simuler l'entraînement
for _ in range(10):
    x = torch.randn(8, 16, 8, 8)
    output = bn(x)

print("5 premiers running_mean après entraînement :", bn.running_mean[:5].tolist())

# Mode évaluation
bn.eval()
print("nMode évaluation - nécessite un gradient :", bn.weight.requires_grad)

# Utiliser les statistiques courantes lors de l’évaluation
x = torch.randn(4, 16, 8, 8)
output = bn(x)
print("Forme de la sortie lors de l’évaluation :", output.shape)

Exemple 3 : Exemple complet de CNN

Structure typique d’un CNN avec normalisation par lots :

Exemple

import torch
import torch.nn as nn

class BNConvNet(nn.Module):
    def __init__(self, num_classes=10):
        super(BNConvNet, self).__init__()
        # Convolution + normalisation par lots + activation + pooling
        self.block1 = nn.Sequential(
            nn.Conv2d(3, 32, kernel_size=3, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2, 2)  # 32 -> 16
        )
        self.block2 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2, 2)  # 16 -> 8
        )
        # Pooling moyen global
        self.gap = nn.AdaptiveAvgPool2d(1)
        self.classifier = nn.Linear(64, num_classes)

    def forward(self, x):
        x = self.block1(x)
        x = self.block2(x)
        x = self.gap(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x

model = BNConvNet()
input_image = torch.randn(2, 3, 32, 32)
output = model(input_image)

print("Forme de l'entrée :", input_image.shape)
print("Forme de sortie :", output.shape)

# Afficher les paramètres de la première couche BN
print("Gamma de la première couche BN :", model.block1[1].weight[:5].tolist())
print("Bêta de la première couche BN :", model.block1[1].bias[:5].tolist())

Exemple 4 : Ne pas utiliser les paramètres affines

Désactiver les paramètres apprenables :

Exemple

import torch
import torch.nn as nn

# Normalisation par lots sans paramètres apprenables
bn_no_affine = nn.BatchNorm2d(16, affine=False)

print("A un poids :", bn_no_affine.weight is not Aucune)
print("A un biais :", bn_no_affine.bias is not Aucune)

# Il effectue toujours la normalisation
x = torch.randn(4, 16, 8, 8)
output = bn_no_affine(x)
print("nForme de sortie :", output.shape)

Questions courantes

Q1 : La normalisation par lots doit-elle être placée avant ou après ReLU ?

Les deux approches sont efficaces. L'article original le place après la convolution et avant l'activation ; en pratique, il est aussi souvent placé après l'activation.

Q2 : Que faire lorsqu'il ne fonctionne pas bien avec de petites tailles de lot ?

  • UtiliserGroupNormau lieu de
  • UtiliserLayerNorm
  • Augmenter la taille du lot
  • Ajuster le paramètre de momentum

Q3 : Pourquoi passer en mode eval lors de l'évaluation ?

Pendant l'entraînement, les statistiques de lot sont utilisées ; pendant l'évaluation, les statistiques courantes sont utilisées. Oublier de basculer entraînera des sorties incohérentes.


Cas d'utilisation

nn.BatchNorm2dLes principaux scénarios d'application incluent :

  • Accélérer l'entraînement: Permet d'utiliser un taux d'apprentissage plus élevé
  • Stabiliser la convergence: Réduit le décalage interne des covariables
  • Régularisation: Fournit un léger effet de régularisation
  • Classification d'images: Utilisée par presque tous les CNN modernes

Remarque : la normalisation par lots nécessite une taille de lot suffisante pendant l'entraînement ; les petits lots peuvent conduire à des statistiques instables.


PyTorch torch.nn 参考手册Manuel de référence torch.nn de PyTorch

Autres extensions