Ir para o conteúdo principal

TabFM contra CatBoost, XGBoost e LightGBM em 10 datasets tabulares

Benchmark próprio do TabFM, o modelo fundacional tabular do Google, contra 3 GBMs em 10 datasets, com bootstrap pareado, Friedman, Wilcoxon e tempo de inferência medido.

O Google liberou o TabFM em 30 de junho de 2026, um modelo fundacional para dados tabulares que promete classificação e regressão sem treino. A primeira coisa que fiz foi desconfiar. Modelo fundacional em dados tabulares é a promessa que a área persegue desde sempre: substituir o gradient boosting, que domina competição e produção há mais de uma década. Em vez de aceitar os números do anúncio, montei um benchmark próprio em 10 datasets contra CatBoost, XGBoost e LightGBM, com validação estatística em cada etapa.

Resumo

  • O TabFM ficou em primeiro lugar em ponto pontual nos 10 datasets, com rank médio exatamente 1.0 no teste de Friedman (χ² = 23.16, p ≈ 0).
  • Olhando dataset por dataset, com bootstrap pareado e correção de Holm-Bonferroni, a vantagem sobre o CatBoost só sobrevive em 2 dos 10.
  • A inferência custa caro: no California Housing foram 39.7 minutos contra 13.4 segundos dos três GBMs somados.
  • Acima de ~17 mil linhas o modelo estourou a memória do Metal Performance Shaders num Mac M1 de 8 GB, deixando 3 datasets de fora.
  • Os pesos pré-treinados vêm sob licença tabfm-non-commercial-v1.0, que proíbe uso comercial, mesmo com o código-base em Apache 2.0.
  • Uma auditoria na configuração revelou 3 bugs no LightGBM que mudaram a conclusão de 4 datasets.

Código, specs, notebooks e resultados: gomesfellipe/benchmark-tabfm-vs-gbm.

Registrei cinco expectativas nas specs antes de rodar qualquer coisa, para poder contrastar depois: que o ganho apareceria em datasets pequenos, que não haveria vazamento tipo LLM, que datasets reais são maiores que os de benchmark, que a inferência seria o gargalo e que ainda assim valeria como ferramenta na caixa. Volto nelas no final.

Como o TabFM funciona, comparado a uma árvore de decisão
#

A comparação com modelos em árvore mostra onde o custo migra. Uma árvore aprende a estrutura a partir dos seus dados: cada nó testa uma variável, escolhe o corte que maximiza ganho de informação e divide o espaço. Um GBM empilha centenas dessas árvores, cada uma corrigindo o resíduo da anterior. Todo o conhecimento fica gravado na estrutura durante o treino, e prever depois é só percorrer nós, o que custa quase nada.

O TabFM inverte a ordem. Ele foi pré-treinado em uma quantidade enorme de tabelas sintéticas, aprendendo como costuma ser a relação entre colunas e alvo em dados tabulares em geral. Quando você entrega o seu dataset, ele não treina: as linhas de treino entram como contexto e as de teste são previstas em uma passagem pela rede, no mesmo espírito do aprendizado em contexto de um LLM.

Duas consequências saem daí. Não existe etapa de treino para cronometrar, só inferência, e é nela que o custo inteiro aparece. E o tamanho do seu dataset vira tamanho de contexto, com todos os limites de memória que isso implica. A documentação registra teto de 500 features, no máximo 10 classes na classificação e degradação a partir de ~150 mil linhas.

O desenho do experimento
#

Escrevi o experimento no estilo spec-driven development, com uma constituição de 11 princípios e 8 specs numeradas antes de qualquer linha de código. Isso teve um efeito colateral que só percebi depois, quando fui auditar dois modelos: cada decisão de configuração já estava escrita e datada, então dava para comparar o que a spec prometia com o que o código realmente fazia.

Dez datasets rodam os quatro modelos. A métrica de cada um foi escolhida pelo problema, não por inércia: PR AUC onde há desbalanceamento forte, RMSE do log onde o alvo é assimétrico, MAE onde a escala é ordinal.

DatasetTipoLinhasMétrica
Auto MPGRegressão398RMSE
Breast Cancer WisconsinClassificação569ROC AUC
Pima Indians DiabetesClassificação768ROC AUC
TitanicClassificação891ROC AUC
Concrete Compressive StrengthRegressão1030RMSE
Ames HousingRegressão2930RMSE do log
Wine QualityRegressão ordinal6497MAE
Telco Customer ChurnClassificação7043PR AUC
MushroomClassificação8124ROC AUC
California HousingRegressão20640RMSE

Todos os quatro recebem o dataset cru, sem feature engineering nem seleção de features. O CatBoost roda com os parâmetros padrão da biblioteca, porque os defaults dele já são agressivos: mil iterações, detector de overfitting automático e regularização L2 embutida. XGBoost e LightGBM não podem ser comparados com os defaults de fábrica (n_estimators=100, sem regularização), senão perderiam pela biblioteca e não pelo algoritmo. Os dois receberam uma configuração fixa, igual para todos os datasets, que imita o comportamento do CatBoost.

Python
# XGBoost
XGBClassifier(  # ou XGBRegressor
    n_estimators=1000, learning_rate=0.03, max_depth=7, reg_lambda=3,
    subsample=0.8, colsample_bytree=0.8, tree_method="hist",
    grow_policy="depthwise", enable_categorical=True,
    early_stopping_rounds=50, eval_metric="auc",  # "rmse"/"l1" em regressão
    random_state=SEED,
)

# LightGBM
LGBMClassifier(  # ou LGBMRegressor
    n_estimators=1000, learning_rate=0.03, num_leaves=127, max_depth=-1,
    reg_lambda=3, subsample=0.8, subsample_freq=1, colsample_bytree=0.8,
    random_state=SEED, verbose=-1,
)

O TabFM roda puro, sem ensemble e sem fine-tuning, com n_estimators=8. Ele precisou ficar isolado num subprocesso próprio, porque torch com backend MPS no mesmo processo que os GBMs causa segfault por conflito de runtimes OpenMP nativos.

Python
from tabfm import tabfm_v1_0_0_pytorch as tv
from tabfm import TabFMClassifier

base = tv.load(model_type="classification", device="mps")
model = TabFMClassifier(model=base, n_estimators=8, random_state=SEED)
model.fit(X_train, y_train)          # não treina de fato, só carrega o contexto
proba = model.predict_proba(X_test)  # aqui está o custo inteiro

Dois datasets exigiram cuidado no split. No California Housing, 39% das linhas compartilham latitude e longitude com outra linha, e o desvio padrão do preço dentro do mesmo ponto é só 22% do desvio geral. Split aleatório vazaria isso, então usei GroupShuffleSplit agrupado por coordenada, inclusive na fatia de validação do early stopping. O Bike Sharing Demand é série temporal, com split cronológico e sem embaralhar.

Como decidi o que conta como diferença real
#

Nenhuma afirmação de superioridade entra no relatório sem teste por trás. O protocolo tem quatro camadas:

  • Intervalo de confiança para toda métrica, via bootstrap com 10000 reamostragens a 95%. Nenhum número solto conta como conclusão.
  • Bootstrap pareado na diferença: a cada reamostragem calculo métrica(A) menos métrica(B) nas mesmas amostras, o que captura a correlação entre modelos avaliados nas mesmas linhas.
  • Teste omnibus antes dos pares, porque com 4 modelos são 6 comparações e sair testando par a par sem antes perguntar “existe alguma diferença aqui?” é pescaria estatística. O Friedman clássico não serve dentro de um dataset só (ele pede vários datasets como blocos), então generalizei o próprio bootstrap pareado: a covariância bootstrap das diferenças alimenta um teste de Wald qui-quadrado com k-1 graus de liberdade.
  • Correção de Holm-Bonferroni nas 6 comparações de cada dataset. O efeito é desigual por tamanho de amostra: no Titanic (179 linhas de teste) ela derruba metade das diferenças que apareciam no intervalo bruto; no California Housing (4192 linhas) quase não muda nada.

