# Understanding the `force_flip_invariance` Parameter in TimesFM

> Learn about the force flip invariance parameter in TimesFM. Discover how it uses dual input processing to ensure accurate affine transformations for reliable time series forecasting.

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

---

**The `force_flip_invariance` parameter is a boolean configuration flag in the `google-research/timesfm` repository that enforces affine transformation symmetry by running the model twice—once on the original input and once on the negated input—then averaging the results to guarantee the mathematical property TimesFM(aX + b) = a × TimesFM(X) + b for any scalar `a` and offset `b`.**

The `force_flip_invariance` parameter appears in the `ForecastConfig` dataclass within the TimesFM (Time Series Foundation Model) codebase. According to the implementation in [`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py), this flag controls whether the forecasting pipeline guarantees symmetry under sign flips and scaling operations, which is crucial for maintaining consistent predictions when input time series undergo affine transformations.

## What Is Flip Invariance in TimesFM?

**Flip invariance** ensures that the model's predictions respect affine transformations of the input time series. When enabled (the default behavior), TimesFM guarantees that for any scalar value `a` (including negative values) and any offset `b`, the following property holds:

\[
\text{TimesFM}(aX + b) = a \times \text{TimesFM}(X) + b
\]

To achieve this, the forecasting pipeline executes **two decode passes**: one using the original input series and another using the *flipped* (negated) input. The model then averages these two predictions, ensuring the final output remains symmetric with respect to sign changes. When the flag is set to `False`, the model skips the second decode pass, returning only the standard forecast. This reduces computational overhead but breaks the symmetry guarantee for negative scalings.

## Implementation Details in the Source Code

### Configuration Definition in [`configs.py`](https://github.com/google-research/timesfm/blob/main/configs.py)

The flag is formally defined in **[`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py)** within the `ForecastConfig` dataclass. At line 42, `force_flip_invariance` is declared as a boolean field defaulting to `True`. This configuration object propagates through the TimesFM initialization and controls the decoding behavior at inference time.

```python

# src/timesfm/configs.py - Line 42

@dataclass
class ForecastConfig:
    max_context: int = 1024
    max_horizon: int = 256
    force_flip_invariance: bool = True  # Default enables symmetry enforcement

```

### Torch Implementation

The Torch-based decoding 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)**. Around line 31, the implementation checks the flag and, when active, invokes `self.model.decode` on `-inputs` (the negated series). It then combines these results with the original predictions through averaging to maintain the affine equivariance property.

```python

# Conceptual flow from src/timesfm/timesfm_2p5/timesfm_2p5_torch.py

if forecast_config.force_flip_invariance:
    # Run decoder on negative inputs

    flipped_pred = self.model.decode(-inputs, ...)
    # Average with original prediction

    prediction = (original_pred + flipped_pred) / 2

```

### Flax Implementation

The Flax (JAX) implementation 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)** utilizes a dedicated helper function `_force_flip_invariance_fn`, defined around line 8. This function manages the transformation of quantile outputs from the negated run and ensures proper averaging to preserve the mathematical invariance across different backend implementations.

## Configuration and Usage Examples

To utilize this feature, instantiate `ForecastConfig` and pass it to your model's compile method. The default configuration enables flip invariance, which is recommended for production forecasting to ensure robustness against input transformations.

```python

# Example 1: Default behavior (flip invariance enabled)

from timesfm.configs import ForecastConfig

cfg = ForecastConfig(
    max_context=1024,
    max_horizon=256,
    force_flip_invariance=True,  # Optional; True is default

)

model.compile(forecast_config=cfg)

```

For latency-sensitive applications where input series are guaranteed to be positively scaled, you can disable the feature to reduce compute by roughly half (avoiding the second decode pass).

```python

# Example 2: Disable for faster inference

cfg = ForecastConfig(
    max_context=1024,
    max_horizon=256,
    force_flip_invariance=False,  # Skip extra decode pass

)

model.compile(forecast_config=cfg)

```

The [`timesfm-forecasting/scripts/forecast_csv.py`](https://github.com/google-research/timesfm/blob/main/timesfm-forecasting/scripts/forecast_csv.py) script demonstrates practical usage at line 68, where the configuration is typically instantiated with default values but can be overridden via command-line arguments or direct modification.

## Summary

- **`force_flip_invariance`** is defined in [`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py) as a boolean field within `ForecastConfig`, defaulting to `True`.
- When enabled, the model runs two decode passes (original and negated inputs) and averages results to guarantee **affine equivariance**: TimesFM(aX + b) = a × TimesFM(X) + b.
- The Torch implementation in [`timesfm_2p5_torch.py`](https://github.com/google-research/timesfm/blob/main/timesfm_2p5_torch.py) handles this by decoding `-inputs` and averaging.
- The Flax implementation in [`timesfm_2p5_flax.py`](https://github.com/google-research/timesfm/blob/main/timesfm_2p5_flax.py) uses `_force_flip_invariance_fn` to manage quantile flipping and averaging.
- Disabling the flag reduces inference latency by eliminating the second decode pass but sacrifices the symmetry guarantee for negative scaling factors.

## Frequently Asked Questions

### What happens when `force_flip_invariance` is set to True?

When enabled, TimesFM executes the decoder twice: once on the original input tensor and once on the negated input (`-inputs`). It then averages these two predictions, which mathematically enforces the property that predictions transform linearly with the input, specifically handling negative scalings correctly.

### Does disabling `force_flip_invariance` affect prediction accuracy?

Disabling the flag does not inherently reduce accuracy for standard positive-scaled inputs, but it removes the guarantee that predictions will correctly transform under affine operations involving negative scalars. If your application involves differenced series or reflections that result in negative values, disabling this flag may lead to inconsistent forecasts.

### Where is the `force_flip_invariance` parameter defined in the codebase?

The parameter is formally defined in **[`src/timesfm/configs.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/configs.py)** at line 42 within the `ForecastConfig` dataclass. It is consumed by the model implementations 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) and [`src/timesfm/timesfm_2p5/timesfm_2p5_flax.py`](https://github.com/google-research/timesfm/blob/main/src/timesfm/timesfm_2p5/timesfm_2p5_flax.py).

### Is there a performance cost to using flip invariance?

Yes. Enabling `force_flip_invariance` approximately doubles the decoding compute because the model runs the full forward pass twice (once per input sign). According to the implementation in [`timesfm_2p5_torch.py`](https://github.com/google-research/timesfm/blob/main/timesfm_2p5_torch.py), this involves calling `self.model.decode` on both the original and negated inputs, which doubles the inference time for the decoding phase.