Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Генерализация (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
Итоги
Генерализация — это главная цель машинного обучения. Модель оценивают не на тренировочных данных, а на новых.
Улучшить генерализацию можно:
- Регуляризацией (L1/L2, Dropout)
- Early Stopping
- Правильным разделением данных
- Data Augmentation
- Crossvalidation
- Больше данных
- Проще модель
Когда вы видите идеальные результаты на train и плохие на test — это первый знак что моделью что-то не так.