Normalização em Lote (Batch Normalization)

A Normalização em Lote (Batch Normalization) (frequentemente BatchNorm ou BN) é uma técnica amplamente utilizada para estabilizar e acelerar o treinamento de redes neurais profundas ao normalizar ativações intermediárias usando estatísticas calculadas sobre o mini-lote atual. Ela foi introduzida por Ioffe & Szegedy (2015) e rapidamente se tornou um componente padrão em muitas arquiteturas, especialmente Redes Neurais Convolucionais e Redes Residuais.

Dentro do tema mais amplo de inicialização e normalização, a BatchNorm é melhor compreendida como um mecanismo que reduz a sensibilidade à escala dos parâmetros e a distribuições de ativações mal condicionadas, permitindo taxas de aprendizado maiores, convergência mais rápida e, frequentemente, melhor generalização.

O que a Normalização em Lote faz

Considere uma camada de rede que produz valores de pré-ativação (frequentemente chamados de logits ou ativações) (x). A BatchNorm transforma essas ativações para que (aproximadamente) elas tenham média zero e variância unitária dentro do mini-lote atual, e então aplica uma transformação afim aprendida para que o modelo possa recuperar qualquer escala/deslocamento necessário.

Fórmula central (por característica)

Dado um mini-lote ( {x_1, \dots, x_m} ) para uma única dimensão de característica:

  1. Calcule a média e a variância do lote: [ \mu_B = \frac{1}{m}\sum_{i=1}^m x_i,\quad \sigma_B^2 = \frac{1}{m}\sum_{i=1}^m (x_i - \mu_B)^2 ]

  2. Normalize: [ \hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} ] onde ( \epsilon ) é uma pequena constante (por exemplo, (10^{-5})) para estabilidade numérica.

  3. Aplique escala e deslocamento aprendidos: [ y_i = \gamma \hat{x}_i + \beta ] onde (\gamma) (escala) e (\beta) (deslocamento) são parâmetros treináveis, um por característica.

Por que \(\gamma\) e \(\beta\) importam

Se apenas normalizássemos para média zero / variância unitária, poderíamos restringir a capacidade de representação. Os parâmetros aprendidos:

  • (\gamma) permite que a rede escolha a escala de ativação apropriada
  • (\beta) permite que ela escolha o deslocamento (offset) de ativação apropriado

De fato, se a normalização fosse prejudicial para uma determinada característica, a rede pode (em princípio) aprender a desfazê-la definindo (\gamma) e (\beta) de acordo (embora não consiga reconstruir perfeitamente os valores originais por exemplo, pois a normalização usa estatísticas dependentes do lote).

BatchNorm para camadas totalmente conectadas vs convolucionais

Camadas totalmente conectadas (densas)

Para uma camada densa com forma de saída ((N, D)) (tamanho do lote (N), características (D)), a BatchNorm normalmente normaliza cada característica ao longo do lote:

  • Calcule (\mu_B) e (\sigma_B^2) para cada uma das (D) dimensões usando as (N) amostras.

Camadas convolucionais (o caso comum)

Para ativações convolucionais com forma ((N, C, H, W)), a BatchNorm normalmente normaliza por canal (C), usando estatísticas sobre as dimensões de lote e espaciais:

  • Para cada canal (c), calcule média/variância sobre todos os valores (N \times H \times W).
  • (\gamma) e (\beta) são aprendidos por canal.

Isso corresponde à intuição de que um canal convolucional representa um mapa de características aprendido cuja distribuição deve ser estabilizada.

Por que a BatchNorm ajuda no treinamento (intuição e teoria)

A BatchNorm é frequentemente motivada por “reduzir a mudança de covariáveis interna”, mas explicações modernas focam mais em otimização e condicionamento.

1) Otimização mais suave e melhor condicionada

O treinamento de redes neurais com Descida do Gradiente pode ser instável quando as distribuições de ativação derivam significativamente à medida que camadas anteriores são atualizadas. A BatchNorm reduz essa deriva mantendo as ativações em uma faixa mais previsível, o que tende a:

  • reduzir ativações e gradientes explosivos/desvanecentes
  • melhorar o condicionamento do problema
  • permitir taxas de aprendizado mais altas
  • reduzir a sensibilidade a escolhas de Inicialização de Pesos

