Russian
Языки
English
Bengali
French
Hindi
Italian
Japanese
Korean
Malayalam
Russian
Spanish
Tamil
Turkish
Vietnamese
Shortcuts

Примечание

Страница создана на основе docs/tutorials/04_qgans_for_loading_random_distributions.ipynb.

qGANs для загрузки случайных распределений

Дана \(k\)-мерная выборки данных. Мы используем квантовую генеративное-состязательную сеть (quantum generative adversarial network), чтобы узнать данные, лежащие в основе случайного распределения и загрузить их непосредственно в квантовое состояние:

\[\big| g_{\theta}\rangle = \sum_{j=0}^{2^n-1} \sqrt{p_{\theta}^{j}}\big| j \rangle\]

где \(p_{\theta}^{j}\) описывает вероятности появления базовых состояний \(\big| j\rangle\).

Цель обучения qGAN — создать состояние \(\big| g_{\theta}\rangle\) где \(p_{\theta}^{j}\), для \(j\in \left\{0, \ldots, {2^n-1} \right\}\), и описать распределение вероятностей, которое близко к распределению, лежащему в основе данных обучения \(X=\left\{x^0, \ldots, x^{k-1} \right\}\).

Для получения дополнительной информации обратитесь к Quantum Generative Adversarial Networks for Learning and Loading Random Distributions Zoufal, Lucchi, Woerner [2019].

Для примера того, как использовать обученные qGAN в приложении, например, в ценообразовании финансовых дериватов, ознакомьтесь с руководством Ценообразование опционов с qGANs.

[1]:
import numpy as np
seed = 71
np.random.seed = seed

import matplotlib.pyplot as plt
%matplotlib inline

from qiskit import QuantumRegister, QuantumCircuit, BasicAer
from qiskit.circuit.library import TwoLocal, UniformDistribution

from qiskit.utils import QuantumInstance, algorithm_globals
from qiskit_machine_learning.algorithms import NumPyDiscriminator, QGAN

algorithm_globals.random_seed = seed

Загрузка данных для обучения

Сначала нам нужно загрузить \(k\)-мерные примеры данных для обучения (здесь k=1).

Далее задается разрешение данных, то есть минимальные/максимальные значения и количество кубитов, используемых для представления каждого измерения данных.

[2]:
# Number training data samples
N = 1000

# Load data samples from log-normal distribution with mean=1 and standard deviation=1
mu = 1
sigma = 1
real_data = np.random.lognormal(mean=mu, sigma=sigma, size=N)

# Set the data resolution
# Set upper and lower data values as list of k min/max data values [[min_0,max_0],...,[min_k-1,max_k-1]]
bounds = np.array([0., 3.])
# Set number of qubits per data dimension as list of k qubit values[#q_0,...,#q_k-1]
num_qubits = [2]
k = len(num_qubits)

Инициализация qGAN

qGAN состоит из квантового генератора \(G_{\theta}\), т.е. анзаца и классического дискриминатора \(D_{\phi}\) - нейросети.

Для реализации квантового генератора, мы выбираем анзац глубиной \(1\), который реализует повороты \(R_Y\) и \(CZ\) вентилей, принимающих однородное распределение в качестве входного состояния. В частности, для \(k>1\) параметры генератора должны быть тщательно отобраны. Например, глубина цепи должна быть \(>1\), потому что большая глубина цепи позволяет представить более сложные структуры.

Используемый здесь классический дискриминатор основан на внедрении нейронных сетей с использованием NumPy. Существует также дискриминатор на основе PyTorch, не установленный по умолчанию при установке Qiskit - см. Optional Install для получения дополнительной информации.

Здесь обе сети обновляются алгоритмом оптимизации ADAM (по умолчанию для qGAN).

[3]:
# Set number of training epochs
# Note: The algorithm's runtime can be shortened by reducing the number of training epochs.
num_epochs = 10
# Batch size
batch_size = 100

 # Initialize qGAN
qgan = QGAN(real_data, bounds, num_qubits, batch_size, num_epochs, snapshot_dir=None)
qgan.seed = 1
# Set quantum instance to run the quantum generator
quantum_instance = QuantumInstance(backend=BasicAer.get_backend('statevector_simulator'),
                                   seed_transpiler=seed, seed_simulator=seed)

# Set entangler map
entangler_map = [[0, 1]]


# Set an initial state for the generator circuit
init_dist = UniformDistribution(sum(num_qubits))

# Set the ansatz circuit
ansatz = TwoLocal(int(np.sum(num_qubits)), 'ry', 'cz', entanglement=entangler_map, reps=1)

# Set generator's initial parameters - in order to reduce the training time and hence the
# total running time for this notebook
init_params = [3., 1., 0.6, 1.6]

# You can increase the number of training epochs and use random initial parameters.
# init_params = np.random.rand(ansatz.num_parameters_settable) * 2 * np.pi

# Set generator circuit by adding the initial distribution infront of the ansatz
g_circuit = ansatz.compose(init_dist, front=True)

# Set quantum generator
qgan.set_generator(generator_circuit=g_circuit, generator_init_params=init_params)
# The parameters have an order issue that following is a temp. workaround
qgan._generator._free_parameters = sorted(g_circuit.parameters, key=lambda p: p.name)
# Set classical discriminator neural network
discriminator = NumPyDiscriminator(len(num_qubits))
qgan.set_discriminator(discriminator)

Запуск обучения qGAN

Во время обучения параметры дискриминатора и генератора обновляются поочередно в отношении функции потери:

\[L_G\left(\phi, \theta\right) = -\frac{1}{m}\sum\limits_{l=1}^{m}\left[\log\left(D_{\phi}\left(g^{l}\right)\right)\right]\]

и

\[L_D\left(\phi, \theta\right) = \frac{1}{m}\sum\limits_{l=1}^{m}\left[\log D_{\phi}\left(x^{l}\right) + \log\left(1-D_{\phi}\left(g^{l}\right)\right)\right],\]

где \(m\) означает размер пакета и \(g^l\) описывает выборки данных, сгенерированные квантовым генератором.

Пожалуйста, обратите внимание, что в данном блокноте обучение проводилось в кратчайшие сроки с выбором известной начальной точки (init_params). Без таких предварительных знаний обучение может занять большее время.

[4]:
# Run qGAN
result = qgan.run(quantum_instance)
[5]:
print('Training results:')
for key, value in result.items():
    print(f'  {key} : {value}')
Training results:
  params_d : [ 0.03697158  0.61015372 -0.48103428 ... -0.1661673  -0.20186384
 -0.08584337]
  params_g : [2.95229918 0.9522102  0.55218478 1.64793094]
  loss_d : 0.6925
  loss_g : [0.7246]
  rel_entr : 0.107

Прогресс обучения и результаты

Теперь мы определили эволюцию генератора и функцию потери дискриминатора во время обучения, а также прогресс в относительной энтропии между подготовленным и целевым распределением.

Наконец, мы также сравниваем совокупную функцию распределения (CDF) подготовленного распределения с CDF целевого распределения.

[6]:
# Plot progress w.r.t the generator's and the discriminator's loss function
t_steps = np.arange(num_epochs)
plt.figure(figsize=(6,5))
plt.title("Progress in the loss function")
plt.plot(t_steps, qgan.g_loss, label='Generator loss function', color='mediumvioletred', linewidth=2)
plt.plot(t_steps, qgan.d_loss, label='Discriminator loss function', color='rebeccapurple', linewidth=2)
plt.grid()
plt.legend(loc='best')
plt.xlabel('time steps')
plt.ylabel('loss')
plt.show()
../_images/tutorials_04_qgans_for_loading_random_distributions_10_0.png
[7]:
# Plot progress w.r.t relative entropy
plt.figure(figsize=(6,5))
plt.title('Relative Entropy')
plt.plot(np.linspace(0, num_epochs, len(qgan.rel_entr)), qgan.rel_entr, color='mediumblue', lw=4, ls=':')
plt.grid()
plt.xlabel('time steps')
plt.ylabel('relative entropy')
plt.show()
../_images/tutorials_04_qgans_for_loading_random_distributions_11_0.png
[8]:
#Plot the CDF of the resulting distribution against the target distribution, i.e. log-normal
log_normal = np.random.lognormal(mean=1, sigma=1, size=100000)
log_normal = np.round(log_normal)
log_normal = log_normal[log_normal <= bounds[1]]
temp = []
for i in range(int(bounds[1] + 1)):
    temp += [np.sum(log_normal==i)]
log_normal = np.array(temp / sum(temp))

plt.figure(figsize=(6,5))
plt.title('CDF (Cumulative Distribution Function)')
samples_g, prob_g = qgan.generator.get_output(qgan.quantum_instance, shots=10000)
samples_g = np.array(samples_g)
samples_g = samples_g.flatten()
num_bins = len(prob_g)
plt.bar(samples_g,  np.cumsum(prob_g), color='royalblue', width= 0.8, label='simulation')
plt.plot( np.cumsum(log_normal),'-o', label='log-normal', color='deepskyblue', linewidth=4, markersize=12)
plt.xticks(np.arange(min(samples_g), max(samples_g)+1, 1.0))
plt.grid()
plt.xlabel('x')
plt.ylabel('p(x)')
plt.legend(loc='best')
plt.show()
../_images/tutorials_04_qgans_for_loading_random_distributions_12_0.png
[9]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
QiskitNone
Terra0.17.0.dev0+346ffa8
Aer0.8.0
Ignis0.6.0.dev0+d6f1ad7
AquaNone
IBM Q Provider0.13.0.dev0+10f19e0
System information
Python3.8.8 (default, Feb 24 2021, 13:46:16) [Clang 10.0.0 ]
OSDarwin
CPUs6
Memory (Gb)16.0
Wed Mar 31 23:30:54 2021 CEST

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.