What Is REVIN Normalization in TimesFM? A Complete Technical Guide
REVIN (Reversible Instance Normalization) is a per-instance preprocessing technique in TimesFM that normalizes time-series data by subtracting the mean and dividing by the standard deviation, then reverses this operation after forecasting to restore the original scale.
TimesFM, Google's open-source foundation model for time-series forecasting, employs REVIN normalization to handle datasets with varying magnitudes without requiring explicit scale learning. This lightweight preprocessing step ensures numerical stability during training while preserving the ability to map predictions back to their original measurement units. Understanding how REVIN normalization in TimesFM works is essential for deploying or fine-tuning models from the google-research/timesfm repository.
How REVIN Normalization Works in TimesFM
REVIN operates on the principle of instance-wise standardization. For each time-series sample—or each channel within a multivariate sample—it calculates the mean μ and standard deviation σ, then transforms the data into a zero-mean, unit-variance space where the transformer model operates.
The "reversible" aspect is architecturally critical. After the model generates predictions in the normalized space, the exact same μ and σ statistics computed during input preprocessing are used to denormalize the outputs. This guarantees loss-less round-tripping between raw and normalized representations.
The Mathematical Logic
The algorithm follows four distinct operations:
- Broadcast statistics – Aligns μ and σ with input tensor dimensions by adding singleton dimensions (
None) to handle shape mismatches - Normalization – Applies
(x - μ) / σwith a safety guard against division by zero - Denormalization – Reverses the transform via
x * σ + μwhen thereverse=Trueflag is set - Numerical safety – Uses the
_TOLERANCEconstant to prevent division when σ approaches zero
REVIN Implementation in the TimesFM Source Code
The core logic lives in framework-specific utility modules, with identical mathematical operations implemented for both PyTorch and JAX/Flax backends.
PyTorch Implementation
In src/timesfm/torch/util.py, the revin() function handles normalization for the PyTorch backend:
def revin(x: torch.Tensor, mu: torch.Tensor, sigma: torch.Tensor, reverse: bool = False):
"""Reversible instance normalization."""
# Broadcast μ / σ to match the input dimensions.
if len(mu.shape) == len(x.shape) - 1:
mu = mu[..., None]
sigma = sigma[..., None]
elif len(mu.shape) == len(x.shape) - 2:
mu = mu[..., None, None]
sigma = sigma[..., None, None]
if reverse: # denormalize
return x * sigma + mu
else: # normalize
return (x - mu) / torch.where(sigma < _TOLERANCE, 1.0, sigma)
JAX/Flax Implementation
The JAX equivalent in src/timesfm/flax/util.py provides the same API with JIT compilation:
@functools.partial(jax.jit, static_argnames=("reverse",))
def revin(
x: Float[Array, "b ..."],
mu: Float[Array, "b ..."],
sigma: Float[Array, "b ..."],
reverse: bool = False,
):
"""Reversible per‑instance normalization."""
if len(mu.shape) == len(x.shape) - 1:
mu = mu[..., None]
sigma = sigma[..., None]
elif len(mu.shape) == len(x.shape) - 2:
mu = mu[..., None, None]
sigma = sigma[..., None, None]
if reverse:
return x * sigma + mu
else:
return (x - mu) / jnp.where(sigma < _TOLERANCE, 1.0, sigma)
Where REVIN Is Applied in the Model Pipeline
According to the source code in src/timesfm/timesfm_2p5/timesfm_2p5_torch.py, REVIN integration occurs at three critical points in the forecasting pipeline.
Input Normalization
Before the transformer encoder processes patched inputs, raw values are normalized using context statistics:
normed_inputs = revin(patched_inputs, context_mu, context_sigma, reverse=False)
Output Denormalization
After the decoder generates predictions in normalized space, the revin() function restores original units:
renormed_outputs = revin(normed_outputs, context_mu, context_sigma, reverse=True)
Autoregressive Decoding
During iterative generation, each newly created patch undergoes normalization with updated running statistics (new_mu, new_sigma) before subsequent model calls, then denormalization for the final forecast output.
Practical Usage Examples
Here is how to apply REVIN normalization when preprocessing data for TimesFM inference:
import torch
from src.timesfm.torch import util as timesfm_util
# Example: normalize a batch of time-series
batch = torch.randn(8, 96, 3) # (batch, time, channels)
mu = batch.mean(dim=1) # per-instance mean
sigma = batch.std(dim=1) # per-instance std
normed = timesfm_util.revin(batch, mu, sigma, reverse=False)
# ... feed `normed` to TimesFM ...
# After obtaining predictions `pred_normed`, revert:
pred_raw = timesfm_util.revin(pred_normed, mu, sigma, reverse=True)
For JAX users, the pattern remains identical:
import jax.numpy as jnp
from src.timesfm.flax import util as timesfm_util
batch = jnp.asarray(np.random.randn(8, 96, 3))
mu = jnp.mean(batch, axis=1)
sigma = jnp.std(batch, axis=1)
normed = timesfm_util.revin(batch, mu, sigma, reverse=False)
pred_raw = timesfm_util.revin(pred_normed, mu, sigma, reverse=True)
Summary
- REVIN normalization in TimesFM performs per-instance standardization using mean subtraction and division by standard deviation
- The
revin()function insrc/timesfm/torch/util.pyandsrc/timesfm/flax/util.pyprovides bidirectional transforms via thereverseboolean parameter - Input tensors are normalized before entering the transformer encoder, and predictions are denormalized afterward to preserve original scale
- The implementation includes safeguards against division by near-zero values through the
_TOLERANCEconstant - This preprocessing enables TimesFM to handle time-series with vastly different magnitudes without requiring the model to learn scale-invariant features implicitly
Frequently Asked Questions
Why is it called "Reversible" Instance Normalization?
It is called reversible because the same mean (μ) and standard deviation (σ) statistics used to normalize the input are stored and reused to denormalize the model's predictions. This ensures forecast values are returned in the original data scale rather than remaining in the normalized space, providing loss-less recovery of the original magnitude.
Does REVIN normalization affect model accuracy?
Yes, REVIN typically improves accuracy by removing scale-related distractions, allowing the transformer to learn temporal patterns rather than magnitude differences. According to the TimesFM source code, this approach stabilizes training across heterogeneous datasets with varying value ranges while maintaining interpretability in the original units.
How does TimesFM handle near-zero standard deviations?
The implementation guards against division by zero using a _TOLERANCE threshold. When σ falls below this value, the denominator defaults to 1.0, preventing numerical instability while preserving the mean subtraction for centering the data distribution.
Can I use REVIN normalization outside of TimesFM?
Absolutely. The revin() function is a standalone utility that can be imported from src.timesfm.torch.util or src.timesfm.flax.util and applied to any time-series preprocessing pipeline requiring reversible per-instance normalization, independent of the broader TimesFM architecture.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →