Boucles d'optimisation
Au cours de cette leçon, nous apprendrons à utiliser un optimiseur pour explorer de manière itérative les états quantiques paramétrés de notre ansatz :
- Création d'une boucle d'optimisation
- Comprendre les compromis lors de l'utilisation d'optimiseurs locaux et globaux
- Explorer les plateaux stériles et comment les éviter
À un niveau élevé, les optimiseurs sont essentiels à l'exploration de notre espace de recherche. L'optimiseur utilise les évaluations de la fonction de coût pour sélectionner l'ensemble suivant de paramètres dans une boucle variationnelle, et répète le processus jusqu'à ce qu'il atteigne un état stable. À ce stade, un ensemble optimal de valeurs de paramètres est renvoyé.
Optimiseurs locaux et globaux
Nous commencerons par définir notre problème avant d'explorer chaque classe d'optimiseur. Nous commencerons par un circuit contenant huit paramètres variationnels :
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")Output:
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 costfrom qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()Optimiseurs locaux
Les optimiseurs locaux recherchent un point qui minimise la fonction de coût à partir d'un ou de plusieurs points initiaux ( ) et se déplacent vers différents points en fonction de ce qu'ils observent dans la région qu'ils sont en train d'évaluer lors d'itérations successives. Cela signifie que la convergence de ces algorithmes est généralement rapide, mais qu'elle peut dépendre fortement du point initial. Les optimiseurs locaux sont incapables de voir au-delà de la région qu'ils évaluent et peuvent être particulièrement vulnérables aux minima locaux, signalant une convergence lorsqu'ils en trouvent un et 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"
)
resultOutput:
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 recherchent le point qui minimise la fonction de coût sur plusieurs régions de son domaine (c'est-à-dire non local), en l'évaluant itérativement (c'est-à-dire à l'itération ) sur un ensemble de vecteurs de paramètres déterminés par l'optimiseur. Cela les rend moins sensibles aux minima locaux et quelque peu indépendants de l'initialisation, mais aussi beaucoup plus lents à converger vers une solution proposée.
Optimisation par bootstrapping
Le bootstrapping, ou la définition de la valeur initiale des paramètres sur la base d'une optimisation antérieure, peut aider notre optimiseur à converger plus rapidement vers une solution. Nous appelons cela le point initial , et l'état initial. Cet état initial diffère de notre état de référence , car le premier se concentre sur les paramètres initiaux définis au cours de notre boucle d'optimisation, tandis que le second se concentre sur l'utilisation de solutions "de référence" connues. Elles peuvent coïncider si (c'est-à-dire l'opération d'identité).
Lorsque les optimiseurs locaux convergent vers des minima locaux non optimaux, nous pouvons essayer d'amorcer l'optimisation globalement et d'affiner la convergence localement. Bien que cela nécessite la mise en place de deux charges de travail variationnelles, cela permet à l'optimiseur de trouver une solution plus optimale que l'optimiseur local seul.
Optimiseurs basés sur les gradients et sans gradients
Basé sur le gradient
Pour notre fonction de coût , si nous avons accès au gradient de la fonction à partir d'un point initial, la manière la plus simple de minimiser la fonction est de mettre à jour les paramètres dans le sens de la descente la plus raide de la fonction. En d'autres termes, nous mettons à jour les paramètres en tant que , où est le taux d'apprentissage - un petit Un hyperparamètre est un paramètre que nous utilisons pour contrôler notre algorithme. Le terme hyper le distingue des paramètres (θ) que notre algorithme tente de trouver. positif qui contrôle la taille de la mise à jour. Nous continuons ainsi jusqu'à ce que nous convergions vers Un minimum local est le point le plus bas de la fonction, pour une petite gamme de valeurs de thêta. En revanche, un minimum global est le point le plus bas, n'importe où dans notre fonction (c'est-à-dire pour n'importe quelle valeur de θ). de la fonction de coût, .
Nous pouvons utiliser cette fonction de coût et un optimiseur pour calculer les paramètres optimaux
# SciPy minimizer routine
from scipy.optimize import minimize
x0 = np.ones(8)
result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="BFGS"
)
resultOutput:
message: Optimization terminated successfully.
success: True
status: 0
fun: -3.9999999999997025
x: [ 1.000e+00 1.000e+00 1.571e+00 3.220e-07 2.009e-01
-2.009e-01 6.342e-01 -6.342e-01]
nit: 14
jac: [-1.192e-07 -2.980e-08 8.345e-07 1.103e-06 5.960e-08
0.000e+00 -5.960e-08 2.980e-08]
hess_inv: [[ 1.000e+00 1.872e-10 ... 5.077e-05 3.847e-05]
[ 1.872e-10 1.000e+00 ... -5.208e-05 -4.060e-05]
...
[ 5.077e-05 -5.208e-05 ... 7.243e-01 -2.604e-01]
[ 3.847e-05 -4.060e-05 ... -2.604e-01 8.179e-01]]
nfev: 144
njev: 16
Les principaux inconvénients de ce type d'optimisation sont la vitesse de convergence, qui peut être très lente, et l'absence de garantie d'obtenir la solution optimale.
Sans gradient
Les algorithmes d'optimisation sans gradient ne nécessitent pas d'informations sur le gradient et peuvent être utiles dans les situations où le calcul du gradient est difficile, coûteux ou trop bruyant. Elles ont également tendance à être plus robustes dans la recherche d'optima globaux, alors que les méthodes basées sur le gradient ont tendance à converger vers des optima locaux. Nous allons explorer quelques cas où un optimiseur sans gradient peut aider à éviter les plateaux stériles. Cependant, les méthodes sans gradient nécessitent des ressources informatiques plus importantes, en particulier pour les problèmes avec des espaces de recherche de haute dimension.
Voici un exemple qui utilise l'optimiseur COBYLA à la place de l'optimiseur :
# SciPy minimizer routine
from scipy.optimize import minimize
x0 = np.ones(8)
result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="COBYLA"
)
resultOutput:
message: Optimization terminated successfully.
success: True
status: 1
fun: -3.999999973369678
x: [ 1.631e+00 1.492e+00 1.571e+00 3.142e+00 1.375e+00
-1.767e+00 1.484e+00 1.658e+00]
nfev: 137
maxcv: 0.0
Plateaux arides
En fait, le paysage des coûts peut être assez complexe, comme le montrent les collines et les vallées de l'exemple ci-dessous. La méthode d'optimisation nous fait naviguer dans le paysage des coûts, à la recherche du minimum, comme le montrent les points et les lignes noirs. Nous pouvons constater que deux des trois recherches aboutissent à un minimum local du paysage, plutôt qu'à un minimum global.
Quel que soit le type de méthode d'optimisation utilisé, si le paysage des coûts est relativement plat, il peut être difficile pour la méthode de déterminer la direction appropriée de la recherche. Ce scénario est appelé Lorsque les gradients des circuits quantiques paramétrés deviennent exponentiellement petits par rapport au nombre de qubits, l'optimisation devient difficile, voire impossible., où le paysage des coûts devient progressivement plus plat (et donc plus difficile à déterminer pour atteindre le minimum). Pour un large éventail de circuits quantiques paramétrés, la probabilité que le gradient le long d'une direction raisonnable soit non nul avec une précision donnée diminue de manière exponentielle lorsque le nombre de qubits augmente.
Bien que ce domaine fasse encore l'objet de recherches actives, nous avons quelques recommandations pour améliorer les performances d'optimisation :
- Le bootstrapping peut aider la boucle d'optimisation à éviter de rester bloquée dans un espace de paramètres où le gradient est faible.
- Expérimentation d'un ansatz efficace sur le plan matériel : étant donné que nous utilisons un système quantique bruyant comme oracle de boîte noire, la qualité de ces évaluations peut influer sur les performances de l'optimiseur. L'utilisation d'un ansatz efficace sur le plan matériel, tel que
EfficientSU2peut éviter de produire des gradients exponentiellement petits. - Expérimentation de la suppression et de l'atténuation des erreurs : les primitives de la bibliothèque « IBM Quantum » offrent une interface simple permettant de tester différentes valeurs pour
optimization_leveletresilience_setting, respectivement. Cela peut réduire l'impact du bruit et rendre le processus d'optimisation plus efficace. - Expérimentation avec des optimiseurs sans gradient : Contrairement aux algorithmes d'optimisation basés sur le gradient, les optimiseurs tels que
COBYLAne s'appuient pas sur les informations de gradient pour optimiser les paramètres et sont donc moins susceptibles d'être affectés par le plateau stérile.
Récapitulatif
Cette leçon vous a appris à définir votre boucle d'optimisation :
- Création d'une boucle d'optimisation
- Comprendre les compromis lors de l'utilisation d'optimiseurs locaux et globaux
- Explorer les plateaux stériles et comment les éviter
Notre charge de travail variationnelle de haut niveau est terminée :
Ensuite, nous explorerons des algorithmes variationnels spécifiques en gardant ce cadre à l'esprit.