Entre datasets, com n = 10, vale o Friedman clássico com post-hoc de Nemenyi, mais o Wilcoxon signed-rank pareado para as comparações diretas do TabFM contra cada GBM. Rodar os dois post-hoc foi deliberado, e a diferença entre eles virou o achado mais interessante do consolidado.

Resultado dataset a dataset
#

DatasetMétricaTabFMCatBoostLightGBMXGBoostOmnibus (p)Pares que sobrevivem a Holm
Auto MPGRMSE ↓2.02632.33222.40662.66860.073TabFM > XGBoost
Breast CancerROC AUC ↑0.99670.99500.99170.99240.700nenhum
Pima DiabetesROC AUC ↑0.82650.81610.82280.80220.496nenhum
TitanicROC AUC ↑0.86440.85880.83720.83430.173nenhum
ConcreteRMSE ↓3.95774.11314.51164.79440.032nenhum
Ames HousingRMSE log ↓0.10240.10530.10730.10610.850nenhum
Wine QualityMAE ↓0.37090.48430.45280.4443≈ 0os 6 pares
Telco ChurnPR AUC ↑0.66390.66100.64860.61660.00033 pares, todos contra o XGBoost
MushroomROC AUC ↑1.00001.00000.99980.99810.0145TabFM e CatBoost > LightGBM
California HousingRMSE ↓0.35340.42740.42750.4320≈ 0TabFM > os 3 GBMs

O TabFM tem a melhor métrica pontual em todos os dez, com um empate exato contra o CatBoost no Mushroom. Essa é a leitura que rende manchete. A honesta é outra: em cinco dos dez nenhuma comparação sobrevive à correção de Holm, ou seja, os quatro modelos estão empatados e a vitória do TabFM é ruído dentro do intervalo. Em apenas dois dos dez ele bate o CatBoost com significância isolada. Ter a melhor métrica em dez de dez e ter vantagem comprovada sobre o segundo colocado em dois de dez são resultados diferentes, e vale dizer os dois.

Onde a diferença é real, ela é grande. No Wine Quality o MAE cai de 0.4443 para 0.3709, uma redução de 16.5%, e o ranking fica 100% resolvido, com os seis pares estatisticamente distintos. No California Housing o RMSE cai de 0.4274 para 0.3534, redução de 17.3%. São os dois casos onde eu diria, sem ressalva, que o TabFM ganhou.

Também vale notar onde a expectativa falhou. Eu esperava vantagem em datasets pequenos, e é justamente ali que nada é significativo: Breast Cancer (569 linhas), Pima (768), Titanic (891) e Concrete (1030) terminam todos em empate. As duas vitórias claras vieram nos datasets de 6497 e 20640 linhas.

O consolidado entre os 10 datasets
#

Ranqueando os quatro modelos dentro de cada dataset e rodando o Friedman clássico: χ² = 23.16, 3 graus de liberdade, p ≈ 0. Existe diferença de rank médio.

1234TabFMCatBoostLightGBMXGBoost1.02.33.13.6Rank médio (1 = melhor), 10 datasets, Friedman χ² = 23.16, p ≈ 0

O rank médio do TabFM é exatamente 1.0, ou seja, ele foi o melhor em 100% da amostra. O post-hoc de Nemenyi, com diferença crítica de 1.4832, é mais contido: confirma TabFM sobre XGBoost (diferença de rank 2.6) e sobre LightGBM (2.1), e para no CatBoost (1.3, logo abaixo do limiar). Nenhuma comparação entre os três GBMs excede a diferença crítica.

O Nemenyi é conservador por construção, porque controla o erro em todos os pares simultaneamente. Por isso a spec também pedia o Wilcoxon signed-rank pareado, mais poderoso quando a pergunta é sobre dois modelos específicos:

ComparaçãonWpSignificativo?
TabFM contra CatBoost100.00.0039Sim
TabFM contra XGBoost100.00.0020Sim
TabFM contra LightGBM100.00.0020Sim

W = 0 nos três casos porque o TabFM venceu em ponto pontual em todos os datasets, com o único empate exato no Mushroom.

Isso não é contradição entre os testes, é diferença de propósito. Quando a pergunta é “o TabFM é melhor que o CatBoost?”, isolada, a resposta é sim, com p = 0.0039. Quando a pergunta é “ele é melhor que os três ao mesmo tempo, com controle de erro simultâneo?”, a resposta contra o CatBoost ainda não crava, nem com n = 10. Reportar os dois é mais honesto do que escolher o que soa melhor.

O custo: 39.7 minutos contra 13.4 segundos
#

A comparação justa é (treino + predição do GBM) contra (inferência do TabFM), porque o GBM paga adiantado e o TabFM paga na hora de usar.

DatasetLinhas de treinoTabFM (inferência)3 GBMs somados
Auto MPG31333.3s2.3s
Breast Cancer45561.0s2.8s
Pima Diabetes61473.3s3.5s
Titanic71254.7s1.9s
Concrete82488.2s5.4s
Ames Housing2344613.7s (10.2 min)19.1s
Wine Quality5198637.7s (10.6 min)11.0s
Telco Churn5634605.5s (10.1 min)8.5s
Mushroom6499982.0s (16.4 min)10.1s
California Housing164482381.0s (39.7 min)13.4s
California HousingMushroomTelco ChurnWine QualityAmes HousingTitanicBreast CancerPima DiabetesConcreteAuto MPG178x97x71x58x32x29x22x21x16x14xInferência do TabFM dividida pelo tempo de treino + predição dos 3 GBMs somadosMacBook M1, 8 GB, backend MPS

O custo não cresce só com o número de linhas. O Mushroom, com 6499 linhas, levou mais tempo que o Wine Quality com 5198, e a diferença é que as 22 features do Mushroom são todas categóricas. Dimensionalidade e cardinalidade categórica pesam tanto quanto a contagem de linhas.

Isso apareceu de novo no teto de memória. Três datasets ficaram de fora porque o TabFM não rodou neles neste M1 de 8 GB: Bank Marketing (36168 linhas de treino), Adult (39074) e Bike Sharing Demand (13903). No Bank Marketing testei as hipóteses uma a uma. Não era pressão de memória do momento, porque fechei tudo e o erro se repetiu no mesmo teto de 9.07 GiB. Não era teto de software do PyTorch, porque com PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 o erro só ficou mais cru, vindo direto do driver Metal. Era memória física acabando mesmo. O Bike Sharing é o caso curioso: estourou com menos linhas que o California Housing, que rodou full-scale, e a diferença são as 4 features categóricas. O teto real neste hardware fica entre 16448 e 36168 linhas de treino, e não fui atrás do valor exato porque não valia o tempo.

A assimetria de custo é o argumento prático mais forte contra produção hoje. Em previsão de demanda o modelo raramente é a entrega final: ele alimenta política de estoque e sortimento, e em forecast recursivo cada previsão vira entrada da próxima, multiplicando a inferência a cada passo. Foi assim que a solução global de LightGBM venceu a competição M5. Com 40 minutos por passada, esse desenho não fecha.

Duas auditorias que mudaram conclusões
#

Esta é a parte que eu quase não publiquei, e acabou sendo a mais útil.

Terminada a primeira rodada, fui reler o relatório e uma coisa não fechava: o LightGBM perdia de forma consistente em todos os datasets. Isso costuma ser sinal de configuração ruim, não de algoritmo inferior. Fui auditar o código e achei três bugs:

1. subsample=0.8 era um no-op. O LightGBM só ativa subamostragem de linhas se subsample_freq for maior que zero, e eu nunca setei. O parâmetro ficava silenciosamente ignorado, então ele treinava com 100% das linhas em toda árvore enquanto o XGBoost aplicava o subsample de verdade. A configuração era simétrica no papel e assimétrica na execução.

2. num_leaves=63 era redundante com max_depth=6. Uma árvore binária de profundidade 6 tem no máximo 64 folhas, então quem limitava a árvore era o max_depth. Na prática a vantagem estrutural do LightGBM, o crescimento leaf-wise, ficava anulada: ele se comportava como uma árvore limitada por nível, igual ao XGBoost.

3. O eval_metric do early stopping não batia com a métrica de benchmark. No Titanic e no Breast Cancer o LightGBM parava as árvores no melhor binary_logloss, o default, enquanto o benchmark reportava ROC AUC. No Wine Quality o benchmark é MAE e o corte usava l2. O early stopping otimizava um alvo diferente do que era reportado.

Corrigi os três, que valem igualmente para todos os datasets, e re-rodei. O efeito não foi cosmético:

DatasetLightGBM antesDepoisEfeito na conclusão
Titanic0.81390.8372Omnibus deixa de ser significativo, dataset vira empate geral
Ames Housing0.11070.1073Única diferença significativa desaparece
Wine Quality0.49660.4528LightGBM sai de pior modelo para segundo melhor
California Housing0.43680.4275LightGBM alcança o CatBoost

O TabFM continuou com rank 1.0, então a conclusão principal não mudou. Mas quatro conclusões locais mudaram, e duas delas eram afirmações de superioridade que eu já tinha escrito.

Corrigir o LightGBM criou o problema simétrico. Com num_leaves=127 e sem teto de profundidade ele passou a crescer leaf-wise de verdade, enquanto o XGBoost seguia crescendo nível a nível com max_depth=6, ou seja, com a mesma classe de sub-configuração que eu tinha acabado de corrigir do outro lado. Testei duas variantes: A, mantendo o mecanismo depthwise com max_depth=7, e B, usando grow_policy="lossguide" com max_leaves=127 para crescer best-first igual ao LightGBM. E fiz uma coisa que recomendo: travei o critério de decisão antes de rodar, definindo que venceria a variante com menor rank médio estilo Friedman.

Foi bom ter travado. A variante B ganhou com significância em dois datasets e com efeitos maiores, contra uma vitória significativa da A, mas caiu atrás até do LightGBM no Ames Housing, e o rank ordinal não pesa tamanho de efeito, só posição. A venceu por 3.3333 contra 3.5000. Sem o critério pré-registrado, seria fácil olhar o Wine Quality e trocar de vencedora depois do fato.

A lição das duas auditorias juntas vale mais que qualquer número da tabela: em benchmark de GBM, boa parte do que parece diferença de algoritmo é diferença de configuração. Os três GBMs, que chegaram a ter 2.2% de distância entre si no California Housing, terminaram dentro de 1.1% depois das correções.

Esperado contra encontrado
#

ExpectativaO que o experimento mostrou
1. Vantagem em datasets pequenosNão confirmada. Nos 4 menores (569 a 1030 linhas) nada é significativo. As 2 vitórias claras foram em 6497 e 20640 linhas
2. Não é vazamento tipo LLMConfirmada por construção. O pré-treino é em dados sintéticos, e o dataset entra como contexto, não como treino
3. Datasets reais são maioresConfirmada da pior forma. Acima de ~17 mil linhas o modelo nem roda neste hardware
4. Inferência é gargaloConfirmada e medida. De 14x a 178x mais lento que os 3 GBMs somados, chegando a 39.7 minutos
5. Ferramenta na caixaConfirmada com ressalva. Ganha consistentemente (Wilcoxon p ≤ 0.0039 contra os 3), mas a licença impede uso comercial

Então eu colocaria em produção?
#

Não hoje, e a razão principal não é a métrica, que é boa, é o princípio da parcimônia.

Tem também a licença. O código-base está sob Apache 2.0, mas os pesos pré-treinados vêm sob tabfm-non-commercial-v1.0, que proíbe uso comercial. No lançamento o README não mencionava isso e os pesos eram baixados silenciosamente do Hugging Face, o que gerou uma leva de posts apontando o risco de usar sem perceber. Na prática de consultoria, isso decide a conversa antes da métrica: dá para avaliar internamente, não dá para integrar numa entrega de cliente.

