Skip to content

Conversation

ParamThakkar123
Copy link

Reference Issues/PRs

Fixes #1957

What does this implement/fix? Explain your changes.

This refactor moves legacy loss compatibility mappings and tensor shape checks to metric tags in the respective _pkg classes.
Test-specific parameters and dataloader configurations are now provided by a standardized _get_test_dataloaders_from method in each metric package.
All test logic for selecting compatible losses and checking output shapes is now tag-driven, improving maintainability and extensibility.
Legacy mapping code and if/else logic have been removed from the test suite.

What should a reviewer concentrate their feedback on?

Did you add any tests for the change?

Any other comments?

PR checklist

  • The PR title starts with either [ENH], [MNT], [DOC], or [BUG]. [BUG] - bugfix, [MNT] - CI, test framework, [ENH] - adding or improving code, [DOC] - writing or improving documentation or docstrings.
  • Added/modified tests
  • Used pre-commit hooks when committing to ensure that code is compliant with hooks. Install hooks with pre-commit install.
    To run hooks independent of commit, execute pre-commit run --all-files

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@ParamThakkar123
Copy link
Author

@fkiraly

@ParamThakkar123
Copy link
Author

Converting this to draft PR. Looking for feedback

@ParamThakkar123 ParamThakkar123 marked this pull request as draft September 9, 2025 15:55
Copy link
Member

@phoeenniixx phoeenniixx left a comment

Choose a reason for hiding this comment

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

Thanks and Welcome to pytorch-forecasting @ParamThakkar123!
I have few questions/suggestions:

  • Donot use get_test_train_params for model_pkg as the fixtures come from get_base_test_params

  • I suspect somewhere compatible_loss list is returned empty and this is the reason, some models are looking for get_test_train_params (which should not happen for v1).

  • Also, can you please update the description of the PR to add the following info:

    • The EXACT changes you are doing to the files
    • Why are you doing it
    • Expected behavior of the test framework after these changes.

    This would make reviewing easy for the reviewers.

@phoeenniixx
Copy link
Member

phoeenniixx commented Sep 10, 2025

If you have any problems/doubts, please feel free to ping us on discord. You can also join weekly community meet which happens every Friday at 13:00 UTC at the meetups channels on discord.
https://discord.com/invite/54ACzaFsn7

@ParamThakkar123
Copy link
Author

Hello @phoeenniixx Thanks for the amazing feedback. And yeah there are some metrics for which no compatible losses are found. So should I skip them in the test loop?

@ParamThakkar123
Copy link
Author

ParamThakkar123 commented Sep 10, 2025

Or what kind of changes should I exactly be doing ?

@ParamThakkar123
Copy link
Author

ParamThakkar123 commented Sep 10, 2025

A fallback?

Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

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

Ahead of a review - you are reformatting a larger number of files.
Could you kindly do that in a separate pull request, to avoid a large scope?

@ParamThakkar123
Copy link
Author

Ahead of a review - you are reformatting a larger number of files. Could you kindly do that in a separate pull request, to avoid a large scope?

Yes. Will do that

@phoeenniixx
Copy link
Member

And yeah there are some metrics for which no compatible losses are found.

So, here we use metrics as loss and, these compatible losses are calculated for the models which are being tested. These compatible losses are called in test_all_estimators to pair the compatible losses with the models. So what is happening, imo, is right now get_compatible_losses is not collecting all the losses correctly.

So should I skip them in the test loop?

These were collected before, so it should be possible to collect them with the new changes, so, I think we should not skip them. Rather, please check if there are some bugs

To check if all the losses are being collected correctly, please run tests from TestAllPtForecasters for both v1 and v2.

Ideally, both of these tests should pass and all the losses should be collected correctly.

Copy link

codecov bot commented Sep 10, 2025

Codecov Report

❌ Patch coverage is 60.57692% with 41 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@e1cc1ce). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...h_forecasting/metrics/base_metrics/_base_object.py 21.42% 11 Missing ⚠️
pytorch_forecasting/tests/_loss_mapping.py 70.00% 6 Missing ⚠️
...ributions_pkg/_beta/_beta_distribution_loss_pkg.py 62.50% 3 Missing ⚠️
...g/_log_normal/_log_normal_distribution_loss_pkg.py 62.50% 3 Missing ⚠️
...rmal/_multivariate_normal_distribution_loss_pkg.py 57.14% 3 Missing ⚠️
...nomial/_negative_binomial_distribution_loss_pkg.py 62.50% 3 Missing ⚠️
...implicit_quantile_network_distribution_loss_pkg.py 66.66% 1 Missing ⚠️
...tions_pkg/_normal/_normal_distribution_loss_pkg.py 66.66% 1 Missing ⚠️
...cs/_point_pkg/_cross_entropy/_cross_entropy_pkg.py 66.66% 1 Missing ⚠️
...ch_forecasting/metrics/_point_pkg/_mae/_mae_pkg.py 66.66% 1 Missing ⚠️
... and 8 more
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1967   +/-   ##
=======================================
  Coverage        ?   87.12%           
=======================================
  Files           ?      158           
  Lines           ?     9358           
  Branches        ?        0           
=======================================
  Hits            ?     8153           
  Misses          ?     1205           
  Partials        ?        0           
Flag Coverage Δ
cpu 87.12% <60.57%> (?)
pytest 87.12% <60.57%> (?)

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

☔ View full report in Codecov by Sentry.
📢 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.

@ParamThakkar123
Copy link
Author

@phoeenniixx @fkiraly

@fkiraly
Copy link
Collaborator

fkiraly commented Sep 11, 2025

@ParamThakkar123, how did you test whether the tests now get collected correctly?

@ParamThakkar123
Copy link
Author

ParamThakkar123 commented Sep 11, 2025

I ran the tests as mentioned by @phoeenniixx multiple times and looked at the errors that occurred then found bugs in my code which were related to some tags in the for loop for LOSS_SPECIFIC_PARAMS. Fixed them, ran tests locally again and pushed when all passed. Also while running the tests I added a print statement in the test code to check if anywhere compatible_losses is returned empty and it didn't after I made some more imports in the _loss_mapping.py actually the core issue was I wasn't importing some _pkgs which were actually required for certain losses. I made the imports, modified tags and ran the tests

@fkiraly

@ParamThakkar123 ParamThakkar123 marked this pull request as ready for review September 11, 2025 11:42
Copy link
Member

@phoeenniixx phoeenniixx left a comment

Choose a reason for hiding this comment

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

Nice! This is really good!
I made some requests, please have a look at them
Additionally,

  • Please remove the files which are being added due to formatting (as @fkiraly mentioned). I suspect you are using pre-commit run --all-files everytime before commiting, and that is why they get committed everytime.
  • I would suggest to use pre-commit run --files <path_to_the_changed_files> instead.
  • If you are using linux, and cli to commit, pre-commit automatically runs on the changed files, when you use git commit, so idts you would need to run pre-commit manually there. But if you are on windows (or maybe MacOS, I donot have any experience with MacOS), i would suggest using pre-commit run --files <path_to_the_changed_files> rather than pre-commit run --all-files

@@ -16,6 +17,15 @@ class BetaDistributionLoss_pkg(_BasePtMetric):
"distribution_type": "beta",
"info:metric_name": "BetaDistributionLoss",
"requires:data_type": "beta_distribution_forecast",
"clip_target": True,
Copy link
Member

Choose a reason for hiding this comment

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

I was wondering if we need clip_target and data_loader_kwargs in tags as they donot convey any useful info, rather they are the params to make the dataloaders more comaptible with each metric, maybe we should move it somewhere else in the class?

Copy link
Author

Choose a reason for hiding this comment

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

Yes. You're right. Where do you I should be moving it ?

Copy link
Member

Choose a reason for hiding this comment

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

maybe they can be one of the properties? or args in __init__?
what do you think is a better idea? a property or an arg?

Copy link
Member

Choose a reason for hiding this comment

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

@fkiraly what is your opinion about this?

Copy link
Author

@ParamThakkar123 ParamThakkar123 Sep 12, 2025

Choose a reason for hiding this comment

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

