Cicli di ottimizzazione
In questa lezione impareremo a utilizzare un ottimizzatore per esplorare iterativamente gli stati quantistici parametrizzati del nostro ansatz:
- Bootstrap di un ciclo di ottimizzazione
- Comprendere i compromessi nell'utilizzo di ottimizzatori locali e globali
- Esplorare gli altipiani sterili e come evitarli
Ad alto livello, gli ottimizzatori sono fondamentali per esplorare il nostro spazio di ricerca. L'ottimizzatore utilizza le valutazioni delle funzioni di costo per selezionare la serie successiva di parametri in un ciclo variazionale e ripete il processo fino a raggiungere uno stato stabile. In questa fase, viene restituito un insieme ottimale di valori dei parametri .
Ottimizzatori locali e globali
Prima di esplorare ogni classe di ottimizzatori, imposteremo il nostro problema. Inizieremo con un circuito contenente otto parametri variazionali:
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()Ottimizzatori locali
Gli ottimizzatori locali cercano un punto che minimizzi la funzione di costo a partire da uno o più punti iniziali e si spostano su punti diversi in base a ciò che osservano nella regione che stanno valutando nelle iterazioni successive. Ciò implica che la convergenza di questi algoritmi sarà solitamente veloce, ma può dipendere fortemente dal punto iniziale. Gli ottimizzatori locali non sono in grado di vedere oltre la regione in cui stanno valutando e possono essere particolarmente vulnerabili ai minimi locali, segnalando la convergenza quando ne trovano uno e ignorando altri stati con valutazioni più favorevoli.
# 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
Ottimizzatori globali
Gli ottimizzatori globali cercano il punto che minimizza la funzione di costo in diverse regioni del suo dominio (cioè non locali), valutandola in modo iterativo (cioè all'iterazione ) su un insieme di vettori di parametri determinati dall'ottimizzatore. Ciò li rende meno suscettibili ai minimi locali e in qualche modo indipendenti dall'inizializzazione, ma anche significativamente più lenti a convergere verso una soluzione proposta.
Ottimizzazione del bootstrapping
Il bootstrapping, ovvero l'impostazione del valore iniziale dei parametri sulla base di un'ottimizzazione precedente, può aiutare il nostro ottimizzatore a convergere più rapidamente verso una soluzione. Si parla di punto iniziale e di come stato iniziale. Questo stato iniziale differisce dal nostro stato di riferimento , poiché il primo si concentra sui parametri iniziali impostati durante il nostro ciclo di ottimizzazione, mentre il secondo si concentra sull'utilizzo di soluzioni "di riferimento" note. Possono coincidere se (cioè l'operazione di identità).
Quando gli ottimizzatori locali convergono verso minimi locali non ottimali, possiamo provare a fare il bootstrap dell'ottimizzazione a livello globale e a perfezionare la convergenza a livello locale. Sebbene ciò richieda l'impostazione di due carichi di lavoro variazionali, consente all'ottimizzatore di trovare una soluzione più ottimale rispetto al solo ottimizzatore locale.
Ottimizzatori basati sul gradiente e senza gradiente
Basato sul gradiente
Per la nostra funzione di costo , se abbiamo accesso al gradiente della funzione a partire da un punto iniziale, il modo più semplice per minimizzare la funzione è aggiornare i parametri verso la direzione di massima discesa della funzione. Cioè, aggiorniamo i parametri come , dove è il tasso di apprendimento - un piccolo Un iperparametro è un parametro che utilizziamo per controllare il nostro algoritmo. Il termine iper lo distingue dai parametri (θ) che il nostro algoritmo cerca di trovare. positivo che controlla la dimensione dell'aggiornamento. Continuiamo a farlo finché non convergiamo a un Un minimo locale è il punto più basso della funzione, per un piccolo intervallo di valori di theta. Al contrario, un minimo globale è il punto più basso, in qualsiasi punto della nostra funzione (cioè per qualsiasi valore di θ). della funzione di costo, .
Possiamo utilizzare questa funzione di costo e un ottimizzatore per calcolare i parametri ottimali
# 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
I principali svantaggi di questo tipo di ottimizzazione sono la velocità di convergenza, che può essere molto lenta, e la mancanza di garanzia di raggiungere la soluzione ottimale.
Senza gradiente
Gli algoritmi di ottimizzazione senza gradiente non richiedono informazioni sul gradiente e possono essere utili in situazioni in cui il calcolo del gradiente è difficile, costoso o troppo rumoroso. Inoltre, tendono a essere più robusti nel trovare gli ottimali globali, mentre i metodi basati sul gradiente tendono a convergere verso gli ottimali locali. Esploreremo alcuni casi in cui un ottimizzatore senza gradiente può aiutare a evitare i plateau sterili. Tuttavia, i metodi privi di gradiente richiedono risorse computazionali più elevate, soprattutto per problemi con spazi di ricerca altamente dimensionali.
Ecco un esempio che utilizza l'ottimizzatore COBYLA invece dell'ottimizzatore:
# 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
Altipiani aridi
In effetti, il panorama dei costi può essere piuttosto complicato, come dimostrano le colline e le valli dell'esempio seguente. Il metodo di ottimizzazione ci fa navigare nel panorama dei costi, alla ricerca del minimo, come mostrato dai punti e dalle linee nere. Si può notare che due delle tre ricerche finiscono in un minimo locale del paesaggio, piuttosto che in uno globale.
Indipendentemente dal tipo di metodo di ottimizzazione utilizzato, se il panorama dei costi è relativamente piatto, può essere difficile per il metodo determinare la direzione di ricerca appropriata. Questo scenario viene definito Quando i gradienti dei circuiti quantistici parametrizzati diventano esponenzialmente piccoli rispetto al numero di qubit, rendendo l'ottimizzazione difficile e potenzialmente impossibile., dove il panorama dei costi diventa progressivamente più piatto (e quindi più difficile da determinare la direzione verso il minimo). Per un'ampia gamma di circuiti quantistici parametrizzati, la probabilità che il gradiente lungo qualsiasi direzione ragionevole sia non nullo con una precisione fissa diminuisce esponenzialmente all'aumentare del numero di qubit.
Anche se quest'area è ancora oggetto di ricerca attiva, abbiamo alcune raccomandazioni per migliorare le prestazioni dell'ottimizzazione:
- Il bootstrapping può aiutare il ciclo di ottimizzazione a non rimanere bloccato in uno spazio di parametri in cui il gradiente è piccolo.
- Sperimentazione di ansatz efficienti dal punto di vista hardware : poiché stiamo usando un sistema quantistico rumoroso come oracolo black-box, la qualità di queste valutazioni può influenzare le prestazioni dell'ottimizzatore. L'utilizzo di ansatz efficienti dal punto di vista hardware, come ad esempio
EfficientSU2può evitare di produrre gradienti esponenzialmente piccoli. - Sperimentazione con la soppressione e la mitigazione degli errori : le primitive di
IBM Quantumoffrono un'interfaccia semplice per sperimentare con vari valori rispettivamente peroptimization_leveleresilience_setting. Ciò può ridurre l'impatto del rumore e rendere più efficiente il processo di ottimizzazione. - Sperimentazione di ottimizzatori senza gradiente : A differenza degli algoritmi di ottimizzazione basati sul gradiente, gli ottimizzatori come
COBYLAnon si basano sulle informazioni sul gradiente per ottimizzare i parametri e quindi hanno meno probabilità di essere influenzati dal plateau sterile.
Riepilogo
In questa lezione avete imparato a definire il vostro ciclo di ottimizzazione:
- Bootstrap di un ciclo di ottimizzazione
- Comprendere i compromessi nell'utilizzo di ottimizzatori locali e globali
- Esplorare gli altipiani sterili e come evitarli
Il nostro carico di lavoro variazionale di alto livello è completo:
Successivamente, esploreremo algoritmi variazionali specifici tenendo conto di questo quadro.