2) Invariância à escala e gradientes mais estáveis

Como a normalização remove boa parte do efeito de escalonamento nos pesos anteriores, a rede se torna menos sensível à magnitude dos parâmetros em certas direções. Isso pode tornar a dinâmica de treinamento mais tolerante e pode mudar como a regularização (como Decaimento de Pesos) se comporta na prática.

3) Regularização via ruído do lote

A BatchNorm usa estatísticas do mini-lote, que são estimativas ruidosas das estatísticas da população. Isso injeta um tipo de estocasticidade nas ativações, frequentemente atuando como um regularizador implícito (às vezes reduzindo a necessidade de muito Dropout, especialmente em CNNs).

Comportamento em treinamento vs inferência

Um detalhe crítico: a BatchNorm se comporta de forma diferente durante treinamento e inferência.

Modo de treinamento: usar estatísticas do lote

Durante o treinamento:

  • (\mu_B) e (\sigma_B^2) são calculados a partir do mini-lote atual.
  • A normalização usa esses valores do lote diretamente.
  • Estimativas acumuladas (descritas a seguir) são atualizadas.

Isso significa que a saída para um exemplo depende de outros exemplos no mesmo lote.

Modo de inferência: usar estimativas acumuladas (da população)

No momento da inferência, você normalmente quer um comportamento determinístico que não dependa da composição do lote atual (que pode ter tamanho 1). Portanto, a BatchNorm usa médias acumuladas da média e da variância acumuladas durante o treinamento.

Uma abordagem comum é uma média móvel exponencial (EMA) (exponential moving average): [ \mu_{\text{running}} \leftarrow (1-\alpha)\mu_{\text{running}} + \alpha \mu_B ] [ \sigma^2_{\text{running}} \leftarrow (1-\alpha)\sigma^2_{\text{running}} + \alpha \sigma_B^2 ] onde (\alpha) é uma taxa de atualização (frequentemente chamada de momentum, mas a definição exata difere entre frameworks).

Na inferência, normalize usando (\mu_{\text{running}}) e (\sigma^2_{\text{running}}), e não estatísticas do lote.

Armadilha de framework: a definição de “momentum” difere

  • PyTorch usa: [ \text{running} \leftarrow (1-\text{momentum})\cdot \text{running} + \text{momentum}\cdot \text{batch} ] Assim, momentum maior atualiza mais rápido.

  • Keras/TF historicamente usam uma convenção tipo “decaimento”: [ \text{running} \leftarrow \text{momentum}\cdot \text{running} + (1-\text{momentum})\cdot \text{batch} ] Assim, momentum maior atualiza mais devagar.

Ao portar modelos, isso pode afetar os resultados de forma perceptível.

Implicação prática: você deve alternar os modos corretamente

Se você esquecer de definir o modo de inferência (por exemplo, model.eval() no PyTorch), o modelo continuará usando estatísticas do lote, causando:

  • dependência da saída na composição do lote
  • queda de acurácia e previsões não determinísticas
  • problemas severos quando o tamanho do lote = 1

Onde posicionar a BatchNorm em uma rede

Há alguns padrões comuns; a “melhor” escolha pode depender das convenções da arquitetura.

Padrão comum: Linear/Conv → BatchNorm → Ativação

Este é o padrão mais típico em CNNs modernas:

  • Conv2d -> BatchNorm2d -> ReLU

Raciocínio: a BatchNorm estabiliza a distribuição antes da não linearidade, o que ajuda a manter as ativações em um regime em que os gradientes são saudáveis.

Alternativa: Linear/Conv → Ativação → BatchNorm

Menos comum, mas às vezes usada. Normalizar após não linearidades pode mudar o comportamento de representação (por exemplo, saídas de ReLU são não negativas; a BatchNorm as recentralizaria).

Redes residuais (estilo ResNet)

Variantes de ResNet comumente usam BN dentro de cada bloco residual. Duas convenções bastante vistas:

  • Pós-ativação (ResNet v1 clássica): Conv -> BN -> ReLU -> Conv -> BN -> +skip -> ReLU
  • Pré-ativação (ResNet v2): BN -> ReLU -> Conv -> BN -> ReLU -> Conv -> +skip

