Skip to content
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

add termination callback to SPSA #6839

Merged
merged 44 commits into from
Sep 6, 2021
Merged

Conversation

peendebak
Copy link
Contributor

Summary

The SPSA optimizer is suitable for noisy optimization if evaluation of the cost function is expensive. The current implementation terminates after the maximum number of iterations, even if the optimizer already converged to a local optimum.

This PR adds a callback termination_callback that can be implemented by the user to abort the optimization.

An example:

from qiskit.algorithms.optimizers import SPSA
import numpy as np

def objective(x, a=2):
    objective.n=objective.n+1
    return (x[0]-a)**2 + 4*(x[1])**2 + .01*np.random.rand()

class AverageDecreaseTermination:
    
    def __init__(self, N : int, tolerance :  float = 0):
        """ Callback to terminate optmization when the average decrease over the last N data points is smaller than the specified tolerance """ 
        self.N = N
        self.tolerance = tolerance
        self.values = []
    
    def __call__(self, parameters, value) -> bool:
        """ 
        Returns:
            True if the optimization loop should be aborted 
        """
        self.values.append(value)
        
        if len(self.values)>self.N:
            last_values = self.values[-self.N:]
            pp=np.polyfit(range(self.N), last_values, 1)
            slope=pp[0] / self.N 
            
            #print(f'AverageDecreaseTermination: slope {slope}')
            if slope>self.tolerance:
                return True
        return False
    
# SPSA optimization       
objective.n=0
optimizer = SPSA()
point, value, iterations = optimizer.optimize(2, objective, initial_point = (.75,0))
print(f'point {point}, value {value}, iterations {iterations}, objective evaluations {objective.n}')


# SPSA optimization with early abort
objective.n=0
termination_callback = AverageDecreaseTermination(8)
optimizer = SPSA(termination_callback=termination_callback)
point, value, iterations = optimizer.optimize(2, objective, initial_point = (1.5,0))
print(f'point {point}, value {value}, iterations {iterations}, objective evaluations {objective.n}')

Details and comments

For noisy optimization a simple termination criterium such as a tolerance on decrease of the objective function is not suitable. For this reason a callback is specified so that the user can choose which termination criterium to use.

To keep the number of objective evaluations as low as possible, the internal evaluations of the loss function have been used to provide an estimate of the objective value.

@peendebak peendebak requested review from manoelmarques, woodsp-ibm and a team as code owners July 30, 2021 10:05
@peendebak peendebak force-pushed the feat/spsa_termination branch from 1224260 to f5c204c Compare July 30, 2021 12:36
@Cryoris
Copy link
Contributor

Cryoris commented Jul 30, 2021

That's an interesting addition 👍🏻 could you make sure that QN-SPSA (which derives from SPSA) is adjusted accordingly and that the termination callback is included in the settings?

@peendebak
Copy link
Contributor Author

@Cryoris Addressed the review comments

@woodsp-ibm woodsp-ibm added the mod: algorithms Related to the Algorithms module label Aug 3, 2021
@woodsp-ibm
Copy link
Member

An ability to allow SPSA to stop ahead of max iters has often asked for more than once but finding suitable criteria was not so easy. This seems like a neat way to address that!

@woodsp-ibm
Copy link
Member

@nonhermitian I know you had commented in the past about terminating SPSA prior to max iters and there was an issue at one point. I believe you mentioned some thoughts around heuristics for termination. Do you think this mechanism can cater to what you had in mind?

@nonhermitian
Copy link
Contributor

It looks like it can be quite generic so yeah I would think so.

It was hard to find a reliable way to terminate, but this would allow further exploration of that.

@peendebak peendebak requested a review from Cryoris August 30, 2021 06:57
woodsp-ibm
woodsp-ibm previously approved these changes Sep 2, 2021
Copy link
Member

@woodsp-ibm woodsp-ibm left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for this contribution - for the idea, improving the optimizers with it, and for your patience/effort in sorting out all the comments and suggestions to complete this.

qiskit/algorithms/optimizers/spsa.py Outdated Show resolved Hide resolved
qiskit/algorithms/optimizers/qnspsa.py Outdated Show resolved Hide resolved
Co-authored-by: Julien Gacon <gaconju@gmail.com>
@peendebak peendebak requested a review from Cryoris September 6, 2021 11:58
Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

Thanks for the effort @peendebak!

@Cryoris Cryoris added automerge Changelog: New Feature Include in the "Added" section of the changelog labels Sep 6, 2021
@mergify mergify bot merged commit c562808 into Qiskit:main Sep 6, 2021
@peendebak peendebak deleted the feat/spsa_termination branch September 6, 2021 21:46
@kdk kdk added this to the 0.19 milestone Nov 15, 2021
ElePT pushed a commit to ElePT/qiskit that referenced this pull request Jun 27, 2023
* add termination callback to SPSA

* add release notes

* fix linting

* update QNSPSA for termination_callback

* fix linting

* fix linting

* fix typo

* add termination callback to settings

* fix tests

* add example to release notes

* add example

* fix release notes

* address review comments

* whitespae

* address review comments

* address review comments

* rename to termination_checker; pass Optimizer as argument

* complete renames

* Update qiskit/algorithms/optimizers/spsa.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* address review comments

* fix pylint

* trigger build

* fix signature of callback

* fix pylint

* fix pylint

* Update qiskit/algorithms/optimizers/spsa.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* update name of callback signature

* fix pylint

Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
Co-authored-by: Julien Gacon <gaconju@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
ElePT pushed a commit to ElePT/qiskit-algorithms-test that referenced this pull request Jul 17, 2023
* add termination callback to SPSA

* add release notes

* fix linting

* update QNSPSA for termination_callback

* fix linting

* fix linting

* fix typo

* add termination callback to settings

* fix tests

* add example to release notes

* add example

* fix release notes

* address review comments

* whitespae

* address review comments

* address review comments

* rename to termination_checker; pass Optimizer as argument

* complete renames

* Update qiskit/algorithms/optimizers/spsa.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* address review comments

* fix pylint

* trigger build

* fix signature of callback

* fix pylint

* fix pylint

* Update qiskit/algorithms/optimizers/spsa.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* update name of callback signature

* fix pylint

Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
Co-authored-by: Julien Gacon <gaconju@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog mod: algorithms Related to the Algorithms module
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants