Можно ли настраивать только Batch Normalization, не трогая архитектуру нейронной сети?

«Можно ли настраивать только Batch Normalization, не трогая архитектуру нейронной сети?» — вопрос из категории Нейронные сети и Deep Learning, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, это распространенная практика тонкой настройки (fine-tuning) или стабилизации обучения. Параметры Batch Normalization (BN) слоев можно и часто нужно настраивать независимо от весов сверточных или полносвязных слоев.

Какие параметры BN можно настраивать и зачем:

Параметр (PyTorch) Назначение Типичные значения / Настройка
momentum Определяет, как быстро обновляются скользящие средние (running mean/var). По умолчанию ~0.1. Увеличение (например, до 0.3) делает статистики более устойчивыми к мини-батчам, уменьшение — более адаптивными.
eps (epsilon) Малое число для численной стабильности при делении на дисперсию. По умолчанию 1e-5. Увеличение (например, до 1e-4) может помочь при очень малых дисперсиях.
affine Включает/выключает обучаемые параметры масштаба (weight - γ) и сдвига (bias - β). affine=True (по умолчанию). При affine=False слой только нормализует, не сдвигая и не масштабируя.
track_running_stats Включает/выключает расчет скользящих статистик. Обычно True. При False использует статистики текущего батча даже в режиме оценки (eval()).

Практический пример настройки в PyTorch:

import torch.nn as nn

# Создание сверточной сети с настроенным BatchNorm
model = nn.Sequential(
    nn.Conv2d(3, 64, kernel_size=3, padding=1),
    # Настраиваемый BN: меньший momentum для быстрой адаптации, отключен affine
    nn.BatchNorm2d(64, momentum=0.01, eps=1e-4, affine=False),
    nn.ReLU(),
    nn.MaxPool2d(2),
    nn.Conv2d(64, 128, kernel_size=3, padding=1),
    # Другой BN: стандартный momentum, но увеличенный eps
    nn.BatchNorm2d(128, eps=1e-3),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d(1),
    nn.Flatten(),
    nn.Linear(128, 10)
)

# При fine-tuning часто "замораживают" все слои, кроме BN
for name, param in model.named_parameters():
    if 'bn' not in name and 'bias' not in name:  # Замораживаем веса conv/fc
        param.requires_grad = False
    else:
        param.requires_grad = True  # Оставляем обучаемыми BN и bias

Критически важный нюанс: Эффективность BN сильно зависит от размера мини-батча. При очень маленьких батчах (например, < 16) статистики становятся шумными, и BN может работать плохо. В таких случаях стоит рассмотреть альтернативы: Layer Normalization (для RNN/Transformers), Group Normalization или Instance Normalization (для стилей).