Projetos de pré-ativação frequentemente melhoram a otimização para redes muito profundas, em parte devido a um melhor fluxo de gradientes.

Transformers e modelos de sequência

A BatchNorm geralmente é menos comum em Transformers; Normalização de Camada (Layer Normalization) é preferida porque não depende de estatísticas do lote e funciona naturalmente com comprimentos de sequência variáveis e tamanhos de lote pequenos. A BatchNorm ainda pode aparecer em alguns blocos de MLP ou front-ends no estilo CNN.

Ressalvas práticas e armadilhas comuns

1) Tamanhos de lote pequenos podem quebrar a BatchNorm

Com (N) pequeno, as estatísticas do lote ficam ruidosas:

  • o treinamento se torna instável
  • as médias acumuladas se tornam estimativas ruins
  • a acurácia pode degradar significativamente

Isso é comum em tarefas de detecção/segmentação com imagens grandes, em que a memória da GPU força tamanhos de lote como 1–4.

Mitigações comuns:

  • BatchNorm Sincronizada (SyncBN) (Synchronized BatchNorm): calcular estatísticas entre múltiplas GPUs para aumentar o tamanho de lote efetivo.
  • BatchNorm Fantasma (Ghost BatchNorm): dividir um lote grande em “lotes fantasma” menores para estatísticas de BN para introduzir regularização (o problema oposto).
  • Trocar para normalizações independentes do tamanho do lote, como Normalização de Grupo (Group Normalization) ou Normalização de Camada.

2) BatchNorm interage com Dropout

Tanto Dropout quanto BatchNorm adicionam ruído durante o treinamento:

  • Dropout zera ativações aleatoriamente.
  • BatchNorm normaliza usando estatísticas do lote que são afetadas por essa aleatoriedade.

Essa interação pode ser contraproducente se não for tratada com cuidado.

Orientação prática:

  • Em CNNs com BatchNorm, você frequentemente precisa de menos Dropout (ou nenhum).
  • Se você usar Dropout, um padrão comum é ... -> BN -> ReLU -> Dropout, para que a BN veja ativações mais “limpas” e o Dropout atue depois.
  • Evite colocar Dropout antes da BN a menos que você tenha um motivo forte; isso pode distorcer as estatísticas da BN.

3) Decaimento de pesos com parâmetros da BatchNorm

Como a BatchNorm introduz parâmetros treináveis (\gamma) e (\beta), e como a BN torna alguns pesos invariantes à escala, escolhas padrão de Decaimento de Pesos podem se comportar de forma inesperada.

Prática comum em muitas receitas de treinamento:

  • Não aplicar decaimento de pesos em:
    • (\gamma) (escala) e (\beta) (deslocamento) da BatchNorm
    • vieses (frequentemente)
  • Aplicar decaimento de pesos principalmente em pesos convolucionais e lineares

Isso é especialmente padrão ao usar otimizadores com decaimento de pesos desacoplado (por exemplo, AdamW). Não é uma lei rígida, mas é um padrão muito comum e geralmente benéfico.

4) Ajuste fino de modelos pré-treinados: “congelar” a BatchNorm

Ao fazer ajuste fino com lotes pequenos (comum em aprendizado por transferência), as estatísticas acumuladas da BN podem derivar e prejudicar o desempenho.

Abordagens típicas:

  • Congelar BN: manter as camadas BN em modo de avaliação para que usem as estatísticas acumuladas pré-treinadas, enquanto treina o restante da rede.
  • Ou atualizar as estatísticas da BN, mas usar SyncBN / tamanhos de lote efetivos maiores.

No PyTorch, “congelar BN” frequentemente significa:

  • chamar model.eval() ou colocar apenas os módulos BN em eval
  • ainda permitir que outras camadas treinem

Cuidado: eval() também afeta Dropout e outros comportamentos de tempo de treinamento.

5) Vazamento de dados via composição do lote (e lotes não i.i.d.)

Como a BN depende de estatísticas do lote, ela assume que os lotes são razoavelmente i.i.d. Se os lotes contêm correlações estruturadas (por exemplo, frames consecutivos, classes agrupadas, múltiplos recortes da mesma imagem), a BN pode:

  • vazar informação entre amostras dentro de um lote
  • criar incompatibilidade entre treino/inferência se os lotes de inferência forem compostos de forma diferente

