Перейти к содержанию

Мониторинг дрифта данных

~8 минут чтения

Предварительно: Наблюдаемость LLM | Сравнение Experiment Tracking

Модели в production деградируют неизбежно. По данным Arize AI, 91% ML-моделей теряют качество в первый год после деплоя. Средний time-to-detect для data drift без мониторинга -- 3-6 месяцев, за которые бизнес-метрики могут просесть на 10-30%. PSI > 0.25 на ключевых фичах -- это сигнал к немедленному переобучению. Мониторинг дрифта -- не "nice-to-have", а обязательная часть MLOps pipeline.


Зачем нужен мониторинг дрифта

Модель обучена на данных из прошлого. Мир меняется -- данные тоже. Без мониторинга модель деградирует тихо: accuracy падает, но никто не замечает пока бизнес-метрики не проседают.

Ключевой инсайт: дрифт -- это не вопрос "если", а вопрос "когда". Каждая production модель столкнется с дрифтом.


1. Типы дрифта

Тип Что меняется Пример Как обнаружить
Data drift (covariate shift) \(P(X)\) -- распределение фичей После COVID средний чек вырос 3x Статистические тесты на фичах
Concept drift \(P(Y\|X)\) -- связь фичей с таргетом "Спам" раньше = нигерийские письма, теперь = фишинг через AI Мониторинг model performance
Label drift (prior probability shift) \(P(Y)\) -- распределение таргета Fraud rate вырос с 0.1% до 2% Мониторинг prediction distribution
Feature drift Отдельные фичи меняются Новый формат телефонных номеров Per-feature statistical tests

Data Drift vs Concept Drift

Data drift: входные данные изменились, но правила те же. Модель видит непривычные inputs.

Concept drift: правила изменились. Те же inputs -> другие правильные outputs. Это опаснее, потому что data distribution может выглядеть нормально.


2. Статистические тесты

Kolmogorov-Smirnov (KS) Test

Измеряет максимальное расстояние между двумя CDF (cumulative distribution functions).

\[D_{KS} = \sup_x |F_{ref}(x) - F_{prod}(x)|\]
  • Порог: p-value < 0.05 = дрифт обнаружен
  • Для: непрерывные фичи
  • Плюс: не требует бинаризации, чувствителен к любому типу различий
  • Минус: теряет мощность на малых выборках

Population Stability Index (PSI)

Стандарт в банковской сфере для мониторинга скоринговых моделей.

\[PSI = \sum_{i=1}^{n} (p_i - q_i) \cdot \ln\frac{p_i}{q_i}\]

где \(p_i\) -- доля наблюдений в бине \(i\) для production, \(q_i\) -- для reference.

PSI Интерпретация
< 0.1 Нет значимого дрифта
0.1 - 0.25 Умеренный дрифт, требует внимания
> 0.25 Значительный дрифт, модель нужно переобучить

Jensen-Shannon Divergence (JSD)

Симметричная версия KL-divergence. Диапазон \([0, 1]\) (при log base 2).

\[JSD(P \| Q) = \frac{1}{2} D_{KL}(P \| M) + \frac{1}{2} D_{KL}(Q \| M), \quad M = \frac{P + Q}{2}\]
  • Порог: > 0.1 -- подозрение, > 0.2 -- значимый дрифт
  • Для: любые распределения (дискретные и непрерывные)
  • Плюс: всегда определена (в отличие от KL, не делит на 0)

Comparison

Тест Тип фичей Чувствительность Интерпретируемость Скорость
KS Непрерывные Высокая Средняя Быстро
PSI Любые (бины) Средняя Высокая (пороги) Быстро
JSD Любые Высокая Средняя Быстро
Chi-squared Категориальные Высокая Высокая Быстро
Wasserstein Непрерывные Высокая Высокая (масштаб) Средне

PSI и KS тесты дают false positives на больших выборках

При N > 100K почти ЛЮБОЕ различие будет статистически значимым (p < 0.05). Тест показывает "дрифт", хотя разница 0.001 в среднем. Решение: используйте effect size (Wasserstein distance, PSI) вместо p-value. PSI < 0.1 = незначимо, даже если KS p-value = 0.0001. Для production систем: alert на PSI > 0.25, не на p-value.


3. Архитектура мониторинга

graph LR
    subgraph Production["Production Pipeline"]
        A[Model Predictions] --> B[Log Features + Predictions]
    end

    subgraph Monitor["Monitoring Layer"]
        B --> C[Compute Statistics]
        C --> D{Drift Detected?}
        D -->|PSI > 0.25| E[Alert]
        D -->|PSI < 0.1| F[OK]
        D -->|0.1-0.25| G[Watch]
    end

    subgraph Action["Response"]
        E --> H[Investigate Root Cause]
        H --> I[Retrain / Rollback]
    end

    style A fill:#e8eaf6,stroke:#3f51b5
    style D fill:#fff3e0,stroke:#ef6c00
    style E fill:#fce4ec,stroke:#c62828
    style F fill:#e8f5e9,stroke:#4caf50

