Source code for ts2.models.single_session.stat_baseline.forecasting.trailing_mean

"""Trailing-window mean, held flat over the horizon.

Each unit's horizon is the average of its own last ``K`` observed bins. Reads observed
bins only, so val (full window) and test (future zeroed) give the identical prediction.
"""

import logging

import torch

from ..base import LOG_EPS, StatBaseline

log = logging.getLogger(__name__)

K_GRID = [1, 2, 3, 5, 8, 13, 21, 34, 45]  # trailing-window length (bins)


[docs] class TrailingMean(StatBaseline): """Trailing-window mean, held flat over the horizon. Args: k: trailing-window length (bins). ``None`` selects on val over ``K_GRID``. """ TASK = "forecasting" NAME = "trailing_mean" def __init__(self, k: int | None = None): super().__init__() self._k_arg = k self.k: int = k if k is not None else 5
[docs] def fit(self, train_dataset, val_dataset): self._check_horizon() obs_end = self._obs_end ks = [self._k_arg] if self._k_arg is not None else K_GRID val_counts = torch.from_numpy(self._windows(val_dataset)) # (B, T, N) target = val_counts[:, obs_end:, :] # (B, forecast_ind, N) best = (-float("inf"), self.k) for k in ks: k_eff = min(k, obs_end) # cannot look back past the observed portion tw_mean = val_counts[:, obs_end - k_eff : obs_end, :].mean(dim=1, keepdim=True) pred = tw_mean.clamp_min(LOG_EPS).log().expand(-1, self.forecast_ind, -1) score = self._score(pred.contiguous(), target) if score > best[0]: best = (score, k) self.val_score, self.k = best window_ms = self.k * self.bin_size * 1_000 log.info(f"{self.NAME}: selected K={self.k} bins ({window_ms:.0f} ms trailing window)")
[docs] def predict(self, spikes: torch.Tensor, **_) -> torch.Tensor: B, T, N = spikes.shape obs_end = T - self.forecast_ind k_eff = min(self.k, obs_end) tw_mean = spikes[:, obs_end - k_eff : obs_end, :].mean(dim=1, keepdim=True) log_rate = tw_mean.clamp_min(LOG_EPS).log() # (B, 1, N) return log_rate.expand(B, T, N).contiguous()