양자 커널 훈련
사용 예상 시간: Heron r3 프로세서에서 1분 미만 (참고: 이는 추정치이며, 실제 실행 시간은 다를 수 있습니다.)
학습 목표
-
커널 방법과 그 사용 사례
-
양자 커널, 그리고 양자 커널이 어떻게 향상된 특성 공간을 제공하는지
-
양자 커널 Circuit 구성
-
Qiskit 패턴을 사용한 양자 커널 훈련 방법: 매핑, 최적화, 실행 및 후처리
사전 요구 사항
-
양자 커널, 그 중요성, 그리고 실제 활용 방법
-
양자 커널과 서포트 벡터 머신 소개 (동영상)
-
실제 양자 커널 (동영상)
군론에 대한 기본적인 이해도 있으면 도움이 됩니다.
배경
커널 방법은 머신러닝 응용 분야에서 일반적으로 사용됩니다. 이 맥락에서 "커널"은 커널 행렬 또는 그 개별 항목을 의미합니다. 일반적으로 커널은 고차원 _특성 공간_에 인코딩된 데이터 간의 유사도 측정값으로, 예를 들어 서포트 벡터 머신을 사용한 분류 작업에 활용될 수 있습니다.
양자 커널 방법은 양자 컴퓨터를 사용하여 커널을 추정하는 방법입니다. 양자 컴퓨터가 데이터를 양자 강화 특성 공간에 인코딩할 수 있다는 것은 잘 알려져 있으며, 이를 통해 고전적인 유사 방법을 효과적으로 대체할 수 있습니다. 와 에 대해 (일반적으로 ), 는 특성 맵 입니다. 의 목표는 데이터 범주를 초평면으로 구분하는 것입니다. 특성 매핑된 공간의 벡터를 인수로 받아, 커널 함수 는 내적을 반환합니다: . 고전적으로는 커널 함수를 쉽게 평가할 수 있는 특성 맵, 즉 특성 매핑된 공간에서의 내적을 원래 데이터 벡터로 표현할 수 있고 와 를 직접 구성할 필요가 없는 경우가 관심 대상입니다. 양자 커널의 경우, 특성 매핑은 양자 Circuit을 통해 수행되며 커널은 Circuit에서 샘플링된 측정 확률을 사용하여 추정됩니다.
이 튜토리얼에서는 이진 분류에 사용되는 양자 커널 행렬의 항목을 평가하기 위한 Qiskit 패턴을 구축하는 방법을 설명합니다.
요구 사항
이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:
- Qiskit SDK v2.3.1 이상 (시각화 지원 포함)
- Qiskit Runtime v0.44.0 이상 (
pip install qiskit-ibm-runtime)
설정
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-runtime
# General Imports and helper functions
import urllib.request
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from qiskit.circuit import Parameter, ParameterVector, QuantumCircuit
from qiskit.circuit.library import unitary_overlap
from qiskit.primitives import StatevectorSampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
# Download the dataset (portable across platforms)
urllib.request.urlretrieve(
"https://raw.githubusercontent.com/qiskit-community/prototype-quantum-kernel-training/main/data/dataset_graph7.csv",
"dataset_graph7.csv",
)
def visualize_counts(res_counts, num_qubits, num_shots):
"""Visualize the outputs from the Qiskit Sampler primitive."""
zero_prob = res_counts.get(0, 0.0)
top_10 = dict(
sorted(res_counts.items(), key=lambda item: item[1], reverse=True)[
:10
]
)
top_10.update({0: zero_prob})
by_key = dict(sorted(top_10.items(), key=lambda item: item[0]))
x_vals, y_vals = list(zip(*by_key.items()))
x_vals = [bin(x_val)[2:].zfill(num_qubits) for x_val in x_vals]
y_vals_prob = []
for t in range(len(y_vals)):
y_vals_prob.append(y_vals[t] / num_shots)
y_vals = y_vals_prob
plt.bar(x_vals, y_vals)
plt.xticks(rotation=75)
plt.title("Results of sampling")
plt.xlabel("Measured bitstring")
plt.ylabel("Probability")
plt.show()
def get_training_data():
"""Read the training data."""
df = pd.read_csv("dataset_graph7.csv", sep=",", header=None)
training_data = df.values[:20, :]
ind = np.argsort(training_data[:, -1])
X_train = training_data[ind][:, :-1]
return X_train
소규모 시뮬레이터 예제
이 섹션에서는 "오류가 있는 코셋 레이블링" 문제의 7 qubit 인스턴스에 대한 Qiskit 패턴의 네 단계를 살펴보고, Qiskit의 StatevectorSampler 프리미티브를 사용하여 단일 커널 행렬 항목을 평가합니다. 상태 벡터 시뮬레이터는 샷 노이즈를 제외하면 정확하며 QPU 시간을 소비하지 않고 방법 전체를 보여줍니다. 이후 하드웨어 예제 섹션에서 실제 하드웨어로 동일한 인스턴스를 반복합니다.
1단계: 고전적 입력을 양자 문제로 변환
-
입력: 훈련 데이터셋.
-
출력: 커널 행렬 항목 계산을 위한 추상 Circuit.
여기서 해결하려는 이진 분류 문제는 "오류가 있는 코셋 레이블링"이라고 합니다. 입력 훈련 데이터셋에는 군과 부분군으로 형성된 두 코셋으로 구성된 군 구조가 포함되어 있습니다. 군은 Qubit에 대해 으로 취하며, 이는 행렬의 특수 유니타리 군으로 자연에서 광범위하게 적용됩니다. 예를 들어, 입자 물리학의 표준 모델이 있습니다. 간선 와 정점 를 갖는 그래프에 대해 인 (그래프 안정자) 부분군 를 취합니다. 안정자는 이 되도록 안정자 상태를 고정한다는 점에 유의하세요. 마지막으로, 두 를 무작위로 추출하여 두 좌잉여류 을 정의합니다.
데이터셋과 생성 방법에 대한 자세한 내용은 Quantum Kernel Training Toolkit의 이 노트북을 참조하세요.
커널 행렬의 한 항목을 평가하는 데 사용되는 양자 Circuit을 생성합니다.
입력 데이터를 사용하여 Circuit의 매개변수화된 게이트에 대한 회전 각도를 결정합니다.
간단히 하기 위해 데이터 샘플 x1=14와 x2=19를 사용하겠습니다.
참고: 이 튜토리얼에 사용된 데이터셋은 여기에서 다운로드할 수 있습니다.
# Prepare training data
X_train = get_training_data()
# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)
entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]
fm = QuantumCircuit(num_qubits)
training_param = Parameter("θ")
feature_params = ParameterVector("x", num_qubits * 2)
fm.ry(training_param, fm.qubits)
for cz in entangler_map:
fm.cz(cz[0], cz[1])
for i in range(num_qubits):
fm.rz(-2 * feature_params[2 * i + 1], i)
fm.rx(-2 * feature_params[2 * i], i)
# Assign tunable parameter to known optimal value and set the data params for
# first two samples
x1 = 14
x2 = 19
unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])
# Create the overlap circuit
overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
overlap_circ.draw("mpl", scale=0.6, style="iqp")
2단계: 양자 하드웨어 실행을 위한 문제 최적화
-
입력: 특정 Backend에 최적화되지 않은 추상 Circuit.
-
출력: 선택된 QPU에 최적화된 목표 Circuit.
이 섹션에서 사용하는 상태 벡터 시뮬레이터 경로의 경우, Backend별 최적화가 필요하지 않습니다: 추상 Circuit을 직접 샘플링할 수 있습니다. 이 단계는 아래의 하드웨어 예제에서 실행하며, 여기서는 optimization_level=3을 사용하는 generate_preset_pass_manager로 실제 QPU에 맞게 Circuit을 트랜스파일합니다.
3단계: Qiskit 프리미티브를 사용한 실행
-
입력: 추상 Circuit.
-
출력: 준확률 분포.
Qiskit의 StatevectorSampler 프리미티브를 사용하여 Circuit 샘플링으로부터 얻은 상태의 준확률 분포를 재구성합니다. 커널 행렬 생성 작업에서는 특히 |0> 상태를 측정할 확률에 관심이 있습니다.
sampler = StatevectorSampler()
# Execute and get counts
num_shots = 10_000
results = sampler.run([overlap_circ], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
# Plot counts
visualize_counts(counts, num_qubits, num_shots)
4단계: 후처리 및 원하는 고전적 형식으로 결과 반환
-
입력: 확률 분포.
-
출력: 단일 커널 행렬 요소.
오버랩 Circuit에서 을 측정할 확률을 계산한 뒤, 이 오버랩 Circuit이 나타내는 샘플에 해당하는 커널 행렬 위치(행 15, 열 20)에 그 값을 채웁니다.
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (simulator): {kernel_matrix[x1, x2]}")
Fidelity (simulator): 0.8261
하드웨어 예제
양자 커널 행렬은 개의 훈련 샘플에 대해 개의 항목을 가지며, 각 항목은 특성 맵의 크기에 따라 2 qubit 게이트 깊이가 증가하는 오버랩 Circuit을 실행해야 합니다. 따라서 이 튜토리얼을 더 큰 문제로 확장하면 두 가지 비용이 복합적으로 발생합니다: 커널 행렬당 QPU 시간이 에 따라 이차적으로 증가하고, unitary_overlap의 깊이(특성 맵과 그 수반 연산자를 합성함)가 현재 하드웨어의 시스템 크기 및 연결성에서 충실도를 저하시킵니다. 데모를 짧게 유지하고 깔끔한 비교를 위해, 소규모 예제에서와 동일한 7 qubit 인스턴스를 실제 QPU에서 실행하고 단일 커널 행렬 항목의 충실도를 위에서 계산한 시뮬레이터 값과 비교합니다.
# ------------------------------ Step 1 ------------------------------
# Prepare training data
X_train = get_training_data()
# Empty kernel matrix
num_samples = np.shape(X_train)[0]
kernel_matrix = np.full((num_samples, num_samples), np.nan)
# Prepare feature map for computing overlap
num_features = np.shape(X_train)[1]
num_qubits = int(num_features / 2)
entangler_map = [[0, 2], [3, 4], [2, 5], [1, 4], [2, 3], [4, 6]]
fm = QuantumCircuit(num_qubits)
training_param = Parameter("θ")
feature_params = ParameterVector("x", num_qubits * 2)
fm.ry(training_param, fm.qubits)
for cz in entangler_map:
fm.cz(cz[0], cz[1])
for i in range(num_qubits):
fm.rz(-2 * feature_params[2 * i + 1], i)
fm.rx(-2 * feature_params[2 * i], i)
# Assign tunable parameter to known optimal value and
# set the data params for first two samples
x1 = 14
x2 = 19
unitary1 = fm.assign_parameters(list(X_train[x1]) + [np.pi / 2])
unitary2 = fm.assign_parameters(list(X_train[x2]) + [np.pi / 2])
# Create the overlap circuit
overlap_circ = unitary_overlap(unitary1, unitary2)
overlap_circ.measure_all()
# ------------------------------ Step 2 ------------------------------
service = QiskitRuntimeService()
# backend = service.least_busy(
# operational=True, simulator=False, min_num_qubits=overlap_circ.num_qubits
# )
backend = service.backend("ibm_pittsburgh")
print(f"Using backend: {backend.name}")
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
overlap_ibm = pm.run(overlap_circ)
# ------------------------------ Step 3 ------------------------------
sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["TUT_QKT"]
num_shots = 10_000
results = sampler.run([overlap_ibm], shots=num_shots).result()
counts = results[0].data.meas.get_int_counts()
visualize_counts(counts, num_qubits, num_shots)
# ------------------------------ Step 4 ------------------------------
kernel_matrix[x1, x2] = counts.get(0, 0.0) / num_shots
print(f"Fidelity (hardware): {kernel_matrix[x1, x2]}")
Using backend: ibm_pittsburgh
Fidelity (hardware): 0.7517
전체 커널 행렬을 채우려면 개의 고유 항목 각각에 대해 양자 실험을 실행해야 합니다. 아래 그림은 이 데이터셋에 대한 결과 행렬을 보여줍니다; 더 진한 빨간색은 1.0에 가까운 충실도를 나타냅니다.
다음 단계
이 작업이 흥미로우셨다면 다음 자료도 살펴보세요:
-
Quantum Kernel Training Toolkit - 이 튜토리얼의 기반이 된 프로토타입 저장소
-
Quantum Kernel Training for Machine Learning Applications - 훈련 가능한 매개변수 훈련 방법을 보여주는 Qiskit Machine Learning 튜토리얼
-
양자 머신러닝 소개 - 양자 머신러닝 과정
-
IBM Research의 양자 머신러닝 - IBM의 QML 연구 개요
-
군 구조를 가진 데이터를 위한 공변 양자 커널 - 이 튜토리얼의 기반이 된 논문