Feature store и train/serve skew (B4)

Фаза 8 улучшала модель. Здесь — вопрос, от которого зависит, доедет ли улучшение до пользователя: откуда ранкер берёт фичи и те ли это фичи, на которых он учился. Утечка через время, протухание, расхождение обучения и сервинга — измерено на том же логе и том же протоколе, что D2b.

⚠ Секции 2–5 — реальный замер на Brightkite (готовый офлайн-артефакт, VPS видит только JSON). Секции 1 и 6 — живая синтетическая механика: джойн по времени и симулятор расхождения, считаются на лету, без весов и без сырых данных.

загрузка артефакта feature store…

Теория простым языком

Feature store — единственный модуль учебника, где инфраструктура важнее модели. Причина простая: когда офлайн-прирост не воспроизводится, объяснением часто оказывается не алгоритм, а то, что фича на обучении и фича на сервинге — разные величины с одним именем. Здесь мы этот механизм измеряем, а не пересказываем.

▸Зачем отдельный сервис фичей, если есть SQL и таблица
БылоДо сих пор фичи в проекте считались скриптом: агрегаты по логу, джойн к меткам, обучение (D2b, Фаза 8).
ПроблемаСкрипт не знает про время и про сервинг. Ему всё равно, что агрегат посчитан по всему логу (утечка), что онлайн ту же фичу считает другой код на другом языке (skew), что джоб пересчёта не отработал третьи сутки (staleness), и что фичу переименовали в апстриме (сломанный контракт).
ИдеяFeature store делает фичу версионированным объектом с временем: одно определение на офлайн и онлайн, as-of join по времени события, гарантии свежести, реестр и контракты. Тогда «те же фичи» — это проверяемое утверждение, а не надежда.
Стало лучшеЗамер на Brightkite: дырявая таблица фичей рисует +2.96 п.п. в отчёте, а в офлайн-replay с фичами на момент запроса остаётся +0.2 п.п., что по парному интервалу от нуля не отличается; протухание снимка на 30 дней стоит −1.45 п.п.; падение сервиса персональных фичей — −8.76 п.п. Все три проблемы существуют без единой строчки про модель.
Осталось слабымЭто дорогая инфраструктура: два хранилища (офлайн для обучения, онлайн key-value для низкой латентности), backfill истории, мониторинг, дежурство. На раннем этапе продукта аккуратный скрипт с честным as-of join решает 80% задачи, и начинать надо с него.
ДальшеB6 — re-rank поверх ранкера (квоты, eligibility, разнообразие), потом сборка полного capstone. В индустрии дальше: streaming-фичи, on-demand feature views, embedding store.

Четыре обязанности feature store

1. Point-in-time correctness. К каждому событию присоединяется значение фичи, известное на момент события, а не последнее известное. Это as-of join, и это не оптимизация — это определение корректности обучающей выборки. Условий на самом деле два, и второе забывают чаще: помимо feature.event_ts ≤ prediction_ts нужно ещё feature.available_at ≤ prediction_ts. Событие могло произойти во второй день, доехать до хранилища на пятый, а предсказание делаться на третий: время события в порядке, а фичи в тот момент не существовало — обучение снова увидит то, чего у сервинга не будет. Отдельно решается политика равенства: если снимок фичи с тем же таймстемпом уже включает само целевое событие, «≤» — это уже утечка, и граница должна быть строгой.
2. Train/serve consistency. Одно определение фичи, исполняемое обоими путями. Если офлайн считает pandas, а онлайн — руками написанный Java-код, расхождение вопрос времени, а не вероятности.
3. Freshness и SLA. У каждой фичи есть горизонт устаревания: у «визитов за полгода» он дни, у «товаров в корзине» — секунды. SLA задаётся замером деградации, а не вкусом.
4. Backfill и версионирование. Новая фича должна быть пересчитана вглубь истории по тем же правилам, иначе обучение увидит её только на свежем куске данных. Определение меняется — версия меняется: старая модель продолжает получать старую версию.

Утечка (leakage) — точное определение — Фича содержит информацию, недоступную в момент предсказания. Три источника: временная (агрегат посчитан по будущим событиям — наш случай), таргетная (в фиче сидит сам лейбл или его производная: «сумма покупки» для предсказания покупки), групповая (статистика посчитана по всей выборке, включая валидацию — так течёт target encoding без внутреннего фолда). Общее у всех трёх — не рост метрики, а невалидность оценки: обычно она завышена, но гарантии нет, утечка может и ухудшить качество, если уводит обучение в сторону сигнала, которого на сервинге не будет. Проверять стоит не «есть ли утечка вообще», а «мог ли этот признак быть вычислен в момент запроса».
Training-serving skew — Систематическое расхождение между фичами обучения и сервинга. Виды: разные единицы или нормализация, разные окна агрегации, разные значения по умолчанию для пропусков, разный порядок/имена колонок, разное время отсечки (батч vs запрос). Про инвариантность важно не ошибиться: ранжирование сохраняется при строго монотонном преобразовании итогового скора. Преобразование одной фичи внутри многопризнаковой модели таким свойством не обладает — оно меняет её баланс с остальными и может переставить кандидатов. В нашем замере часть искажений почти не сдвинула Recall@10 из-за конкретных весов, корреляций фичей и запаса по позиции таргета, а не из-за общего закона: те же искажения переписывают заметную часть состава топ-10, а в симуляторе аффинное преобразование одной фичи двигает и AUC. Поэтому skew ищут не метрикой качества, а мониторингом распределений фичей, доли дефолтов, доли значений вне диапазона и калибровки предсказаний.
Offline store / online store — Offline store — исторический слой (колоночное хранилище, партиционирование по времени): нужен для обучения и backfill, оптимизирован под большие сканы и as-of join. Online store — key-value (Redis/DynamoDB и подобные) с последним значением фичи на ключ: нужен для сервинга за единицы миллисекунд, читается по одному ключу. Одно определение фичи материализуется в оба. Отсюда и берутся две главные проблемы модуля: если материализация отстала — staleness; если реализации разошлись — skew. Отдельный класс — on-demand фичи (считаются в момент запроса из контекста: время суток, устройство, текущая сессия): их в online store нет, и именно они чаще всего расходятся с офлайном.

Как это связано с остальным учебником

Утечку через время мы уже ловили дважды: в валидации (random split против temporal) и в D2b (метаданные мест выводятся только из train). Разница в уровне: там протокол оценки, здесь — хранилище фичей, из-за чего одна и та же ошибка попадает сразу во все модели компании. Мониторинг расхождения фичей — прямое продолжение дашборда B7, а вывод «офлайн-дельта не заменяет онлайн-замер» — это Фаза 14. Это ступень 2 из 3 к полному capstone: дальше B6 re-rank constraints, потом сборка.

⚠️ Что может пойти не так

  • Джойнить фичи к меткам по ключу без условия на время — самая дорогая строчка SQL в индустрии: метрика вырастет, прод не заметит улучшения.
  • Считать «фича квазистатична, можно агрегировать по всему логу» — координата места и его типичный час выглядят статичными, но в наших замерах они тоже часть утечки.
  • Проверять утечку только метрикой: подозрительно высокое качество — сигнал, но слабый. Дешевле контракт на фичу и range-check (у нас 85.9% дырявых строк recency вышли за собственный диапазон).
  • Считать train/serve skew поймавшимся, если офлайн-метрика не просела: часть искажений её почти не двигает, а выдачу переписывают на десятки процентов.
  • Заполнять пропуск нулём «по умолчанию»: ноль — это значение, и модель прочитает его как утверждение о мире, а не как «неизвестно». Дефолт — часть контракта фичи, а не деталь реализации.
  • Строить стриминг фичей до того, как измерена кривая freshness: у наших фич сутки простоя стоят около десятой доли пункта recall — значит, вопрос решается кривой и ценой инфраструктуры, а не вкусом. Оговорка в обе стороны: сама цена батча и стриминга этим замером не считается.
  • Добавлять фичу без backfill: модель увидит её только на последнем куске истории и научится тому, что это «признак недавних событий».

🧠 Проверь себя: Ранкер выкатили, офлайн-метрики стабильны, жалоб нет. Через неделю выясняется, что онлайн-конверсия просела. Логи показывают: сервис персональных фичей отдаёт по таймауту 12% запросов, в этих случаях фичи заполняются нулями. Что здесь главная системная проблема?

Где это в дорожной карте

B4 — Feature Store & Training-Serving Skew, ступень 2 из 3 на пути к полному capstone (Фаза 8 → B4 → B6 → сборка). Измеренная часть — на реальном Brightkite по протоколу D2b; механика джойна и симулятор скью — синтетические и живые. Главный урок модуля: модель бывает хороша офлайн и плоха онлайн из-за фичей, а не из-за алгоритма.

Что дальше

До финальной сборки не хватает ещё 7 модулей по этому пути.

Порядок здесь — рекомендация из карты курса, ничего не блокируется. Отметка «прочитано» хранится только в этом браузере.

Источники