google-research/timesfm · error · ValueError

Output dims must be a multiple of 4: {config.output_dims} %

Error message

Output dims must be a multiple of 4: {config.output_dims} % 4 != 0.

What it means

RandomFourierFeatures requires output_dims to be divisible by 4 because the layer computes num_projected_features = output_dims // 4 (phase_shifts has shape (2, output_dims//4)). A non-multiple of 4 raises ValueError in __init__.

Source

Thrown at src/timesfm/torch/dense.py:67

      self.activation = nn.Identity()
    else:
      raise ValueError(f"Activation: {config.activation} not supported.")

  def forward(self, x: torch.Tensor) -> torch.Tensor:
    return self.output_layer(
        self.activation(self.hidden_layer(x))
    ) + self.residual_layer(x)


class RandomFourierFeatures(nn.Module):
  """Random Fourier features layer."""

  def __init__(self, config: configs.RandomFourierFeaturesConfig):
    super().__init__()
    self.config = config

    if config.output_dims % 4 != 0:
      raise ValueError(
          f"Output dims must be a multiple of 4: {config.output_dims} % 4 != 0."
      )
    num_projected_features = config.output_dims // 4

    self.phase_shifts = nn.Parameter(torch.zeros(2, num_projected_features))
    self.projection_layer = nn.Linear(
        in_features=config.input_dims,
        out_features=num_projected_features,
        bias=config.use_bias,
    )
    self.residual_layer = nn.Linear(
        in_features=config.input_dims,
        out_features=config.output_dims,
        bias=config.use_bias,
    )

  def forward(self, x: torch.Tensor) -> torch.Tensor:
    projected = self.projection_layer(x)

View on GitHub (pinned to 331c6d33cb)

Solutions

  1. Round output_dims to the nearest multiple of 4 before constructing the config (e.g. 1022 -> 1024).
  2. Use shipped reference values (multiples of 4 such as 1280/1024) as templates.
  3. Add a config-time check: assert output_dims % 4 == 0.
  4. If a non-multiple size is truly needed, modify the layer to pad num_projected_features, noting this changes the weights format.

Example fix

// before
config = RandomFourierFeaturesConfig(output_dims=1002)  # ValueError
// after
config = RandomFourierFeaturesConfig(output_dims=1004)  # divisible by 4
Defensive patterns

Strategy: validation

Validate before calling

if cfg.output_dims % 4 != 0:
    cfg = dataclasses.replace(cfg, output_dims=math.ceil(cfg.output_dims / 4) * 4)

Try / catch

try:
    rff = RandomFourierFeatures(cfg)
except ValueError as e:
    if "multiple of 4" in str(e):
        cfg = dataclasses.replace(cfg, output_dims=(cfg.output_dims // 4 + 1) * 4)
        rff = RandomFourierFeatures(cfg)
    else:
        raise

Prevention

When it happens

Trigger: Constructing RandomFourierFeatures(RandomFourierFeaturesConfig(output_dims=N)) where N % 4 != 0 — e.g. output_dims=100 or 1023.

Common situations: Tuning the RFF dimension for a custom head with an arbitrary size; scaling dims from another model without this constraint; accidentally setting output_dims to an input feature count.

Related errors


AI-assisted analysis of google-research/timesfm@331c6d33cb (2026-08-29). Data as JSON: /api/errors/d149be2534648fac. Report an issue: GitHub.