注釈

このページは docs/tutorials/08_quantum_kernel_trainer.ipynb から生成されました。

機械学習アプリケーション向けの量子カーネルトレーニング#

このチュートリアルでは、機械学習アプリケーション用のラベル付きデータセットで量子カーネルをトレーニングします。基本的な手順を説明するために、二値分類タスクに Quantum Kernel Alignment(QKA)を使用します。QKAは、最大SVMマージンに収束しながら、パラメーター化された量子カーネルをデータセットに繰り返し適応させる手法です。QKAの詳細については、プレプリントの “Covariant quantum kernels for data with group structure” を参照してください。

量子カーネルをトレーニングするためのエントリポイントは、 QuantumKernelTrainer クラスです。基本的な手順は次のとおりです。

  1. データセットを準備する

  2. 量子特徴マップを定義する

  3. TrainableKernel インスタンスと QuantumKernelTrainer オブジェクトを設定する

  4. QuantumKernelTrainer.fit メソッドを使用して、データセットのカーネルパラメーターをトレーニングする

  5. トレーニングされた量子カーネルを機械学習モデルに渡す

ローカル、外部、Qiskitパッケージをインポートし、オプティマイザーのコールバッククラスを定義する#

[1]:
# External imports
from pylab import cm
from sklearn import metrics
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# Qiskit imports
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.visualization import circuit_drawer
from qiskit.circuit.library import ZZFeatureMap
from qiskit_algorithms.optimizers import SPSA
from qiskit_machine_learning.kernels import TrainableFidelityQuantumKernel
from qiskit_machine_learning.kernels.algorithms import QuantumKernelTrainer
from qiskit_machine_learning.algorithms import QSVC
from qiskit_machine_learning.datasets import ad_hoc_data


class QKTCallback:
    """Callback wrapper class."""

    def __init__(self) -> None:
        self._data = [[] for i in range(5)]

    def callback(self, x0, x1=None, x2=None, x3=None, x4=None):
        """
        Args:
            x0: number of function evaluations
            x1: the parameters
            x2: the function value
            x3: the stepsize
            x4: whether the step was accepted
        """
        self._data[0].append(x0)
        self._data[1].append(x1)
        self._data[2].append(x2)
        self._data[3].append(x3)
        self._data[4].append(x4)

    def get_callback_data(self):
        return self._data

    def clear_callback_data(self):
        self._data = [[] for i in range(5)]

データセットを準備する#

このガイドでは、Qiskit Machine Learning の ad_hoc.py データセットを使用して、カーネルトレーニングプロセスを示します。 こちら のドキュメントを参照してください。

[2]:
adhoc_dimension = 2
X_train, y_train, X_test, y_test, adhoc_total = ad_hoc_data(
    training_size=20,
    test_size=5,
    n=adhoc_dimension,
    gap=0.3,
    plot_data=False,
    one_hot=False,
    include_sample_total=True,
)

plt.figure(figsize=(5, 5))
plt.ylim(0, 2 * np.pi)
plt.xlim(0, 2 * np.pi)
plt.imshow(
    np.asmatrix(adhoc_total).T,
    interpolation="nearest",
    origin="lower",
    cmap="RdBu",
    extent=[0, 2 * np.pi, 0, 2 * np.pi],
)

plt.scatter(
    X_train[np.where(y_train[:] == 0), 0],
    X_train[np.where(y_train[:] == 0), 1],
    marker="s",
    facecolors="w",
    edgecolors="b",
    label="A train",
)
plt.scatter(
    X_train[np.where(y_train[:] == 1), 0],
    X_train[np.where(y_train[:] == 1), 1],
    marker="o",
    facecolors="w",
    edgecolors="r",
    label="B train",
)
plt.scatter(
    X_test[np.where(y_test[:] == 0), 0],
    X_test[np.where(y_test[:] == 0), 1],
    marker="s",
    facecolors="b",
    edgecolors="w",
    label="A test",
)
plt.scatter(
    X_test[np.where(y_test[:] == 1), 0],
    X_test[np.where(y_test[:] == 1), 1],
    marker="o",
    facecolors="r",
    edgecolors="w",
    label="B test",
)

plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0.0)
plt.title("Ad hoc dataset for classification")

plt.show()
../_images/tutorials_08_quantum_kernel_trainer_4_0.png

量子特徴マップを定義する#

次に、古典的なデータを量子状態空間にエンコードする量子特徴マップを設定します。ここでは、 QuantumCircuit を使用してトレーニング可能な回転レイヤーを設定し、 QiskitZZFeatureMap を使用して入力データを表します。

[3]:
# Create a rotational layer to train. We will rotate each qubit the same amount.
training_params = ParameterVector("θ", 1)
fm0 = QuantumCircuit(2)
fm0.ry(training_params[0], 0)
fm0.ry(training_params[0], 1)

# Use ZZFeatureMap to represent input data
fm1 = ZZFeatureMap(2)

# Create the feature map, composed of our two circuits
fm = fm0.compose(fm1)

print(circuit_drawer(fm))
print(f"Trainable parameters: {training_params}")
     ┌──────────┐┌──────────────────────────┐
q_0: ┤ Ry(θ[0]) ├┤0                         ├
     ├──────────┤│  ZZFeatureMap(x[0],x[1]) │