O TabFM entrega ganho real e sustentado quando o problema tem estrutura que os GBMs não capturam bem, como no Wine Quality e no California Housing. Em cinco dos dez datasets ele empata estatisticamente com um CatBoost rodando com parâmetros de fábrica, que treina e prevê em segundos, roda em qualquer lugar e não tem restrição de licença. Trocar segundos por dezenas de minutos, mais um teto de memória na faixa de dezenas de milhares de linhas, mais uma licença não comercial, para ganhar métrica numa fração dos casos, é um trade que não fecha para mim.

Onde ele faz sentido hoje: prova de conceito, baseline rápido em dataset pequeno para saber quanto dá para extrair de um problema antes de investir em feature engineering, e exploração de casos onde as métricas de GBM empacaram e você quer saber se o teto é do dado ou do modelo. Vale acompanhar. Não é substituto do CatBoost no pipeline de amanhã.

O achado mais reaproveitável do experimento, porém, não é sobre o TabFM. É que auditar a configuração encontrou três bugs que mudaram quatro conclusões, e que travar o critério de decisão antes de olhar o resultado impediu a escolha da variante que parecia melhor num recorte. Isso vale para qualquer benchmark, com ou sem modelo fundacional envolvido. É a mesma disciplina que uso em write-up de competição, aplicada ao próprio experimento.

O repositório tem as 8 specs, a constituição, o código do pipeline, um notebook executado por dataset, os CSVs de métricas, significância e tempos, e o relatório final. A seed é global e fixa, e rodar os 10 datasets do zero num M1 leva cerca de 1h30 só de inferência do TabFM.

Bash
git clone https://github.com/gomesfellipe/benchmark-tabfm-vs-gbm.git
cd benchmark-tabfm-vs-gbm
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

Perguntas frequentes
#

O TabFM substitui o XGBoost e o LightGBM?

Nos meus testes ele bate os dois com significância consolidada, tanto no Nemenyi quanto no Wilcoxon (p = 0.0020 contra cada um). Mas substituir envolve custo: a inferência foi de 14x a 178x mais lenta que os três GBMs somados, e os pesos têm licença não comercial. Como substituto direto em produção, não.

E contra o CatBoost?

É a comparação mais apertada. O Wilcoxon pareado entre os 10 datasets dá p = 0.0039 a favor do TabFM, mas o Nemenyi não crava (diferença de rank 1.3 contra diferença crítica de 1.4832), e dataset a dataset a vantagem só sobrevive à correção de Holm em 2 dos 10. O CatBoost com parâmetros de fábrica é um adversário duro.

O TabFM não estaria "vazando" os dados, como um LLM que já viu tudo na internet?

Não por esse mecanismo. O pré-treino é feito em tabelas sintéticas geradas artificialmente, não em datasets públicos reais. O seu dataset entra como contexto no momento da inferência, não como dado de treino do modelo.

Quantas linhas o TabFM aguenta?

A documentação fala em degradação a partir de ~150 mil linhas, com tetos de 500 features e 10 classes. Na prática, num Mac M1 de 8 GB com backend MPS, o teto real ficou entre 16448 e 36168 linhas de treino. E não é função só de linhas: um dataset com 13903 linhas e 4 features categóricas estourou memória enquanto outro com 16448 linhas e 8 features numéricas rodou.

Referências
#

Mentoria · vagas limitadas

Estou abrindo poucas vagas de mentoria gratuita em Data Science e IA.

Sessões pelo ADPList. Garanta a sua.

Agende uma mentoria
Fellipe Gomes
Autor
Fellipe Gomes
Data Science Specialist @ Accenture | Kaggle Master

Sou formado em estatística e atuo como cientista de dados desde 2017. Compartilho meus estudos e evolução por meio de artigos, tutoriais e projetos de código aberto. Se quiser saber mais sobre meu trabalho, sinta-se à vontade para entrar em contato através das minhas redes sociais.

Recebe os próximos posts por email

Data science, IA e agentes. Sem spam, cancela quando quiser.

Confirmar inscrição

Recomendados