Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AutoregressionTask #2639

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

Conversation

keves1
Copy link

@keves1 keves1 commented Mar 12, 2025

This PR adds the following:

Together these additions enable training air quality forecasting models as well as other autoregression tasks as additional datasets and models are added.

@github-actions github-actions bot added documentation Improvements or additions to documentation datasets Geospatial or benchmark datasets models Models and pretrained weights testing Continuous integration testing trainers PyTorch Lightning trainers datamodules PyTorch Lightning datamodules labels Mar 12, 2025
@keves1
Copy link
Author

keves1 commented Mar 13, 2025

@adamjstewart See below, this test passes when I run it locally but it is failing here. I don't understand this error message, do you know how to resolve this?

FAILED tests/trainers/test_autoregression.py::TestAutoregressionTask::test_trainer[True-air_quality] - ValueError: Does not validate against any of the Union subtypes
Subtypes: [<class 'NoneType'>, <class 'torchgeo.trainers.base.BaseTask'>]
Errors:
  - Expected a <class 'NoneType'>
  - Unexpected keyword arguments: `num_outputs`
Given value type: <class 'jsonargparse._namespace.Namespace'>
Given value: Namespace(class_path='torchgeo.trainers.AutoregressionTask', init_args=Namespace(model='lstm_seq2seq', input_size=3, input_size_decoder=1, hidden_size=1, output_size=1, target_indices=[2], encoder_indices=[2, 12, 13], decoder_indices=[2], timesteps_ahead=1, num_layers=1, loss='mse', lr=0.001, patience=10, teacher_force_prob=None))

@adamjstewart adamjstewart added this to the 0.7.0 milestone Mar 13, 2025
@adamjstewart adamjstewart mentioned this pull request Feb 21, 2025
29 tasks
Copy link
Collaborator

@adamjstewart adamjstewart left a comment

Choose a reason for hiding this comment

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

Looks like a great start! For datasets, I'm wondering if we also want to consider spatiotemporal datasets like the one you found and whether we should add GeoDatasets. For models, I'm wondering if we should also add a GNN since that's commonly used for non-gridded data. Some kind of model that combines both and can make spatiotemporal predictions would be cool. But none of those are required for a first pass. Let's first clean this up and get it merged.

I don't know why the tests are failing, but it's only the minimum version tests, so worst case scenario we can bump the minimum supported versions. We're already doing that when we drop Python 3.10 support anyway, so I would ignore them for now and focus on everything else.

@@ -1,5 +1,6 @@
Dataset,Task,Source,License,# Samples,# Classes,Size (px),Resolution (m),Bands
`ADVANCE`_,C,"Google Earth, Freesound","CC-BY-4.0","5,075",13,512x512,0.5,RGB
`Air Quality`_,"R,T","UCI Machine Learning Repository","CC-BY-4.0","9,358",,,,
Copy link
Collaborator

Choose a reason for hiding this comment

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

self.val_dataset = Subset(dataset, val_indices)
self.test_dataset = Subset(dataset, test_indices)

def on_after_batch_transfer(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this needed? Is there a problem with the base class implementation?

Copy link
Author

Choose a reason for hiding this comment

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

I don't think we want to be applying a Kornia augmentation (self.aug) to this data since it is not an image, so this was my way of avoiding that. I think your suggestion for a no-op data augmentation would make this override unnecessary.

"""
super().__init__(AirQuality, batch_size, num_workers, **kwargs)
self.val_split_pct = val_split_pct
self.test_split_pct = test_split_pct
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we add some kind of no-op data augmentation to override the base class?

Copy link
Author

Choose a reason for hiding this comment

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

That would be great, is there something like that in Kornia? I didn't see anything when I looked through the docs. Or is there another way to do it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

No not really. We would have to write our own, or use one that won't apply like normalization.

output_sequence_len: The number of steps to predict forward. Defaults to 1.
num_layers: Number of LSTM layers in the encoder and decoder. Defaults to 1.
teacher_force_prob: Probability of using teacher forcing. If None, does not
use teacher forcing. Defaults to None.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of documenting and passing all of these arguments one at a time, maybe we could just have an extra **kwargs argument that gets passed to the LSTM class?

Copy link
Author

Choose a reason for hiding this comment

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

That sounds great, I'll work on that.

decoder_indices: list[int] | None = None,
timesteps_ahead: int = 1,
num_layers: int = 1,
loss: str = 'mse',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
loss: str = 'mse',
loss: Literal['mse', 'mae'] = 'mse',

batch: The output of your DataLoader.
batch_idx: Integer displaying index of this batch.
"""
self._shared_step(batch, batch_idx, 'val')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add plotting here?

metrics = getattr(self, f'{stage}_metrics', None)
if metrics:
metrics(y_hat, future_steps)
self.log_dict({f'{k}': v for k, v in metrics.compute().items()})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we somewhere revert normalization before calculating metrics? Are we normalizing both inputs and outputs or only inputs?



class TestLSTMSeq2Seq:
@torch.no_grad()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we should be adding torch.no_grad to more of our tests to speed them up...

@adamjstewart adamjstewart removed this from the 0.7.0 milestone Mar 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
datamodules PyTorch Lightning datamodules datasets Geospatial or benchmark datasets documentation Improvements or additions to documentation models Models and pretrained weights testing Continuous integration testing trainers PyTorch Lightning trainers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants