Машинное обучение
Кросс-валидация и борьба с переобучением
Модель показывала 99% accuracy при разработке, но в production accuracy рухнул до 60%. Причиной оказался не баг в коде - проблема была в том, как оценивалась модель. То, как вы измеряете качество модели, не менее важно, чем сама модель.
- **Подбор гиперпараметров** - Grid Search и Random Search используют cross-validation для оценки каждой комбинации параметров. Без CV подбор гиперпараметров превращается в подгонку под один конкретный split данных, и лучшие параметры окажутся не лучшими на новых данных
- **Медицинская диагностика** - при обучении модели на снимках пациентов Group K-Fold предотвращает data leakage между снимками одного человека. Без группировки модель "узнаёт" пациента, а не болезнь, и accuracy в CV завышается на 10-20% по сравнению с реальным
- **Обучение нейросетей** - Early Stopping используется практически в каждом training pipeline: от ResNet до BERT. Без него нейросеть с миллионами параметров неизбежно переобучается на training data, запоминая шум вместо паттернов
Предварительные знания
Как статистики научились переиспользовать одни и те же данные
Главная проблема кросс-валидации стара: как оценить модель на данных, когда каждый образец на вес золота и отдельный тестовый набор позволить себе нельзя? Идея откладывать часть данных и менять её ролями ходила ещё с 1930-х, но строгого обоснования не имела. Оно появилось в 1974 году, когда Мервин Стоун опубликовал работу 'Cross-Validatory Choice and Assessment of Statistical Predictions' в Journal of the Royal Statistical Society. Годом позже, в 1975, Сеймур Гайссер предложил свой метод повторного использования выборки для прогнозирования и обосновал применение одних и тех же данных и для обучения, и для честной оценки. Их работы превратили неформальный приём в принципиальную процедуру. Схема leave-one-out (LOOCV), где тестовым по очереди становится каждое отдельное наблюдение, это крайний случай их подхода. K-fold кросс-валидация, разбивающая данные на k частей с поочерёдной их ролью теста, стала практичным компромиссом: достаточно фолдов для устойчивой оценки и достаточно мало, чтобы держать затраты под контролем. Полвека спустя k-fold по-прежнему остаётся способом по умолчанию оценить, как модель поведёт себя на невиданных ранее данных.
K-Fold Cross-Validation
Самый распространённый способ оценки модели - разделить данные на train и test (holdout). Но у holdout есть серьёзная проблема: результат **сильно зависит от того, какие именно данные попали в test**. Один случайный split может дать accuracy 95%, а другой - 88%. Какой из них настоящий? Мы не знаем. Holdout на маленьких данных - как бросить монетку один раз и решить, честная она или нет. **K-Fold Cross-Validation** решает эту проблему: вместо одного разбиения делается K разбиений, и модель оценивается K раз.
Алгоритм K-Fold прост: данные делятся на K равных частей (folds). На каждой итерации одна часть становится валидационной, а остальные K-1 - обучающими. Модель обучается K раз, каждый раз на новом разбиении. Итоговая метрика - **среднее** по всем K итерациям. Стандартное отклонение показывает **стабильность** модели: если разброс большой, модель чувствительна к выбору данных.
**Выбор K: 5 или 10?** - **K=5** - стандартный выбор. Каждый fold содержит 20% данных. Хороший баланс между вычислительной стоимостью и надёжностью оценки. - **K=10** - чуть надёжнее, но в 2 раза дороже. Каждый fold содержит 10% данных, и обучение на 90% данных ближе к обучению на полном датасете. - **K=3** - экономный вариант для очень больших датасетов, где даже одно обучение занимает часы. Эмпирическое правило: K=5 для большинства задач, K=10 если данных мало (меньше 5000) и вычисления быстрые.
Почему K-Fold лучше holdout? Во-первых, **каждая точка данных участвует в валидации ровно один раз** - ни одна не теряется. Во-вторых, мы получаем не одно число, а **распределение оценок**, что позволяет оценить стабильность модели. В-третьих, среднее по K оценкам **менее шумное**, чем одна оценка на одном split. На практике cross-validation - стандарт индустрии для сравнения моделей и подбора гиперпараметров.
В 5-Fold Cross-Validation модель обучается 5 раз на разных разбиениях. Какой процент данных используется для обучения на каждой итерации?
Stratified и специальные виды
Обычный K-Fold делит данные случайно, не обращая внимания на распределение классов. Если в датасете 90% класса A и 10% класса B, случайное разбиение может создать fold, в котором класса B вообще нет. Модель обучится без примеров редкого класса и покажет нереалистичную метрику. **Stratified K-Fold** решает эту проблему: он гарантирует, что **пропорции классов в каждом fold совпадают с пропорциями во всём датасете**.
**Group K-Fold** - ещё одна важная вариация. Представьте медицинское исследование: у одного пациента может быть 10 снимков. Если часть снимков одного пациента попадёт в train, а часть - в test, модель может просто "узнать" пациента, а не научиться диагностике. Это называется **data leakage** - утечка данных между train и test. Group K-Fold гарантирует, что **все данные одной группы (пациента) целиком находятся в одном fold**.
**Time Series Split - особый случай:** Временные ряды нельзя перемешивать! Если модель при обучении "видит" данные из будущего, она будет показывать нереально хорошие метрики. TimeSeriesSplit соблюдает хронологический порядок: - Обучение всегда на **прошлых** данных - Валидация всегда на **будущих** данных - Обучающая выборка **растёт** с каждым fold Это единственный правильный способ cross-validation для прогнозирования цен, погоды, спроса и любых временных данных.
Частая ошибка новичков - применять StandardScaler или другую нормализацию **до** cross-validation. Если вы нормализуете весь датасет, а потом делите на folds, валидационный fold "знает" статистики обучающих данных (среднее, дисперсия). Это data leakage. Правильный подход: **Pipeline**, где нормализация происходит внутри каждого fold заново. sklearn делает это автоматически, если обернуть scaler и модель в Pipeline.
В медицинском датасете у каждого из 200 пациентов есть 5 снимков (1000 снимков всего). Вы используете обычный 5-Fold CV вместо Group K-Fold. Что произойдёт?
Leave-One-Out (LOO)
Leave-One-Out (LOO) - это крайний случай K-Fold, где **K = N** (количество образцов). На каждой итерации ровно один образец используется для валидации, а все остальные N-1 - для обучения. Если в датасете 500 точек, модель обучается 500 раз, каждый раз оставляя другую точку для проверки. LOO даёт **наименее смещённую оценку**: модель обучается почти на всех данных (N-1 из N), что максимально близко к обучению на полном датасете.
У LOO парадоксальное свойство: имея **наименьшее смещение** (bias), он одновременно имеет **наибольшую дисперсию** (variance) среди методов CV. Почему? Потому что обучающие выборки разных итераций перекрываются на N-2 из N-1 точек - они почти идентичны. Получаются N очень похожих моделей, и их предсказания сильно коррелируют. Среднее коррелированных оценок имеет высокую дисперсию, в отличие от среднего независимых оценок.
**Bias-Variance tradeoff в cross-validation:** - **LOO (K=N):** bias - минимальный (обучение на N-1 точках), variance - максимальная (оценки сильно коррелируют) - **10-Fold:** bias - чуть выше (обучение на 90% данных), variance - умеренная - **5-Fold:** bias - ещё выше (обучение на 80% данных), variance - наименьшая (folds более независимы) - **2-Fold:** bias - максимальный (обучение на 50%), variance - низкая На практике 5-Fold и 10-Fold дают лучший **общий** результат (MSE = bias^2 + variance), чем LOO. Поэтому LOO используется редко.
**Когда использовать LOO?** Только при очень маленьких датасетах (менее 50-100 образцов), где каждая точка на счету и потеря даже 20% на валидацию (при 5-Fold) существенна. В медицине, где данных мало и каждый образец стоит дорого, LOO встречается чаще. Для больших датасетов LOO непрактичен: N обучений модели при N=100000 - это неоправданно долго, а результат не лучше 5-Fold или 10-Fold.
Leave-One-Out даёт наименьшее смещение (bias) среди методов CV. Почему при этом его общая ошибка оценки может быть выше, чем у 5-Fold?
Early Stopping
Cross-validation помогает **оценить** модель, но не предотвращает переобучение во время обучения. **Early Stopping** - техника, которая решает именно эту задачу: мы мониторим validation loss на каждой эпохе обучения и **останавливаемся, когда loss перестаёт улучшаться**. Интуиция проста: в начале обучения модель учит полезные паттерны (train и val loss падают), но в какой-то момент начинает запоминать шум в обучающих данных (train loss падает, val loss растёт). Early Stopping ловит этот момент.
Ключевой параметр Early Stopping - **patience** (терпение): сколько эпох без улучшения мы готовы ждать. Маленький patience (2-3) может остановить обучение слишком рано, когда val loss временно поднялся, но потом продолжил бы падать. Большой patience (20-50) позволяет модели "пережить" временные подъёмы, но рискует переобучиться. На практике patience = 5-10 - хорошая отправная точка. Важно: после остановки мы **восстанавливаем веса лучшей эпохи** (restore best weights), а не используем последние.
**Early Stopping = скрытая регуляризация:** Early Stopping ограничивает сложность модели, не давая ей запомнить обучающие данные. Это эффект, аналогичный L2-регуляризации (weight decay): чем раньше мы останавливаемся, тем ближе веса к начальным (обычно маленьким) значениям, и тем проще модель. Преимущество перед L2: не нужно подбирать коэффициент регуляризации lambda. Вместо этого модель сама "находит" оптимальную сложность через момент остановки. Недостаток: требует выделить validation set из обучающих данных, что уменьшает объём данных для обучения.
На практике Cross-Validation и Early Stopping работают вместе: CV используется для **выбора гиперпараметров** (архитектура, learning rate, размер батча), а Early Stopping - для **определения количества эпох** в каждом fold. После выбора лучших гиперпараметров модель обучается на всех данных (кроме test set) с Early Stopping, и финальная оценка делается **один раз** на отложенном test set. Это стандартный pipeline, который защищает от переобучения на каждом уровне.
Cross-validation решает все проблемы оценки модели
CV может давать оптимистичные (завышенные) оценки при data leakage, temporal dependence или distribution shift между обучением и production
Если в данных есть утечка информации (например, признаки содержат целевую переменную в замаскированном виде), CV этого не обнаружит - все folds покажут высокую метрику. Если данные зависят от времени, а вы используете обычный K-Fold вместо TimeSeriesSplit, будущие данные утекут в обучение. Если распределение данных в production отличается от обучающего (distribution shift) - например, модель обучалась на пользователях из одной страны, а используется в другой - CV на обучающих данных не предскажет падение качества. Всегда проверяйте: нет ли утечки, сохраняется ли временной порядок, совпадает ли distribution обучения и применения.
При Early Stopping с patience=5 validation loss показал следующую динамику по эпохам: 0.50, 0.45, 0.42, 0.43, 0.44, 0.41, 0.39. На какой эпохе произойдёт остановка?
Итоги
- **K-Fold Cross-Validation:** данные делятся на K частей, модель обучается K раз - каждая часть по очереди становится валидационной. Среднее по K оценкам надёжнее одного holdout, а стандартное отклонение показывает стабильность модели. K=5 или K=10 - стандартный выбор
- **Специализированные виды CV:** Stratified K-Fold сохраняет пропорции классов, Group K-Fold предотвращает data leakage между группами (пациенты, пользователи), TimeSeriesSplit соблюдает хронологический порядок - выбор метода определяется структурой данных
- **LOO - крайний случай:** K=N даёт минимальное смещение (обучение на N-1 точках), но максимальную дисперсию из-за корреляции между folds. Практически полезен только для очень маленьких датасетов (менее 50 образцов)
- **Early Stopping + CV в production:** CV подбирает гиперпараметры, Early Stopping определяет количество эпох, а отложенный test set даёт финальную честную оценку - именно такой pipeline защитил бы модель из нашего примера от провала с 99% до 60%
Связанные темы
Cross-validation и Early Stopping - фундаментальные инструменты, которые связывают оценку модели с регуляризацией и подбором гиперпараметров:
- Метрики и оценка модели — Cross-validation вычисляет метрики (accuracy, F1, AUC) на каждом fold, давая надёжную оценку вместо одного числа. Без правильных метрик CV бесполезна: можно получить высокий accuracy при несбалансированных классах, упустив плохой recall на редком классе
- Подбор гиперпараметров — Grid Search, Random Search и Bayesian Optimization используют cross-validation как внутренний цикл оценки. Каждая комбинация гиперпараметров оценивается через K-Fold CV, и лучшая комбинация выбирается по средней метрике
Вопросы для размышления
- Почему применение StandardScaler до split на folds создаёт data leakage, даже если утечка кажется минимальной? Как это влияет на разницу между CV-оценкой и реальной production-метрикой?
- Если LOO имеет наименьшее смещение среди всех методов CV, почему на практике 5-Fold часто даёт более точную итоговую оценку? Как это связано с bias-variance tradeoff?
- Early Stopping называют "скрытой регуляризацией". Если у модели уже есть L2-регуляризация (weight decay), имеет ли смысл добавлять Early Stopping? Могут ли они мешать друг другу?
Связанные уроки
- ml-43-hyperparameters — CV даёт оценки для тюнинга
- ml-05-evaluation — CV агрегирует метрики оценки
- ml-08-regularization — CV выявляет и сдерживает переобучение
- stat-18-bootstrap — Оба ресемплируют для оценки обобщения
- stat-01-sampling — Фолды опираются на репрезентативную выборку
- stat-05-hypothesis