Плато для естественного градиента
Возникают ли у естественных градиентов «бесплодные плато» — области, где градиенты экспоненциально малы и обучение затрудняется? Попробуйте в IBM Quantum Lab построить приведённый график для естественных градиентов вместо обычных. Нужно написать новую функцию sample_natural_gradients, вычисляющую естественный градиент вместо градиента.
В исходном опыте используется RealAmplitudes с линейными связями, от 2 до 12 кубитов и числом повторений, равным числу кубитов. Глобальный оператор — $Z^{\otimes n}$. Для каждой схемы sample_gradients берёт 100 независимых наборов параметров из $[0,\pi]$, оценивает производную по параметру с индексом n−1 и возвращает выборку. Строится дисперсия этих производных в зависимости от n и экспоненциальная аппроксимация. На рисунках сохранены исходная схема и исходный график обычного градиента.
Ниже исходные определения и образцы Gradient/NaturalGradient, необходимые для изменения функции. Два print в исходном образце evaluate_natural_gradient относятся к включённой двухкубитной демонстрации: сам опыт здесь задаётся sample_gradients и циклом в конце.
import numpy as np
import matplotlib.pyplot as plt
from qiskit.opflow import Gradient
from qiskit.circuit.library import RealAmplitudes
ansatz = RealAmplitudes(num_qubits=2, reps=1,
entanglement='linear').decompose()
ansatz.draw()
from qiskit.opflow import Z, I
hamiltonian = Z ^ Z
from qiskit.opflow import StateFn, PauliExpectation
expectation = StateFn(hamiltonian, is_measurement=True) @ StateFn(ansatz)
pauli_basis = PauliExpectation().convert(expectation)
from qiskit import Aer
from qiskit.utils import QuantumInstance
from qiskit.opflow import PauliExpectation, CircuitSampler
quantum_instance = QuantumInstance(Aer.get_backend('qasm_simulator'),
# we'll set a seed for reproducibility
shots = 8192, seed_simulator = 2718,
seed_transpiler = 2718)
sampler = CircuitSampler(quantum_instance)
def evaluate_expectation(theta):
# pylint: disable=missing-function-docstring
value_dict = dict(zip(ansatz.parameters, theta))
result = sampler.convert(pauli_basis, params=value_dict).eval()
return np.real(result)
# initial_point = np.random.random(ansatz.num_parameters)
initial_point = np.array([0.43253681, 0.09507794, 0.42805949, 0.34210341])
gradient = Gradient().convert(expectation)
gradient_in_pauli_basis = PauliExpectation().convert(gradient)
sampler = CircuitSampler(quantum_instance)
def evaluate_gradient(theta):
# pylint: disable=missing-function-docstring
value_dict = dict(zip(ansatz.parameters, theta))
result = sampler.convert(gradient_in_pauli_basis,
params=value_dict).eval()
return np.real(result)
from qiskit.opflow import NaturalGradient
natural_gradient = (NaturalGradient(regularization='ridge')
.convert(expectation))
natural_gradient_in_pauli_basis = PauliExpectation().convert(
natural_gradient)
sampler = CircuitSampler(quantum_instance, caching="all")
def evaluate_natural_gradient(theta):
# pylint: disable=missing-function-docstring
value_dict = dict(zip(ansatz.parameters, theta))
result = sampler.convert(natural_gradient, params=value_dict).eval()
return np.real(result)
print('Vanilla gradient:', evaluate_gradient(initial_point))
print('Natural gradient:', evaluate_natural_gradient(initial_point))
from qiskit.opflow import I
def sample_gradients(num_qubits, reps, local=False):
"""Sample the gradient of our model for ``num_qubits`` qubits and
``reps`` repetitions.
We sample 100 times for random parameters and compute the gradient
of the first RY rotation gate.
"""
index = num_qubits - 1
# local or global operator
if local:
operator = Z ^ Z ^ (I ^ (num_qubits - 2))
else:
operator = Z ^ num_qubits
# real amplitudes ansatz
ansatz = RealAmplitudes(num_qubits, entanglement='linear', reps=reps)
# construct Gradient we want to evaluate for different values
expectation = StateFn(operator,
is_measurement=True).compose(StateFn(ansatz))
grad = Gradient().convert(expectation,
params=ansatz.parameters[index])
# evaluate for 100 different, random parameter values
num_points = 100
grads = []
for _ in range(num_points):
# points are uniformly chosen from [0, pi]
point = np.random.uniform(0, np.pi, ansatz.num_parameters)
value_dict = dict(zip(ansatz.parameters, point))
grads.append(sampler.convert(grad, value_dict).eval())
return grads
num_qubits = list(range(2, 13))
reps = num_qubits # number of layers = numbers of qubits
gradients = [sample_gradients(n, r) for n, r in zip(num_qubits, reps)]
fit = np.polyfit(num_qubits, np.log(np.var(gradients, axis=1)), deg=1)
x = np.linspace(num_qubits[0], num_qubits[-1], 200)
plt.figure(figsize=(7, 3))
plt.semilogy(num_qubits,
np.var(gradients, axis=1),
'o-',
label='measured variance')
plt.semilogy(x,
np.exp(fit[0] * x + fit[1]),
'--', c='C3',
label=f'exponential fit w/ {fit[0]:.2f}')
plt.xlabel('number of qubits')
plt.ylabel(r'$\mathrm{Var}[\partial_{\theta 1}\langle E(\theta)\rangle]$')
plt.legend(loc='best');
Решения пока нет.
Сообщить об ошибке
Войти, чтобы отправить материал.