@phoeenniixx I think we can keep it as an arg?

Copy link
Collaborator

Choose a reason for hiding this comment

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

where is it being passed?

@ParamThakkar123
Copy link
Author

@phoeenniixx I have implemented the changes you suggested. Can you please review it ?

@@ -1,7 +1,25 @@
"""NHiTS package container."""

from pytorch_forecasting.metrics.distributions import (
BetaDistributionLoss,
ImplicitQuantileNetworkDistributionLoss,
Copy link
Member

Choose a reason for hiding this comment

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

why are we importing these classes and DISTR_LOSSES_NUMERIC here in _nhits_pkg? are they usedf anywhere in the file?

Copy link
Author

Choose a reason for hiding this comment

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

@phoeenniixx I did that because there's a for loop in the code at line number 108 which loops over this DISTR_LOSSES_NUMERIC array

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I see, but that still doesnt explain the imports of loss classes, from what i can see, they were already being imported in _get_test_dataloaders_from see here

Copy link
Member

Choose a reason for hiding this comment

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

Also, I am a bit uncomfortable about defining DISTR_LOSSES_NUMERIC, we imported it before as they were already present in _loss_mapping, and now you are refactoring it, so I think we could also refactor a little here? Like we just see if the loss is MultivariateNormalDistributionLoss, and we return dataloaders_fixed_window_without_covariates() and for rest of the distribution losses, we perform required operations and return dataloaders_with_covariates? idts we would need DISTR_LOSSES_NUMERIC then do we?

Copy link
Author

Choose a reason for hiding this comment

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

Okay, So probably what we can do here is remove the redundant import but keep the DISTR_LOSSES_NUMERIC as it is

Copy link
Member

Choose a reason for hiding this comment

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

I think we could even refactor get_test_dataloaders_from of nhits_pkg here as well :)
Please look at my previous comment. what do you think?

Also, why are we importing the unused classes here? (referring to your latest commit)

Copy link
Member

Choose a reason for hiding this comment

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

I think we dont even need to use DISTR_LOSSES_NUMERIC now, thanks to your brilliant refactoring :)

Copy link
Author

Choose a reason for hiding this comment

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

Okay got it @phoeenniixx I will make the suggested changes

Copy link
Member

@phoeenniixx phoeenniixx Sep 12, 2025

Choose a reason for hiding this comment

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

Just a heads up: there are other losses as well being tested for nhits along with distribution losses (like point predictions losses), so you'd have to add support for them as well, like previously there was for TweedieLoss(see the previous check for the loss) and for other losses dataloaders_fixed_window_without_covariates was being passed...

@ParamThakkar123
Copy link
Author

@phoeenniixx I made the changes. Does the recent change look better now ?

@phoeenniixx
Copy link
Member

@phoeenniixx I made the changes. Does the recent change look better now ?

Are all the tests passing locally?

@ParamThakkar123
Copy link
Author

yup

Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

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

  • I think clip_target and data_load_kwargs are not tags. To know where they are best moved, where are they being passed and when?
  • I would rename expected_loss_ndim to loss_ndim or similar, or n_pred_dim?

@ParamThakkar123
Copy link
Author

@fkiraly They are being passed in the _get_test_dataloaders_from function

@fkiraly
Copy link
Collaborator

fkiraly commented Sep 14, 2025

They are being passed in the _get_test_dataloaders_from function

I see - that is a test config function, so I would either encode the parameters there, or in an additional private function - not in tags.

"""
compatible_losses = []
for pkg in METRIC_PKGS:
pkg_pred_types = pkg._tags.get("info:pred_type", [])
Copy link
Member

Choose a reason for hiding this comment

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

Here you could use get_class_tags, see here for the example.

@phoeenniixx
Copy link
Member

They are being passed in the _get_test_dataloaders_from function

I see - that is a test config function, so I would either encode the parameters there, or in an additional private function - not in tags.

Yes, that's why I proposed using property here... I think that could be a good way to access these params, and we could also add a way to change the value of this property if required, that would make it extensible as well?

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.

[ENH] refactor _loss_mapping to tags of metrics, entirely
3 participants