← Назад к вопросам

Какие обучаемые параметры есть в BatchNorm?

2.2 Middle🔥 161 комментариев
#Глубокое обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие обучаемые параметры есть в BatchNorm?

Batch Normalization (BatchNorm) — это техника нормализации, которая имеет обучаемые параметры, критические для эффективности сети. Многие ошибочно думают, что BatchNorm не содержит обучаемых параметров.

Структура BatchNorm

BatchNorm содержит два обучаемых параметра и два статистических параметра:

Четыре параметра в BatchNorm:
1. γ (gamma) - масштаб - ОБУЧАЕМЫЙ
2. β (beta) - смещение - ОБУЧАЕМЫЙ
3. μ (mu) - среднее - СТАТИСТИЧЕСКИЙ (не обучаемый)
4. σ² (sigma²) - дисперсия - СТАТИСТИЧЕСКИЙ (не обучаемый)

Алгоритм BatchNorm

1. Нормализация (по батчу):
   x_normalized = (x - mean(x)) / sqrt(var(x) + ε)

2. Масштабирование и смещение (ОБУЧАЕМЫЕ):
   y = γ * x_normalized + β

3. Обновление бегущих статистик (для инференса):
   running_mean = momentum * running_mean + (1 - momentum) * batch_mean
   running_var = momentum * running_var + (1 - momentum) * batch_var

Практическая демонстрация

import torch
import torch.nn as nn

# BatchNorm1d (для полносвязных слоёв)
bn = nn.BatchNorm1d(num_features=64)

print("Параметры BatchNorm1d:")
for name, param in bn.named_parameters():
    print(f"  {name}: {param.shape}")

# Output:
# weight: torch.Size([64])  ← γ (gamma) - масштаб
# bias: torch.Size([64])    ← β (beta) - смещение

print("\nСтатистические параметры (не обучаемые):")
print(f"  running_mean: {bn.running_mean.shape}")
print(f"  running_var: {bn.running_var.shape}")
print(f"  momentum: {bn.momentum}")

# BatchNorm2d (для сверток)
bn2d = nn.BatchNorm2d(num_features=64)

print("\nПараметры BatchNorm2d (для каждого канала):")
for name, param in bn2d.named_parameters():
    print(f"  {name}: {param.shape}")

# Output:
# weight: torch.Size([64])  ← γ для каждого канала
# bias: torch.Size([64])    ← β для каждого канала

Обучаемые параметры: γ и β

γ (gamma) - Масштаб (Scale)

# Инициализируется единицами (нет трансформации по умолчанию)
defaults_gamma = torch.ones(64)
print(f"Начальное значение γ: {defaults_gamma[:5]}")

# Во время обучения сеть учится масштабировать нормализованный вывод
# Большое γ → усилить признак
# Малое γ → ослабить признак

# Пример: если нормализованный выход не информативен,
# γ может быть близко к 0 (игнорировать нормализацию)
print("\nВозможные значения γ после обучения:")
print("  γ = 0.5 → половина интенсивности нормализованного выхода")
print("  γ = 2.0 → удвоенная интенсивность")
print("  γ ≈ 0 → почти игнорирует нормализацию (редко)")

β (beta) - Смещение (Shift)

# Инициализируется нулями
defaults_beta = torch.zeros(64)
print(f"Начальное значение β: {defaults_beta[:5]}")

# Во время обучения сеть учится смещать нормализованный выход
# Позитивное β → сдвинуть вправо
# Негативное β → сдвинуть влево

print("\nВозможные значения β после обучения:")
print("  β = 0.5 → сдвинуть на +0.5")
print("  β = -1.0 → сдвинуть на -1.0")
print("  β = 0.0 → нет смещения (редко)")

Полный пример с обучением

import torch
import torch.nn as nn
import torch.optim as optim

class SimpleNetWithBN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(100, 64)
        self.bn1 = nn.BatchNorm1d(64)  # BatchNorm после fc1
        self.fc2 = nn.Linear(64, 10)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.bn1(x)  # Нормализация
        x = torch.relu(x)
        x = self.fc2(x)
        return x

model = SimpleNetWithBN()
optimizer = optim.SGD(model.parameters(), lr=0.01)

print("Обучаемые параметры:")
for name, param in model.named_parameters():
    print(f"  {name}: {param.shape}, requires_grad={param.requires_grad}")

# Тренировочный цикл
model.train()  # ВАЖНО: BatchNorm работает по-другому в train и eval

x = torch.randn(32, 100)  # Батч из 32 примеров
y_true = torch.randint(0, 10, (32,))

output = model(x)
loss = nn.CrossEntropyLoss()(output, y_true)

optimizer.zero_grad()
loss.backward()  # γ и β получают градиенты
optimizer.step()  # γ и β обновляются

print("\nПосле обновления:")
print(f"  γ: {model.bn1.weight[:5]}")
print(f"  β: {model.bn1.bias[:5]}")
print(f"\nГрадиенты были вычислены и параметры обновлены!")

Статистические параметры (НЕ обучаемые)

bn = nn.BatchNorm1d(64)

print("Статистические параметры (для инференса):")
print(f"  running_mean: {bn.running_mean}")
print(f"  running_var: {bn.running_var}")
print(f"  momentum: {bn.momentum}")
print(f"  eps: {bn.eps}")

# Во время ОБУЧЕНИЯ:
# - Используется среднее и дисперсия ТЕКУЩЕГО БАТЧА
# - После каждого батча обновляются running_mean и running_var

# Во время ИНФЕРЕНСА:
# - Используются running_mean и running_var (не батча!)
# - Это позволяет модели работать с одиночными примерами

model.eval()  # Переходим в режим инференса
x_single = torch.randn(1, 100)  # Один пример
output = model(x_single)  # Использует running_mean, running_var

Как работает обновление параметров

# Формула BackProp для γ и β:

# Цепное правило:
# ∂Loss/∂γ = ∂Loss/∂y * ∂y/∂γ
# ∂Loss/∂β = ∂Loss/∂y * ∂y/∂β

# где y = γ * x_norm + β

# Это означает:
# ∂y/∂γ = x_norm    (как влияет γ на выход)
# ∂y/∂β = 1         (как влияет β на выход)

# Обновление градиентного спуска:
# γ_new = γ_old - lr * ∂Loss/∂γ
# β_new = β_old - lr * ∂Loss/∂β

print("\nПример вычисления градиентов:")
x_normalized = torch.randn(32, 64)  # Нормализованные данные
loss_grad = torch.randn(32, 64)     # Градиент от следующего слоя

# Градиент для γ
grad_gamma = (loss_grad * x_normalized).sum(dim=0)  # Сумма по батчу
print(f"  ∂Loss/∂γ shape: {grad_gamma.shape}")

# Градиент для β
grad_beta = loss_grad.sum(dim=0)  # Сумма по батчу
print(f"  ∂Loss/∂β shape: {grad_beta.shape}")

Можно ли отключить обучение γ и β?

bn = nn.BatchNorm1d(64)

# Заморозить параметры γ и β
for param in bn.parameters():
    param.requires_grad = False

print("Параметры заморожены:")
for name, param in bn.named_parameters():
    print(f"  {name}: requires_grad={param.requires_grad}")

# Или использовать эту функцию:
from torch.nn.utils import freeze_module
# freeze_module(bn)  # Требует PyTorch 1.11+

# Обычно заморозить BatchNorm имеет смысл при:
# - Transfer learning (использование предтренированной модели)
# - Fine-tuning с очень маленькой скоростью обучения

BatchNorm vs LayerNorm vs GroupNorm

# BatchNorm: нормализуется по батчу (разные статистики на разные примеры)
# LayerNorm: нормализуется по признакам (одинаковые статистики)
# GroupNorm: нормализуется по группам каналов

bn = nn.BatchNorm1d(64)      # Нормирует по батчу
ln = nn.LayerNorm(64)        # Нормирует по всем 64 признакам
gn = nn.GroupNorm(8, 64)     # Нормирует по 8 группам из 64 каналов

print("Параметры LayerNorm:")
for name, param in ln.named_parameters():
    print(f"  {name}: {param.shape}")

# LayerNorm также имеет γ и β!
# GroupNorm также имеет γ и β!

Инициализация и значения по умолчанию

bn = nn.BatchNorm1d(64)

print("Значения после инициализации:")
print(f"  γ (weight): min={bn.weight.min():.4f}, max={bn.weight.max():.4f}")
print(f"           (все ~1.0)")
print(f"  β (bias): min={bn.bias.min():.4f}, max={bn.bias.max():.4f}")
print(f"          (все ~0.0)")
print(f"\nБегущие статистики:")
print(f"  running_mean: {bn.running_mean}")
print(f"  running_var: {bn.running_var}")
print(f"  (inicialised to 0 and 1 respectively)")

Практические советы

✓ Проверяй требует ли слой градиентов:

model = SimpleNetWithBN()
for name, param in model.named_parameters():
    print(f"{name}: requires_grad={param.requires_grad}")

✓ Правильно переключай train/eval режимы:

model.train()   # Во время обучения
# ... обучение ...

model.eval()    # Во время валидации/инференса
# ... инференс ...

✓ Учитывай моментум при инференсе:

# Если обучалась с momentum=0.1, бегущие статистики обновлялись медленно
# Может потребоваться больше примеров для хорошей оценки

✗ НЕ используй BatchNorm если:

  • Батч очень маленький (< 4 примера) — статистика нестабильна
  • Рекуррентные сети (используй LayerNorm)
  • Очень большая дисперсия размеров батчей

Вывод: BatchNorm содержит ДВА обучаемых параметра (γ и β), которые критичны для его функциональности!