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

Что такое генерализация?

1.3 Junior🔥 21 комментариев
#Тестирование

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

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

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

Генерализация (Generalization)

Генерализация — это способность модели хорошо работать с новыми, не виданными ранее данными. В машинном обучении это означает, что модель не просто запомнила тренировочные данные, а научилась выявлять真правильные паттерны и закономерности.

Проблема: Переобучение vs Недообучение

Ошибка модели
      |
      |     ❌ Недообучение (Underfitting)
      |     /\ Модель слишком простая
      |    /  \
      |   /    \    ✅ Оптимальная генерализация
      |  /      \  /\
      | /        \/  \
      |            \  \   ❌ Переобучение (Overfitting)
      |             \ \  Модель заучила шум
      |________________\
      Сложность модели

Переобучение (Overfitting)

Проблема: Модель идеально работает на тренировочных данных, но плохо на новых данных.

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# Генерируем данные с шумом
X = np.random.randn(100, 1)
y = 2*X.squeeze() + np.random.randn(100) * 0.1  # y = 2x + шум

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# ❌ ПЕРЕОбучение: полином 10 степени
feat_overfit = PolynomialFeatures(degree=10)
X_train_poly_overfit = feat_overfit.fit_transform(X_train)
X_test_poly_overfit = feat_overfit.transform(X_test)

model_overfit = LinearRegression()
model_overfit.fit(X_train_poly_overfit, y_train)

train_error = mean_squared_error(y_train, model_overfit.predict(X_train_poly_overfit))
test_error = mean_squared_error(y_test, model_overfit.predict(X_test_poly_overfit))

print(f"Переобучение:")
print(f"  Train error: {train_error:.6f}")  # Очень маленькая
print(f"  Test error:  {test_error:.6f}")   # Очень большая (переобучение!)

# ✅ Хорошая генерализация: полином 2 степени
feat_good = PolynomialFeatures(degree=2)
X_train_poly_good = feat_good.fit_transform(X_train)
X_test_poly_good = feat_good.transform(X_test)

model_good = LinearRegression()
model_good.fit(X_train_poly_good, y_train)

train_error_good = mean_squared_error(y_train, model_good.predict(X_train_poly_good))
test_error_good = mean_squared_error(y_test, model_good.predict(X_test_poly_good))

print(f"\nХорошая генерализация:")
print(f"  Train error: {train_error_good:.6f}")  # Приемлема
print(f"  Test error:  {test_error_good:.6f}")   # Близка к train (хорошо!)

Недообучение (Underfitting)

Проблема: Модель слишком простая, плохо работает даже на тренировочных данных.

# ❌ НЕДООбучение: линейная модель для нелинейных данных
feat_underfit = PolynomialFeatures(degree=1)  # Просто линия
X_train_poly_underfit = feat_underfit.fit_transform(X_train)
X_test_poly_underfit = feat_underfit.transform(X_test)

model_underfit = LinearRegression()
model_underfit.fit(X_train_poly_underfit, y_train)

train_error_underfit = mean_squared_error(y_train, model_underfit.predict(X_train_poly_underfit))
test_error_underfit = mean_squared_error(y_test, model_underfit.predict(X_test_poly_underfit))

print(f"Недообучение:")
print(f"  Train error: {train_error_underfit:.3f}")  # Большая
print(f"  Test error:  {test_error_underfit:.3f}")   # Тоже большая
# Обе ошибки большие = недообучение

Стратегии улучшения генерализации

1. Регуляризация (Regularization)

from sklearn.linear_model import Ridge, Lasso

# Ridge (L2 регуляризация) — штраф за большие веса
model_ridge = Ridge(alpha=1.0)  # alpha контролирует силу регуляризации
model_ridge.fit(X_train_poly, y_train)

# Lasso (L1 регуляризация) — может обнулять веса (feature selection)
model_lasso = Lasso(alpha=0.1)
model_lasso.fit(X_train_poly, y_train)

# В глубоком обучении
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(128, activation='relu', 
                         kernel_regularizer=tf.keras.regularizers.l2(0.01)),  # L2
    tf.keras.layers.Dense(64, activation='relu',
                         kernel_regularizer=tf.keras.regularizers.l1(0.01)),  # L1
    tf.keras.layers.Dense(10, activation='softmax')
])

2. Dropout — случайно отключаем нейроны

import tensorflow as tf

# Dropout помогает от переобучения в глубоких сетях
model = tf.keras.Sequential([
    tf.keras.layers.Dense(256, activation='relu'),
    tf.keras.layers.Dropout(0.3),  # 30% нейронов отключаются
    
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.3),
    
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.2),  # Меньше на последних слоях
    
    tf.keras.layers.Dense(10, activation='softmax')
])

3. Early Stopping — останавливаемся когда переобучение начинается

import tensorflow as tf
from tensorflow.keras.callbacks import EarlyStopping

early_stop = EarlyStopping(
    monitor='val_loss',      # Мониторим validation loss
    patience=5,              # Если 5 эпох нет улучшения — стоп
    restore_best_weights=True  # Вернуть лучшие веса
)

model.fit(
    X_train, y_train,
    epochs=100,
    batch_size=32,
    validation_split=0.2,
    callbacks=[early_stop]  # Используем early stopping
)

4. Data Augmentation — увеличиваем данные

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# Для изображений
data_gen = ImageDataGenerator(
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True,
    zoom_range=0.2
)

# Генерирует вариации тренировочных изображений
data_gen.fit(X_train)
model.fit(data_gen.flow(X_train, y_train, batch_size=32))

# Для текста — синонимы, перефразировки

5. Cross-Validation — проверяем на разных подмножествах

from sklearn.model_selection import cross_val_score

# Разделяем данные на K частей (обычно K=5 или K=10)
# Тренируем K раз, каждый раз на K-1 частях, тестируем на 1
scores = cross_val_score(
    model, 
    X, y, 
    cv=5,  # 5-fold cross-validation
    scoring='accuracy'
)

print(f"Scores: {scores}")
print(f"Mean: {scores.mean():.4f} (+/- {scores.std():.4f})")

# Если scores сильно отличаются — плохая генерализация

6. Больше данных

# Самый простой способ — собрать больше данных
# Генерализация зависит от соотношения samples/parameters

size_of_dataset = 10000  # samples
model_parameters = 1000000  # weights

ratio = size_of_dataset / model_parameters
if ratio < 10:  # Слишком мало данных
    print("Нужно больше данных или проще модель")

Метрики генерализации

import matplotlib.pyplot as plt

# Правильный способ: separate test set
# 60% train, 20% validation, 20% test

from sklearn.model_selection import train_test_split

X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)

# Validation set для выбора гиперпараметров
# Test set для финальной оценки (никогда не трогаем до конца)

model.fit(X_train, y_train, epochs=50, validation_data=(X_val, y_val))

# Финальная оценка
test_accuracy = model.evaluate(X_test, y_test)

Кривые обучения (Learning Curves)

def plot_learning_curves(X_train, y_train, X_val, y_val, model):
    train_sizes = [100, 500, 1000, 5000, 10000]
    train_scores = []
    val_scores = []
    
    for size in train_sizes:
        model.fit(X_train[:size], y_train[:size], epochs=10, verbose=0)
        train_scores.append(model.evaluate(X_train[:size], y_train[:size]))
        val_scores.append(model.evaluate(X_val, y_val))
    
    plt.plot(train_sizes, train_scores, label='Train')
    plt.plot(train_sizes, val_scores, label='Validation')
    plt.legend()
    plt.xlabel('Training Set Size')
    plt.ylabel('Accuracy')
    plt.title('Learning Curves')
    
    # Если кривые далеко — переобучение
    # Если обе высокие и близко — хорошая генерализация
    # Если обе низко — недообучение

Правила большого пальца

Хорошая генерализация:

  • Train и Validation loss близки
  • Loss падает на обоих
  • Accuracy > 85% на test set
  • Кривые обучения плоские

Переобучение:

  • Train loss << Validation loss
  • Validation loss начинает расти
  • Train accuracy 99%, test accuracy 70%
  • Большой gap между кривыми

Недообучение:

  • Обе ошибки большие
  • Loss не падает
  • Accuracy < 50% даже на train

Итоги

Генерализация — это главная цель машинного обучения. Модель оценивают не на тренировочных данных, а на новых.

Улучшить генерализацию можно:

  1. Регуляризацией (L1/L2, Dropout)
  2. Early Stopping
  3. Правильным разделением данных
  4. Data Augmentation
  5. Crossvalidation
  6. Больше данных
  7. Проще модель

Когда вы видите идеальные результаты на train и плохие на test — это первый знак что моделью что-то не так.

Что такое генерализация? | PrepBro