Zum Hauptinhalt springen

Optimierungsschleifen

In dieser Lektion lernen wir, wie man einen Optimierer einsetzt, um die parametrisierten Quantenzustände unseres Ansatzes iterativ zu erkunden:

  • Eine Optimierungsschleife bootstrappen
  • Kompromisse beim Einsatz lokaler und globaler Optimierer verstehen
  • Barren Plateaus erkunden und wie man sie vermeidet

Auf hoher Ebene sind Optimierer zentral für die Erkundung unseres Suchraums. Der Optimierer nutzt Auswertungen der Kostenfunktion, um in einer variationalen Schleife den nächsten Parametersatz auszuwählen, und wiederholt diesen Prozess, bis ein stabiler Zustand erreicht ist. In diesem Stadium wird ein optimaler Satz von Parameterwerten θ\vec\theta^* zurückgegeben.

Ein Diagramm wichtiger Faktoren bei der Optimierung, darunter Barren Plateaus, Gradienten- vs. gradientenfreie Optimierer und Bootstrapping.

Lokale und globale Optimierer

Zunächst richten wir unser Problem ein, bevor wir jede Optimiererklasse erkunden. Wir beginnen mit einem Circuit, der acht variationale Parameter enthält:

# 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")

Output of the previous code cell

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()

Lokale Optimierer

Lokale Optimierer suchen nach einem Punkt, der die Kostenfunktion minimiert, ausgehend von einem oder mehreren Anfangspunkten C(θ0)C(\vec{\theta_0}), und wechseln zu anderen Punkten basierend auf dem, was sie in der Region beobachten, die sie bei aufeinanderfolgenden Iterationen auswerten. Das bedeutet, dass die Konvergenz dieser Algorithmen in der Regel schnell ist, aber stark vom Anfangspunkt abhängen kann. Lokale Optimierer können nicht über die Region hinaussehen, in der sie auswerten, und sind besonders anfällig für lokale Minima: Sie melden Konvergenz, sobald sie eines finden, und ignorieren andere Zustände mit günstigeren Auswertungen.

# 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

Globale Optimierer

Globale Optimierer suchen nach dem Punkt, der die Kostenfunktion über mehrere Regionen ihres Definitionsbereichs hinweg minimiert (d.h. nicht-lokal), und werten sie iterativ (d.h. bei Iteration ii) über eine Menge von Parametervektoren Θi:=θi,jjJopti\Theta_i := \\{ {\vec\theta_{i,j} | j \in \mathcal{J}_\text{opt}^i} \\} aus, die vom Optimierer bestimmt wird. Dadurch sind sie weniger anfällig für lokale Minima und etwas unabhängig von der Initialisierung, konvergieren jedoch deutlich langsamer zu einer vorgeschlagenen Lösung.

Bootstrapping der Optimierung

Bootstrapping, also das Setzen des Anfangswerts für die Parameter θ\vec\theta basierend auf einer vorherigen Optimierung, kann unserem Optimierer helfen, schneller zu einer Lösung zu konvergieren. Wir bezeichnen dies als Anfangspunkt θ0\vec\theta_0, und ψ(θ0)=UV(θ0)ρ|\psi(\vec\theta_0)\rangle = U_V(\vec\theta_0)|\rho\rangle als Anfangszustand. Dieser Anfangszustand unterscheidet sich von unserem Referenzzustand ρ|\rho\rangle: Ersterer konzentriert sich auf anfängliche Parameter, die während unserer Optimierungsschleife gesetzt werden, während Letzterer auf die Verwendung bekannter „Referenz"-Lösungen ausgerichtet ist. Sie können übereinstimmen, wenn UV(θ0)IU_V(\vec\theta_0) \equiv I gilt (d.h. die Identitätsoperation).

Wenn lokale Optimierer zu nicht-optimalen lokalen Minima konvergieren, können wir versuchen, die Optimierung global zu bootstrappen und die Konvergenz lokal zu verfeinern. Obwohl dies die Einrichtung zweier variationaler Arbeitsabläufe erfordert, ermöglicht es dem Optimierer, eine optimalere Lösung zu finden als der lokale Optimierer allein.

Gradientenbasierte und gradientenfreie Optimierer

Gradientenbasiert

Für unsere Kostenfunktion C(θ)C(\vec\theta) gilt: Wenn wir Zugriff auf den Gradienten der Funktion C(θ)\vec{\nabla} C(\vec\theta) ab einem Anfangspunkt haben, ist der einfachste Weg zur Minimierung der Funktion, die Parameter in Richtung des steilsten Abstiegs zu aktualisieren. Das heißt, wir aktualisieren die Parameter als θn+1=θnηC(θ)\vec\theta_{n+1} = \vec\theta_n - \eta \vec{\nabla} C(\vec\theta), wobei η\eta die Lernrate ist – ein kleiner, positiver Hyperparameter, der die Größe der Aktualisierung steuert. Wir setzen dies fort, bis wir zu einem lokalen Minimum der Kostenfunktion C(θ)C({\vec\theta^*}) konvergieren. Wir können diese Kostenfunktion und einen Optimierer verwenden, um optimale Parameter zu berechnen.

# SciPy minimizer routine
from scipy.optimize import minimize

x0 = np.ones(8)

result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="BFGS"
)

result
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

Die wesentlichen Nachteile dieser Art der Optimierung sind die Konvergenzgeschwindigkeit, die sehr langsam sein kann, und die fehlende Garantie, die optimale Lösung zu erreichen.

Graph von f(theta) gegen theta; mehrere Punkte zeigen verschiedene Zustände eines Gradientenabstiegsalgorithmus beim Auffinden des Minimums einer Kurve.

Gradientenfrei

Gradientenfreie Optimierungsalgorithmen benötigen keine Gradienteninformation und können in Situationen nützlich sein, in denen die Berechnung des Gradienten schwierig, teuer oder zu verrauscht ist. Sie tendieren auch dazu, robuster bei der Suche nach globalen Optima zu sein, während gradientenbasierte Methoden dazu neigen, zu lokalen Optima zu konvergieren. Wir werden einige Szenarien erkunden, in denen ein gradientenfreier Optimierer Barren Plateaus helfen kann zu vermeiden. Gradientenfreie Methoden erfordern jedoch höhere Rechenressourcen, insbesondere bei Problemen mit hochdimensionalen Suchräumen.

Hier ist ein Beispiel, das stattdessen den COBYLA-Optimierer verwendet:

# SciPy minimizer routine
from scipy.optimize import minimize

x0 = np.ones(8)

result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="COBYLA"
)

result
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

Barren Plateaus

Tatsächlich kann die Kostenlandschaft ziemlich komplex sein, wie die Hügel und Täler im folgenden Beispiel zeigen. Die Optimierungsmethode navigiert uns durch die Kostenlandschaft auf der Suche nach dem Minimum, dargestellt durch die schwarzen Punkte und Linien. Wir können sehen, dass zwei der drei Suchen in einem lokalen Minimum der Landschaft enden, statt im globalen.

Eine komplexe gekrümmte Fläche mit vielen Gipfeln und Tälern.

Unabhängig von der verwendeten Optimierungsmethode kann es schwierig sein, die geeignete Suchrichtung zu bestimmen, wenn die Kostenlandschaft relativ flach ist. Dieses Szenario wird als Barren Plateau bezeichnet, bei dem die Kostenlandschaft zunehmend flacher wird (und es damit schwieriger wird, die Richtung zum Minimum zu bestimmen). Für eine breite Palette parametrisierter Quantencircuits nimmt die Wahrscheinlichkeit, dass der Gradient in einer vernünftigen Richtung ungleich null ist (bei einer bestimmten Genauigkeit), exponentiell mit der Anzahl der Qubits ab.

Ein Diagramm, das ein geografisches Plateau im Vergleich zu einem Berghang zeigt, um zu erklären, warum ein Gradient uns hilft, ein Minimum zu finden, und ein Plateau unsere Bemühungen behindert.

Während dieses Gebiet noch aktiv erforscht wird, haben wir einige Empfehlungen zur Verbesserung der Optimierungsleistung:

  • Bootstrapping kann helfen, zu verhindern, dass die Optimierungsschleife in einem Parameterraum stecken bleibt, in dem der Gradient klein ist.
  • Experimentieren mit hardware-effizienten Ansätzen: Da wir ein verrauschtes Quantensystem als Blackbox-Orakel verwenden, kann die Qualität dieser Auswertungen die Leistung des Optimierers beeinflussen. Die Verwendung hardware-effizienter Ansätze, wie EfficientSU2, kann die Erzeugung exponentiell kleiner Gradienten vermeiden.
  • Experimentieren mit Fehlersuppression und Fehlerminderung: Die Qiskit Runtime Primitives bieten eine einfache Schnittstelle, um mit verschiedenen Werten für optimization_level bzw. resilience_setting zu experimentieren. Dies kann den Einfluss von Rauschen verringern und den Optimierungsprozess effizienter gestalten.
  • Experimentieren mit gradientenfreien Optimierern: Im Gegensatz zu gradientenbasierten Optimierungsalgorithmen stützen sich Optimierer wie COBYLA nicht auf Gradienteninformationen zur Parameteroptimierung und sind daher weniger anfällig für das Barren-Plateau-Problem.

Zusammenfassung

In dieser Lektion hast du gelernt, wie du deine Optimierungsschleife definierst:

  • Eine Optimierungsschleife bootstrappen
  • Kompromisse beim Einsatz lokaler und globaler Optimierer verstehen
  • Barren Plateaus erkunden und wie man sie vermeidet

Unser variationaler Arbeitsablauf auf hoher Ebene ist nun vollständig:

Ein Quantencircuit mit zwei unitären Operatoren: einem zur Vorbereitung des Referenzzustands und einem zweiten zur Variation des Zustands mithilfe variationaler Parameter.

Als Nächstes werden wir spezifische variationale Algorithmen mit diesem Framework erkunden.