Что такое переобучение и как его диагностировать

Переобучение (overfitting) — одна из центральных проблем машинного обучения. Оно возникает, когда модель слишком точно подстраивается под обучающую выборку, включая случайный шум в данных, и теряет способность обобщаться на новые, невидимые данные.

Диагностический признак: низкая ошибка на обучающей выборке при существенно высокой ошибке на валидационной или тестовой. Например: обучающая MSE = 0.04, валидационная MSE = 0.47 — явный сигнал переобучения.

Компромисс смещения и дисперсии

Теоретически, ошибка модели на новых данных раскладывается на три компоненты:

Total Error = Bias² + Variance + Irreducible Noise
  • Смещение (Bias): систематическая ошибка — насколько среднее предсказание отличается от истинного значения. Высокое смещение → недообучение.
  • Дисперсия (Variance): чувствительность модели к изменениям обучающей выборки. Высокая дисперсия → переобучение.
  • Неустранимый шум: случайная ошибка, присущая данным.

Увеличение сложности модели снижает смещение, но повышает дисперсию. Уменьшение — наоборот. Цель — найти оптимальную точку.

Методы борьбы с переобучением

1. Увеличение объёма обучающих данных

Самый эффективный способ. Переобучение часто возникает, когда модель слишком сложна для имеющегося объёма данных. С ростом n дисперсия модели снижается пропорционально 1/n. К сожалению, получить больше данных не всегда возможно — тогда применяют регуляризацию и другие техники.

2. L2-регуляризация (Ridge)

Добавляет к функции потерь штраф за большие веса:

L(w) = MSE(w) + λ · Σ wᵢ²

Параметр λ контролирует интенсивность регуляризации. При больших λ веса стремятся к нулю, модель упрощается. Геометрически: L2-ограничение имеет форму гиперсферы — оптимум сдвигается к её поверхности, веса уменьшаются, но не обнуляются.

from sklearn.linear_model import Ridge

model = Ridge(alpha=1.0)  # alpha = λ
model.fit(X_train, y_train)
print(model.score(X_val, y_val))

3. L1-регуляризация (Lasso)

Штраф — сумма абсолютных значений весов:

L(w) = MSE(w) + λ · Σ |wᵢ|

Ключевое отличие от L2: L1 приводит к разреженным решениям. Часть весов становится ровно нулём — это эквивалентно автоматическому отбору признаков. Геометрически L1-ограничение — гиперромб с угловыми точками, совпадающими с осями координат.

Когда использовать Lasso: когда вы подозреваете, что многие признаки не информативны и хотите автоматически их исключить.

4. Elastic Net

Комбинирует L1 и L2:

L(w) = MSE(w) + λ₁ · Σ |wᵢ| + λ₂ · Σ wᵢ²

Сочетает разреженность Lasso с устойчивостью Ridge. Особенно эффективен при сильно коррелирующих признаках.

5. Дропаут (Dropout) — для нейронных сетей

Во время обучения случайно «выключает» нейроны с вероятностью p (обычно 0.2–0.5). Каждый шаг обучения работает с другой подсетью, что предотвращает совместную адаптацию нейронов.

import torch.nn as nn

model = nn.Sequential(
    nn.Linear(64, 128),
    nn.ReLU(),
    nn.Dropout(p=0.3),   # 30% нейронов выключаются
    nn.Linear(128, 10)
)

При инференсе все нейроны активны, их веса масштабируются на (1-p). Можно интерпретировать как ансамблирование экспоненциально большого числа подсетей.

6. Ранняя остановка (Early Stopping)

Мониторинг метрики на валидационной выборке в процессе обучения. Обучение прекращается, когда метрика не улучшается на протяжении patience эпох.

# PyTorch Lightning / ручная реализация
best_val_loss = float('inf')
patience_counter = 0
patience = 10

for epoch in range(max_epochs):
    train_model(epoch)
    val_loss = evaluate(val_loader)

    if val_loss < best_val_loss:
        best_val_loss = val_loss
        save_checkpoint()
        patience_counter = 0
    else:
        patience_counter += 1
        if patience_counter >= patience:
            print(f"Early stopping at epoch {epoch}")
            break

7. Кросс-валидация для диагностики

k-fold кросс-валидация позволяет получить надёжную оценку обобщающей способности. Если стандартное отклонение по фолдам велико — признак высокой дисперсии (переобучения).

from sklearn.model_selection import cross_val_score
import numpy as np

scores = cross_val_score(model, X, y, cv=5, scoring='neg_mse')
print(f"MSE: {-scores.mean():.3f} ± {scores.std():.3f}")

Как выбрать метод регуляризации

Практическое руководство по выбору:

  • Много нерелевантных признаков? → Lasso (L1) для автоматического отбора.
  • Признаки коррелируют между собой? → Ridge (L2) или Elastic Net.
  • Нейронные сети? → Dropout + Weight Decay (L2) + Early Stopping.
  • Деревья решений / Random Forest? → ограничение глубины дерева, min_samples_leaf, max_features.
  • Можно получить больше данных? → это приоритет перед регуляризацией.

Итог

Переобучение — не признак плохой модели. Это естественное следствие оптимизации на конечной выборке. Регуляризация — не «костыль», а фундаментальный инструмент, добавляющий к задаче оптимизации априорные знания о том, какими должны быть «хорошие» параметры. Понимание математики регуляризации — ключ к осознанному выбору метода под конкретную задачу.