Este é um motivo pelo qual a BN pode ser complicada em alguns cenários de aprendizado por reforço ou aprendizado métrico, onde a composição do lote é atípica.

6) Precisão mista e estabilidade numérica

Com Treinamento com Precisão Mista (Mixed Precision Training), os cálculos da BN geralmente são mantidos internamente em FP32 para manter a estabilidade. A maioria dos frameworks principais lida com isso automaticamente, mas se você implementar camadas customizadas semelhantes à BN, garanta que o acúmulo de média/variância seja feito com precisão suficiente.

Exemplos práticos

Exemplo 1: Um bloco Conv-BN-ReLU padrão (PyTorch)

import torch
import torch.nn as nn

class ConvBNReLU(nn.Module):
    def __init__(self, in_ch, out_ch, k=3, stride=1, padding=1):
        super().__init__()
        self.conv = nn.Conv2d(in_ch, out_ch, k, stride=stride, padding=padding, bias=False)
        self.bn   = nn.BatchNorm2d(out_ch)  # per-channel BN
        self.act  = nn.ReLU(inplace=True)

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

Notas:

  • bias=False é comum porque o (\beta) da BN pode absorver o papel de um termo de viés.
  • O posicionamento é Conv -> BN -> ReLU, o padrão mais comum.

Exemplo 2: Modo correto de treinamento vs inferência (PyTorch)

model = ConvBNReLU(3, 64)

# Training
model.train()
out_train = model(torch.randn(32, 3, 224, 224))  # uses batch statistics

# Inference / evaluation
model.eval()
with torch.no_grad():
    out_eval = model(torch.randn(1, 3, 224, 224))  # uses running statistics

Se você esquecer model.eval(), a chamada de inferência com um único exemplo calculará média/variância a partir de um lote de tamanho 1, frequentemente produzindo saídas pouco confiáveis.

Exemplo 3: Excluir parâmetros da BN do decaimento de pesos (padrão tipo PyTorch)

decay, no_decay = [], []
for name, param in model.named_parameters():
    if not param.requires_grad:
        continue
    if name.endswith(".bias") or "bn" in name.lower() or "batchnorm" in name.lower():
        no_decay.append(param)
    else:
        decay.append(param)

optimizer = torch.optim.AdamW(
    [{"params": decay, "weight_decay": 1e-4},
     {"params": no_decay, "weight_decay": 0.0}],
    lr=3e-4
)

Isso reflete uma convenção comum: decaimento de pesos em pesos, não em parâmetros afins da BN ou vieses.

BatchNorm como parte da prática moderna de treinamento

A BatchNorm não é apenas um “truque de normalização” — ela muda de forma significativa a dinâmica de treinamento:

  • Ela frequentemente permite configurações de otimização mais agressivas (taxas de aprendizado mais altas, cronogramas mais rápidos).
  • Ela pode reduzir a sensibilidade à inicialização e ajudar redes profundas a treinarem de forma confiável.
  • Ela adiciona regularização implícita, às vezes reduzindo a dependência de Dropout.

Ao mesmo tempo, ela introduz novas preocupações:

  • dependência do tamanho do lote e da composição do lote
  • diferenças de comportamento entre treino/inferência que exigem gerenciamento cuidadoso de modo
  • interações com regularização e procedimentos de ajuste fino

Quando usar BatchNorm (regras práticas)

  • Use BatchNorm por padrão em CNNs quando os tamanhos de lote forem moderadamente grandes (por exemplo, 32+ no total entre dispositivos).
  • Prefira SyncBN ou alternativas (GroupNorm/LayerNorm) quando os tamanhos de lote forem pequenos.
  • Seja deliberado com Dropout; frequentemente reduza-o quando a BN estiver presente.
  • Considere excluir parâmetros da BN do decaimento de pesos.
  • Em aprendizado por transferência com lotes pequenos, considere congelar as estatísticas acumuladas da BN.

Conceitos relacionados

A BatchNorm fica na interseção entre otimização, inicialização e design arquitetural. Tópicos relacionados que você pode querer ler a seguir: