-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Better error message when dataloader or datamodule is None #14614
Conversation
d8ba236
to
2e16932
Compare
class _NO_DATA(Sentinel): | ||
"""A sentinel representing the default value for 'no dataloader passed to Trainer method'.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Sometimes we see sentinels defined as
DEFAULT = object()
But this does not work for us, because pickling (e.g. ddp_spawn) will re-instantiate this object and then checks like dataloader is DEFAULT
have the wrong value!
for more information, see https://pre-commit.ci
with pytest.raises(ValueError, match="You explicitly passed .*dataloaders=None.* but this is not supported"): | ||
trainer_fn = getattr(trainer, trainer_fn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be outside the raises
block
with pytest.raises(ValueError, match="You explicitly passed .*dataloaders=None.* but this is not supported"): | |
trainer_fn = getattr(trainer, trainer_fn) | |
trainer_fn = getattr(trainer, trainer_fn) | |
with pytest.raises(ValueError, match="You explicitly passed .*dataloaders=None.* but this is not supported"): |
with pytest.raises(ValueError, match="You explicitly passed .*datamodule=None.* but this is not supported"): | ||
trainer_fn = getattr(trainer, trainer_fn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with pytest.raises(ValueError, match="You explicitly passed .*datamodule=None.* but this is not supported"): | |
trainer_fn = getattr(trainer, trainer_fn) | |
trainer_fn = getattr(trainer, trainer_fn) | |
with pytest.raises(ValueError, match="You explicitly passed .*datamodule=None.* but this is not supported"): |
|
||
def _check_dataloader_none(stage: str, **dataloader_args: Any) -> None: | ||
for arg_name, value in dataloader_args.items(): | ||
dataloader_method = arg_name if not arg_name.endswith("s") else arg_name[:-1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you pass the RunningStage
object instead of the value, you can use stage.dataloader_prefix
to construct the method name
@@ -61,6 +61,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). | |||
- When using multiple loggers, by default checkpoints and profiler output now get saved to the log dir of the first logger in the list ([14325](https://github.com/Lightning-AI/lightning/pull/14325)) | |||
|
|||
|
|||
- Explicitly passing `train_dataloaders=None`, `val_dataloaders=None`, `dataloaders=None` or `datamodule=None` is officially no longer supported and will inform using a better error message than before ([14614](https://github.com/Lightning-AI/lightning/pull/14614)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this is a huge breaking change as described in #14602 (comment).
Very often people write scripts with
train_dataloader = None
if ...:
train_dataloader = ...
trainer.fit(model, train_dataloader=train_dataloader)
(you had to update examples like this in our CI)
I don't think we can afford to break this usecase, sure, it can be error-prone, but it's a perfectly valid Python pattern when you want to pass arguments optionally.
I strongly think it should be a PossibleUserWarning
for this reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we make it a warning, then another error will raise later on and completely overshadow any warning printed earlier. It won't help the user.
The only other option I see is to change the message in "No trainining_step defined ..." to hint at the possibility that one of the dataloaders is None. But this is very strange. Ideally we would want to tell the user directly what the issue is, not a list of possibilities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possibility would be to check at the same time whether there' a *_dataloader
fallback. If there is, allow None
and proceed normally. Otherwise, raise an error.
If we do this, we should also re-write the "No train_dataloader()
method defined" error as it would be covered by this new error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have an alternative implementation here: #14637
My brain is melting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Much better
What does this PR do?
Fixes #14601
Fixes #14602
Does your PR introduce any breaking changes? If yes, please list them.
Yes, when the user set None explicitly before but had dataloader methods implemented in the module.
But I couldn't find another way to provide a meaningful error message.
Before submitting
PR review
Anyone in the community is free to review the PR once the tests have passed.
Before you start reviewing make sure you have read Review guidelines. In short, see the following bullet-list:
Did you have fun?
I made sure I had fun coding 🙃