.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "generated/recipes/008_callbacks.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_generated_recipes_008_callbacks.py: .. _callbacks: How to Implement Your Callback with OptunaHub ============================================= This recipe shows how to implement and register your own callback with OptunaHub. Callbacks are used when you want to insert custom processing **after each trial completes**. Typical use cases include: - Uploading the current best result to an external server (e.g., W&B, MLflow). - Sending a notification when a new best value is found. - Stopping the study early based on custom criteria by calling :meth:`~optuna.Study.stop`. A callback is simply a callable with the following signature: .. code-block:: python def callback(study: optuna.Study, trial: optuna.trial.FrozenTrial) -> None: ... Optuna calls each registered callback once per trial, after the objective function returns and the trial state has been recorded. At that point :class:`~optuna.Study` already reflects the updated best value / best params, and ``trial`` is a :class:`~optuna.trial.FrozenTrial` (immutable). The simplest way to implement a callback is to define a plain function: .. GENERATED FROM PYTHON SOURCE LINES 30-44 .. code-block:: Python from __future__ import annotations import optuna def my_callback(study: optuna.Study, trial: optuna.trial.FrozenTrial) -> None: print(f"Trial {trial.number} finished.") print(f" params : {trial.params}") print(f" value : {trial.value}") if trial.state == optuna.trial.TrialState.COMPLETE: print(f" best_value : {study.best_value}") .. GENERATED FROM PYTHON SOURCE LINES 45-47 If your callback needs to hold internal state (e.g., a connection to an external service), you can implement it as a class with a ``__call__`` method instead. .. GENERATED FROM PYTHON SOURCE LINES 47-71 .. code-block:: Python class MyCallback: """A callback that prints trial information after each completed trial. Args: verbose: If ``True``, also print the full ``params`` dict. """ def __init__(self, verbose: bool = True) -> None: self._verbose = verbose def __call__(self, study: optuna.Study, trial: optuna.trial.FrozenTrial) -> None: # This method is called after every trial regardless of its state. if trial.state != optuna.trial.TrialState.COMPLETE: return print(f"Trial {trial.number} finished.") if self._verbose: print(f" params : {trial.params}") print(f" value : {trial.value}") print(f" best_value : {study.best_value}") .. GENERATED FROM PYTHON SOURCE LINES 72-74 The callback is passed to :meth:`~optuna.Study.optimize` via the ``callbacks`` argument. Multiple callbacks can be specified as a list; they are called in order after each trial. .. GENERATED FROM PYTHON SOURCE LINES 74-82 .. code-block:: Python def objective(trial: optuna.trial.Trial) -> float: x = trial.suggest_float("x", -10, 10) y = trial.suggest_int("y", -5, 5) return x**2 + y**2 .. GENERATED FROM PYTHON SOURCE LINES 83-84 Run the study with a plain function callback. .. GENERATED FROM PYTHON SOURCE LINES 84-87 .. code-block:: Python study = optuna.create_study() study.optimize(objective, n_trials=5, callbacks=[my_callback]) .. rst-class:: sphx-glr-script-out .. code-block:: none Trial 0 finished. params : {'x': 0.2033135467391638, 'y': 2} value : 4.041336398287658 best_value : 4.041336398287658 Trial 1 finished. params : {'x': 1.7823095255951387, 'y': 4} value : 19.17662724502717 best_value : 4.041336398287658 Trial 2 finished. params : {'x': -6.295251202196699, 'y': 2} value : 43.63018769875898 best_value : 4.041336398287658 Trial 3 finished. params : {'x': 2.383371664471955, 'y': 0} value : 5.680460491007818 best_value : 4.041336398287658 Trial 4 finished. params : {'x': 1.9451731350949153, 'y': -1} value : 4.783698525494982 best_value : 4.041336398287658 .. GENERATED FROM PYTHON SOURCE LINES 88-89 Run another study with the class-based callback. .. GENERATED FROM PYTHON SOURCE LINES 89-92 .. code-block:: Python study = optuna.create_study() study.optimize(objective, n_trials=5, callbacks=[MyCallback(verbose=True)]) .. rst-class:: sphx-glr-script-out .. code-block:: none Trial 0 finished. params : {'x': 2.035320735238379, 'y': -5} value : 29.142530495291297 best_value : 29.142530495291297 Trial 1 finished. params : {'x': 1.882135148259307, 'y': 3} value : 12.542432716313083 best_value : 12.542432716313083 Trial 2 finished. params : {'x': -9.187128669561764, 'y': 3} value : 93.4033331910837 best_value : 12.542432716313083 Trial 3 finished. params : {'x': -9.615333741861827, 'y': -5} value : 117.45464296738656 best_value : 12.542432716313083 Trial 4 finished. params : {'x': -2.0173057378872183, 'y': -3} value : 13.069522440112696 best_value : 12.542432716313083 .. GENERATED FROM PYTHON SOURCE LINES 93-96 After implementing your own callback, you can register it with OptunaHub. See :doc:`002_registration` for how to register your callback with OptunaHub. The category name to use when placing your package in the registry is ``callbacks``: .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.008 seconds) .. _sphx_glr_download_generated_recipes_008_callbacks.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 008_callbacks.ipynb <008_callbacks.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 008_callbacks.py <008_callbacks.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 008_callbacks.zip <008_callbacks.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_