Kvantové variační obvody a kvantové neuronové sítě
V této lekci implementujeme několik variačních kvantových obvodů pro úlohu klasifikace dat – takzvaných variačních kvantových klasifikátorů (VQC). V určitém období bylo běžné označovat podmnožinu VQC jako kvantové neuronové sítě (QNN) podle analogie s klasickými neuronovými sítěmi. Existují skutečně případy, kdy struktury převzaté z klasických neuronových sítí, jako jsou konvoluční vrstvy, hrají ve VQC důležitou roli. V takových případech, kde je analogie silná, může být označení QNN užitečné. Parametrizované kvantové obvody však nemusí sledovat obecnou strukturu neuronové sítě – například ne všechna data musí být načtena v první (vstupní) vrstvě; můžeme načíst část dat v první vrstvě, aplikovat některé Gate a poté načíst další data (proces nazývaný „reuploading" dat). QNN bychom proto měli považovat za podmnožinu parametrizovaných kvantových obvodů a při hledání užitečných kvantových obvodů bychom se neměli omezovat analogií s klasickými neuronovými sítěmi.
Datová sada, se kterou v této lekci pracujeme, se skládá z obrazů obsahujících vodorovné a svislé pruhy. Naším cílem je zařadit dosud neviděné obrazy do jedné ze dvou kategorií podle orientace jejich čáry. Dosáhneme toho pomocí VQC. Postupně se budeme věnovat způsobům, jak výpočet zlepšit a škálovat. Tato datová sada je klasicky mimořádně snadno klasifikovatelná. Byla zvolena pro svou jednoduchost, abychom se mohli soustředit na kvantovou část problému a podívat se na to, jak se vlastnost datové sady může promítnout do části kvantového obvodu. U tak jednoduchých případů, kde jsou klasické algoritmy tak efektivní, nelze realisticky očekávat kvantové zrychlení.
Po skončení této lekce bys měl/a umět:
- Načíst data z obrazu do kvantového Circuit
- Sestavit Ansatz pro VQC (nebo QNN) a upravit ho podle svého problému
- Natrénovat svůj VQC/QNN a použít ho k přesným predikcím na testovacích datech
- Škálovat problém a rozpoznat limity současných kvantových počítačů
Generování dat
Začneme sestavením dat. Datové sady nejsou v rámci frameworku Qiskit patterns většinou explicitně generovány. Typ a příprava dat jsou však pro úspěšné použití kvantového výpočtu ve strojovém učení klíčové. Kód níže definuje datovou sadu obrazů s pevnými rozměry v pixelech. Celý jeden řádek nebo sloupec obrazu dostane hodnotu a zbývající pixely dostanou náhodné hodnoty na intervalu . Náhodné hodnoty představují šum v našich datech. Prohlédni si kód a ujisti se, že rozumíš způsobu generování obrazů. Později obrazy zvětšíme.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime scipy scikit-learn
# This code defines the images to be classified:
import numpy as np
# Total number of "pixels"/qubits
size = 8
# One dimension of the image (called vertical, but it doesn't matter). Must be a divisor of `size`
vert_size = 2
# The length of the line to be detected (yellow). Must be less than or equal to the smallest dimension of the image (`<=min(vert_size,size/vert_size)`
line_size = 2
def generate_dataset(num_images):
images = []
labels = []
hor_array = np.zeros((size - (line_size - 1) * vert_size, size))
ver_array = np.zeros((round(size / vert_size) * (vert_size - line_size + 1), size))
j = 0
for i in range(0, size - 1):
if i % (size / vert_size) <= (size / vert_size) - line_size:
for p in range(0, line_size):
hor_array[j][i + p] = np.pi / 2
j += 1
# Make two adjacent entries pi/2, then move down to the next row. Careful to avoid the "pixels" at size/vert_size - linesize, because we want to fold this list into a grid.
j = 0
for i in range(0, round(size / vert_size) * (vert_size - line_size + 1)):
for p in range(0, line_size):
ver_array[j][i + p * round(size / vert_size)] = np.pi / 2
j += 1
# Make entries pi/2, spaced by the length/rows, so that when folded, the entries appear on top of each other.
for n in range(num_images):
rng = np.random.randint(0, 2)
if rng == 0:
labels.append(-1)
random_image = np.random.randint(0, len(hor_array))
images.append(np.array(hor_array[random_image]))
elif rng == 1:
labels.append(1)
random_image = np.random.randint(0, len(ver_array))
images.append(np.array(ver_array[random_image]))
# Randomly select 0 or 1 for a horizontal or vertical array, assign the corresponding label.
# Create noise
for i in range(size):
if images[-1][i] == 0:
images[-1][i] = np.random.rand() * np.pi / 4
return images, labels
hor_size = round(size / vert_size)
Všimni si, že výše uvedený kód také vygeneroval štítky označující, zda obrazy obsahují svislou (+1) nebo vodorovnou (-1) čáru. Nyní použijeme sklearn k rozdělení datové sady 100 obrazů na trénovací a testovací sadu (spolu s odpovídajícími štítky). Zde používáme datové sady k trénování, přičemž zbývajících je vyhrazeno pro testování.
from sklearn.model_selection import train_test_split
np.random.seed(42)
images, labels = generate_dataset(200)
train_images, test_images, train_labels, test_labels = train_test_split(
images, labels, test_size=0.3, random_state=246
)
Vykresleme několik prvků naší datové sady, abychom viděli, jak tyto čáry vypadají:
import matplotlib.pyplot as plt
# Make subplot titles so we can identify categories
titles = []
for i in range(8):
title = "category: " + str(train_labels[i])
titles.append(title)
# Generate a figure with nested images using subplots.
fig, ax = plt.subplots(4, 2, figsize=(10, 6), subplot_kw={"xticks": [], "yticks": []})
for i in range(8):
ax[i // 2, i % 2].imshow(
train_images[i].reshape(vert_size, hor_size),
aspect="equal",
)
ax[i // 2, i % 2].set_title(titles[i])
plt.subplots_adjust(wspace=0.1, hspace=0.3)
Každý z těchto obrazů je stále spárován se svým štítkem v train_labels v jednoduché podobě seznamu:
print(train_labels[:8])
[1, 1, 1, 1, -1, 1, 1, 1]