-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Better error message when dataloader or datamodule is None #14614
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
Changes from 10 commits
239d2a9
c0c363e
2e16932
ff700dd
f1917bb
796d0b5
e6194f5
2f95973
12cea42
d6c8d1c
ac68a08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,8 @@ | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import Any, Optional | ||
|
||
import pytorch_lightning as pl | ||
from lightning_lite.utilities.warnings import PossibleUserWarning | ||
from pytorch_lightning.accelerators.ipu import IPUAccelerator | ||
|
@@ -308,3 +310,23 @@ def _check_datamodule_checkpoint_hooks(trainer: "pl.Trainer") -> None: | |
"`LightningDataModule.on_load_checkpoint` was deprecated in" | ||
" v1.6 and will be removed in v1.8. Use `load_state_dict` instead." | ||
) | ||
|
||
|
||
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 commentThe reason will be displayed to describe this comment to others. Learn more. If you pass the |
||
if value is None: | ||
raise ValueError( | ||
f"You explicitly passed `Trainer.{stage}({arg_name}=None, ...)`, but this is not supported." | ||
" You should either a) pass in valid dataloader(s) or" | ||
f" b) remove the argument from `.{stage}()` and implement `def {dataloader_method}(self):` in your" | ||
f" LightningModule/LightningDataModule instead." | ||
) | ||
|
||
|
||
def _check_datamodule_none(stage: str, datamodule: Optional["pl.LightningDataModule"]) -> None: | ||
if datamodule is None: | ||
raise ValueError( | ||
f"You explicitly passed `Trainer.{stage}(datamodule=None, ...)`, but this is not supported." | ||
f" Please pass in valid `LightningDataModule` or remove the argument from `.{stage}()`." | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ | |
from torch import Tensor | ||
from torch.utils.data import DataLoader | ||
from torchmetrics import Metric | ||
from typing_extensions import Protocol, runtime_checkable | ||
from typing_extensions import Literal, Protocol, runtime_checkable | ||
|
||
from lightning_lite.utilities.types import _LRScheduler, ReduceLROnPlateau | ||
|
||
|
@@ -139,3 +139,25 @@ class LRSchedulerConfig: | |
strict: bool = True | ||
# opt_idx assigned internally if not assigned by user | ||
opt_idx: Optional[int] = None | ||
|
||
|
||
class _SentinelMeta(type): | ||
"""Metaclass representing a sentinel value by the name of the class. | ||
|
||
Reference: https://stackoverflow.com/a/69243488/1162383 | ||
See also: https://peps.python.org/pep-0661/ | ||
""" | ||
|
||
def __repr__(cls) -> str: | ||
return f"<{cls.__name__}>" | ||
|
||
def __bool__(cls) -> Literal[False]: | ||
return False | ||
|
||
|
||
class Sentinel(metaclass=_SentinelMeta): | ||
"""Subclass this to create a new sentinel.""" | ||
|
||
|
||
class _NO_DATA(Sentinel): | ||
"""A sentinel representing the default value for 'no dataloader passed to Trainer method'.""" | ||
Comment on lines
+162
to
+163
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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
(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.Uh oh!
There was an error while loading. Please reload this page.
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.
Uh oh!
There was an error while loading. Please reload this page.
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, allowNone
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 errorThere 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