Skip to content

More options in events filtering  #2853

@vfdev-5

Description

@vfdev-5

🚀 Feature

The idea is coming from this discussion: Project-MONAI/MONAI#5958 (reply in thread)

We would like to support the following use-cases:

  1. before/after can work together with every
event = Events.ITERATION_COMPLETED(after=9, before=21, every=5)
# execute for iterations [10, 15, 20]
  1. once can accept list of values
event = Events.ITERATION_COMPLETED(once=[5, 8, 23])
# execute once for iterations 5, 8 and 23

How to help with this issue

Events filtering logic is coded here:

def __call__(
self,
event_filter: Optional[Callable] = None,
every: Optional[int] = None,
once: Optional[int] = None,
before: Optional[int] = None,
after: Optional[int] = None,
) -> "CallableEventWithFilter":
"""
Makes the event class callable and accepts either an arbitrary callable as filter
(which must take in the engine and current event value and return a boolean) or an every or once value
Args:
event_filter: a filter function to check if the event should be executed when
the event type was fired
every: a value specifying how often the event should be fired
once: a value specifying when the event should be fired (if only once)
before: a value specifying the number of occurrence that event should be fired before
after: a value specifying the number of occurrence that event should be fired after
Returns:
CallableEventWithFilter: A new event having the same value but a different filter function
"""
if (
sum(
(
event_filter is not None,
every is not None,
once is not None,
(before is not None or after is not None),
)
)
!= 1
):
raise ValueError("Only one of the input arguments should be specified except before and after")
if (event_filter is not None) and not callable(event_filter):
raise TypeError("Argument event_filter should be a callable")
if (every is not None) and not (isinstance(every, numbers.Integral) and every > 0):
raise ValueError("Argument every should be integer and greater than zero")
if (once is not None) and not (isinstance(once, numbers.Integral) and once > 0):
raise ValueError("Argument once should be integer and positive")
if (before is not None) and not (isinstance(before, numbers.Integral) and before >= 0):
raise ValueError("Argument before should be integer and greater or equal to zero")
if (after is not None) and not (isinstance(after, numbers.Integral) and after >= 0):
raise ValueError("Argument after should be integer and greater or equal to zero")
if every is not None:
if every == 1:
# Just return the event itself
event_filter = None
else:
event_filter = self.every_event_filter(every)
if once is not None:
event_filter = self.once_event_filter(once)
if before is not None or after is not None:
event_filter = self.before_and_after_event_filter(before, after)
# check signature:
if event_filter is not None:
_check_signature(event_filter, "event_filter", "engine", "event")
return CallableEventWithFilter(self.value, event_filter, self.name)

We would like to update the following functions:

event_filter = self.once_event_filter(once)

and

event_filter = self.before_and_after_event_filter(before, after)

such that we could cover proposed use-cases. Finally, we need to write few tests here: https://github.com/pytorch/ignite/blob/master/tests/ignite/engine/test_custom_events.py

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions