Qiskit Machine Learning v0.5 移行ガイド#

このチュートリアルでは、コードを Qiskit Machine Learning v0.4 から v0.5 へマイグレーションするプロセスをガイドします。

はじめに#

Qiskit Machine Learning のリリース0.5における主な焦点は、Qiskitで導入されたPrimitiveへの量子カーネルや量子ニューラルネットワークなどのベースの計算ブロックの移行と、アルゴリズムにおけるprimitiveの拡張サポートです。

目次:

  • Primitiveの概要

  • 新量子カーネル

  • 新量子ニューラル・ネットワーク

  • その他の注意すべき非推奨事項

Primitiveの概要#

量子コンピューターが古典コンピューターと異なる点は、出力に非古典的な確率分布を生成することができる点です。確率分布の基本的な操作は、確率分布からのサンプリングと確率分布に基づく量の推定です。このサンプリングと推定という操作が、量子アルゴリズム開発の基本的な構成要素となっています。そのため、 `こちら <https://research.ibm.com/blog/qiskit-runtime-for-useful-quantum-computing>`_で発表したように,この2つの操作を実装したSamplerとEstimatorという基本プリミティブが導入されました。

  • Samplerクラスは、量子回路のビット列の確率または準確率を計算します。基本クラスは qiskit.primitives.BaseSampler です。

  • Estimatorクラスは、量子回路や観測値の期待値を推定するクラスです。基本クラスは qiskit.primitives.BaseEstimator です。

Qiskit Terraはコアインターフェースと2つの実装を提供します:

  • 状態ベクトルベースのリファレンス実装です。この実装はバックエンドやシミュレーターを必要とせず、 quantum_info パッケージのクラスに依存しています。

  • バックエンドベースのprimitiveは、primitiveを直接サポートしないプロバイダー/バックエンドをサポートするためのものです。この実装では、primitiveに渡すバックエンドのインスタンスが必要です。

Qiskit Terra primitiveに関するより詳しい情報は documentation に記載されています。

他の実装についても触れておくとよいでしょう:

  • Aer primitiveは、Aerシミュレーターで使用されるものです。これらはTerraの対応するインターフェースを拡張したもので、Terraのprimitiveと同じように使用することができます。詳しくは documentation を参照してください。

  • IBMのデバイスで使用するためのRumtive primitiveです。実際のハードウェアでのクラウドコンピューティングに特化した実装です。`こちら __<https://qiskit.org/documentation/partners/qiskit_ibm_runtime/apidocs/runtime_service.html>``__を参照してください。

Terraはprimitiveとともに、QMLで非常に有用なprimitive的アルゴリズムを持っており、0.5の新機能で使用されています。

この2つのアルゴリズムは、コアprimitiveと非常によく似ており、同じメソッドシグネチャーを共有しているため、primitiveパッケージに含まれていないにもかかわらず、高レベルのprimitiveとして呼び出すことができます。

新量子カーネル#

以前の実装では、1つのクラス QuantumKernel がすべてを担っていました。

  • 回路の構築

  • 回路の実行と回路間の重なりの評価

  • 学習用パラメーターを提供

  • パラメーターに割り当てられた値の追跡

この実装は高度で柔軟性に欠け、新しいprimitiveのサポートを追加するのは困難でした。そこで、柔軟かつ拡張可能な新しい量子カーネルを開発しました。新しい設計の目標は以下の通りです。

  • Primitiveに移行し、Fidelity アルゴリズムを活用します。これにより、ユーザーは独自のFidelity 計算の実装をプラグインすることができます。

  • 訓練可能な機能を専用のクラスに抽出する。

  • 他のカーネルが拡張可能な基本クラスを導入する。

量子カーネルの新しい設計を次の図に示します。

量子カーネルダイアグラム

新しいカーネルは、 quantum_instance パラメーターを除いて、同じインターフェースと同じパラメーターを公開しています。このパラメーターは直接的に置き換えることができず、代わりにfidelityパラメーターを使用しなければなりません。バックエンドの処理・選択は、以前は``quantum_instance``を使用していましたが、現在は fidelity に与えられたSampler primitiveを介して処理されます。

図に示すような新しい階層が導入されます。

  • ベースとなる抽象クラス BaseKernel が導入されました。すべての具体的な実装は、このクラスを継承する必要があります。

  • Fidelity ベースの量子カーネル FidelityQuantumKernel が追加されました。これは、以前の量子カーネル実装をそのまま置き換えたものです。新しいクラスは、オーバーラップを推定し、カーネル行列を構築するために、Fidelity(忠実度)のインスタンスを取るという違いがあります。

  • また、量子カーネルを学習するための抽象クラス TrainableKernel が追加されました.

  • Fidelity ベースの量子カーネル TrainableFidelityQuantumKernel が導入されました.これは、従来の量子カーネルを 置き換える もので、訓練可能なカーネルが必要な場合に使用します。トレーナである QuantumKernelTrainer は,新型と旧型の両方の量子カーネルを受け入れることができるようになりました。

以前の量子カーネル実装である`QuantumKernel <https://qiskit.org/documentation/machine-learning/stubs/qiskit_machine_learning.kernels.QuantumKernel.html>`__ は,新しい抽象クラスを継承しており,新しく導入されたインターフェースと互換性を持っています.この実装は 現在 非推奨 であり,将来のリリースで非推奨となり,その後削除される予定です。新しいプリミティブベースの量子カーネルを使用する必要があります。

QSVCQSVR、その他のカーネルベースのアルゴリズムは更新され、両方の実装で動作するようになります。

例えば,QSVM分類器は以下のように学習させることができます。

データセットの準備#

ランダム性を固定します。

from qiskit.utils import algorithm_globals

algorithm_globals.random_seed = 123456

Scikit-learn を使用して簡単なデータセットを生成します。

from sklearn.datasets import make_blobs

features, labels = make_blobs(
    n_samples=20,
    centers=2,
    center_box=(-1, 1),
    cluster_std=0.1,
    random_state=algorithm_globals.random_seed,
)

量子カーネルの以前の実装#

前回の実装では、 QuantumInstance のインスタンスを作成するところから始めました。このクラスは、量子回路が実行される場所を定義します。今回は、量子インスタンスに状態ベクトルシミュレーターをラップしています。

from qiskit import BasicAer
from qiskit.utils import QuantumInstance

sv_qi = QuantumInstance(
    BasicAer.get_backend("statevector_simulator"),
    seed_simulator=algorithm_globals.random_seed,
    seed_transpiler=algorithm_globals.random_seed,
)

その後、量子カーネルを作ります。

from qiskit.circuit.library import ZZFeatureMap
from qiskit_machine_learning.kernels import QuantumKernel

feature_map = ZZFeatureMap(2)
previous_kernel = QuantumKernel(feature_map=feature_map, quantum_instance=sv_qi)

そして最終的にはSVM分類器に適合します。

from qiskit_machine_learning.algorithms import QSVC

qsvc = QSVC(quantum_kernel=previous_kernel)
qsvc.fit(features, labels)
qsvc.score(features, labels)
0.95

新しい量子カーネル実装#

新しい実装では、Fidelityのインスタンスを作成するところから始めます。Fidelityはオプションで、何も渡されない場合は量子カーネルが自動的に作成します。しかし、ここでは、説明のために手動で作成します。Fidelityのインスタンスを作成するために、Samplerを渡します。Samplerとは、量子回路を実行する際に参照する実装のことであり、量子回路が実行される場所を定義します。QiskitのRuntime serviceを活用するために、QiskitRuntimeService <https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.QiskitRuntimeService.html> からSampler インスタンスを作成することができます。

from qiskit.algorithms.state_fidelities import ComputeUncompute
from qiskit.primitives import Sampler

fidelity = ComputeUncompute(sampler=Sampler())

次に、fidelify (忠実度) インスタンスで新しい量子カーネルを作成します。

from qiskit_machine_learning.kernels import FidelityQuantumKernel

feature_map = ZZFeatureMap(2)
new_kernel = FidelityQuantumKernel(feature_map=feature_map, fidelity=fidelity)

そして、前と同じようにSVM分類器を当てはめます。

from qiskit_machine_learning.algorithms import QSVC

qsvc = QSVC(quantum_kernel=new_kernel)
qsvc.fit(features, labels)
qsvc.score(features, labels)
0.95

新量子ニューラル・ネットワーク#

量子ニューラルネットワークの変更は、量子カーネルほど劇的なものではありません。また、既存のニューラルネットワークを置き換えるものとして、2つの新しいネットワークが導入されています。 SamplerQNNEstimatorQNN で、既存の CircuitQNNOpflowQNNTwoLayerQNN を置き換えるもので、詳細は以下の通りです。

SamplerQNN#

新しい Sampler Quantum Neural Network は、sampler primitive、sampler Gradientsを活用し、 CircuitQNN直接置き換える ものです。

新しい SamplerQNN は既存の CircuitQNN と同様のインターフェイスを公開しますが、いくつかの違いがあります。1つは quantum_instance パラメーターです。このパラメーターは直接の置き換えがなく、代わりに sampler パラメーターを使用する必要があります。 gradient パラメーターは CircuitQNN の実装と同じ名前を保っていますが、入力としてOpflow gradientクラスを受け付けなくなりました。代わりに、このパラメーターは(オプションでカスタム)primitive gradientを期待します。 sampling option は、現在samplerが公開していない情報であり、将来の低レベルprimitiveに対応する可能性があるため、当面の間、削除されました。

CircuitQNN をベースとした VQC のような既存の学習アルゴリズムは、両方の実装を受け入れるように更新されました。 NeuralNetworkClassifier の実装は変更されていません。

既存の CircuitQNN は、現在 保留中の非推奨 となっており、将来のリリースで非推奨となり、その後削除される予定です。

ここでは、両ネットワークを用いた変分量子分類器の学習方法を紹介します。この目的のために、量子カーネルのために生成されたデータセットを再利用します。両者の量子ニューラルネットワークでは、特徴量マップ、ansatzを構築し、それらを1つの量子回路に結合する必要があります。

from qiskit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes

num_inputs = 2
feature_map = ZZFeatureMap(num_inputs)
ansatz = RealAmplitudes(num_inputs, reps=1)

circuit = QuantumCircuit(num_inputs)
circuit.compose(feature_map, inplace=True)
circuit.compose(ansatz, inplace=True)

同様に、解釈関数も必要です。ここでは、ビット列を:math:0 または \(1\) にマップする、通常のパリティ関数を定義します。

def parity(x):
    return "{:b}".format(x).count("1") % 2

両方のネットワークから同じ結果が得られるように、初期点を固定します。

initial_point = algorithm_globals.random.random(ansatz.num_parameters)

CircuitQNN を用いた分類器の構築#

CircuitQNN のインスタンスを作成し、量子カーネル用に作成した量子インスタンスを再利用します。

from qiskit_machine_learning.neural_networks import CircuitQNN

circuit_qnn = CircuitQNN(
    circuit=circuit,
    input_params=feature_map.parameters,
    weight_params=ansatz.parameters,
    interpret=parity,
    output_shape=2,
    quantum_instance=sv_qi,
)

ネットワークから分類器を構築し、それを訓練し、スコアをつけます。良い結果を目指しているわけではないので、全体の実行時間を短縮するために、反復回数は少なめに設定されています。

from qiskit.algorithms.optimizers import COBYLA
from qiskit_machine_learning.algorithms import NeuralNetworkClassifier

classifier = NeuralNetworkClassifier(
    neural_network=circuit_qnn,
    loss="cross_entropy",
    one_hot=True,
    optimizer=COBYLA(maxiter=40),
    initial_point=initial_point,
)
classifier.fit(features, labels)
classifier.score(features, labels)
0.6

SamplerQNN を用いた分類器の構築#

QuantumInstance の代わりに参照元 Sampler のインスタンスを作成します。

from qiskit.primitives import Sampler

sampler = Sampler()

ここで、 SamplerQNN のインスタンスを作成します。 CircuitQNN との違いは、量子インスタンスではなく、samplerを渡すことです。

from qiskit_machine_learning.neural_networks import SamplerQNN

sampler_qnn = SamplerQNN(
    circuit=circuit,
    input_params=feature_map.parameters,
    weight_params=ansatz.parameters,
    interpret=parity,
    output_shape=2,
    sampler=sampler,
)

通常通り分類器を構築し、フィットさせます。 neural_network として、作成した SamplerQNN を渡していますが、これだけの違いです。

classifier = NeuralNetworkClassifier(
    neural_network=sampler_qnn,
    loss="cross_entropy",
    one_hot=True,
    optimizer=COBYLA(maxiter=40),
    initial_point=initial_point,
)
classifier.fit(features, labels)
classifier.score(features, labels)
0.6

量子ニューラルネットワークを手動で構築する代わりに、 VQC をトレーニングすることができます。 VQC は、量子インスタンスとsamplerを受け取り、渡された内容に応じて、CircuitQNNSamplerQNN をそれぞれ自動的に構築します。

EstimatorQNN#

新しい Estimator quantum neural network は、Estimator primitive、Estimator gradientsを活用し、 OpflowQNN**直接置き換える ** ものです。

新しい EstimatorQNN は、既存の OpflowQNN と同様のインターフェースを公開しますが、いくつかの相違点があります。1つは quantum_instance パラメーターです。このパラメーターには直接的な代替がなく、代わりに estimator パラメーターを使用する必要があります。 gradient パラメーターは OpflowQNN の実装と同じ名前を持ちますが、入力としてOpflow gradientクラスを受け付けなくなりました。代わりに、このパラメーターは(オプションでカスタム)primitive gradientを期待するものです。

