-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Lazy eval refactor #6257
Lazy eval refactor #6257
Conversation
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
…arameter, refactoring spatial arrays to support lazy_evaluation call time parameter, refactoring _apply_transform to pass call time lazy_evaluation flag Signed-off-by: Ben Murray <ben.murray@gmail.com>
… transforms Signed-off-by: Ben Murray <ben.murray@gmail.com>
lazy_evaluation initing / calls Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
croppad/array Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
meaningful . Adding ApplyPending and ApplyPendingd transforms Signed-off-by: Ben Murray <ben.murray@gmail.com>
respectively Signed-off-by: Ben Murray <ben.murray@gmail.com>
Filter for metatensors in ApplyPending / ApplyPendingd classes Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
hi @atbenmurray sorry, earlier I didn't notice this PR is pending review. please address the merging conflicts I'll test and merge it. |
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Gone through the merge from dev. I still need to test things before we merge! |
for more information, see https://pre-commit.ci
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
for more information, see https://pre-commit.ci
Signed-off-by: Ben Murray <ben.murray@gmail.com>
…o lazy_eval_refactor
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
…pply_pending. Fixing various tests by moving to use of 'overrides' on apply_pending Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
…o lazy_eval_refactor
for more information, see https://pre-commit.ci
monai/transforms/compose.py
Outdated
return data | ||
|
||
|
||
class ComposeCompiler: |
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.
As we've discussed today at the meeting I'd suggest something like LazyPolicy
given the current state of this class. If the intent is to evolve this to do more complicated work to "compile" in some manner we might want to put that into a new class anyway and keep something to do policy like this separate.
if invertible is False: | ||
if reasons is not None: | ||
reason_text = "\n".join(reasons) | ||
raise RuntimeError(f"Unable to run inverse on 'data' for the following reasons:\n{reason_text}") | ||
else: | ||
raise RuntimeError("Unable to run inverse on 'data'; no reason logged in trace data") |
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 invertible is False: | |
if reasons is not None: | |
reason_text = "\n".join(reasons) | |
raise RuntimeError(f"Unable to run inverse on 'data' for the following reasons:\n{reason_text}") | |
else: | |
raise RuntimeError("Unable to run inverse on 'data'; no reason logged in trace data") | |
if invertible is False: | |
reason_text = "No reason logged in trace data" if reasons is None else "\n".join([""]+list(reasons)) | |
raise RuntimeError(f"Unable to run inverse on 'data': {reason_text}") |
/build |
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Cleaner tensor ops for test_compose Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Signed-off-by: Ben Murray <ben.murray@gmail.com>
…vertible. Removed LAZY from default transform_info(). It is now added during 'track_transform_meta' Signed-off-by: Ben Murray <ben.murray@gmail.com>
…o lazy_eval_refactor
for more information, see https://pre-commit.ci
Signed-off-by: Ben Murray <ben.murray@gmail.com>
…o lazy_eval_refactor
for more information, see https://pre-commit.ci
…ing out of order execution for brevity Signed-off-by: Ben Murray <ben.murray@gmail.com>
…o lazy_eval_refactor
|
||
def __init__(self): | ||
# construct the list of options | ||
options = {"reorder": {"lazy_last": self.reorder_lazy_last, "lazy_last_nosync": self.reorder_lazy_last_nosync}} |
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 would avoid having nested structures like this, instead:
options = {"reorder": {"lazy_last": self.reorder_lazy_last, "lazy_last_nosync": self.reorder_lazy_last_nosync}} | |
options = {("reorder","lazy_last"): self.reorder_lazy_last, ("reorder","lazy_last_nosync"): self.reorder_lazy_last_nosync} |
Also the string keywords here should be in enums and the structure that's expected should be documented in the docstring.
options = {"reorder": {"lazy_last": self.reorder_lazy_last, "lazy_last_nosync": self.reorder_lazy_last_nosync}} | ||
self.options = options | ||
|
||
def __call__(self, transforms, lazy: bool | None, options: dict | None = None): |
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.
options
is only ever used with one key-value pair so maybe just have two variables here. Otherwise eval_options
or something, with more docstring on what it means.
if len(options.keys()) > 1: | ||
raise ValueError("Only one option can currently be set") | ||
|
||
for k, v in options.items(): |
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.
k, v = monai.utils.first(options.items())
?
t.lazy_evaluation = self.lazy_evaluation | ||
self.options = options | ||
self.logger_name = logger_name | ||
self.execution_options = ExecutionOptions() |
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.
self.execution_options = ExecutionOptions() | |
self.exec_options = ExecutionOptions() if exec_options is None else exec_options |
monai/transforms/traits.py
Outdated
Args: | ||
enabled: True if the transform should operate in a lazy fashion, False if not. | ||
""" | ||
raise NotImplementedError() | ||
|
||
@property | ||
def partially_lazy(self): |
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.
def partially_lazy(self): | |
def partially_lazy(self) -> bool: |
Signed-off-by: Ben Murray <ben.murray@gmail.com>
Reduced lazy resampling functionality for MONAI 1.2 ### Description This PR is a subset of #6257 intended for MONAI 1.2. It contains the basic resampling strategy that has been approved for the 1.2 release during MONAI core dev meeting of 19th May, 2023. Draft status: * still to do * doc strings * topic page * resolve compose reference doc issue ### 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). - [x] 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`. - [x] In-line docstrings updated. - [x] Documentation updated, tested `make html` command in the `docs/` folder. --------- Signed-off-by: Ben Murray <ben.murray@gmail.com> Signed-off-by: monai-bot <monai.miccai2019@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Co-authored-by: Nic Ma <nma@nvidia.com> Co-authored-by: monai-bot <monai.miccai2019@gmail.com>
This is out of date. We'll revisit further lazy resampling functionality in new PRs. See #7151 for details |
Lazy evaluation refactor
This PR contains a reworking of the lazy evaluation mechanism on dev to provide the following:
options=None
(default) mode guarantees that all pending operations are evaluated before evaluating non-lazy _apply_transformsor transforms with lazy set to False. This means that all pipelines should be able to execute lazily without breaking (the first thing that users will try)
options={'reorder': 'lazy_last'}
mode that moves all lazy operations past non-lazy ones, (bounded by use ofApplyPending/ApplyPendingd) and guarantees invertibility
options={'reorder': 'lazy_last_nosync'}
mode that relies on ApplyPending/ApplyPendingd to cause application ofpending transforms, and precisely mimics the behaviour of the lazy execution on dev.
lazy=True
overrides the lazy flag on lazy transforms, making them all execute lazilylazy=None
uses the lazy flags set on transforms, and can execute them lazily or non-lazily dependinglazy=False
(default) causes lazy processing to be disabled and all lazy transforms will execute non-lazily__call__
. This means that lazy behaviour can be overridden without mutating the transform instanceApplyPending
andApplyPendingd
replace the use ofIdentity
andIdentityd
for causing pending ops to be evaluated when using thelazy_last[_nosync]
optionsoverrides
andoverride_keys
have been consolidated into overridesoverride_keys=('a', 'b'), overrides={'mode': ('bilinear', None), 'padding_mode: (None, 'zeros')'}
overrides={'a': {'mode': 'bilinear'}, 'b': {'padding_mode': 'zeros'}}
log_stats
andverbose
have been replaced withlogger_name
, consistent with other parts of MONAITypes of changes
lazy=True/None
andoptions=None
is new functionality relative todev
lazy=True/None
andoptions={"reorder": "lazy_last"}
is new functionality relative todev
lazy=None
and settinglazy=True
on a transform is new functionality relative todev
Identity[d]
doesn't cause pending operations to be evaluated; they must be replaced withApplyPending[d]
lazy=True
andoptions={"reorder": "lazy_last_nosync"} (with
Identity[d]being replaced by
ApplyPending[d]) should be identical in behaviour to
dev`./runtests.sh -f -u --net --coverage
../runtests.sh --quick --unittests --disttests
.make html
command in thedocs/
folder.