# How to Compile the TimesFM Model for Forecasting: PyTorch and JAX Guide

> Compile the TimesFM model for forecasting with PyTorch and JAX. Load weights, configure lengths, and use model.compile() for high-performance batched inference.

- Repository: [Google Research/timesfm](https://github.com/google-research/timesfm)
- Tags: how-to-guide
- Published: 2026-04-02

---

**To compile the TimesFM model, load the pretrained weights for your chosen backend, configure the context and horizon lengths, and call `model.compile()` to build an optimized decode kernel that validates input dimensions and enables high-performance batched inference.**

The `google-research/timesfm` repository provides a 200M parameter time-series foundation model with dual backend support. Compiling the TimesFM model is a mandatory initialization step that prepares the architecture for inference by aligning patch sizes, enforcing context limits, and generating backend-specific execution kernels. This guide details the compilation API for both PyTorch and Flax/JAX implementations using the exact source paths and method signatures from the codebase.

## Why Compile the TimesFM Model?

Compilation performs three critical functions before you can call `model.forecast()`:

- **Kernel Generation**: Creates a custom decode closure (PyTorch) or `nnx.pmap` kernel (Flax) that executes the forward pass with fixed `max_context` and `max_horizon` dimensions.
- **Validation**: Automatically adjusts input and output lengths to be multiples of the model's patch sizes (`p` for input patches, `o` for output patches) and verifies that `max_context + max_horizon` does not exceed the model's internal context limit.
- **Configuration Storage**: Persists a `ForecastConfig` object (PyTorch) or scalar parameters (Flax) that control optional behaviors including input normalization, flip invariance, and continuous quantile heads.

According to `src/timesfm/timesfm_2p5/timesfm_2p5_base.py:59-61`, the base class explicitly checks that `self.compiled_decode` exists and raises a clear error if compilation was skipped.

## Compiling the PyTorch Backend

The PyTorch implementation requires a `ForecastConfig` dataclass and performs rigorous limit checking during compilation.

### Step-by-Step Compilation Process

In [`src/timesfm/timesfm_2p5/timesfm_2p5_torch.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/timesfm_2p5/timesfm_2p5_torch.py), the `compile()` method executes the following sequence (lines 68-124):

1. **Size Alignment**: Adjusts `max_context` and `max_horizon` to be multiples of patch sizes `p` and `o` (lines 68-84).
2. **Limit Enforcement**: Validates that `max_context + max_horizon` does not exceed `self.model.config.context_limit`, raising an error if violated (lines 84-89).
3. **Config Storage**: Assigns the `ForecastConfig` instance to `self.forecast_config` (line 94).
4. **Kernel Construction**: Builds a `_compiled_decode` closure that handles tensor casting, optional normalization, and quantile processing (lines 96-124).
5. **Assignment**: Stores the closure in `self.compiled_decode` (line 87).

### PyTorch Compilation Example

```python
import torch
import numpy as np
import timesfm
from timesfm import ForecastConfig

# Load the pretrained TimesFM-2.5 200M PyTorch model

model = timesfm.TimesFM_2p5_200M_torch.from_pretrained(
    "google/timesfm-2.5-200m-pytorch"
)

# Configure forecasting parameters

fc = ForecastConfig(
    max_context=1024,          # Input window length (adjusted to patch multiple)

    max_horizon=256,           # Prediction steps (adjusted to patch multiple)

    normalize_inputs=True,     # Enable Revin normalization

    use_continuous_quantile_head=True,
    force_flip_invariance=True,
    infer_is_positive=True,
    fix_quantile_crossing=True,
)

# Compile the model (creates optimized decode kernel)

model.compile(fc)

# Execute forecast

inputs = [np.linspace(0, 1, 100), np.sin(np.linspace(0, 20, 67))]
point, quantile = model.forecast(horizon=12, inputs=inputs)

```

The `ForecastConfig` dataclass is defined in [`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py), while the compilation logic resides in [`src/timesfm/timesfm_2p5/timesfm_2p5_torch.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/timesfm_2p5/timesfm_2p5_torch.py).

## Compiling the Flax/JAX Backend

The Flax implementation uses direct integer arguments rather than a configuration object and leverages JAX's `nnx.pmap` for parallel execution.

### JAX Compilation Parameters

In [`src/timesfm/timesfm_2p5/timesfm_2p5_flax.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/timesfm_2p5/timesfm_2p5_flax.py), the `compile()` method (lines 43-73) performs:

- **Patch Alignment**: Rounds `context` and `horizon` to valid patch multiples using the same logic as PyTorch (lines 43-56).
- **Parameter Storage**: Assigns `self.context`, `self.horizon`, and `self.per_core_batch_size` (lines 58-60).
- **Parallel Kernel**: Constructs `compiled_decode_kernel` using `nnx.pmap` to call `model.decode` across all available devices (lines 62-73).

Unlike the PyTorch backend, the Flax implementation does not explicitly check context limits during compilation; out-of-bounds errors surface during kernel execution.

### Flax Compilation Example

```python
import jax.numpy as jnp
import timesfm
from timesfm import TimesFM_2p5_200M_flax

# Load the Flax/JAX checkpoint

model = TimesFM_2p5_200M_flax.from_pretrained(
    "google/timesfm-2.5-200m-flax"
)

# Compile with explicit integers (must be patch multiples)

model.compile(context=1024, horizon=256, per_core_batch_size=1)

# Prepare inputs and forecast

inputs = [jnp.linspace(0, 1, 100), jnp.sin(jnp.linspace(0, 20, 67))]
point, quantile = model.forecast(horizon=12, inputs=inputs)

```

Post-decode processing in Flax (flip invariance, quantile head application, and crossing fixes) occurs in separate JIT-compiled helpers invoked during `forecast()`, as seen in [`src/timesfm/timesfm_2p5/timesfm_2p5_flax.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/timesfm_2p5/timesfm_2p5_flax.py) around lines 70-150.

## Summary

Compiling the TimesFM model is a required prerequisite for inference that ensures optimal performance and valid input dimensions:

- **PyTorch**: Pass a `ForecastConfig` object to `compile()`; the method validates context limits at `src/timesfm/timesfm_2p5/timesfm_2p5_torch.py:84-89`.
- **Flax/JAX**: Pass integer `context` and `horizon` values; compilation builds an `nnx.pmap` kernel at `src/timesfm/timesfm_2p5/timesfm_2p5_flax.py:62-73`.
- Both backends validate patch-size alignment and store compilation state required by the base class check in `src/timesfm/timesfm_2p5/timesfm_2p5_base.py:59-61`.
- Execute compilation once after `from_pretrained()` and before the first `forecast()` call.

## Frequently Asked Questions

### What happens if I call forecast() without compiling the TimesFM model?

The base class implementation in `src/timesfm/timesfm_2p5/timesfm_2p5_base.py:59-61` explicitly checks for the presence of `self.compiled_decode`. If you attempt to run inference before compilation, the model raises a clear runtime error indicating that the decode kernel has not been initialized.

### Can I change the context length after compilation?

No. The compilation process fixes `max_context` and `max_horizon` to create an optimized decode kernel. If you need to forecast with different input or output lengths, you must re-invoke `model.compile()` with the new dimensions. This constraint applies to both the PyTorch and Flax/JAX backends.

### How do the PyTorch and JAX compilation approaches differ?

**PyTorch compilation** uses a `ForecastConfig` dataclass from [`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py) and enforces strict context limit checks during the compile phase. **JAX compilation** accepts direct integer arguments for `context` and `horizon`, builds a parallelized kernel using `nnx.pmap`, and delegates limit validation to runtime. The PyTorch backend stores a closure for post-processing, while Flax applies post-decode transformations through separate JIT-compiled functions.

### What is the correct per_core_batch_size for JAX compilation?

The `per_core_batch_size` parameter in Flax compilation determines the batch size per device before parallelization. Set this value based on your hardware memory constraints; the total batch size equals `per_core_batch_size` multiplied by the device count. For single-device inference, use `per_core_batch_size=1` as shown in the Flax example, then scale up for multi-GPU or TPU pods.