VQR のような TwoLayerQNN に基づく既存の学習アルゴリズムは、両方の実装を受け入れるように更新されます。 NeuralNetworkRegressor の実装は変更されていません。

既存の OpflowQNN は、現在 保留中の非推奨 となっており、将来のリリースで非推奨となり、その後削除される予定です。

両方のネットワークを用いた変分量子回帰の学習方法を紹介します。まず、単純な回帰データセットを生成するところから始めます。

import numpy as np

num_samples = 20
eps = 0.2
lb, ub = -np.pi, np.pi
features = (ub - lb) * np.random.rand(num_samples, 1) + lb
labels = np.sin(features[:, 0]) + eps * (2 * np.random.rand(num_samples) - 1)

まだ、量子ニューラルネットワークともに、特徴量マップ、ansatzを構築し、それらを組み合わせて一つの量子回路にする必要があります。

from qiskit.circuit import Parameter

num_inputs = 1
feature_map = QuantumCircuit(1)
feature_map.ry(Parameter("input"), 0)

ansatz = QuantumCircuit(1)
ansatz.ry(Parameter("weight"), 0)

circuit = QuantumCircuit(num_inputs)
circuit.compose(feature_map, inplace=True)
circuit.compose(ansatz, inplace=True)

両方のネットワークから同じ結果が得られるように、初期点を固定します。

initial_point = algorithm_globals.random.random(ansatz.num_parameters)

OpflowQNN を用いた回帰器の構築#

OpflowQNN のインスタンスを作成し、量子カーネル用に作成した量子インスタンスを再利用します。

from qiskit.opflow import PauliSumOp, StateFn
from qiskit_machine_learning.neural_networks import OpflowQNN

observable = PauliSumOp.from_list([("Z", 1)])
operator = StateFn(observable, is_measurement=True) @ StateFn(circuit)

opflow_qnn = OpflowQNN(
    operator=operator,
    input_params=feature_map.parameters,
    weight_params=ansatz.parameters,
    quantum_instance=sv_qi,
)

ネットワークから回帰器を構築し、それを訓練し、スコアをつけます。この場合、勾配ベースのオプティマイザーを使用するため、ネットワークは勾配の枠組みを利用し、データセットの性質上、非常に早く収束します。

from qiskit.algorithms.optimizers import L_BFGS_B
from qiskit_machine_learning.algorithms import NeuralNetworkRegressor

regressor = NeuralNetworkRegressor(
    neural_network=opflow_qnn,
    optimizer=L_BFGS_B(maxiter=5),
    initial_point=initial_point,
)
regressor.fit(features, labels)
regressor.score(features, labels)
0.9681198723451012

EstimatorQNN を用いた回帰器の構築#

リファレンスであるEstimatorのインスタンスを作成します。Qiskitのruntimeサービスを活用するため、`QiskitRuntimeService <https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.QiskitRuntimeService.html>`__からEstimatorのインスタンスを作成することもできます。

from qiskit.primitives import Estimator

estimator = Estimator()

ここで、EstimatorQNN のインスタンスを作成する。このネットワークは \(Z^{\otimes n}\) という観測量をします。ここで \(n\) は量子ビットの数です。

from qiskit_machine_learning.neural_networks import EstimatorQNN

estimator_qnn = EstimatorQNN(
    circuit=circuit,
    input_params=feature_map.parameters,
    weight_params=ansatz.parameters,
    estimator=estimator,
)

変量量子回帰器を構築し、それをフィッティングします。この場合、勾配ベースのオプティマイザーを使用するため、ネットワークは自動的に作成される default estimator gradient を使用します。

from qiskit.algorithms.optimizers import L_BFGS_B
from qiskit_machine_learning.algorithms import VQR

regressor = NeuralNetworkRegressor(
    neural_network=estimator_qnn,
    optimizer=L_BFGS_B(maxiter=5),
    initial_point=initial_point,
)
regressor.fit(features, labels)
regressor.score(features, labels)
0.9681198723451012

量子ニューラルネットワークを手動で構築する代わりに、 VQR をトレーニングすることができます。 VQR は、量子インスタンスとestimatorを受け取り、渡された内容に応じて、 TwoLayerQNNEstimatorQNN をそれぞれ自動的に構築します。

その他の注意すべき非推奨事項#

上記で明確に言及されていない他のいくつかのコンポーネントも、非推奨または非推奨保留となっています:

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
Thu Sep 14 13:57:31 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.