← Назад к вопросам
Что такое переобучение? Какие есть способы борьбы с ним?
2.0 Middle🔥 282 комментариев
#Машинное обучение
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Переобучение (Overfitting): диагностика и методы борьбы
Переобучение — это ситуация, когда модель слишком хорошо подгоняется к тренировочным данным и теряет способность обобщаться на новые данные. Модель запоминает частности тренировочного набора вместо того, чтобы изучать общие закономерности.
Признаки переобучения
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.model_selection import train_test_split
# Создание данных с истинной зависимостью + шум
np.random.seed(42)
X = np.linspace(0, 10, 50).reshape(-1, 1)
y_true = np.sin(X.ravel())
y = y_true + np.random.normal(0, 0.3, len(y_true)) # добавляем шум
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 1. Недообучение (Underfitting)
model_under = LinearRegression()
model_under.fit(X_train, y_train)
y_pred_train_under = model_under.predict(X_train)
y_pred_test_under = model_under.predict(X_test)
train_error_under = np.mean((y_train - y_pred_train_under)**2)
test_error_under = np.mean((y_test - y_pred_test_under)**2)
axes[0].scatter(X_train, y_train, alpha=0.5, label='Тренировка')
axes[0].scatter(X_test, y_test, alpha=0.5, label='Тест')
axes[0].plot(X, model_under.predict(X), 'r-', label='Модель', linewidth=2)
axes[0].set_title(f'UNDERFITTING\nTrain MSE={train_error_under:.3f}, Test MSE={test_error_under:.3f}')
axes[0].legend()
# 2. Хорошее обучение (Good Fit)
poly = PolynomialFeatures(degree=3)
X_train_poly = poly.fit_transform(X_train)
X_test_poly = poly.transform(X_test)
X_poly = poly.transform(X)
model_good = LinearRegression()
model_good.fit(X_train_poly, y_train)
y_pred_train_good = model_good.predict(X_train_poly)
y_pred_test_good = model_good.predict(X_test_poly)
train_error_good = np.mean((y_train - y_pred_train_good)**2)
test_error_good = np.mean((y_test - y_pred_test_good)**2)
axes[1].scatter(X_train, y_train, alpha=0.5, label='Тренировка')
axes[1].scatter(X_test, y_test, alpha=0.5, label='Тест')
X_sorted = np.sort(X, axis=0)
axes[1].plot(X_sorted, model_good.predict(poly.transform(X_sorted)), 'g-', label='Модель', linewidth=2)
axes[1].set_title(f'GOOD FIT\nTrain MSE={train_error_good:.3f}, Test MSE={test_error_good:.3f}')
axes[1].legend()
# 3. Переобучение (Overfitting)
poly_over = PolynomialFeatures(degree=15) # очень высокая степень!
X_train_poly_over = poly_over.fit_transform(X_train)
X_test_poly_over = poly_over.transform(X_test)
X_poly_over = poly_over.transform(X)
model_over = LinearRegression()
model_over.fit(X_train_poly_over, y_train)
y_pred_train_over = model_over.predict(X_train_poly_over)
y_pred_test_over = model_over.predict(X_test_poly_over)
train_error_over = np.mean((y_train - y_pred_train_over)**2)
test_error_over = np.mean((y_test - y_pred_test_over)**2)
axes[2].scatter(X_train, y_train, alpha=0.5, label='Тренировка')
axes[2].scatter(X_test, y_test, alpha=0.5, label='Тест')
X_sorted = np.sort(X, axis=0)
axes[2].plot(X_sorted, model_over.predict(poly_over.transform(X_sorted)), 'r-', label='Модель', linewidth=2)
axes[2].set_title(f'OVERFITTING\nTrain MSE={train_error_over:.3f}, Test MSE={test_error_over:.3f}')
axes[2].legend()
plt.tight_layout()
plt.show()
print("Анализ:")
print(f"Underfitting: Train ошибка большая, Test ошибка большая")
print(f"Good Fit: Train ошибка маленькая, Test ошибка маленькая (примерно равны)")
print(f"Overfitting: Train ошибка очень маленькая, Test ошибка БОЛЬШАЯ (gap!)")
print(f"\nГап между Train и Test:")
print(f" Underfitting: {test_error_under - train_error_under:.3f}")
print(f" Good Fit: {test_error_good - train_error_good:.3f}")
print(f" Overfitting: {test_error_over - train_error_over:.3f}")
Методы борьбы с переобучением
1. Regularization (Регуляризация)
from sklearn.linear_model import Ridge, Lasso, ElasticNet
# L2 регуляризация (Ridge)
model_ridge = Ridge(alpha=1.0) # alpha контролирует силу регуляризации
model_ridge.fit(X_train_poly_over, y_train)
# L1 регуляризация (Lasso)
model_lasso = Lasso(alpha=0.01)
model_lasso.fit(X_train_poly_over, y_train)
# ElasticNet (комбинация L1 и L2)
model_elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
model_elastic.fit(X_train_poly_over, y_train)
print("Регуляризация:")
print(f"OLS Train MSE: {np.mean((y_train - y_pred_train_over)**2):.4f}")
print(f"OLS Test MSE: {np.mean((y_test - y_pred_test_over)**2):.4f}")
print(f"Ridge Test MSE: {model_ridge.score(X_test_poly_over, y_test):.4f}")
print(f"Lasso Test MSE: {model_lasso.score(X_test_poly_over, y_test):.4f}")
2. Cross-Validation (Кросс-валидация)
from sklearn.model_selection import cross_val_score, KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
X_all = np.vstack([X_train, X_test])
y_all = np.concatenate([y_train, y_test])
# Трансформация для полиномиальной модели
poly = PolynomialFeatures(degree=15)
X_all_poly = poly.fit_transform(X_all)
scores = cross_val_score(
Ridge(alpha=1.0),
X_all_poly, y_all,
cv=kf,
scoring='neg_mean_squared_error'
)
print(f"CV MSE scores: {-scores}")
print(f"Mean CV MSE: {-scores.mean():.4f} (+/- {scores.std():.4f})")
3. Early Stopping (Ранняя остановка)
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
# Создание модели
model = Sequential([
Dense(64, activation='relu', input_shape=(X_train_poly_over.shape[1],)),
Dense(32, activation='relu'),
Dense(1)
])
model.compile(optimizer='adam', loss='mse')
# Early Stopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=10, # остановка, если val_loss не улучшается 10 эпох
restore_best_weights=True
)
history = model.fit(
X_train_poly_over, y_train,
validation_data=(X_test_poly_over, y_test),
epochs=100,
callbacks=[early_stop],
verbose=0
)
print(f"Обучение остановилось на эпохе {len(history.history['loss'])}")
print(f"Final Train Loss: {history.history['loss'][-1]:.4f}")
print(f"Final Val Loss: {history.history['val_loss'][-1]:.4f}")
4. Dropout (Выключение нейронов)
from tensorflow.keras.layers import Dropout
model_with_dropout = Sequential([
Dense(128, activation='relu', input_shape=(X_train_poly_over.shape[1],)),
Dropout(0.3), # выключаем 30% нейронов во время обучения
Dense(64, activation='relu'),
Dropout(0.2),
Dense(32, activation='relu'),
Dense(1)
])
model_with_dropout.compile(optimizer='adam', loss='mse')
model_with_dropout.fit(X_train_poly_over, y_train, epochs=50, verbose=0)
print(f"Model with Dropout Test MSE: {model_with_dropout.evaluate(X_test_poly_over, y_test)}")
5. Data Augmentation (Увеличение датасета)
from sklearn.utils import resample
# Создание синтетических примеров через бутстрэп
X_augmented = X_train.copy()
y_augmented = y_train.copy()
for _ in range(5): #增加 5 раз
indices = np.random.choice(len(X_train), size=len(X_train), replace=True)
X_augmented = np.vstack([X_augmented, X_train[indices]])
y_augmented = np.concatenate([y_augmented, y_train[indices]])
print(f"Original train size: {len(X_train)}")
print(f"Augmented train size: {len(X_augmented)}")
6. Feature Selection (Отбор признаков)
from sklearn.feature_selection import SelectKBest, f_regression
# Оставляем только самые важные признаки
selector = SelectKBest(score_func=f_regression, k=5)
X_train_selected = selector.fit_transform(X_train_poly_over, y_train)
X_test_selected = selector.transform(X_test_poly_over)
model_selected = Ridge(alpha=1.0)
model_selected.fit(X_train_selected, y_train)
print(f"Selected features MSE: {model_selected.score(X_test_selected, y_test):.4f}")
print(f"Number of features: {X_train_selected.shape[1]}")
7. Ensemble Methods (Ансамблевые методы)
from sklearn.ensemble import BaggingRegressor, RandomForestRegressor, GradientBoostingRegressor
# Bagging
model_bagging = BaggingRegressor(n_estimators=10, random_state=42)
model_bagging.fit(X_train_poly_over, y_train)
bagging_score = model_bagging.score(X_test_poly_over, y_test)
# Random Forest
model_rf = RandomForestRegressor(n_estimators=100, max_depth=5, random_state=42)
model_rf.fit(X_train[:, 0:1], y_train) # используем исходный X
rf_score = model_rf.score(X_test[:, 0:1], y_test)
# Gradient Boosting
model_gb = GradientBoostingRegressor(learning_rate=0.1, max_depth=3, random_state=42)
model_gb.fit(X_train[:, 0:1], y_train)
gb_score = model_gb.score(X_test[:, 0:1], y_test)
print(f"Bagging Score: {bagging_score:.4f}")
print(f"Random Forest Score: {rf_score:.4f}")
print(f"Gradient Boosting Score: {gb_score:.4f}")
Чеклист для диагностики переобучения
def check_overfitting(y_train, y_pred_train, y_test, y_pred_test):
from sklearn.metrics import mean_squared_error
train_mse = mean_squared_error(y_train, y_pred_train)
test_mse = mean_squared_error(y_test, y_pred_test)
gap = test_mse - train_mse
gap_ratio = test_mse / train_mse if train_mse > 0 else float('inf')
print(f"Train MSE: {train_mse:.4f}")
print(f"Test MSE: {test_mse:.4f}")
print(f"Gap: {gap:.4f}")
print(f"Test/Train Ratio: {gap_ratio:.2f}")
if gap < 0.01 and gap_ratio < 1.05:
print("\nВывод: Хорошее обучение (Good Fit)")
elif gap > 0.1 and gap_ratio > 1.5:
print("\nВывод: ПЕРЕОБУЧЕНИЕ (Overfitting)")
elif train_mse > 0.1 and test_mse > 0.1:
print("\nВывод: НЕДООБУЧЕНИЕ (Underfitting)")
else:
print("\nВывод: Модель в норме")
check_overfitting(y_train, y_pred_train_over, y_test, y_pred_test_over)
Практическая стратегия
print("СТРАТЕГИЯ БОРЬБЫ С ПЕРЕОБУЧЕНИЕМ:")
print("="*50)
print("\n1. ДИАГНОСТИКА:")
print(" - Строй learning curves (train vs val loss)")
print(" - Смотри гап между train и test ошибками")
print("\n2. ЕСЛИ ПЕРЕОБУЧЕНИЕ:")
print(" Сначала:")
print(" - Добавь больше тренировочных данных")
print(" - Упрости модель (уменьши количество параметров)")
print(" Потом:")
print(" - Добавь регуляризацию (L1/L2)")
print(" - Используй Dropout или Early Stopping")
print(" - Применяй ensemble методы")
print("\n3. ВАЖНО:")
print(" - Всегда используй отдельное test множество!")
print(" - Не подстраивай гиперпараметры на test")
print(" - Используй кросс-валидацию для надежной оценки")
Переобучение — одна из главных проблем в ML. Правильная диагностика и применение методов регуляризации — критические навыки для успешного построения моделей.