Обычно дрейф в GBDT ловят через PSI на предсказаниях или KS-тест на фичах. Но эти методы не видят внутреннюю структуру ансамбля — сдвиг в распределении leaf-эмбеддингов часто проявляется раньше, чем упадет качество или поплывут предсказания. Типичная ошибка: доверять только output-метрикам и пропускать фундаментальные изменения в том, как модель "читает" данные.
Идея: контрастивное обучение на leaf-эмбеддингах
Когда объект проходит через GBDT, каждый decision tree возвращает индекс листа. Собирая бинарные индикаторы (попал/не попал) по всем деревьям, получаем разреженный эмбеддинг размерности
num_trees * max_leaves. Контрастивное обучение (SimCLR или SupCon) проецирует эти векторы в dense латентное пространство. В проде средний эмбеддинг батча сравнивается с референсным — резкий рост расстояния сигнализирует о дрейфе. Пример кода:def get_leaf_embeddings(model, X):
leaf_idx = model.predict(X, pred_leaf=True)
emb = ...
return emb
def contrastive_loss(emb_pos, emb_neg, margin=1.0):
pos_dist = torch.sum((emb_pos - emb_neg)**2, dim=1)
loss = torch.mean(F.relu(pos_dist - margin))
return loss
# На проде:
mean_emb = get_leaf_embeddings(model, batch_X).mean(0)
drift_score = torch.dist(mean_emb_ref, mean_emb_new)
Преимущества для production
Во-первых, раннее обнаружение: leaf-структура меняется до того, как target поплывет — это дает время на reaction, например, переобучение или fallback-модель. Во-вторых, подход работает с любым GBDT (LightGBM, XGBoost, CatBoost) без доступа к таргету — достаточно признакового пространства. В-третьих, не нужна разметка: контрастивная пара формируется из аугментированных эмбеддингов того же батча, что утилизирует дрейф без ручного контроля.
Инженерные trade-offs и типичная ошибка
На практике возникает компромисс: latency vs sensitivity. В real-time инференсе батч из N объектов может не успеть пройти через embedder внутри decision path — требуется асинхронный пайплайн (например, ставить мониторинг на отдельном sidecar-процессе). Ошибка — использовать универсальный порог для разных моделей. Подбирать чувствительность нужно эмпирически на production-данных через validation на исторических дрифтах. Также не забывайте про data quality: если в батче 50% missing values, leaf-индексы исказятся, и эмбеддинг укажет на дрейф там, где его нет.
Практический совет
Для production внедрения используйте window-based мониторинг: считайте средний leaf-эмбеддинг на скользящем окне (например, 1000 объектов) и сравнивайте с эталонным, полученным на train-данных. В качестве метрики дрейфа берите cosine distance между эмбеддингами — она менее чувствительна к масштабу, чем L2. Если distance превышает 95-й перцентиль на baseline — запускайте alert. Это позволит не дожидаться, пока target упадет на 2%.
Вывод: Leaf-эмбеддинги с контрастивным обучением дают интерпретируемый, быстрый и независимый от target способ детекции дрейфа в GBDT, но требуют аккуратного подбора порога и учета latency в real-time пайплайнах.