Boucles d'optimisation
Durant cette leçon, nous allons apprendre à utiliser un optimiseur pour explorer de façon itérative les états quantiques paramétrés de notre ansatz :
- Amorcer une boucle d'optimisation
- Comprendre les compromis entre optimiseurs locaux et globaux
- Explorer les plateaux stériles et comment les éviter
À haut niveau, les optimiseurs sont au cœur de l'exploration de notre espace de recherche. L'optimiseur utilise les évaluations de la fonction de coût pour sélectionner le prochain ensemble de paramètres dans une boucle variationnelle, et répète le processus jusqu'à atteindre un état stable. À ce stade, un ensemble optimal de valeurs de paramètres est retourné.
Optimiseurs locaux et globaux
Commençons par mettre en place notre problème avant d'explorer chaque classe d'optimiseur. Nous démarrerons avec un circuit contenant huit paramètres variationnels :
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit scipy
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import TwoLocal
import numpy as np
theta_list = (2 * np.pi * np.random.rand(1, 8)).tolist()
observable = SparsePauliOp.from_list([("XX", 1), ("YY", -3)])
reference_circuit = QuantumCircuit(2)
reference_circuit.x(0)
variational_form = TwoLocal(
2,
rotation_blocks=["rz", "ry"],
entanglement_blocks="cx",
entanglement="linear",
reps=1,
)
ansatz = reference_circuit.compose(variational_form)
ansatz.decompose().draw("mpl")
def cost_func_vqe(params, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator
Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (Estimator): Estimator primitive instance
Returns:
float: Energy estimate
"""
pub = (ansatz, hamiltonian, params)
cost = estimator.run([pub]).result()[0].data.evs
return cost
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
Optimiseurs locaux
Les optimiseurs locaux cherchent un point qui minimise la fonction de coût en partant d'un ou plusieurs points initiaux , puis se déplacent vers d'autres points en fonction de ce qu'ils observent dans la région qu'ils évaluent à chaque itération successive. Cela implique que la convergence de ces algorithmes est généralement rapide, mais peut dépendre fortement du point initial. Les optimiseurs locaux ne voient pas au-delà de la région qu'ils évaluent et sont particulièrement vulnérables aux minima locaux : ils signalent une convergence dès qu'ils en trouvent un, en ignorant d'autres états avec des évaluations plus favorables.
# SciPy minimizer routine
from scipy.optimize import minimize
x0 = np.ones(8)
result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="SLSQP"
)
result
message: Optimization terminated successfully
success: True
status: 0
fun: -3.9999999964520634
x: [ 1.000e+00 1.000e+00 -1.571e+00 -4.556e-05 -1.207e+00
-1.935e+00 4.079e-01 -4.079e-01]
nit: 12
jac: [ 0.000e+00 0.000e+00 -7.957e-04 2.543e-04 1.381e-03
1.381e-03 5.430e-04 5.431e-04]
nfev: 112
njev: 12
Optimiseurs globaux
Les optimiseurs globaux cherchent le point qui minimise la fonction de coût sur plusieurs régions de son domaine (c'est-à-dire de façon non locale), en l'évaluant de façon itérative (c'est-à-dire à l'itération ) sur un ensemble de vecteurs de paramètres déterminé par l'optimiseur. Cela les rend moins sensibles aux minima locaux et relativement indépendants de l'initialisation, mais aussi nettement plus lents à converger vers une solution proposée.
Amorçage de l'optimisation
L'amorçage (bootstrapping), qui consiste à fixer la valeur initiale des paramètres à partir d'une optimisation préalable, peut aider l'optimiseur à converger plus rapidement vers une solution. On appelle cela le point initial , et l'état initial. Cet état initial diffère de notre état de référence : le premier porte sur les paramètres initiaux fixés pendant notre boucle d'optimisation, tandis que le second repose sur des solutions de « référence » connues. Ils peuvent coïncider si (c'est-à-dire l'opération identité).
Lorsque les optimiseurs locaux convergent vers des minima locaux non optimaux, on peut essayer d'amorcer l'optimisation globalement, puis d'affiner la convergence localement. Bien que cela nécessite de mettre en place deux charges de travail variationnelles, cette approche permet à l'optimiseur de trouver une solution plus optimale que l'optimiseur local seul.
Optimiseurs avec et sans gradient
Avec gradient
Pour notre fonction de coût , si nous avons accès au gradient de la fonction à partir d'un point initial, la façon la plus simple de minimiser la fonction est de mettre à jour les paramètres dans la direction de la descente la plus abrupte. Autrement dit, on met à jour les paramètres comme suit : , où est le taux d'apprentissage — un petit