Переобучение: триггеры и человек в цикле
Переобучение замыкает жизненный цикл — вопрос лишь в том, что его запускает и кто принимает решение.
Переобучение (retraining) — обновление модели на свежих данных; запускается по триггеру (расписание, дрейф, падение качества) и завершается решением выкатить новую версию.
Зачем переобучать
Мир меняется, и зафиксированная модель устаревает (дрейф, концепт-дрейф). Переобучение возвращает качество, перестраивая модель на актуальных данных. Это последний этап цикла, который снова замыкает его на «данные». Главные вопросы: когда переобучать и кто решает выкатывать.
Три типа триггеров
| Триггер | Суть | Минус |
| По расписанию | раз в день/неделю/месяц | тратит ресурсы зря, если ничего не менялось; запаздывает при резком сдвиге |
| По дрейфу | PSI/KS превысил порог | дрейф входов ≠ всегда падение качества |
| По качеству | онлайн-метрика просела | метки запаздывают, реакция позже |
На практике триггеры комбинируют: например, проверка дрейфа ежедневно по расписанию, а решение о переобучении — при пробитии порога качества или сильном дрейфе.
Логика триггера своими руками
Смоделируем монитор, который решает, пора ли переобучать, по двум условиям.
def need_retrain(psi, f1_now, f1_baseline, psi_th=0.25, drop_th=0.03):
drift = psi > psi_th
quality_drop = (f1_baseline - f1_now) > drop_th
reasons = []
if drift:
reasons.append(f"дрейф PSI={psi:.2f}>{psi_th}")
if quality_drop:
reasons.append(f"падение f1 на {(f1_baseline-f1_now):.2f}")
return (drift or quality_drop), reasons
cases = [
(0.05, 0.91, 0.92), # всё хорошо
(0.30, 0.90, 0.92), # сильный дрейф
(0.08, 0.86, 0.92), # упало качество
]
for psi, now, base in cases:
fire, why = need_retrain(psi, now, base)
verdict = "ПЕРЕОБУЧИТЬ " + "; ".join(why) if fire else "ок"
print(f"PSI={psi:.2f} f1={now:.2f} (base {base:.2f}) -> {verdict}")
Вывод:
PSI=0.05 f1=0.91 (base 0.92) -> ок PSI=0.30 f1=0.90 (base 0.92) -> ПЕРЕОБУЧИТЬ дрейф PSI=0.30>0.25 PSI=0.08 f1=0.86 (base 0.92) -> ПЕРЕОБУЧИТЬ падение f1 на 0.06
Человек в цикле (human-in-the-loop)
Даже на высоком уровне зрелости решение «выкатить переобученную модель» часто оставляют человеку. Автоматика готовит кандидата, прогоняет гейт качества, но финальный promote в Production делает инженер — особенно там, где цена ошибки высока (медицина, финансы, право). Это страховка от автоматического выезда плохой модели и от обучения на отравленных/аномальных данных.
триггер --> авто-переобучение --> гейт качества --> кандидат
|
человек: review + approve --+--> promote -> Production
|
reject -+--> разобраться
Полностью автоматическое переобучение
В зрелых системах с низкой ценой ошибки и хорошим мониторингом цикл замыкают полностью: триггер → переобучение → гейт → канарейка → авто-promote, человек лишь наблюдает дашборды. Это уровень 1–2 зрелости. Но даже здесь оставляют аварийный rollback и алерты.
Как работает под капотом
Монитор дрейфа/качества (из прошлой секции) при срабатывании триггера дёргает оркестратор (Airflow/Kubeflow), который запускает пайплайн обучения на свежей версии данных, прогоняет тесты данных и модели, регистрирует кандидата в реестре со стадией Staging. Дальше либо человек, либо автоматика (по гейту) переводит его в Production через канарейку. Весь путь логируется как lineage: какой триггер, на каких данных, какие метрики.
Частые ошибки
- Только расписание. Переобучение по календарю запаздывает при резком сдвиге и жжёт ресурсы, когда ничего не менялось.
- Авто-promote без гейта. Плохой кандидат уедет в прод; всегда нужен порог качества.
- Учиться на отравленных данных. Без валидации входных данных переобучение закрепит аномалию.
- Убирать человека там, где цена ошибки высока. В чувствительных доменах human-in-the-loop обязателен.
Итог
- Переобучение запускают триггеры: расписание, дрейф, падение качества — обычно их комбинируют.
- Кандидат всегда проходит гейт качества; решение о promote может принимать человек (human-in-the-loop) или автоматика.
- Чем выше цена ошибки, тем важнее человек в цикле и аварийный rollback; всё фиксируется как lineage.