{"record":{"id":"d149be2534648fac","repo":"google-research/timesfm","slug":"output-dims-must-be-a-multiple-of-4-config-outpu-d149be","errorCode":null,"errorMessage":"Output dims must be a multiple of 4: {config.output_dims} % 4 != 0.","messagePattern":"Output dims must be a multiple of 4: (.+?) % 4 != 0\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/timesfm/torch/dense.py","lineNumber":67,"sourceCode":"      self.activation = nn.Identity()\n    else:\n      raise ValueError(f\"Activation: {config.activation} not supported.\")\n\n  def forward(self, x: torch.Tensor) -> torch.Tensor:\n    return self.output_layer(\n        self.activation(self.hidden_layer(x))\n    ) + self.residual_layer(x)\n\n\nclass RandomFourierFeatures(nn.Module):\n  \"\"\"Random Fourier features layer.\"\"\"\n\n  def __init__(self, config: configs.RandomFourierFeaturesConfig):\n    super().__init__()\n    self.config = config\n\n    if config.output_dims % 4 != 0:\n      raise ValueError(\n          f\"Output dims must be a multiple of 4: {config.output_dims} % 4 != 0.\"\n      )\n    num_projected_features = config.output_dims // 4\n\n    self.phase_shifts = nn.Parameter(torch.zeros(2, num_projected_features))\n    self.projection_layer = nn.Linear(\n        in_features=config.input_dims,\n        out_features=num_projected_features,\n        bias=config.use_bias,\n    )\n    self.residual_layer = nn.Linear(\n        in_features=config.input_dims,\n        out_features=config.output_dims,\n        bias=config.use_bias,\n    )\n\n  def forward(self, x: torch.Tensor) -> torch.Tensor:\n    projected = self.projection_layer(x)","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/google-research/timesfm/blob/331c6d33cb1ac2611de3056d0ac7164aab6301eb/src/timesfm/torch/dense.py#L49-L85","documentation":"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__.","triggerScenarios":"Constructing RandomFourierFeatures(RandomFourierFeaturesConfig(output_dims=N)) where N % 4 != 0 — e.g. output_dims=100 or 1023.","commonSituations":"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.","solutions":["Round output_dims to the nearest multiple of 4 before constructing the config (e.g. 1022 -> 1024).","Use shipped reference values (multiples of 4 such as 1280/1024) as templates.","Add a config-time check: assert output_dims % 4 == 0.","If a non-multiple size is truly needed, modify the layer to pad num_projected_features, noting this changes the weights format."],"exampleFix":"// before\nconfig = RandomFourierFeaturesConfig(output_dims=1002)  # ValueError\n// after\nconfig = RandomFourierFeaturesConfig(output_dims=1004)  # divisible by 4","handlingStrategy":"validation","validationCode":"if cfg.output_dims % 4 != 0:\n    cfg = dataclasses.replace(cfg, output_dims=math.ceil(cfg.output_dims / 4) * 4)","typeGuard":null,"tryCatchPattern":"try:\n    rff = RandomFourierFeatures(cfg)\nexcept ValueError as e:\n    if \"multiple of 4\" in str(e):\n        cfg = dataclasses.replace(cfg, output_dims=(cfg.output_dims // 4 + 1) * 4)\n        rff = RandomFourierFeatures(cfg)\n    else:\n        raise","preventionTips":["Round output_dims up to the nearest multiple of 4 in config factories.","Use reference dims (1280, 1024) that satisfy the constraint.","Add an assert output_dims % 4 == 0 wherever configs are built.","Note the // 4 coupling with phase_shifts shape when resizing."],"tags":["configuration","value-error","neural-network","dimension-mismatch"],"backgroundTag":"dimension-not-divisible","analyzedSha":"331c6d33cb1ac2611de3056d0ac7164aab6301eb","analyzedAt":"2026-08-29T01:04:23.138Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}