No dia 31 de agosto de 2026 o Google lançou o TimesFM 3.0, um modelo fundacional de séries temporais e na mesma semana eu já estava me questionando: Esse modelo bate um gradient boosting básico? Quais são os prós e contras? Então usei a competição M5 de previsão de demanda do Walmart do Kaggle para construir meus próprios benchmarks.
A pergunta que me interessa não é só quem ganha mas quanto custa cada ponto de acurácia, em esforço humano e em máquina. Um modelo fundacional promete previsão sem treino; o gradient boosting global precisa de alguma engenharia de features e certa experiência para entregar resultados satisfatórios. Medir os dois na mesma régua mostra onde cada promessa se paga.
Desenho, protocolo, specs e expectativas foram registrados no GitHub antes de qualquer configuração rodar.
Resumo
- Um LightGBM básico sem tuning de hiperparâmetros vence um TimesFM 3.0 com covariáveis no WRMSSE por 8,1% (0.58372 contra 0.63534 no placar privado do Kaggle) e roda 5,1× mais rápido, em CPU de laptop contra GPU T4 alugada.
- Trocar qual estatística se lê da distribuição preditiva (mediana por média) corta de 49% a 59% do erro do TimesFM 3.0.
- O zero-shot cobre 80% da distância entre o
sNaivee o melhor LightGBM, um resultado bem decente para um modelo que não precisa de treino.
O que o TimesFM 3.0 traz de novo#
São 330M de parâmetros, decoder-only, com patch de 32 passos. A novidade arquitetural é a atenção alternada: causal temporal dentro de cada série, e atenção de variate entre séries no mesmo timestep. É isso que permite alimentar o modelo com um grupo de séries relacionadas e deixar que ele use uma para prever a outra.
Ele gera o horizonte inteiro num único forward, sem decodificação iterativa, e devolve nove quantis por passo. O código é Apache-2.0; os pesos vêm sob timesfm-non-commercial-license-v1.0, restrita a uso não-comercial. Vale repetir porque decide a conversa antes da métrica: dá para avaliar internamente, não dá para entregar a cliente.
Os três modos de entrada que testei usam o mesmo checkpoint e nenhum treino. Zero-shot aqui quer dizer que nenhum peso é atualizado com o dado do M5: covariável e alvo conjunto entram na hora da inferência, não no treino.
Clique para ver os três modos de entrada do TimesFM 3.0
# 1. univariado: só o histórico da série
forecaster.predict_batch(ctx, horizon=28, return_quantiles=True)
# 2. + covariáveis conhecidas no futuro (preço, SNAP, evento, calendário)
forecaster.predict_batch(
ctx, horizon=28, past_future_covariates=cov,
return_quantiles=True, make_positive=True,
)
# 3. multivariado: o grupo dept x store entra junto e as séries
# se enxergam pela atenção de variate
forecaster.predict_batch(grupo, horizon=28, return_quantiles=True)Por que o M5, e por que ele é held-out genuíno#
O M5 são 30.490 séries diárias de venda do Walmart em três estados, com hierarquia de 12 níveis, demanda intermitente, e preço e calendário de benefício social como drivers (M5 Competitors’ Guide, 2020). É o problema de previsão de demanda de varejo mais estudado que existe, com leaderboard de 5.558 equipes e métrica própria.
O que decide a escolha é outra coisa: o M5 é held-out genuíno para o TimesFM 3.0. O card do modelo declara o corpus de pré-treino, e o M5 não está nele. A auditoria de contaminação TSFMAudit (arXiv:2605.26161, Tabela 7) rotula o M5 como não-exposto para o TimesFM, e marca exposição documentada para Chronos, Kairos, Moirai e TiRex.
Isso é raro. A maioria dos benchmarks de varejo já foi vista por algum modelo fundacional, e boa parte dos resultados publicados de modelo fundacional no M5 é sobre modelos que já viram o M5. O M5 aqui é exceção, pelo que o card do modelo declara. Essa garantia vem da documentação, não de uma auditoria que eu mesmo tenha rodado.
Os concorrentes e as duas assimetrias#
Do lado do fundacional, os três arms são o mesmo checkpoint com entradas diferentes: só o histórico, mais covariáveis, e o grupo dept × store junto. Nenhum recebe treino. Produção exigiria o TimesFM 2.5, porque os pesos do 3.0 são não-comerciais.
Clique para ver o código do TimesFM 3.0
QUANTILES = np.arange(0.1, 0.91, 0.1)
COVARIATES = ["sell_price", "snap", "is_event", "day_of_week", "month", "weekend"]
def trim_context(series, min_len=32):
"""Corta os zeros antes da primeira venda: 900 dias de zero pré-lançamento
não são histórico, são ausência de produto. É a mesma convenção que o
denominador do RMSSE usa para definir 'período ativamente à venda'."""
nz = np.flatnonzero(series)
if nz.size == 0:
return series[-min_len:].astype(np.float32)
return series[max(0, min(nz[0], len(series) - min_len)):].astype(np.float32)
# 30.490 séries x 1941 passos x 6 covariáveis não cabem em memória de uma vez,
# então a inferência corre em blocos de `chunk` séries
for lo in range(0, n, chunk):
hi = min(lo + chunk, n)
ctx = [trim_context(sales[s, :fold_idx]) for s in range(lo, hi)]
# covariáveis past-future: passado real + futuro conhecido (preço, SNAP,
# calendário), alinhados no tempo com o contexto de cada série
cov = []
for j, s in enumerate(range(lo, hi)):
past = slice(fold_idx - len(ctx[j]), fold_idx)
fut = slice(fold_idx, fold_idx + horizon)
cov.append(np.stack([
np.concatenate([panel[c][s, past], panel[c][s, fut]])
for c in COVARIATES
]).astype(np.float32))
out = forecaster.predict_batch(
ctx, horizon=horizon, past_future_covariates=cov,
return_quantiles=True, make_positive=True,
)
# .forecast é o quantil MEDIANO (q50), não a média. Em série intermitente a
# mediana colapsa em zero, então guardo os 9 quantis para reconstruir a
# média depois, sem escolher a estatística por mim aqui.Do outro lado, um LightGBM global: um único modelo para as 30.490 séries, objetivo Tweedie, lags múltiplos de 7. As configurações que disputam o placar são estas:
| Configuração | Treino | O que entra na previsão |
|---|---|---|
snaive | nenhum | repete a última semana |
tfm_zero | nenhum | só o histórico da série, uma por vez |
tfm_cov | nenhum | + preço, SNAP, evento, calendário |
lgbm_min | 1 modelo, 30.490 séries | lags 7/14/28, categóricas, SNAP, evento |
lgbm_roll | idem | + médias móveis de 7 e 28 dias |
*_mean | pós-processamento | a média reconstruída dos 9 quantis no lugar da mediana |
Duas assimetrias separam os paradigmas, e nenhuma é defeito de desenho.
A primeira é recursivo contra one-shot. O LightGBM prevê o passo 1, realimenta a predição como lag e prevê o passo 2, vinte e oito vezes, acumulando erro. O TimesFM 3.0 emite os 28 passos de uma vez.
A segunda é mediana contra média. O ponto nativo do TimesFM 3.0 é o quantil mediano. O WRMSSE é erro quadrático, cuja predição ótima é a média, e em série intermitente a mediana colapsa em zero. A mediana é o funcional errado para essa métrica, um erro de especificação que o pós-processamento corrige.
A estatística lida pesa muito na escolha do modelo#
Trocar qual quantil se lê da mesma distribuição preditiva corta de 49% a 59% do erro do TimesFM 3.0 no backtest. Na origem oficial o efeito é da mesma ordem, num modelo só: o tfm_cov sai de 1.48355 para 0.63534, ou 57%.

