Skip to content

[Callbacks] FEA new hook for beginning of tasks#33494

Merged
jeremiedbb merged 20 commits intoscikit-learn:callbacksfrom
jeremiedbb:add-on-fit-task-begin-hook
Mar 14, 2026
Merged

[Callbacks] FEA new hook for beginning of tasks#33494
jeremiedbb merged 20 commits intoscikit-learn:callbacksfrom
jeremiedbb:add-on-fit-task-begin-hook

Conversation

@jeremiedbb
Copy link
Copy Markdown
Member

@jeremiedbb jeremiedbb commented Mar 9, 2026

As discussed during the last meeting, this PR proposes an different version of the callback protocol with 4 callbacks

BaseCallback
-setup
-teardown

FitCallback(BaseCallback)
- on_fit_task_end
- on_fit_task_begin

Previoulsy on_fit_begin used to act as a setup and begin of the root task, and on_fit_end used to act as a teardown and end of the root task.

Now all nodes of the context tree call the same hook at the end the task, including the root. In addition, they all call a same hook at the beginning of the task.

Side effect: setup and tear down don't need to be tied to the callback context, so we can make the decorator deal with setup and teardown it self and we don't need to store the context as an attribute of the estimator anymore which is nice.

ping @ogrisel @FrancoisPgm @StefanieSenger @lesteve

Copy link
Copy Markdown
Member

@ogrisel ogrisel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, here is a first pass of feedback.

assert callback.count_hooks("on_fit_task_begin") == expected_n_tasks
assert callback.count_hooks("on_fit_task_end") == expected_n_tasks
assert callback.count_hooks("on_fit_end") == 1
assert callback.count_hooks("fit_teardown") == 1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are great assertions but I think it would be nice to also have one about the sequence of events with estimator names and task names.

That would make a stronger test but also be helpful for SLEP reviewers to better understand the dynamics induced by the callback API design choices.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and it's in my todo list :)
but maybe can be done in a separate PR ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-referencing our previous discussion about this, starting in #33394 (comment).

assert callback.count_hooks("on_fit_task_begin") == expected_n_tasks
assert callback.count_hooks("on_fit_task_end") == expected_n_tasks
assert callback.count_hooks("on_fit_end") == 1
assert callback.count_hooks("fit_teardown") == 1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-referencing our previous discussion about this, starting in #33394 (comment).

@github-actions github-actions bot added the CI:Linter failure The linter CI is failing on this PR label Mar 10, 2026
@github-actions github-actions bot removed the CI:Linter failure The linter CI is failing on this PR label Mar 10, 2026
@jeremiedbb
Copy link
Copy Markdown
Member Author

Following up a discussion we had with @ogrisel and @FrancoisPgm, I pushed a new commit where the protocol is reworked. Related to this #33494 (comment)

There's now a base protocol for setup and teardown.
Then a protocol for beginning and end of fit tasks.

It keeps the door open for new protocols for beginning and end of function/predict/transform tasks, while allowing a callback to just implement a minimal protocol for its usage (e.g. _BaseCallback + FunctionCallback for a function only callback).

To allow callbacks to do different things during setup/teardown while not having a specific setup and teardown in each protocal, we thought that the setup and teardown hooks would receive the method where the callback context is created. I haven't implemented that yet since we don't have that kind of need yet. We can add this enhancement a bit later.

Copy link
Copy Markdown
Member

@lesteve lesteve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good, a few comments below.

# Only call the `on_fit_task_begin` hook of callbacks that are not
# propagated. For propagated callbacks, the hook will be called by the
# sub-estimator's root context (both represent the same task).
if callback not in getattr(self, "_propagated_callbacks", []):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what is the reason to change isinstance check to attribute check? Is there some subtlety involved or it for simplicity?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is an attr check because we want to detect the callbacks that were propagated from a parent meta-estimator. For auto-propagated callbacks, we still want to call on_fit_task_begin here for the root meta-estimator.

@jeremiedbb
Copy link
Copy Markdown
Member Author

I merged #33522 into this branch to showcase how the new hooks work with the required changes from #33522.

Basically we need to come back to a setup during context initialization in fit and set the context as an attribute to be able to have the teardown done in the finally block of the decorator.

We should therefore merge #33522 before this one

Copy link
Copy Markdown
Member

@ogrisel ogrisel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave it another pass and it looks good to me as well.

Copy link
Copy Markdown
Contributor

@FrancoisPgm FrancoisPgm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few super minor nitpicks and some docstrings to update but oterwise LGTM thx :)

@jeremiedbb
Copy link
Copy Markdown
Member Author

Thanks for the reviews. I'm merging this one as well with 2 approvals to be able to update the SLEP.

@jeremiedbb jeremiedbb merged commit 66b1eed into scikit-learn:callbacks Mar 14, 2026
25 checks passed
@jeremiedbb jeremiedbb moved this to Done in Labs Mar 14, 2026
@jeremiedbb jeremiedbb added this to Labs Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants