Implement window_size for decomposed forecasting in TimesFM 2.5 - #487
Implement window_size for decomposed forecasting in TimesFM 2.5#487philyuchkoff wants to merge 3 commits into
Conversation
bdff12d to
8d491be
Compare
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
This drops the existing uncompiled-model guard. When forecast_config is None, the first condition is false and the elif not self.forecast_config.return_backcast dereferences None, so forecast_with_covariates() now raises AttributeError instead of the documented “Model is not compiled” ValueError. Please keep the compile check first and add an uncompiled regression.
- Add moving_average() function to split series into trend and residual - Modify forecast(): when window_size > 0, decompose inputs into trend/residual, run forecast on both, sum the outputs - Block forecast_with_covariates() with explicit error when window_size > 0 - Update configs.py: remove TODO, add full parameter description - Add 9 unit tests for moving_average and integration tests for forecast() with window_size
8d491be to
51da429
Compare
The previous change replaced 'if forecast_config is None' with a window_size check, dropping the uncompiled guard. When forecast_config is None, this caused an AttributeError instead of the documented ValueError. Restore the compile check first, then check window_size.
|
@sylvesterkaczmarek |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
Hi, decomposition now runs before the existing max_context truncation. For long inputs, the retained trend/residual values can therefore be influenced by samples outside the configured model context; the v1 path truncated first and then applied the moving average. Could the input be clipped to max_context before moving_average()?
Truncate long inputs to max_context before applying moving_average(), matching v1 behavior. Without this, the trend/residual values were influenced by samples outside the configured model context.
|
@sylvesterkaczmarek |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
Re-checked both issues I raised. The uncompiled-model guard is again evaluated before window_size, preserving the documented ValueError, and long inputs are clipped to max_context before moving-average decomposition, matching the v1 ordering. Both findings are resolved.
Summary
Implements the
window_sizeparameter inForecastConfigthat was declared but never implemented (TODO(siriuz42)).Decomposed forecasting was originally present in TimesFM 1.0 but was lost during the 2.5 migration. This PR restores the feature.
How it works
When
window_size > 0is set inForecastConfig:moving_average()forecast(trend) + forecast(residual)This improves long-range forecast quality by letting the model separately handle slow trends and fast residuals.
Changes
src/timesfm/timesfm_2p5/timesfm_2p5_base.py: Addedmoving_average(), modifiedforecast(), blockedforecast_with_covariates()with explicit error whenwindow_size > 0src/timesfm/configs.py: ReplacedTODO(siriuz42)with full descriptiontests/test_base_utils.py: 9 unit tests formoving_average()(all pass)tests/test_model_loading.py: Integration tests forforecast()withwindow_sizeand error case with covariatesEdge cases
window_size = 0(default): backwards-compatible, no behavior changewindow_size >= len(ts): uses actual array length, decomposition degenerateswindow_size = 1: trend equals original series, residual is zeroforecast_with_covariates()raisesValueErrorwith clear messageSee
docs/plans/2026-09-03-window-size-design.mdfor full design rationale and algorithm.