Production Pipeline

from evidently.report import Report
from evidently.metric_preset import DataDriftPreset
import pandas as pd

def check_drift(reference_data: pd.DataFrame, production_data: pd.DataFrame) -> dict:
    """Check data drift between reference and production datasets."""
    report = Report(metrics=[DataDriftPreset()])
    report.run(
        reference_data=reference_data,
        current_data=production_data,
    )
    result = report.as_dict()

    drift_share = result["metrics"][0]["result"]["share_of_drifted_columns"]
    is_drift = drift_share > 0.3  # >30% columns drifted

    return {
        "drift_detected": is_drift,
        "drift_share": drift_share,
        "details": result["metrics"][0]["result"]["drift_by_columns"],
    }

Monitoring Schedule

Частота Когда использовать
Real-time Fraud detection, ad bidding -- цена ошибки высока
Hourly Recommendations, search ranking
Daily Credit scoring, content moderation
Weekly Long-term models, batch predictions

4. Инструменты

Tool Тип Drift Detection Сильные стороны Слабые стороны
Evidently Open-source KS, PSI, Wasserstein, JSD, Chi2 Гибкость, отчеты, интеграция с любым стеком Нет managed service
WhyLabs SaaS whylogs profiling + statistical tests Enterprise alerting, root cause analysis Коммерческий
Arize SaaS PSI, embedding drift Embedding monitoring, LLM-specific Коммерческий
NannyML Open-source CBPE (без ground truth) Оценка performance без labels Менее зрелый
Great Expectations Open-source Data validation (не drift) Data quality checks Не мониторинг, а валидация

Decision Framework

graph TD
    A[Нужен мониторинг дрифта] --> B{Бюджет?}
    B -->|Open-source| C{LLM/Embeddings?}
    B -->|Enterprise| D{Root Cause Analysis?}
    C -->|Да| E[NannyML + custom]
    C -->|Нет| F[Evidently]
    D -->|Критично| G[WhyLabs]
    D -->|Nice-to-have| H[Arize]

    style A fill:#e8eaf6,stroke:#3f51b5
    style F fill:#e8f5e9,stroke:#4caf50
    style G fill:#f3e5f5,stroke:#9c27b0
    style H fill:#fff3e0,stroke:#ef6c00

5. LLM-специфичный дрифт

Для LLM мониторинг дрифта отличается от табличных моделей:

Аспект Табличные модели LLM
Входы Числовые фичи Текст, промпты
Дрифт фичей PSI/KS на каждой фиче Embedding drift (cosine distance)
Output drift Prediction distribution Response length, topic shift, refusal rate
Ground truth Часто доступен Редко доступен

Embedding drift detection:

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def embedding_drift(ref_embeddings: np.ndarray, prod_embeddings: np.ndarray) -> float:
    """Compute drift as 1 - average cosine similarity between centroids."""
    ref_centroid = ref_embeddings.mean(axis=0, keepdims=True)
    prod_centroid = prod_embeddings.mean(axis=0, keepdims=True)
    sim = cosine_similarity(ref_centroid, prod_centroid)[0, 0]
    return 1.0 - sim  # 0 = no drift, 1 = max drift

6. Response Strategies

Стратегия Когда Сложность
Alert + investigate Любой drift Низкая
Fallback model Performance drop > threshold Средняя
Auto-retrain Scheduled + drift-triggered Высокая
Online learning Continuous stream, fast drift Очень высокая

Retrain Triggers

Trigger Описание Пример
Time-based Регулярное переобучение Каждую неделю
Performance-based Accuracy dropped > 5% AUC < 0.85
Drift-based PSI > 0.25 на >30% фичей Seasonal shift detected
Hybrid Time OR performance OR drift Best practice

Для интервью

Q: "Как вы мониторите data drift в production?"

Три уровня: (1) Feature-level: PSI на каждой фиче, alert при PSI > 0.25, watch при 0.1-0.25. Для категориальных -- Chi-squared. (2) Model-level: prediction distribution shift, confidence calibration. (3) Business-level: conversion rate, revenue per user. Инструмент: Evidently (open-source) для отчетов + custom alerts в Grafana.

Q: "Разница между data drift и concept drift?"

Data drift (\(P(X)\) изменился): входные данные другие, но правила те же. Пример: средний чек вырос после инфляции, но "дорогая покупка" по-прежнему > \(500. **Concept drift** (\)P(Y|X)$ изменился): правила изменились при тех же данных. Пример: покупка на $500 раньше была нормальной, теперь -- подозрительная. Concept drift опаснее: data distribution может выглядеть нормально.

Q: "PSI vs KS test -- когда какой?"

PSI для бизнес-репортинга: интерпретируемые пороги (< 0.1 / 0.1-0.25 / > 0.25), стандарт в банках. KS для исследования: non-parametric, чувствителен к любому типу различий, но на больших выборках (N > 100K) дает false positives. Рекомендация: PSI для alerting (effect size), KS для exploratory analysis (p-value + effect size).



Частые заблуждения

Заблуждение: обнаружили дрифт -- значит нужно срочно переобучать модель

Дрифт != деградация performance. Data drift (P(X) изменился) может не влиять на качество модели, если изменения в области, где модель уверена. Сначала проверьте business metrics и model performance. Если accuracy не упала -- достаточно увеличить частоту мониторинга. Переобучение без деградации -- это waste of compute и риск regression.

Заблуждение: concept drift можно поймать стандартными тестами на фичах

Concept drift (P(Y|X) изменился) коварен тем, что P(X) может остаться прежним. KS/PSI на фичах покажут "все ок", а модель уже ошибается. Единственный надежный способ обнаружить concept drift -- мониторить prediction performance с ground truth labels. Если labels недоступны в реальном времени -- используйте proxy (NannyML CBPE, confidence calibration, prediction distribution shift).

Заблуждение: для LLM достаточно мониторить embedding drift

Embedding drift (cosine distance между centroid'ами) ловит грубые изменения в распределении запросов, но пропускает тонкие: смену intent при похожей лексике, рост adversarial inputs, изменение длины и структуры промптов. Полноценный LLM-мониторинг включает: embedding drift + response length distribution + topic modeling + refusal rate + latency percentiles + user feedback signals.


Вопросы для собеседования

Вы видите PSI = 0.18 на важной фиче. Ваши действия?

❌ "PSI > 0.1, значит дрифт есть, переобучаем модель" -- преждевременная реакция без анализа impact.

✅ Сильный ответ: PSI 0.18 -- зона "watch" (0.1-0.25). Действия: (1) Проверить model performance metrics -- если accuracy/AUC не упали, дрифт может быть безвредным. (2) Визуализировать распределение фичи (reference vs production) -- понять характер изменения (сдвиг среднего? хвосты?). (3) Проверить другие фичи -- если дрифт только в одной, вероятно локальная аномалия. (4) Увеличить частоту мониторинга (daily -> hourly). (5) Установить alert на PSI > 0.25. Переобучение только если подтверждена деградация performance.

Как мониторить drift для LLM-приложения, где нет четких фичей?

❌ "Используем PSI на входном тексте" -- PSI не работает напрямую с текстом.

✅ Сильный ответ: Для LLM мониторинг многоуровневый: (1) Input drift -- embedding centroids (cosine distance > 0.1 = alert), topic distribution через lightweight classifier, средняя длина промпта. (2) Output drift -- response length distribution, refusal rate, confidence scores. (3) Behavioral drift -- latency P50/P99, token usage, tool call patterns. (4) Quality proxy -- user thumbs up/down ratio, regeneration rate, session abandonment. Инструменты: Arize для embedding drift, Langfuse для LLM-specific metrics, custom dashboards в Grafana.

Спроектируйте pipeline мониторинга для модели кредитного скоринга.

❌ "Запускаем Evidently раз в неделю" -- нет архитектуры, нет response strategy.

✅ Сильный ответ: Архитектура: (1) Data layer -- логируем features + predictions + timestamps в feature store. (2) Compute layer -- daily batch job: PSI на каждой фиче (reference = training data), prediction distribution (mean/std/percentiles), performance metrics (когда labels доступны, обычно 30-60 дней задержка). (3) Alert layer -- PSI > 0.25 на >30% фичей = P1 alert, PSI > 0.1 на >50% = P2. (4) Response -- auto-trigger retrain pipeline при P1; при P2 -- notify ML team + increase monitoring frequency. (5) Regulatory -- квартальный отчет о стабильности модели (PSI trend, performance trend). Tool: Evidently для compute, Grafana для dashboards, PagerDuty для alerts.


Sources

  1. Evidently AI -- "Data Drift Detection" documentation
  2. NannyML -- "Estimating Performance Without Ground Truth"
  3. Arize -- "Embedding Drift Monitoring for LLMs"
  4. Google -- "Monitoring Machine Learning Models in Production" (2022)
  5. scikit-multiflow -- "Concept Drift Detection Methods"

See Also