---
title: "Previsão agora é uma chamada de biblioteca: anotações de quem rodou o TimesFM 2.5"
url: https://tiarebalbi.com/pt-br/blog/running-timesfm-2-5-zero-shot-forecasting
markdown: https://tiarebalbi.com/pt-br/blog/running-timesfm-2-5-zero-shot-forecasting.md
description: "Mão na massa com o TimesFM 2.5 do Google: precisão zero-shot contra uma baseline seasonal-naive, como ele se comporta após uma quebra de regime e casos de uso de backend que valem a pena."
author: "Tiarê Balbi Bonamini"
locale: pt-br
published: 2026-08-26
updated: 2026-08-26
category: "AI"
tags: ["forecasting", "machine-learning", "timesfm", "observability", "capacity-planning", "python"]
translation: https://tiarebalbi.com/en/blog/running-timesfm-2-5-zero-shot-forecasting
---
# Previsão agora é uma chamada de biblioteca: anotações de quem rodou o TimesFM 2.5

Entreguei a um modelo de 200 milhões de parâmetros cinco semanas de telemetria falsa que ele nunca tinha visto — contagens horárias de requisições com ciclo diário, queda no fim de semana e uma leve tendência de alta — e pedi a próxima semana. Sem treinamento, sem tuning, sem nenhuma pista sobre a frequência dos dados. Ele superou uma baseline seasonal-naive em 15% e produziu cada previsão em 0,6 segundo na CPU da máquina em que rodei. Depois desloquei a série para um novo patamar uma semana antes da previsão, do jeito que um lançamento ou uma migração desloca tráfego real, e o ranking se inverteu: a baseline mais burra que conheço venceu por um fator de 1,5.

Os dois resultados são o ponto destas anotações. O [TimesFM 2.5](https://github.com/google-research/timesfm) é o argumento mais forte até agora de que previsão está virando uma chamada de biblioteca em vez de um projeto de modelagem — e o formato da falha que ele me mostrou é exatamente o que checar antes de plugá-lo em qualquer coisa que importe.

## O que chamou a atenção de todo mundo

O TimesFM começou como uma aposta de pesquisa de que a receita dos LLMs se transfere para séries temporais. O [post original do Google Research](https://research.google/blog/a-decoder-only-foundation-model-for-time-series-forecasting/) (fevereiro de 2024, com o paper no ICML 2024) descreve um transformer decoder-only que lê uma série em patches — 32 pontos temporais de entrada, 128 de saída por passo — pré-treinado em cerca de 100 bilhões de pontos temporais do mundo real, boa parte deles Google Trends e pageviews da Wikipédia. A afirmação que fez as pessoas prestarem atenção: em zero-shot, ele se aproxima de modelos como DeepAR e PatchTST que foram treinados no dataset alvo. Treine uma vez em tudo, preveja qualquer coisa — a mesma inversão que os modelos de linguagem provocaram no NLP, onde o treinamento por tarefa colapsou em pré-treinar-e-depois-promptar.

A [versão 2.5](https://github.com/google-research/timesfm), lançada em 15 de setembro de 2025, é o motivo de eu finalmente ter rodado o modelo. Três mudanças se destacam nas notas de release. O modelo encolheu dos 500M de parâmetros da 2.0 para 200M e ficou mais preciso. O contexto máximo cresceu de 2.048 pontos para 16.384 — o suficiente para entregar dois anos de dados horários. E as partes desconfortáveis da API antiga sumiram: acabou o indicador de frequência que era preciso adivinhar, e entrou uma cabeça opcional de quantis de 30M de parâmetros que emite quantis contínuos até um horizonte de 1.000 passos. No [GIFT-Eval](https://arxiv.org/abs/2410.10393), o benchmark comunitário para previsão geral, o Google reportou a 2.5 [liderando os foundation models zero-shot tanto em MASE quanto em CRPS](https://www.marktechpost.com/2025/09/16/google-ai-ships-timesfm-2-5-smaller-longer-context-foundation-model-that-now-leads-gift-eval-zero-shot-forecasting/) no lançamento — precisão pontual e probabilística ao mesmo tempo. Essa liderança não durou. O [Chronos-2](https://arxiv.org/abs/2510.15821), publicado um mês depois, em outubro de 2025, reporta resultados de estado da arte no GIFT-Eval à frente do TimesFM 2.5 nas duas métricas, e recebe covariáveis nativamente por in-context learning em vez de por um canal separado. Leia o topo desse leaderboard como alvo móvel, não como propriedade de um modelo. A licença é Apache-2.0.

O sinal mais forte de que isso deixou de ser um artefato de pesquisa: em [novembro de 2025, o Google plugou o TimesFM 2.5 no BigQuery e no AlloyDB](https://cloud.google.com/blog/products/data-analytics/timesfm-models-in-bigquery-and-alloydb) como funções SQL — `AI.FORECAST` está GA no BigQuery, detecção de anomalias está em preview, e o modelo por trás deles agora é treinado em mais de 400 bilhões de pontos temporais. Prever uma tabela virou uma chamada de função que mora onde os dados já estão. Quando uma capacidade cruza de "clone o repositório" para "é uma função SQL", engenheiros de backend a herdam tenham pedido ou não.

## Cinco semanas de telemetria falsa e uma baseline com amnésia

Papers fazem benchmark em varejo, tráfego e clima. Eu me importo com séries no formato daquelas que o trabalho de backend realmente produz, então meu harness de teste gera telemetria horária — carga base em torno de 1.000 requisições por hora, ciclo diário senoidal, queda de 25% no fim de semana, tendência lenta de alta e ruído. Dois cenários: um estável e outro em que o nível salta 60% uma semana antes do início da previsão e permanece lá, do jeito que o tráfego se move depois de um lançamento.

A baseline é seasonal-naive: repita a última semana, sem mudar uma vírgula. É o adversário honesto de qualquer sistema de previsão, porque custa uma linha e nenhum modelo que perde para ela merece a palavra "modelo" em produção.

```python
"""Experimento zero-shot com TimesFM 2.5: séries com formato de telemetria vs seasonal-naive."""
import time

import numpy as np

RNG = np.random.default_rng(42)
HOURS_PER_WEEK = 168
CONTEXT = 5 * HOURS_PER_WEEK   # 5 semanas de histórico horário
HORIZON = HOURS_PER_WEEK       # prever 1 semana à frente


def telemetry(n, base=1000.0, trend_per_hour=0.05, break_at=None, break_factor=1.0):
    """Série horária: sazonalidade diária + semanal, leve tendência, ruído, salto de nível opcional."""
    t = np.arange(n)
    daily = 0.35 * np.sin(2 * np.pi * (t % 24) / 24 - 1.2)
    weekly = np.where((t // 24) % 7 >= 5, -0.25, 0.0)   # queda de fim de semana
    level = base + trend_per_hour * t
    series = level * (1.0 + daily + weekly)
    if break_at is not None:
        series[break_at:] *= break_factor
    return series + RNG.normal(0, 0.03 * base, n)


def seasonal_naive(context, horizon, season=HOURS_PER_WEEK):
    reps = int(np.ceil(horizon / season))
    return np.tile(context[-season:], reps)[:horizon]


def mae(a, b):
    return float(np.mean(np.abs(a - b)))


def main():
    import timesfm

    model = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
        "google/timesfm-2.5-200m-pytorch")
    model.compile(
        timesfm.ForecastConfig(
            max_context=CONTEXT, max_horizon=HORIZON,
            normalize_inputs=True, use_continuous_quantile_head=True,
            fix_quantile_crossing=True,
        )
    )
    scenarios = {
        "steady": telemetry(CONTEXT + HORIZON),
        "regime-break": telemetry(CONTEXT + HORIZON, break_at=CONTEXT - HOURS_PER_WEEK,
                                  break_factor=1.6),
    }
    for name, series in scenarios.items():
        context, actual = series[:CONTEXT], series[CONTEXT:]
        start = time.monotonic()
        point, quantiles = model.forecast(horizon=HORIZON, inputs=[context])
        elapsed = time.monotonic() - start
        tfm_mae = mae(point[0], actual)
        naive_mae = mae(seasonal_naive(context, HORIZON), actual)
        q = quantiles[0]  # (horizonte, 10): média + decis q10..q90
        spread = float(np.mean(q[:, 9] - q[:, 1]))  # largura média da banda q90-q10
        print(f"[{name}] TimesFM MAE={tfm_mae:.1f}  seasonal-naive MAE={naive_mae:.1f}  "
              f"ratio={tfm_mae / naive_mae:.2f}  q10-q90 width={spread:.1f}  "
              f"forecast time={elapsed:.1f}s")


if __name__ == "__main__":
    main()
```

Rode com `python timesfm_experiment.py` depois de `pip install "timesfm[torch]"` — a primeira execução baixa o checkpoint do Hugging Face. Duas linhas merecem comentário. O `ForecastConfig` é onde a ergonomia da 2.5 aparece: `normalize_inputs` cuida da escala, a cabeça contínua de quantis é uma flag e não sobrou nenhum parâmetro de frequência para você chutar errado. E a saída de quantis tem shape `(horizonte, 10)` — a média mais os decis q10 até q90 — o que acaba sendo a coisa mais valiosa que o modelo emite.

Na minha máquina (Python 3.11, torch 2.11, apenas CPU) a saída foi:

```
[steady]       TimesFM MAE=27.8  seasonal-naive MAE=32.7  ratio=0.85  q10-q90 width=102.0  forecast time=0.6s
[regime-break] TimesFM MAE=56.2  seasonal-naive MAE=37.6  ratio=1.49  q10-q90 width=268.2  forecast time=0.6s
```

O cenário estável é a manchete que os papers prometeram, reproduzida na minha mesa: 15% melhor que o seasonal-naive, em zero-shot, numa série que o modelo nunca viu, com uma banda q10–q90 de cerca de ±5% do nível, em 0,6 segundo na CPU. Sem pipeline de treinamento, sem hiperparâmetros, sem GPU.

A quebra de regime é onde a coisa fica instrutiva, e o detalhamento diário mostra um quadro mais nítido que o agregado. O modelo não erra o novo patamar — seu pior dia é o primeiro, em que prevê uma média diária de 1.594 contra 1.675 reais, ainda hedgeando em direção às cinco semanas de histórico mais baixo que recebeu. Depois ele se adapta, acompanha o novo nível dos dias úteis com erro de aproximadamente 1–2% e fica 2–6% acima na queda do fim de semana. O seasonal-naive, que lembra exatamente uma semana — toda ela pós-quebra —, fica mais perto da realidade em quase todos os dias. Amnésia, nesta situação específica, é uma feature: a baseline não pode ser distraída pelo regime antigo porque nunca o viu.

O comportamento que redime o modelo é que ele sinaliza a própria confusão. A banda q10–q90 que ficou em média em 102 requisições por hora no cenário estável foi para 268 em média depois da quebra, e cresceu de 225 no primeiro dia para 377 no sétimo. A previsão pontual perdeu para uma linha de código; a estimativa de incerteza me disse para não confiar na previsão pontual. A figura abaixo mostra os dois painéis — a previsão horária acompanhando o novo regime e as médias diárias expondo o hedge.

​

![Dois painéis: a previsão horária do TimesFM acompanhando o regime pós-quebra, e as médias diárias mostrando o modelo hedgeando em direção ao patamar antigo, mais baixo, no primeiro dia](https://rso2zax703psuq0y.public.blob.vercel-storage.com/postscontent/1787627134542-e8cdkj4k7fr.jpeg)

## O que observar antes de confiar nele

Minha execução trouxe à tona a primeira ressalva diretamente: o modelo extrapola padrões, não causas. Um salto de nível que ele só viu por uma semana é ponderado contra tudo que veio antes. Em termos de produção, a semana seguinte a cada lançamento, migração ou mudança de preço é exatamente quando a previsão é menos confiável — e é também quando todo mundo mais quer uma previsão.

A segunda decorre dela: trate a banda de quantis como a saída principal, não como enfeite. Uma previsão pontual plugada num autoscaler é uma decisão sem barras de erro; a mesma previsão condicionada à largura da banda é uma decisão que sabe quando se abster. Na minha execução com quebra de regime, a banda alargou 2,6x antes de o erro pontual se materializar como problema — esse sinal é de graça, e a flag `fix_quantile_crossing` garante que os decis chegam já ordenados.

Terceiro, o modelo é univariado por série. Ele lê um fluxo de números; não pode saber que um deploy subiu, que uma campanha de marketing começou ou que um feriado está chegando, a menos que essa informação já esteja visível como histórico na própria série. Suporte a covariáveis existe como um [add-on XReg restaurado em outubro de 2025](https://github.com/google-research/timesfm), mas o caminho mágico do zero-shot é histórico-entra, previsão-sai. Qualquer série cujo futuro seja dirigido por eventos fora do próprio passado vai punir essa cegueira.

Quarto, segure os números de benchmark com leveza. Um [paper de outubro de 2025 sobre avaliação de foundation models de séries temporais](https://arxiv.org/abs/2510.13654) argumenta que, à medida que os corpora de pré-treino engolem a maior parte dos dados públicos de séries temporais, sobreposição entre treino e teste e correlação temporal tornam os leaderboards zero-shot propensos a "estimativas de desempenho excessivamente otimistas que não generalizam para cenários do mundo real". Não leio isso como acusação contra nenhum modelo específico — é um problema estrutural da categoria, o mesmo debate de contaminação pelo qual os benchmarks de LLM passaram. A consequência prática é o padrão que usei acima: seu próprio holdout, contra o seasonal-naive, nas suas próprias séries, é o único benchmark que resolve alguma coisa. O harness tem menos de 80 linhas; não há desculpa para pular.

## Onde eu realmente usaria

Os casos de uso pelos quais eu começaria compartilham um formato: séries sazonais, com tendência lenta, em que uma estimativa de nível para a próxima semana ou o próximo dia muda uma decisão, e em que errar é recuperável.

Planejamento de capacidade e pré-escala é o óbvio. Preveja o pico horário de amanhã a partir de seis semanas de histórico e aqueça capacidade à frente da curva em vez de reagir a ela; um autoscaler reativo continua como rede de segurança, então uma previsão ruim custa dinheiro, não disponibilidade. Planejamento de fila e backlog é a mesma matemática que trabalhei nas minhas anotações anteriores sobre aritmética de recuperação de backlog: o tempo de drenagem depende da curva de chegadas que você espera, e uma previsão de chegadas transforma "esse backlog vai zerar antes do pico da noite?" de palpite em inequação. Pré-aquecimento de cache antes de uma rampa de tráfego prevista compra o mesmo ganho de latência que pré-aquecer por cron, menos a ignorância do cron sobre tendência. E projeção de error budget — prever uma série de burn rate para ver se o orçamento sobrevive ao mês — é uma decisão que tolera imprecisão e se beneficia diretamente da banda de quantis.

Se os dados já vivem no BigQuery, o cálculo pende ainda mais: `AI.FORECAST` transforma o experimento em uma única query sem nenhuma infraestrutura, que é a forma mais barata possível de descobrir se um foundation model se paga nas suas séries. O mesmo release de GA trouxe o `AI.EVALUATE`, que pontua uma previsão contra os valores reais separados como holdout — a comparação que defendi acima, em uma segunda query. Passe `model => 'TimesFM 2.5'` explicitamente; o padrão não é a 2.5.

Onde eu não usaria: qualquer coisa com contrato de reação sub-segundo (esse é o trabalho da detecção de anomalias, não da previsão); séries dominadas por eventos externos que o modelo não enxerga — promoções, deploys, tráfego de incidente; a primeira semana após qualquer mudança conhecida de regime, conforme meus próprios resultados acima; e qualquer série em que a razão contra o seasonal-naive volte perto de 1,0, porque um modelo que empata com uma linha de código é puro overhead operacional.

### Pontos que levo daqui

* Em zero-shot, sobre telemetria estável, o TimesFM 2.5 superou o seasonal-naive em 15% em 0,6 segundo na CPU — sem pipeline de treinamento, sem GPU, sem precisar informar a frequência.
* Uma semana depois de um salto de nível de 60%, o mesmo modelo perdeu para o seasonal-naive por 1,5x. A semana seguinte a um lançamento ou migração é quando a previsão é menos confiável e mais desejada.
* Trate a banda q10–q90 como a saída principal. Ela alargou 2,6x no regime quebrado antes de o erro pontual importar — um sinal gratuito de abstenção para qualquer coisa que leia a previsão.
* O modelo é univariado: deploys, promoções e feriados são invisíveis, a menos que já apareçam como histórico na série.
* Posição em leaderboard é temporária — o Chronos-2 assumiu a liderança do GIFT-Eval um mês depois da 2.5. Rode o harness no seu próprio holdout; uma razão contra o seasonal-naive perto de 1,0 significa que o modelo é puro overhead operacional.

A regra de decisão que estou guardando disto: rode o harness contra o seasonal-naive no seu próprio holdout — a razão decide se o modelo merece um lugar no loop, e a banda de quantis decide, hora a hora, se acreditar nele. O experimento que já deixei na fila é o caminho das covariáveis: se o XReg com uma série marcadora de deploys fecha a lacuna da quebra de regime, ou se aquela primeira semana depois de um lançamento simplesmente pertence aos humanos. O Chronos-2 transforma isso numa pergunta de dois modelos, já que ele recebe covariáveis in-context em vez de por um add-on separado.

​
