Skip to content

Commit

Permalink
7107 Add support to validate at training start (#7108)
Browse files Browse the repository at this point in the history
Fixes #7107 .

### Description

This PR added support to optionally execute validation at training start
first, this is useful for transfer learning to validate the initial
model.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Signed-off-by: Nic Ma <[email protected]>
  • Loading branch information
Nic-Ma authored Oct 10, 2023
1 parent 5c6d199 commit fc1350a
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 3 deletions.
10 changes: 9 additions & 1 deletion monai/handlers/validation_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ class ValidationHandler:
"""

def __init__(self, interval: int, validator: Evaluator | None = None, epoch_level: bool = True) -> None:
def __init__(
self, interval: int, validator: Evaluator | None = None, epoch_level: bool = True, exec_at_start: bool = False
) -> None:
"""
Args:
interval: do validation every N epochs or every N iterations during training.
validator: run the validator when trigger validation, suppose to be Evaluator.
if None, should call `set_validator()` before training.
epoch_level: execute validation every N epochs or N iterations.
`True` is epoch level, `False` is iteration level.
exec_at_start: whether to execute a validation first when starting the training.
default to `False`. It can be useful especially for some transfer-learning cases
to validate the initial model before training.
Raises:
TypeError: When ``validator`` is not a ``monai.engines.evaluator.Evaluator``.
Expand All @@ -49,6 +54,7 @@ def __init__(self, interval: int, validator: Evaluator | None = None, epoch_leve
self.validator = validator
self.interval = interval
self.epoch_level = epoch_level
self.exec_at_start = exec_at_start

def set_validator(self, validator: Evaluator) -> None:
"""
Expand All @@ -67,6 +73,8 @@ def attach(self, engine: Engine) -> None:
engine.add_event_handler(Events.EPOCH_COMPLETED(every=self.interval), self)
else:
engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.interval), self)
if self.exec_at_start:
engine.add_event_handler(Events.STARTED, self)

def __call__(self, engine: Engine) -> None:
"""
Expand Down
7 changes: 5 additions & 2 deletions tests/test_handler_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ def _train_func(engine, batch):
# set up testing handler
val_data_loader = torch.utils.data.DataLoader(Dataset(data))
evaluator = TestEvaluator(torch.device("cpu:0"), val_data_loader)
saver = ValidationHandler(interval=2, validator=evaluator)
saver.attach(engine)
ValidationHandler(interval=2, validator=evaluator, exec_at_start=True).attach(engine)
# test execution at start
engine.run(data, max_epochs=1)
self.assertEqual(evaluator.state.max_epochs, 0)
self.assertEqual(evaluator.state.epoch_length, 8)

engine.run(data, max_epochs=5)
self.assertEqual(evaluator.state.max_epochs, 4)
Expand Down

0 comments on commit fc1350a

Please sign in to comment.