Всем привет, меня зовут Сергей Прощаев и в этой статье расскажу про то, что произошло с табличными данными летом 2026 года: появилась модель, которая делает предсказание по таблице вообще без обучения, и первые же замеры показали, что она обходит настроенный градиентный бустинг.
Я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech & E‑commerce, преподаю на курсах разработки и архитектуры в ОТУС. Сразу оговорюсь: я не датасаентист. Но в одном проекте я довольно близко наблюдал за жизнью скоринговой модели на CatBoost — со стороны сервисов, которые её дёргают, и команды, которая держит всё это в проде. И когда мне в рабочий чат прислали ссылку с заголовком в духе «XGBoost всё, приехали», я отреагировал не «ух ты», а «и кто теперь будет это переписывать».
Помню, как коллеги полгода вылизывали пайплайн вокруг той модели: фичи, ретрейн по расписанию, версионирование, мониторинг дрейфа, откат на предыдущую версию за две минуты. Всё это построено вокруг одного допущения — модель нужно обучать на своих данных. Если допущение ломается, ломается половина архитектуры вокруг.
Поэтому я потратил несколько вечеров и разобрался. Сразу честно: своего прогона у меня нет, свободной видеокарты под рукой не оказалось. Поэтому я делал другое — перепроверял, что именно заявлено, кто это уже воспроизвёл независимо и где заканчиваются доказательства.
Ниже: что выпустили, где цифры честные, а где сравнение подкручено самой постановкой эксперимента, и что с этим делать бэкендеру, у которого табличная модель стоит в критическом пути.

Почему деревья держались пятнадцать лет
Табличные данные — это последний рубеж, который глубокое обучение не забрало. Текст, картинки, звук, видео — везде фундаментальные модели победили. А в базах данных, где лежит основная масса корпоративных данных, продолжали выигрывать XGBoost, LightGBM и CatBoost.
Причины известны и вполне инженерные: разнотипные колонки, пропуски, категориальные признаки, маленькие выборки и чувствительность к мусорным фичам. Деревья со всем этим справляются из коробки. Каждые год‑два появлялся очередной нейросетевой подход, который «побеждал бустинг», практики находили изъян в постановке сравнения, и бустинг оставался на месте.
Цена этого господства — бесконечный цикл: инженерия признаков, перебор гиперпараметров, переобучение под каждый новый датасет. На том скоринге, о котором я говорю, это буквально отдельный сервис с расписанием.
Мне как‑то попалась оценка, что львиная доля времени в табличном проекте уходит не на модель, а на подготовку данных и подбор. Похоже на правду, только я бы добавил туда ещё одну статью расходов, о которой обычно не пишут.
Сценарий, который узнает любой, кто сопровождал модель в проде: после очередного ретрейна качество проседает на одном конкретном сегменте, и команда неделями ищет причину в гиперпараметрах. А причина — в источнике: поменялся справочник, категориальная колонка тихо переехала в другой домен значений, и обучение прошло на слегка другом мире, чем инференс. Ни один перебор параметров от этого не спасает. Спасает контур вокруг модели — и вот его как раз строить дольше всего.
Что выпустили 30 июня
TabFM от Google Research — модель, которая читает таблицу как единый контекст: обучающие строки и строки, для которых нужен прогноз, подаются вместе, и результат возвращается за один проход через замороженные веса. Позиционируется как табличный родственник TimesFM, который до этого сделал то же самое для временных рядов.
Отдельно стоит отметить, на чём модель предобучали: на сотнях миллионов синтетических датасетов, сгенерированных структурными причинными моделями. Реальных корпоративных таблиц в обучении нет — и это осознанный выбор, потому что разнообразных открытых табличных данных мало, а с реальными промышленными сразу приходят вопросы приватности и лицензий. Держите эту деталь в голове, к ней придётся вернуться.
Ключевая деталь, на которой я застрял минут на десять: вызов
fit()здесь ничего не обучает. Он сохраняет контекст.
# (Python) from tabfm import TabFMClassifier, tabfm_v1_0_0_pytorch as tabfm_v1_0_0 model = tabfm_v1_0_0.load() # веса тянутся с Hugging Face clf = TabFMClassifier(model=model) clf.fit(X_train, y_train) # градиентного спуска не происходит, # данные просто кладутся в контекст preds = clf.predict(X_test) # один forward pass, веса заморожены
API совместим со scikit‑learn — то есть с точки зрения человека, который встраивает это в сервис, интерфейс не отличается от привычного. Внутри механика другая: чередующиеся слои внимания по строкам и по столбцам, сжатие строки в вектор через CLS‑токены, а поверх — причинный трансформер, для которого ваши обучающие строки работают как промпт.
И вот здесь две вещи, которые я бы выяснил до того, как показывать демо коллегам.
Первая — установка. Пакет, лежащий на PyPI, не умеет подгружать выпущенные веса, ставить нужно из репозитория. Мелочь, но полдня можно потерять на ровном месте.
Вторая важнее и в обзорах почти не встречается. У scikit‑learn‑обёрток есть параметры
max_num_features и max_num_rows, и по умолчанию это 500 признаков и сто строк контекста. Если таблица больше, модель не проглатывает её целиком — она работает с выборкой. То есть фраза «читает всю вашу таблицу» верна только до определённого размера, а дальше начинается сэмплирование, о котором надо знать заранее, иначе объяснить разброс результатов будет нечем.
Идея не с нуля. Линия тянется от TabPFN (2022), который первым показал, что таблицу можно решать через in‑context learning: модель предобучают на синтетических таблицах, а не на ваших. Дальше были TabPFN v2, TabICL, CARTE, версия TabPFN-2.5, которая дотянулась примерно до ста тысяч строк и двух тысяч признаков. TabFM — следующий шаг в этой линии, а не гром среди ясного неба.
Чтобы разница в пайплайнах была наглядной, посмотрите на Рис. 2. Слева — то, как устроено большинство табличных проектов сегодня, справа — то, что предлагает подход foundation‑модели.

Что стоит вынести из этой схемы: исчезает обучение на вашем конкретном датасете, а не обучение вообще — сама модель обучалась долго и дорого, просто не на ваших данных. И контур сопровождения тоже никуда не девается: мониторинг качества, отслеживание дрейфа, воспроизводимость решений остаются. Меняется его характер. Вместо версионирования артефактов модели появляется версионирование контекста, и это отдельная задача, которую пока никто толком не решил.
Что заявлено и где заканчиваются доказательства
Модель проверяли на TabArena — это 51 датасет, из них 38 на классификацию и 13 на регрессию, размером примерно от семисот до ста пятидесяти тысяч строк. В режиме одного прохода без всякого перебора гиперпараметров TabFM обходит тщательно настроенные базовые модели, включая градиентный бустинг. Есть и вторая конфигурация — ансамбль из 32 прогонов с кросс‑признаками, SVD‑признаками и блендингом через неотрицательный МНК. У ансамбля цифры, разумеется, лучше.
И вот здесь у меня как у человека, который много раз видел презентации в жанре «наш продукт быстрее конкурента», сработал рефлекс. Сравнение «zero‑shot без настройки против настроенного XGBoost» звучит красиво, но за XGBoost стоят годы накопленного фольклора по подбору гиперпараметров именно под публичные бенчмарки.
Я бы вообще поменял постановку вопроса. Спрашивать «какая модель лучше» — незрелая формулировка, потому что ответ всегда зависит от того, сколько вы готовы потратить.
Правильная формулировка — качество как функция от бюджета: при пятнадцати минутах на задачу выигрывает одно, при восьми часах подбора — другое, а при неделе инженерии признаков картина может перевернуться ещё раз. Именно такую кривую я бы хотел видеть в релизах, и именно её приходится строить самому.
Теперь чего в публикации нет. Попарных цифр против XGBoost, CatBoost и более ранних табличных foundation‑моделей там не приводится: заявлена конкурентоспособность на бенчмарке в целом, а разбивки «на этом датасете столько, на том столько» относительно конкретных базовых моделей публика не получила.
Второй пробел серьёзнее — нет проверки на грязных корпоративных таблицах: дрейф распределения, редкие категориальные значения, утечки таргета. То есть ровно на том, что решает судьбу табличной модели в реальном сервисе.
Здесь надо отдать должное: Google об этом честно предупреждает, просто не в той части материалов, которую все читают. В карточке модели прямо написано, что обучение шло целиком на синтетике, что поведение на конкретных реальных доменах и на малых группах не охарактеризовано и что перед применением в ответственных сценариях нужно проверять модель на своей отложенной выборке. Проблема не в том, что кто‑то что‑то скрыл. Проблема в том, что до этой оговорки доходит примерно никто, а до заголовка «обошла настроенный XGBoost» — все.
Вспомните, на чём модель предобучали. Сотни миллионов синтетических таблиц из структурных причинных моделей — это красивая и чистая вселенная. Реальная таблица со скорингом красивой не бывает никогда: там есть колонка, которую пять лет назад завели «временно», и три значения статуса, означающие одно и то же. Между «конкурентоспособна на TabArena» и «работает у вас» лежит именно этот зазор, и его никто пока не измерил.
История, ради которой стоило копать
Мне попался разбор Yash Raj Pandey, который сделал ровно то, чего я жду от инженера: попытался сломать чужой результат, а когда не сломал — зафиксировал, где именно улучшил.
Он прогнал TabFM независимо, на трёх машинах. На малых и средних таблицах модель действительно обошла корректно настроенный через Optuna XGBoost на всех десяти сопоставленных по фолдам датасетах. На опорном наборе разрыв под тюнингом даже вырос: 0,877 против 0,821 по точности. Казалось бы, всё, расходимся.
Но дальше начинается то, что отличает замер от рекламы. Автор прогнал всё на нескольких сидах и сам понизил две собственные «победы» до ничьих — отрыв оказался меньше шума измерений. Вот эта дисциплина закрывает целый класс красивых бенчмарков, где метод выглядит хорошо только потому, что тихо пропустил тяжёлые фолды.
Дальше — сюжет, знакомый любому, кто выкатывал что‑то на GPU. Заявленные 22,75 ГБ видеопамяти оказались в основном артефактом аллокатора XLA: реальный расход около 16,95 ГБ, а отключение преаллокации примерно удвоило рабочий контекст, с десяти тысяч строк до двадцати. После того как в репозитории включили bf16 и чанкинг активаций, бэкенд на PyTorch стал держать 3–7 ГБ вместо фиксированных семнадцати у JAX, вмещать сорок тысяч строк там, где JAX падал по памяти на двадцати, и работать в два‑четыре раза быстрее на большом контексте. Попутно нашёлся баг, роняющий predict на любой машине с двумя и более GPU.
Могу себе представить, как выглядел бы такой инцидент: команда берёт первую версию, верит в 22,75 ГБ, закладывает инстанс под неё, а потом полдня ищет, почему на двухкарточной ноде всё падает. Это не гипотетика, это обычный вторник.
Как проверить за вечер: протокол
Минимальный каркас для честного сравнения выглядит так. Ключевое здесь не модель, а условия замера:
# (Python) import numpy as np import optuna from catboost import CatBoostClassifier from sklearn.model_selection import StratifiedKFold from sklearn.metrics import roc_auc_score SEEDS = [0, 1, 2, 3, 4] # без нескольких сидов результат не считается BUDGET_SECONDS = 900 # одинаковый бюджет на подбор для обеих сторон CAT_FEATURES = ["region", "product", "channel"] # фиксируем явно, не угадываем def evaluate(make_model, X, y): scores = [] for seed in SEEDS: cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed) for train_idx, test_idx in cv.split(X, y): X_tr, X_te = X.iloc[train_idx], X.iloc[test_idx] y_tr, y_te = y.iloc[train_idx], y.iloc[test_idx] model = make_model(seed, BUDGET_SECONDS, X_tr, y_tr) proba = model.predict_proba(X_te)[:, 1] scores.append(roc_auc_score(y_te, proba)) return np.mean(scores), np.std(scores) def make_boosting(seed, budget, X_tr, y_tr): # весь бюджет уходит в подбор; сид фиксируется и в сэмплере, и в модели def objective(trial): params = { "depth": trial.suggest_int("depth", 4, 10), "learning_rate": trial.suggest_float("learning_rate", 0.01, 0.3, log=True), "l2_leaf_reg": trial.suggest_float("l2_leaf_reg", 1.0, 10.0, log=True), } inner = StratifiedKFold(n_splits=3, shuffle=True, random_state=seed) folds = [] for tr, va in inner.split(X_tr, y_tr): m = CatBoostClassifier(**params, iterations=2000, random_seed=seed, cat_features=CAT_FEATURES, verbose=0) m.fit(X_tr.iloc[tr], y_tr.iloc[tr], eval_set=(X_tr.iloc[va], y_tr.iloc[va]), early_stopping_rounds=100) # иначе бюджет уйдёт в шум folds.append(roc_auc_score(y_tr.iloc[va], m.predict_proba(X_tr.iloc[va])[:, 1])) trial.set_user_attr("best_iteration", m.get_best_iteration()) return float(np.mean(folds)) study = optuna.create_study(direction="maximize", sampler=optuna.samplers.TPESampler(seed=seed)) study.optimize(objective, timeout=budget) best_iters = study.best_trial.user_attrs["best_iteration"] model = CatBoostClassifier(**study.best_params, iterations=best_iters, random_seed=seed, cat_features=CAT_FEATURES, verbose=0) model.fit(X_tr, y_tr) return model def make_tabfm(seed, budget, X_tr, y_tr): # подбирать нечего; проверьте лимит контекста, иначе строки будут сэмплированы from tabfm import TabFMClassifier, tabfm_v1_0_0_pytorch as tabfm_v1_0_0 clf = TabFMClassifier(model=tabfm_v1_0_0.load(), max_num_rows=len(X_tr)) clf.fit(X_tr, y_tr) return clf
Обратите внимание на две детали.
Первая:
BUDGET_SECONDSуходит в обе стороны и там, где есть что подбирать, реально тратится на подбор. Без этого весь эксперимент превращается в демонстрацию, а не в замер.Вторая:
max_num_rowsвыставлен явно. Оставите по умолчанию — сравните настроенный бустинг на всех данных со ста строками контекста и сделаете неверный вывод.
Результаты имеет смысл сводить в такую форму, иначе через неделю сами не вспомните, при каких условиях получили цифру:
Колонка | Что записываем |
|---|---|
Модель и версия | CatBoost 1.2.x / TabFM 1.0.0, бэкенд PyTorch или JAX |
Режим данных | число строк, доля категориальных признаков, число классов |
Размер контекста | сколько строк реально ушло в модель, а не сколько было в таблице |
Метрика | среднее и стандартное отклонение по всем сидам, не одно число |
Бюджет | одинаковые секунды на обе стороны, зафиксировать явно |
Память и железо | пиковая на GPU замеренная, модель карты, версия CUDA, число карт |
Последние строки не формальность. Судя по опыту тех, кто уже прогонял, основная возня оказывается не в качестве, а в окружении: версии драйверов, поведение аллокатора, поддержка нескольких карт. Качество меряется за час, инфраструктура — за неделю.
Мой вариант, который я обычно использую в таких проверках: сначала прогнать на заведомо маленьком куске данных и убедиться, что вся связка вообще стартует на конкретной машине, и только потом запускать полноценный замер. Иначе есть шанс узнать про баг с двумя картами через три часа ожидания.
Где вывод переворачивается
Теперь важное, что теряется в заголовках. Преимущество foundation‑моделей не универсально — оно зависит от режима данных.
В опубликованных независимых прогонах по девятнадцати датасетам картина такая: на крупных числовых наборах XGBoost и TabICL показали результат лучше, на малых выборках впереди оказались foundation‑модели, а на смешанных данных разрыв в их пользу был шире всего.
Оговорюсь: это результаты конкретных замеров, а не установленный закон природы. Но объяснение выглядит логично — предобученные априорные представления ценны, когда своих данных мало; когда данных много, бустинг выучивает взаимодействия признаков напрямую и обходится без чужих априори.
Отдельно держу в голове, что TabArena — бенчмарк, к которому причастны исследователи из той же лаборатории, что делала TabPFN. Ничего криминального, но независимый бенчмарк и собственный холдаут никто не отменял.
Жёсткие ограничения текущего релиза, которые надо знать до того, как трогать прод:
потолок в 10 классов на классификации — это архитектурное ограничение, а не настройка;
около 500 признаков, на более широких таблицах поведение деградирует;
память растёт вместе с числом строк контекста, а контекст — это ваши данные;
код под Apache 2.0, а веса — под некоммерческой лицензией.
Последний пункт для продуктовой команды означает ровно одно: в текущем виде это инструмент для прототипов и исследований, а не для сервиса, который зарабатывает деньги.
И три вещи, которые я бы проговорил с командой ещё до пилота.
Латентность. Показательный замер: на одном небольшом датасете все модели дали одинаковую стопроцентную точность, но XGBoost отработал за 0,4 секунды, а TabFM — за 49,2 секунды на процессоре и 3,6 секунды на видеокарте. Бустинг на CPU оказался в девять раз быстрее, чем foundation‑модель на GPU. Датасет там учебный, и на других объёмах соотношение будет другим — но порядок величины показателен: в синхронном сценарии одобрения заявки это не абстракция, а SLA, и GPU в критическом пути придётся резервировать.
Объяснимость. У бустинга есть привычные инструменты разбора вклада признаков, и когда служба качества спрашивает, почему конкретной заявке отказали, ответ существует. С моделью, которая читает таблицу как промпт, этот разговор пока выглядит куда менее уверенным.
Воспроизводимость задним числом. Артефакт модели можно положить в реестр и достать через год. Контекст надо ещё уметь зафиксировать, сохранить целиком и доказать, что он был именно таким.
Как выбирать: план действий
Чтобы не гадать, я свёл принятие решения в короткое дерево — Рис. 3. Оно не про то, что «лучше», а про то, что разумно попробовать первым при ваших вводных.

Что здесь главное: ни одна ветка не заканчивается словами «выкинуть бустинг». Меняется не победитель, а точка входа в проект. Раньше первый день новой табличной задачи уходил на сборку baseline, теперь baseline можно получить за один forward pass и сразу понять, есть ли в данных вообще сигнал.
Практики команд, которые уже это гоняют
Равный бюджет вычислений в любом сравнении. Час на одну сторону — час на другую. Иначе это не эксперимент, а презентация.
Несколько сидов обязательно. Разница меньше разброса по сидам — это ничья, а не победа. Готовность понизить собственный результат до ничьей отличает замер от рекламы.
Проверять, сколько строк реально дошло до модели. Лимит контекста по умолчанию способен незаметно превратить ваш эксперимент в сравнение несравнимого.
Смотреть не только на метрику, но и на аллокатор. История с 22,75 ГБ, которые оказались 16,95, — напоминание: цифры из README проверяются на вашем железе.
Лицензия проверяется до пилота, а не после. Открытый код и некоммерческие веса — разные вещи, и юристы объяснят разницу быстрее, чем хотелось бы.
Что в итоге
Мой вывод, который я обычно формулирую для команды одной фразой: XGBoost не умер, у него появился быстрый разведчик.
Никто в здравом уме не пойдёт сейчас переписывать работающий скоринг. Но первый шаг в чек‑листе новых табличных задач я бы уже поменял: сначала zero‑shot прогон foundation‑моделью на пилотном контуре, чтобы за пятнадцать минут понять, какой потолок качества в данных вообще есть, и только потом решение о полноценном пайплайне с ретрейном. Это экономит не проценты метрики, а недели работы там, где сигнала в данных изначально мало.
Если будете проверять на своих данных — напишите в комментариях, на каком режиме у вас перевернулось. Публичных замеров на грязных корпоративных таблицах сейчас нет, и любой честный прогон ценнее ещё одного пересказа релиза.
И да, через год‑полтора кто‑нибудь снова напишет, что бустинг умер. Проверять всё равно придётся руками.

Когда новый подход выглядит убедительно на бенчмарке, главный вопрос быстро смещается от «кто победил» к «как это вообще жить будет в проде». Если хочется разбирать ML не только на уровне метрик, но и через архитектуру системы, ограничения инфраструктуры и выбор подходящей модели под задачу, приходите на открытые уроки:
19 августа, 20:00. «Почему 90% ML-проектов не доходят до продакшена? Разбираем архитектуру настоящей ML-системы». Записаться.
24 августа, 20:00. «Современные модели прогнозирования — TimesNet, TimeGPT и новое поколение моделей временных рядов». Записаться.
Полный список бесплатных уроков августа смотрите в дайджесте.

