Skip to content

Feat/patchtst fm#312

Merged
AzulGarza merged 17 commits intomainfrom
feat/patchtst-fm
Mar 7, 2026
Merged

Feat/patchtst fm#312
AzulGarza merged 17 commits intomainfrom
feat/patchtst-fm

Conversation

@spolisar
Copy link
Collaborator

@spolisar spolisar commented Feb 28, 2026

Add support for the new PatchTST-FM forecasting model.

PatchTST-FM is currently setup to use pytorch's mps backend when available, but there is a chance that will have issues. If it becomes a problem, we can disable that.

For now predicting with levels is disabled.

TODO:

@CLAassistant
Copy link

CLAassistant commented Feb 28, 2026

CLA assistant check
All committers have signed the CLA.

@spolisar spolisar marked this pull request as ready for review March 5, 2026 19:08
@AzulGarza AzulGarza requested review from AzulGarza and Copilot March 5, 2026 19:44
Copy link
Member

@AzulGarza AzulGarza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @spolisar! thanks so much! looks great so far, i left a couple of comments. can also add a plot to the nb? that way we can make sure everything looks good.

Comment on lines +107 to +150
def _left_pad_and_stack_1D(self, tensors: list[torch.Tensor]) -> torch.Tensor:
max_len = max(len(c) for c in tensors)
padded = []
for c in tensors:
assert isinstance(c, torch.Tensor)
assert c.ndim == 1
padding = torch.full(
size=(max_len - len(c),),
fill_value=torch.nan,
device=c.device,
dtype=c.dtype,
)
padded.append(torch.concat((padding, c), dim=-1))
return torch.stack(padded)

def _prepare_and_validate_context(
self,
context: list[torch.Tensor] | torch.Tensor,
) -> torch.Tensor:
if isinstance(context, list):
context = self._left_pad_and_stack_1D(context)
assert isinstance(context, torch.Tensor)
if context.ndim == 1:
context = context.unsqueeze(0)
assert context.ndim == 2
return context

def _maybe_impute_missing(
self, batch: torch.Tensor, dtype=torch.float32
) -> torch.Tensor:
if torch.isnan(batch).any():
batch = batch.to(dtype=dtype).numpy(force=True)
imputed_rows = []
for i in range(batch.shape[0]):
row = batch[i]
imputed_row = LastValueImputation()(row)
imputed_rows.append(imputed_row)
batch = np.vstack(imputed_rows)
batch = torch.tensor(
batch,
dtype=self.dtype,
device=self.device,
)
return batch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these three methods are also being used by sundial

def _left_pad_and_stack_1D(self, tensors: list[torch.Tensor]) -> torch.Tensor:
max_len = max(len(c) for c in tensors)
padded = []
for c in tensors:
assert isinstance(c, torch.Tensor)
assert c.ndim == 1
padding = torch.full(
size=(max_len - len(c),),
fill_value=torch.nan,
device=c.device,
dtype=c.dtype,
)
padded.append(torch.concat((padding, c), dim=-1))
return torch.stack(padded)
def _prepare_and_validate_context(
self,
context: list[torch.Tensor] | torch.Tensor,
) -> torch.Tensor:
if isinstance(context, list):
context = self._left_pad_and_stack_1D(context)
assert isinstance(context, torch.Tensor)
if context.ndim == 1:
context = context.unsqueeze(0)
assert context.ndim == 2
return context
def _maybe_impute_missing(self, batch: torch.Tensor) -> torch.Tensor:
if torch.isnan(batch).any():
batch = batch.float().numpy()
imputed_rows = []
for i in range(batch.shape[0]):
row = batch[i]
imputed_row = LastValueImputation()(row)
imputed_rows.append(imputed_row)
batch = np.vstack(imputed_rows)
batch = torch.tensor(
batch,
dtype=self.dtype,
device=self.device,
)
return batch
. let's abstract them. what comes to my mind is to create a new class, maybe in forecaster.py, called _Processor or a better name. that way we can reuse the same code across different models.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied them from Flowstate, so that sounds good.
The only attributes of the class that are used are dtype and device, so the options that come to mind are:

  • A class with dtype and device attributes
  • A class with static methods and dtype and device added as args where needed
  • Functions with dtype and device added as args where needed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

including them as attributes in the class sounds good.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AzulGarza does this seem good?
db20d39

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@AzulGarza AzulGarza requested a review from Copilot March 5, 2026 20:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@AzulGarza
Copy link
Member

@spolisar let's also take a look at copilot's comments. they are valuable.

@AzulGarza AzulGarza self-requested a review March 6, 2026 23:37
@AzulGarza AzulGarza merged commit 38909cc into main Mar 7, 2026
9 checks passed
@AzulGarza AzulGarza deleted the feat/patchtst-fm branch March 7, 2026 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants