Skip to content

[ENH] softs_v2 Model added - #2232

Open
Muhammad-Rebaal wants to merge 33 commits into
sktime:mainfrom
Muhammad-Rebaal:softs_model
Open

[ENH] softs_v2 Model added#2232
Muhammad-Rebaal wants to merge 33 commits into
sktime:mainfrom
Muhammad-Rebaal:softs_model

Conversation

@Muhammad-Rebaal

@Muhammad-Rebaal Muhammad-Rebaal commented Mar 25, 2026

Copy link
Copy Markdown
Member

Fixes #2231

Hi @fkiraly , @phoeenniixx, @PranavBhatP !

I have implemented the SOFTS (Star Aggregate-Dispatch for Time Series Forecasting) model within the PyTorch Forecasting v2 architecture.

Could you please review the PR?

Here is a summary of the changes made:

  • Isolated Layer Abstraction (pytorch_forecasting/layers/_blocks/_softs_block.py): Implemented the core neural network components, specifically the novel STADModule (Star Aggregate-Dispatch mechanism) and the SoftsEncoderLayer, completely isolated from the base estimating logic to strictly adhere to the project's v2 architectural standards.
  • Model Construction (pytorch_forecasting/models/softs/): Created the main Softs estimator wrapper which inherits from TslibBaseModel. It effectively handles dynamic feature input alignments (history_cont and history_target), optionally applies RevIN scaling, and routes the forward pass through the STAD-based encoders.
  • V2 Package Management (_softs_pkg_v2.py): Established the Softs_pkg_v2 class representing model metadata (capability tags, compute requirements) and defined automated testing configurations (get_test_train_params) tightly integrated with the underlying TslibDataModule.
  • Registry & Exports: Updated the relevant __init__.py files across the layers and models directories to properly expose Softs, Softs_pkg_v2, and the STAD blocks to the broader PyTorch Forecasting ecosystem.

Thank you!

@Muhammad-Rebaal
Muhammad-Rebaal marked this pull request as draft March 25, 2026 17:49
@Muhammad-Rebaal
Muhammad-Rebaal marked this pull request as ready for review March 25, 2026 18:41
@Muhammad-Rebaal
Muhammad-Rebaal marked this pull request as draft March 25, 2026 19:23
@codecov

codecov Bot commented Apr 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.55556% with 6 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@7bcf66c). Learn more about missing BASE report.

Files with missing lines Patch % Lines
pytorch_forecasting/models/softs/_softs_v2.py 92.20% 6 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2232   +/-   ##
=======================================
  Coverage        ?   87.65%           
=======================================
  Files           ?      180           
  Lines           ?    10299           
  Branches        ?        0           
=======================================
  Hits            ?     9028           
  Misses          ?     1271           
  Partials        ?        0           
Flag Coverage Δ
cpu 87.65% <95.55%> (?)
pytest 87.65% <95.55%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Muhammad-Rebaal
Muhammad-Rebaal marked this pull request as ready for review April 29, 2026 19:19

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!
i would suggest adding detailed docstrings with clear descriptions of all the params, so that it is easy to understand the methods and the architecture in general.

Is this code taken from somewhere or is it completely implemented from scratch? I think if it is taken from somewhere, it would be better to add the original authors to the authors tag.

Also, please add the references (like paper, repo etc) to the docstrings as well of the model.


class SoftsEncoderLayer(nn.Module):
"""
Single Encoder layer for SOFTS.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you please add more detailed docstrings for all methods and classes?

"""Get the underlying DataModule class."""
from pytorch_forecasting.data._tslib_data_module import TslibDataModule

return TslibDataModule

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are we using this datamodule? I think this data module is mainly for tslib models, I have no issue with using this, but pls have a look at EncoderDecoderDataModule as well, maybe that would also be helpful.
I have not looked at the architecture, so I have a question: is the model encoder-decoder based model?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We are using TslibDataModule because SOFTS is a direct-projection MLP model. It only consumes historical input sequences and maps them directly to the forecast window, using EncoderDecoderModule felt unnecessary.

From the perspective of data input we can call it encoder-only model.

Code Ref : Code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this can be seen as a encoder-decoder model with decoder being a identity layer?
I think we should use the TslibDataModule only if we are interfacing the model from the tslib package. Otherwise if it fits encoder-decoder model type, we should use EncoderDecoderDataModule

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You need to update this data module as well then

return TslibDataModule

@classmethod
def _get_test_datamodule_from(cls, trainer_kwargs):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I dont think we need this anymore

def get_test_train_params(cls):
params = [
{},
dict(hidden_size=128, n_layers=1, use_revin=True),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you try adding some more params to cover more scenarios?

class Softs(TslibBaseModel):
"""
SOFTS: Efficient Multivariate Time Series Forecasting with Series-Core Fusion.
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add detailed docstrings

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think there are geniune failures, please take a look at that

@fkiraly fkiraly added the ptf-v2 Related to `pytorch-forecasting` v2 label Jun 19, 2026
@fkiraly

fkiraly commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

@phoeenniixx, I think there are no longer failures. Can you please re-review?

(quick question, do we need to add the model to the docs, or is that automatic now?)

@phoeenniixx

Copy link
Copy Markdown
Member

(quick question, do we need to add the model to the docs, or is that automatic now?)

We still need to add the API reference, but the table generation is automatic now!

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! I think this one is almost ready. Just few nitpicks.
Please add the API reference of the model here: http://github.com/sktime/pytorch-forecasting/blob/main/docs/source/m_layer_v2.rst#api-reference

from pytorch_forecasting.models.base._tslib_base_model_v2 import TslibBaseModel


class Softs(TslibBaseModel):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can the BaseModel not work here? I mean we mainly use TslibBaseModel for tslib models only

@Muhammad-Rebaal Muhammad-Rebaal Jun 23, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The model is actually part of the tslib model family that's why I used that. Is there any particular reason to use the base model instead ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought tslib model family was from here: https://github.com/thuml/Time-Series-Library
But this model was taken from here: https://github.com/Secilia-Cxy/SOFTS/
That is why I said it is not a tslib model. Am I missing something here?

@Muhammad-Rebaal Muhammad-Rebaal Jun 23, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, you're right I just misinterpreted thanks for letting me know. I'll adjust that and use the baseClass.

hidden_size=64,
n_layers=1,
use_revin=False,
loss=MAE(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be good if we could add other point prediction losses here as well - just to increase the coverage

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for letting me know I've updated that

"""

_tags = {
"info:name": "SOFTS",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think the name should be same as the class here: Softs in place of SOFTS?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think it should be SOFTS all over the place as the actual model name is SOFTS not Softs and also the convention also follows that across other models.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Then you would have to update the class name. The tag name should be exactly same as the class name

@Muhammad-Rebaal

Copy link
Copy Markdown
Member Author

Hi @phoeenniixx,
I've updated the class_name to SOFTS and use the base_class, also updated the api_reference. Kindly have a look at it.
Thanks

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please use EncoderDecoderTimeSeriesDataModule in place of tslib one, if we are using the BaseModel and not the tslib one, then we need to use the corresponding data module as well. Although the tests are passing, but both the data modules represent different ideologies, and with time as we add more feats will diverge from each other, so we shouldn't use them interchangeably

return x + dispatch_out


class SOFTSEncoderLayer(nn.Module):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should it go to _encoders folder?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I considered this during implementation. Looking at the current _encoders/ contents, both Encoder and EncoderLayer are TimeXer-specific (they take cross, tau, delta params and have global-token logic).
Whereas SOFTSEncoderLayer has a fundamentally different interface it takes a 4D tensor (B, C, L, D) and uses STAD instead of attention, so there's no shared contract between them. _blocks/ currently houses model-specific building blocks like ResidualBlock (for DSIPTs), and SOFTSEncoderLayer + STADModule follow the same pattern self-contained blocks specific to one model. Should I move it to a new _softs/ subfolder under layers/ to make the model association clear.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see, but we can have multiple implementations of encoder layers, no? and that is why we created an _encoders folder that can host multiple implementations. It is not necessary that this encoder layer is just used by SOFTS, what if we see some new model that is derived from SOFTS, that could also use this layer. THe name - SOFTSEncoderLayer already makes the association pretty clear.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, it can be possible that in the future we'd reuse it. I've adjusted that.


return {"prediction": out}

def predict_step(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why do we need a predict_step here? can't the BaseModel's implementation enough?
And if not, why do have not added other step functions like test_step?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, I thoroughly looked into the implementation. The BaseModel's implementation is enough.

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice! I think it is almost ready, just have few doubts (see above)

@Muhammad-Rebaal

Copy link
Copy Markdown
Member Author

Hi @phoeenniixx,
I've made the following changes as mentioned:

  • Moved the softs_encoder block to _encoder directory for future resuability.
  • Removed the overriding predict_step method as Base_models implementation is enough.

Kindly have a look

@phoeenniixx phoeenniixx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request module:models ptf-v2 Related to `pytorch-forecasting` v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ENH] Add v2 interface support for SOFTS (Star Aggregate-Dispatch for Time Series Forecasting)

3 participants