注釈

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

実際のデータセットでの量子モデルの学習#

このチュートリアルでは、分類問題に取り組むために、量子機械学習モデルをどのように学習させるかを説明します。これまでのチュートリアルでは、小規模で人工的なデータセットを取り上げてきました。今回は、現実の古典的なデータセットを用いて、問題の複雑性を高めることにします。我々は、非常に有名ですが、まだ比較的小さな問題であるアイリスの花のデータセットを選ぶことにしました。このデータセットにはWikipediaの ページ があるくらいです。アイリスデータセットはデータサイエンティストにはよく知られていますが、記憶を呼び覚ますために簡単に紹介します。比較のために、まず量子モデルに対応する古典的なモデルを学習します。

では、さっそく始めましょう:

  • まず、データセットをロードし、それがどのように見えるかを探ります。

  • 次に、scikit-learnSVC を使って古典的なモデルを学習し、古典的な手法で分類問題がどの程度解決できるかを見てみましょう。

  • その後、Variational Quantum Classifier(VQC) を紹介します。

  • 最後に、両方のモデルから得られた結果を比較します。

1. データ分析の探索#

まず、このチュートリアルで使用するアイリスのデータセットを調べて、何が含まれているかを見てみましょう。便宜上、この データセット は scikit-learn で利用可能で、簡単にロードすることができます。

[2]:
from sklearn.datasets import load_iris

iris_data = load_iris()

load_iris 関数でパラメーターを指定しなかった場合、辞書のようなオブジェクトが scikit-learn によって返されます。データセットの記述を出力して、中身を見てみましょう。

[3]:
print(iris_data.DESCR)
.. _iris_dataset:

Iris plants dataset
--------------------

**Data Set Characteristics:**

    :Number of Instances: 150 (50 in each of three classes)
    :Number of Attributes: 4 numeric, predictive attributes and the class
    :Attribute Information:
        - sepal length in cm
        - sepal width in cm
        - petal length in cm
        - petal width in cm
        - class:
                - Iris-Setosa
                - Iris-Versicolour
                - Iris-Virginica

    :Summary Statistics:

    ============== ==== ==== ======= ===== ====================
                    Min  Max   Mean    SD   Class Correlation
    ============== ==== ==== ======= ===== ====================
    sepal length:   4.3  7.9   5.84   0.83    0.7826
    sepal width:    2.0  4.4   3.05   0.43   -0.4194
    petal length:   1.0  6.9   3.76   1.76    0.9490  (high!)
    petal width:    0.1  2.5   1.20   0.76    0.9565  (high!)
    ============== ==== ==== ======= ===== ====================

    :Missing Attribute Values: None
    :Class Distribution: 33.3% for each of 3 classes.
    :Creator: R.A. Fisher
    :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
    :Date: July, 1988

The famous Iris database, first used by Sir R.A. Fisher. The dataset is taken
from Fisher's paper. Note that it's the same as in R, but not as in the UCI
Machine Learning Repository, which has two wrong data points.

This is perhaps the best known database to be found in the
pattern recognition literature.  Fisher's paper is a classic in the field and
is referenced frequently to this day.  (See Duda & Hart, for example.)  The
data set contains 3 classes of 50 instances each, where each class refers to a
type of iris plant.  One class is linearly separable from the other 2; the
latter are NOT linearly separable from each other.

.. topic:: References

   - Fisher, R.A. "The use of multiple measurements in taxonomic problems"
     Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions to
     Mathematical Statistics" (John Wiley, NY, 1950).
   - Duda, R.O., & Hart, P.E. (1973) Pattern Classification and Scene Analysis.
     (Q327.D83) John Wiley & Sons.  ISBN 0-471-22361-1.  See page 218.
   - Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System
     Structure and Classification Rule for Recognition in Partially Exposed
     Environments".  IEEE Transactions on Pattern Analysis and Machine
     Intelligence, Vol. PAMI-2, No. 1, 67-71.
   - Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule".  IEEE Transactions
     on Information Theory, May 1972, 431-433.
   - See also: 1988 MLC Proceedings, 54-64.  Cheeseman et al"s AUTOCLASS II
     conceptual clustering system finds 3 classes in the data.
   - Many, many more ...

このデータセットの説明から、いくつかの興味深い点を見出すことができます。

  • データセットには150のサンプル(インスタンス) があります。

  • 各サンプルには4つの特徴量 (属性) があります。

  • データセットには3つのラベル(クラス) があります。

  • 各クラスに同じ数のサンプル(50) があるため、データセットは完全にバランスが取れています。

  • 例えば、がくの長さ(sepal width)は \([4.3, 7.9]\) 、花弁の幅(petal width)は \([0.1, 2.5]\) というように、特徴量が正規化されておらず、値の範囲も異なっていることが分かります。そこで、特徴量を同じスケールに変換することが有効な場合があります。

  • 上の表にあるように、いくつかのケースでは特徴量とクラスの相関が非常に高く、このことから、我々のモデルはデータセットにうまく対応できるはずだと思われるかもしれません。

今回はデータセットの説明だけを調べましたが、 iris_data オブジェクトにはその他のプロパティも用意されています。それでは、データセットに含まれる特徴量とラベルを操作してみましょう。

[4]:
features = iris_data.data
labels = iris_data.target

まず、特徴量を正規化します。つまり、すべての特徴量を同じ尺度で表現するために、簡単な変換を行います。この例では、すべての特徴量を区間 \([0, 1]\) に絞り込みます。正規化は機械学習において一般的な手法であり、しばしばアルゴリズムの数値的安定性や収束性を向上させることにつながります。

Scikit-learn の MinMaxScaler を使用して、この処理を行うことができます。これはパラメーターを指定せずに、必要なことだけを行うもので、データを \([0, 1]\) にマップします。

[5]:
from sklearn.preprocessing import MinMaxScaler

features = MinMaxScaler().fit_transform(features)

では、データがどのように見えるか見てみましょう。特徴量を対にしてプロットし、それらの間に観測可能な相関があるかどうかを確認します。

[6]:
import pandas as pd
import seaborn as sns

df = pd.DataFrame(iris_data.data, columns=iris_data.feature_names)
df["class"] = pd.Series(iris_data.target)

sns.pairplot(df, hue="class", palette="tab10")
[6]:
<seaborn.axisgrid.PairGrid at 0x1c92dbc4188>
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_9_1.png

プロットから、クラス 0 と他の2つのクラスは容易に分離可能であることがわかりますが、クラス 12 は、特に「がくの幅(sepal width)」の特徴に関して、時々絡み合っていることがわかります。

次に、古典的な機械学習がこのデータセットをどのように扱うか見てみましょう。

2. 古典的な機械学習モデルの学習#

モデルを学習する前に、データセットをトレーニングデータセットとテストデータセットの2つに分ける必要があります。前者はモデルの学習に、後者は未知のデータに対してモデルがどの程度の性能を発揮するかを検証するために使います。

いつものように、退屈な仕事はscikit-learnにお願いすることにします。また、結果が再現できるようにseedを固定します。

[7]:
from sklearn.model_selection import train_test_split
from qiskit_algorithms.utils import algorithm_globals

algorithm_globals.random_seed = 123
train_features, test_features, train_labels, test_labels = train_test_split(
    features, labels, train_size=0.8, random_state=algorithm_globals.random_seed
)

Scikit-learnの古典的なサポートベクター分類器を学習させます。簡単のため、パラメーターはいじらず、デフォルトの値を使用します。

[8]:
from sklearn.svm import SVC

svc = SVC()
_ = svc.fit(train_features, train_labels)  # suppress printing the return value

ここで、我々の古典的なモデルがどの程度のパフォーマンスを示すかを確認します。結論の部分でそのスコアを分析します。

[9]:
train_score_c4 = svc.score(train_features, train_labels)
test_score_c4 = svc.score(test_features, test_labels)

print(f"Classical SVC on the training dataset: {train_score_c4:.2f}")
print(f"Classical SVC on the test dataset:     {test_score_c4:.2f}")
Classical SVC on the training dataset: 0.99
Classical SVC on the test dataset:     0.97

スコアからわかるように、古典的なSVCアルゴリズムは非常に良いパフォーマンスを見せています。次は、量子機械学習モデルについてです。

2. 量子機械学習モデルの学習#

量子モデルの例として、変分量子分類器(VQC) を学習します。VQCは Qiskit Machine Learning で利用できる最もシンプルな分類器であり、古典的な機械学習のバックグラウンドを持つ量子機械学習初心者に適した出発点です。

しかし、モデルを学習する前に、VQC クラスを構成するものを調べてみましょう。その中心的な要素は特徴量マップとansatzです。これらが何かを説明します。

私たちのデータは古典的なもので、量子ビットではなくビットの集合で構成されています。データを量子ビットとして符号化する方法が必要なのです。このプロセスは、有効な量子モデルを得るために非常に重要です。我々は通常、このマッピングをデータエンコーディング、データエンベッディング、データローディングと呼び、これが特徴量マップの役割となります。特徴量マップは一般的なMLメカニズムですが、この量子状態へのデータロードのプロセスは、古典的な世界でのみ作用するため、古典的な機械学習には登場しません。

データを読み込んだら、すぐにパラメーター化された量子回路を適用しなければなりません。この回路は、古典的なニューラルネットワークの層と直接的に類似しています。この回路は、調整可能なパラメーター(重み)を持っています。重みは、ある目的関数を最小化するように最適化されます。この目的関数は、予測値と既知のラベル付けされたデータとの距離を特徴づけます。パラメーター化された量子回路は、パラメーター化された試行状態、変分形式、ansatzとも呼ばれます。おそらく、後者が最も広く用いられている用語でしょう。

詳しくは、 量子機械学習のコース をご覧ください。

ここでは ZZFeatureMap を使用することにします。 ZZFeatureMap はQiskitのcircuit ライブラリーに含まれる標準的な特徴量マップの一つです。 num_featuresfeature_dimension として渡すと、特徴量マップは num_features または 4 個の量子ビットを持つことになります。

特徴量マップをゲートに分解し、特徴量マップがどのように見えるかを伝えます。

[10]:
from qiskit.circuit.library import ZZFeatureMap

num_features = features.shape[1]

feature_map = ZZFeatureMap(feature_dimension=num_features, reps=1)
feature_map.decompose().draw(output="mpl", fold=20)
[10]:
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_17_0.png

特徴量ダイアグラムをよく見ると、パラメーター x[0], ..., x[3] が見えます。これらは、特徴量のプレースホルダーです。

Ansatzを作成してプロットします。Ansatz回路の反復構造に注意してください。 これらの繰り返しの数は reps パラメーターを使用して定義します。

[11]:
from qiskit.circuit.library import RealAmplitudes

ansatz = RealAmplitudes(num_qubits=num_features, reps=3)
ansatz.decompose().draw(output="mpl", fold=20)
[11]:
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_19_0.png

この回路には16個のパラメーターがあり、そのパラメーターには θ[0], ..., θ[15] があります。これらは分類器の訓練可能な重みです。

次に、学習プロセスで使用する最適化アルゴリズムを選択します。このステップは、古典的な深層学習フレームワークで見られるものと似ています。学習プロセスを高速化するために、勾配なしオプティマイザーを選択します。Qiskitで利用可能な他のオプティマイザーを探索することもできます。

[12]:
from qiskit_algorithms.optimizers import COBYLA

optimizer = COBYLA(maxiter=100)

次のステップでは、分類器をどこで学習させるかを定義します。学習にはシミュレーターと実物の量子コンピューターがあります。ここでは、シミュレーターを使用します。 Sampler primitiveのインスタンスを作成します。これは状態ベクトルベースのリファレンス実装です。qiskitのruntimeサービスを使用すると、量子コンピューターを使ったsamplerを作成することができます。

[13]:
from qiskit.primitives import Sampler

sampler = Sampler()

ここでは、callback_graph というコールバック関数を追加します。VQCは目的関数を評価するたびに、現在の重みとその重みにおける目的関数の値という2つのパラメーターを指定して、この関数を呼び出します。コールバックは目的関数の値を配列に追加し、反復計算を目的関数の値に対してプロットできるようにします。コールバックは各反復ごとにプロットを更新します。コールバック関数の内部では、先ほど説明した2パラメーターのシグネチャーを持つ限り、どんなことでもできることに注意してください。

[14]:
from matplotlib import pyplot as plt
from IPython.display import clear_output

objective_func_vals = []
plt.rcParams["figure.figsize"] = (12, 6)


def callback_graph(weights, obj_func_eval):
    clear_output(wait=True)
    objective_func_vals.append(obj_func_eval)
    plt.title("Objective function value against iteration")
    plt.xlabel("Iteration")
    plt.ylabel("Objective function value")
    plt.plot(range(len(objective_func_vals)), objective_func_vals)
    plt.show()

これで、分類器を構築し、適合させる準備が整いました。

VQC は、「変分量子分類器」の略称です。特徴量とansatzを受け取り、量子ニューラルネットワークを自動的に構築します。最も単純なケースでは、量子ビットの数と量子インスタンスを渡すだけで、有効な分類器を構築することができます。 Sampler パラメーターを省略することも可能です。この場合、先ほど作成した方法で Sampler インスタンスが作成されます。ここでは、説明のために手動で作成しました。

学習には時間がかかる場合があります。少しお待ちください。

[15]:
import time
from qiskit_machine_learning.algorithms.classifiers import VQC

vqc = VQC(
    sampler=sampler,
    feature_map=feature_map,
    ansatz=ansatz,
    optimizer=optimizer,
    callback=callback_graph,
)

# clear objective value history
objective_func_vals = []

start = time.time()
vqc.fit(train_features, train_labels)
elapsed = time.time() - start

print(f"Training time: {round(elapsed)} seconds")
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_27_0.png
Training time: 303 seconds

それでは、量子モデルが実際のデータセットでどのようなパフォーマンスを発揮するのか見てみましょう。

[16]:
train_score_q4 = vqc.score(train_features, train_labels)
test_score_q4 = vqc.score(test_features, test_labels)

print(f"Quantum VQC on the training dataset: {train_score_q4:.2f}")
print(f"Quantum VQC on the test dataset:     {test_score_q4:.2f}")
Quantum VQC on the training dataset: 0.85
Quantum VQC on the test dataset:     0.87

見ての通り、スコアは高く、このモデルを使って未見のデータに対するラベルを予測することが可能です。

では、さらに良いモデルを得るために、どのようなチューニングをすればよいのかを見ていきましょう。

  • 重要な構成要素は、特徴量マップとansatzです。パラメーターを調整することができます。この例では、回路に追加するゲートパターンの繰り返しを指定する reps パラメーターを変更することができます。この値を大きくすると、より多くのエンタングルメント演算が行われるようになり、パラメーターも多くなります。このように、モデルはより柔軟になりますが、パラメーターが多くなることで複雑さが増し、モデルのトレーニングに時間がかかるのが一般的です。さらに、モデルをオーバーフィットさせてしまう可能性もあります。 Qiskit circuit library で利用可能な他の特徴量マップやansatzを試すこともできますし、カスタム回路を考え出すこともできます。

  • 他のオプティマイザーを試してみるのもよいでしょう。Qiskitには色々なオプティマイザーがあります。その中には勾配がないものもあれば、そうでないものもあります。例えば L_BFGS_B のような勾配ベースのオプティマイザーを選択した場合、トレーニング時間が増加することが予想されます。目的関数に加えて、これらのオプティマイザーは学習パラメーターに関して勾配を評価する必要があり、これは反復あたりの回路実行数の増加につながります。

  • もう一つの方法は、ランダムに(または決定論的に) initial_point をサンプリングし、何度もモデルを適合させることです。

しかし、データセットに含まれる素性が、最新の量子コンピューターが処理できる量よりも多い場合はどうでしょうか。この例では、データセットの特徴量と同じ数の量子ビットを用意しましたが、必ずしもそうではないかもしれません。

4. 特徴量の数の削減#

このセクションでは、データセットの特徴量数を減らし、再度モデルを学習します。今回は、最初のPCA変換を行う以外は同じステップなので、より速く進めます。

4つの特徴量を2つの特徴量のみに変換します。この次元削減は教育的な目的のために行うのであり、前節で見たように、データセットの4つの特徴量を全て使って量子モデルを学習することができます。

さて、この2つの特徴量を1つの図に簡単にプロットすることができます。

[17]:
from sklearn.decomposition import PCA

features = PCA(n_components=2).fit_transform(features)

plt.rcParams["figure.figsize"] = (6, 6)
sns.scatterplot(x=features[:, 0], y=features[:, 1], hue=labels, palette="tab10")
[17]:
<AxesSubplot:>
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_31_1.png

いつものように、まずデータセットを分割し、次に古典的なモデルを当てはめます。

[18]:
train_features, test_features, train_labels, test_labels = train_test_split(
    features, labels, train_size=0.8, random_state=algorithm_globals.random_seed
)

svc.fit(train_features, train_labels)

train_score_c2 = svc.score(train_features, train_labels)
test_score_c2 = svc.score(test_features, test_labels)

print(f"Classical SVC on the training dataset: {train_score_c2:.2f}")
print(f"Classical SVC on the test dataset:     {test_score_c2:.2f}")
Classical SVC on the training dataset: 0.97
Classical SVC on the test dataset:     0.90

結果はまだ良いのですが、最初のバージョンと比べると若干悪くなっています。量子モデルがそれらをどのように扱うか見てみましょう。量子ビットが2つになったので、特徴量マップとAnsatzを作り直さなければなりません。

[19]:
num_features = features.shape[1]

feature_map = ZZFeatureMap(feature_dimension=num_features, reps=1)
ansatz = RealAmplitudes(num_qubits=num_features, reps=3)

また、最適化プロセスを実行する反復回数の最大値を減らしました。

[20]:
optimizer = COBYLA(maxiter=40)

ここで、新しいパラメーターから量子分類器を構築し、学習させます。

[21]:
vqc = VQC(
    sampler=sampler,
    feature_map=feature_map,
    ansatz=ansatz,
    optimizer=optimizer,
    callback=callback_graph,
)

# clear objective value history
objective_func_vals = []

# make the objective function plot look nicer.
plt.rcParams["figure.figsize"] = (12, 6)


start = time.time()
vqc.fit(train_features, train_labels)
elapsed = time.time() - start

print(f"Training time: {round(elapsed)} seconds")
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_39_0.png
Training time: 58 seconds
[22]:
train_score_q2_ra = vqc.score(train_features, train_labels)
test_score_q2_ra = vqc.score(test_features, test_labels)

print(f"Quantum VQC on the training dataset using RealAmplitudes: {train_score_q2_ra:.2f}")
print(f"Quantum VQC on the test dataset using RealAmplitudes:     {test_score_q2_ra:.2f}")
Quantum VQC on the training dataset using RealAmplitudes: 0.58
Quantum VQC on the test dataset using RealAmplitudes:     0.63

さて、スコアは公平なコイントスよりも高いのですが、もっと良くなる可能性があります。目的関数は最後に向かってほぼフラットです。つまり、反復回数を増やしても、モデルの性能は変わらないということです。別のansatzで何ができるかを見てみましょう。

[23]:
from qiskit.circuit.library import EfficientSU2

ansatz = EfficientSU2(num_qubits=num_features, reps=3)
optimizer = COBYLA(maxiter=40)

vqc = VQC(
    sampler=sampler,
    feature_map=feature_map,
    ansatz=ansatz,
    optimizer=optimizer,
    callback=callback_graph,
)

# clear objective value history
objective_func_vals = []

start = time.time()
vqc.fit(train_features, train_labels)
elapsed = time.time() - start

print(f"Training time: {round(elapsed)} seconds")
../_images/tutorials_02a_training_a_quantum_model_on_a_real_dataset_42_0.png
Training time: 74 seconds
[23]:
train_score_q2_eff = vqc.score(train_features, train_labels)
test_score_q2_eff = vqc.score(test_features, test_labels)

print(f"Quantum VQC on the training dataset using EfficientSU2: {train_score_q2_eff:.2f}")
print(f"Quantum VQC on the test dataset using EfficientSU2:     {test_score_q2_eff:.2f}")
Quantum VQC on the training dataset using EfficientSU2: 0.78
Quantum VQC on the test dataset using EfficientSU2:     0.80

スコアは前回の設定よりも良くなっています。おそらく、もっと反復回数を増やせば、さらに良い結果が得られると思います。

5. 結論#

このチュートリアルでは、2つの古典的なモデルと3つの量子機械学習モデルを構築しました。結果とともに全体的な表を出力してみます。

[24]:
print(f"Model                           | Test Score | Train Score")
print(f"SVC, 4 features                 | {train_score_c4:10.2f} | {test_score_c4:10.2f}")
print(f"VQC, 4 features, RealAmplitudes | {train_score_q4:10.2f} | {test_score_q4:10.2f}")
print(f"----------------------------------------------------------")
print(f"SVC, 2 features                 | {train_score_c2:10.2f} | {test_score_c2:10.2f}")
print(f"VQC, 2 features, RealAmplitudes | {train_score_q2_ra:10.2f} | {test_score_q2_ra:10.2f}")
print(f"VQC, 2 features, EfficientSU2   | {train_score_q2_eff:10.2f} | {test_score_q2_eff:10.2f}")
Model                           | Test Score | Train Score
SVC, 4 features                 |       0.99 |       0.97
VQC, 4 features, RealAmplitudes |       0.85 |       0.87
----------------------------------------------------------
SVC, 2 features                 |       0.97 |       0.90
VQC, 2 features, RealAmplitudes |       0.58 |       0.63
VQC, 2 features, EfficientSU2   |       0.78 |       0.80

当然ながら、古典的なモデルの方が量子的なモデルよりも性能が良いです。古典的なMLは長い道のりを歩んできており、量子MLはまだそのレベルに到達していないのです。見ての通り、我々は古典的なサポートベクターマシンを使って最高の結果を得ました。しかし、4つの特徴量で学習させた量子モデルも非常に良い結果でした。しかし、特徴量の数を減らすと、予想通り全てのモデルの性能が落ちました。ですから、もしリソースが許すのであれば、全特徴を持つデータセットでモデルを学習させるべきでしょう。そうでない場合は、データセットサイズ、学習時間、スコアの間で妥協することになるかもしれません。

もう一つの観察は、単純なAnsatzの変更でさえ、より良い結果につながるということです。 EfficientSU2 ansatz を用いた2成分モデルは、 RealAmplitudes を用いたモデルよりも良好な結果を得ることができました。つまり、量子MLでも古典MLと同様にハイパーパラメーターの選択が重要であり、最適なハイパーパラメーターを探索するには長い時間がかかる可能性があります。古典的なMLと同じ手法、例えばランダム/グリッドや、より洗練されたアプローチを適用することができます。

この簡単なチュートリアルで、あなたが古典から量子MLへと飛躍することを期待しています。

[25]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.0
qiskit-aer0.11.0
qiskit-ignis0.7.0
qiskit0.33.0
qiskit-machine-learning0.5.0
System information
Python version3.7.9
Python compilerMSC v.1916 64 bit (AMD64)
Python builddefault, Aug 31 2020 17:10:11
OSWindows
CPUs4
Memory (Gb)31.837730407714844
Fri Oct 14 14:33:06 2022 GMT Daylight Time

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

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.