q_1: ┤ Ry(θ[0]) ├┤1                         ├
     └──────────┘└──────────────────────────┘
Trainable parameters: θ, ['θ[0]']

量子カーネルと量子カーネルトレーナーを設定する#

量子カーネルをトレーニングするには、 TrainableFidelityQuantumKernel (特徴マップとそのパラメーターを保持)と QuantumKernelTrainer (トレーニングプロセスを管理)が必要です。

QuantumKernelTrainer への入力としてカーネル損失関数 SVCLoss を選択することにより、Quantum Kernel Alignment 手法を使用してトレーニングします。これはQiskitでサポートされている損失であるため、文字列 svc_loss を使用できます。ただし、損失を文字列として渡す場合は、デフォルト設定が使用されることに注意してください。カスタム設定の場合は、必要なオプションを使用して明示的にインスタンス化し、 KernelLoss オブジェクトを QuantumKernelTrainer に渡します。

オプティマイザーとして SPSA を選択し、 initial_point 引数を使用してトレーニング可能なパラメーターを初期化します。注: initial_point 引数として渡されるリストの長さは、特徴量マップ内のトレーニング可能なパラメーターの数と等しくなければなりません。

[4]:
# Instantiate quantum kernel
quant_kernel = TrainableFidelityQuantumKernel(feature_map=fm, training_parameters=training_params)

# Set up the optimizer
cb_qkt = QKTCallback()
spsa_opt = SPSA(maxiter=10, callback=cb_qkt.callback, learning_rate=0.05, perturbation=0.05)

# Instantiate a quantum kernel trainer.
qkt = QuantumKernelTrainer(
    quantum_kernel=quant_kernel, loss="svc_loss", optimizer=spsa_opt, initial_point=[np.pi / 2]
)

量子カーネルをトレーニングする#

データセット(サンプルとラベル)で量子カーネルをトレーニングするために、 QuantumKernelTrainerfit メソッドを呼び出します。

QuantumKernelTrainer.fit の出力は QuantumKernelTrainerResult オブジェクトです。結果オブジェクトには次のクラスフィールドが含まれています。

  • optimal_parameters: {parameter: optimal value} のペアを含む辞書

  • optimal_point: 学習により見つけた最適なパラメーター値

  • optimal_value: 最適な点での損失関数の値

  • optimizer_evals: オプティマイザーによって実行される評価の数

  • optimizer_time: 最適化を実行するのにかかった時間

  • quantum_kernel: フィーチャーマップにバインドされた最適な値を持つ TrainableKernel オブジェクト

[5]:
# Train the kernel using QKT directly
qka_results = qkt.fit(X_train, y_train)
optimized_kernel = qka_results.quantum_kernel
print(qka_results)
{   'optimal_circuit': None,
    'optimal_parameters': {ParameterVectorElement(θ[0]): 2.4745458584261386},
    'optimal_point': array([2.47454586]),
    'optimal_value': 7.399057680986741,
    'optimizer_evals': 30,
    'optimizer_result': None,
    'optimizer_time': None,
    'quantum_kernel': <qiskit_machine_learning.kernels.trainable_fidelity_quantum_kernel.TrainableFidelityQuantumKernel object at 0x7f84c120feb0>}

モデルの適合とテスト#

トレーニングされた量子カーネルを機械学習モデルに渡し、モデルを適合させて新しいデータでテストすることができます。ここでは、分類に Qiskit Machine Learning の QSVC を使用します。

[6]:
# Use QSVC for classification
qsvc = QSVC(quantum_kernel=optimized_kernel)

# Fit the QSVC
qsvc.fit(X_train, y_train)

# Predict the labels
labels_test = qsvc.predict(X_test)

# Evalaute the test accuracy
accuracy_test = metrics.balanced_accuracy_score(y_true=y_test, y_pred=labels_test)
print(f"accuracy test: {accuracy_test}")
accuracy test: 0.9

カーネルトレーニングプロセスを視覚化する#

コールバックデータから、トレーニングプロセス中に損失がどのように変化するかをプロットできます。入力を選択すると、急速に収束し、このデータセットで高いテスト精度に達することがわかります。

トレーニングサンプル間の類似性の尺度である最終的なカーネル行列を表示することもできます。

[7]:
plot_data = cb_qkt.get_callback_data()  # callback data
K = optimized_kernel.evaluate(X_train)  # kernel matrix evaluated on the training samples

plt.rcParams["font.size"] = 20
fig, ax = plt.subplots(1, 2, figsize=(14, 5))
ax[0].plot([i + 1 for i in range(len(plot_data[0]))], np.array(plot_data[2]), c="k", marker="o")
ax[0].set_xlabel("Iterations")
ax[0].set_ylabel("Loss")
ax[1].imshow(K, cmap=matplotlib.colormaps["bwr"])
fig.tight_layout()
plt.show()
../_images/tutorials_08_quantum_kernel_trainer_14_0.png
[8]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.25.0
qiskit-aer0.13.0
qiskit-machine-learning0.7.0
System information
Python version3.8.13
Python compilerClang 12.0.0
Python builddefault, Oct 19 2022 17:54:22
OSDarwin
CPUs10
Memory (Gb)64.0
Mon May 29 12:50:08 2023 IST

This code is a part of Qiskit

© Copyright IBM 2017, 2023.

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.