O mecanismo é direto: 69% das séries têm mediana exatamente zero, mesmo vendendo ao longo do período. A maioria dos dias é zero e poucos picos levantam a média sem levantar a mediana. Ler a mediana descarta de 23% a 29% do volume que o próprio modelo espera, o que em previsão de demanda é ruptura, não excesso.
Um produto que vende 3 unidades em 10 dias tem mediana 0 e média 0,3. A mediana responde certo a “qual o dia típico?” e responde errado a “quanto estocar?”.

O que isso vira em unidade de negócio:
| lido na mediana | lido na média | |
|---|---|---|
| volume previsto contra o real | 70% a 78% | 93% a 97% |
| células previstas como exatamente zero | 18% a 38% | 1,5% a 21% |
posição contra o sNaive | pior nas 9 medições | melhor nas 9 medições |
A decomposição de erro mediu o mesmo viés pelo outro lado: 91,8% do MSE no nível 1 é viés puro, não dispersão. Essa é a assinatura de mediana lida por métrica quadrática.
Reconstruir a média a partir dos 9 quantis é pós-processamento alinhado à métrica, com custo de inferência zero, porque os quantis já estão salvos em disco. O estimador é deliberadamente conservador: assume que o pior caso é o quantil 90.
Clique para ver o código do mean_from_quantiles
def mean_from_quantiles(q: np.ndarray) -> np.ndarray:
"""Limite inferior da média a partir dos 9 quantis (0.1..0.9).
E[X] = integral de Q(p) dp em [0,1]. O trapézio cobre [0.1, 0.9];
as caudas entram com a hipótese mais conservadora que existe:
cauda inferior: Q(0) = 0 (não há venda negativa)
cauda superior: Q(1) = q90 (falso e conservador de propósito)
"""
p = np.arange(0.1, 0.91, 0.1)
corpo = np.trapezoid(q, p, axis=-1)
cauda_baixa = 0.1 * (0.0 + q[..., 0]) / 2
cauda_alta = 0.1 * q[..., -1]
return np.clip(corpo + cauda_baixa + cauda_alta, 0, None)Nada disso precisou olhar o placar: o próprio objeto de previsão já denuncia o descasamento, sem usar um único valor real. Reportar um funcional inconsistente com a métrica é defeito de desenho, o assunto de Gneiting (2011), Making and Evaluating Point Forecasts.
A fronteira esforço × acurácia#
O melhor LightGBM domina o melhor TimesFM 3.0 nos dois eixos: 8,1% menos erro e 5,1× mais rápido, em CPU de laptop contra GPU T4 alugada.

Ainda assim, o zero-shot cobre 80% da distância entre o sNaive e o melhor LightGBM, e faz isso sem treino, sem feature e sem hiperparâmetro. A única configuração do TimesFM 3.0 mais rápida que o zero-shot é a de alvos conjuntos. Ela prevê num único forward todas as séries de um mesmo grupo (os itens de um departamento numa loja), com a atenção de variate deixando uma enxergar a outra, e erra 11,1% mais.
| configuração | esforço humano | Kaggle privado |
|---|---|---|
| 1º lugar do M5 (ensemble de 220 modelos) | - | 0.520 |
lgbm_roll | 1 modelo + 4 features | 0.58372 |
lgbm_min | 1 modelo | 0.62541 |
tfm_cov_mean | zero-shot + pós-proc. | 0.63534 |
tfm_zero_mean | zero-shot + pós-proc. | 0.65519 |
snaive | nenhum | 0.84701 |
tfm_cov | zero-shot (mediana) | 1.48355 |
O snaive desta implementação pontuou 0.84701 no placar privado, contra os 0.847 publicados pelo benchmark oficial do M5. Bate em quatro casas, o que valida externamente a métrica, o painel de 60 milhões de linhas e o formato da submissão.
A ponderação da métrica decide o vencedor#
O WRMSSE do M5 é a média simples dos 12 níveis, e os níveis têm de 1 a 30.490 séries. Somando: os níveis 1 a 9 têm 154 séries e carregam 75% da métrica; os níveis 10 a 12 têm 42.686 séries e carregam 25%.
Esse empate entre níveis vem de uma decisão simples. O peso de cada série é a participação dela nas vendas em dólar dos últimos 28 dias, e como a soma em dólar dá o mesmo total em qualquer nível de agregação, os 12 níveis acabam pesando 1/12 cada. Uma série agregada concentra muita receita em poucas séries, então pesa muito; o nível 12 dilui a mesma receita entre 30.490 séries.
Mas peso por dólar é uma escolha de negócio, e nem sempre é o objetivo certo. Já trabalhei em projeto de reposição em que o valor do item não entrava na conta: para o estoquista tanto faz se o produto é caro ou barato, ele precisa estar na prateleira. No e-commerce a assimetria é ainda maior. A falta de um item barato e básico machuca a reputação da loja, porque o cliente generaliza para “aqui nunca tem o básico” e avalia mal o estabelecimento inteiro. Nesses casos a função-alvo é disponibilidade, e uma métrica ponderada por faturamento mediria a coisa errada.

O TimesFM 3.0 ganha o nível 12, o SKU por loja, por 1,6% a 1,9%, com sinal consistente em 7 de 7 origens. E perde os agregados por 11% a 67%. O fundacional ganha o fundo da hierarquia por pouco e perde o topo com folga, e como a métrica pesa o topo três vezes mais, o composto vai para o LightGBM.
Eu tinha pré-registrado o contrário. Minha expectativa era que a vantagem do fundacional se concentraria nos níveis agregados e desapareceria no nível 12, onde a demanda é intermitente. O resultado veio invertido.
Veredito e o que sobrevive a favor do fundacional#
O LightGBM global ganha o WRMSSE por 8,1% (lgbm_roll 0.58372 contra tfm_cov_mean 0.63534), com sinal consistente em 7 de 7 origens dos dois desenhos de backtest, e com 5,1× menos tempo, sem exigir GPU. A configuração que compete em acurácia custou 2.297 s por rodada numa T4, contra 453 s do LightGBM em CPU.
A favor do fundacional ficam dois pontos: cobrir 80% da distância entre o sNaive e o melhor LightGBM sem treinar nada, e uma vantagem pequena mas consistente nos três níveis de baixo, os únicos com previsão direta e os que importam para decisão de reposição em SKU por loja.
Fine-tuning ficou de fora por custo. Se a inferência já custa 2.297 s numa T4, treinar 330 milhões de parâmetros por várias épocas é ordens de grandeza acima: possível na teoria, inviável nas condições deste estudo.
Já tinha rodado uma comparação parecida no lado tabular, TabFM contra GBMs. Em varejo intermitente, árvore ainda ganha, e o rigor de avaliação decide mais do que a escolha do modelo.
Essa disciplina de validação vem das competições do Kaggle, plataforma com que gosto de trabalhar: já documentei aqui as soluções finais do Porto Seguro Data Challenge, da ML Olympiad de educação e da ML Olympiad de saúde.
Perguntas frequentes#
O TimesFM 3.0 é melhor que o LightGBM para previsão de demanda?
No M5, não. O melhor LightGBM vence o WRMSSE por 8,1% (0.58372 contra 0.63534) e roda 5,1× mais rápido, em CPU. O TimesFM 3.0 só ganha nos três níveis mais granulares da hierarquia, que juntos pesam 25% da métrica.
Por que a mediana do TimesFM 3.0 colapsa em zero?
Em demanda intermitente, 69% das séries têm mediana exatamente zero, mesmo vendendo, porque a maioria dos dias é zero e poucos picos levantam só a média. Como o WRMSSE é erro quadrático, ler a mediana descarta de 23% a 29% do volume esperado.
O que é o WRMSSE e por que ele decide o vencedor?
É a média simples dos 12 níveis hierárquicos do M5. Como cada nível pesa 1/12 e tem de 1 a 30.490 séries, 154 séries agregadas carregam 75% da métrica. O veredito do composto reflete o topo da hierarquia, não a previsão no SKU por loja.
Dá para usar o TimesFM 3.0 em produção?
Os pesos vêm sob licença não-comercial e não-produtiva; produção exigiria o TimesFM 2.5. E o custo pesa: a configuração que compete em acurácia custou 2.297 s por rodada numa GPU T4, contra 453 s do LightGBM em CPU, 5,1× mais lento com hardware alugado.
Vale a pena trocar gradient boosting por modelo fundacional?
Depende da estrutura do sinal. Em varejo intermitente, árvore ainda ganha: as 50 primeiras colocações do M5 são todas tree-based. O zero-shot cobre 80% da distância entre o `sNaive` e o melhor LightGBM sem treino, um bom piso rápido para começar.
Referências#
- M5 Forecasting - Accuracy, competição e Competitors' Guide (Kaggle, 2020)
- TimesFM, código e model card (Google Research)
- TSFMAudit: auditoria de contaminação de modelos fundacionais de séries temporais (arXiv:2605.26161)
- Gneiting, T. (2011). Making and Evaluating Point Forecasts. JASA 106(494)
- Makridakis, Spiliotis & Assimakopoulos (2022). The M5 competition: results, findings and conclusions. IJF








