LoginSignup
3
1

More than 1 year has passed since last update.

Pennylaneを用いた量子SVM(Feature map を色々試す)

Last updated at Posted at 2021-10-09

量子SVM

量子SVMは、古典データを量子状態ベクトル空間に移すことで得られるカーネルを用いたSVMです。
カーネルの計算までを量子コンピュータで行い、分離平面の計算は古典的なSVMと同じ方法で行います。
https://qiita.com/notori48/items/a54a5219ffd1ed6666df
https://qiita.com/notori48/items/6367876c3426350fab32

Feature map

カーネルは、古典データを量子状態ベクトル空間にどのように移すかによります。
例えば、古典データ$x$に対して、量子状態ベクトルを角度$x$だけ回す演算 を対応させると、カーネルが決まります。
量子状態ベクトルの回転軸は$x,y,z$軸が考えられますので、回転軸も含めるとカーネルが3種類考えられます。
さらに、$x$軸周りに回した後に$y$軸回りに回すということも考えられます。
このように、埋め込み方に応じて無数のカーネルが考えられます。
埋め込み方を Feature map といいます。
どのようなFeature mapがどのような問題に適するかは、まだまだよくわかっていません。
今回は、いろいろなFeature mapを試してみます。

SDKはPennylaneを用います。

[2021/10/10] 考察を追加しました

1 qubit feature map (1次埋め込み)

一番かんたんなFeature mapの種類は、1 qubit 回転です。
これは先に述べたように、$x,y,z$軸のいずれかの軸回りの回転です。回転角度を古典データで決めます。

def my_feature_map(a):
    for i in range(n_qubits):
        qml.RX(a[i], wires=i)

Pennylaneのテンプレートライブラリを使うと、

def my_feature_map(a):
    AngleEmbedding(a, wires=range(n_qubits), rotation='X') 

このようになります。
(なお、データを2倍してから回転角度に埋め込む実装もよくみられます。スケールは自由ですが、
”角度”に埋め込んでいるのですから最大値が$2\pi$を超えないように注意しましょう。)
入力データが$n$次元であるとき、$n$量子ビットをそれぞれ回転させます。
なお量子ビット数が潤沢にある(例えば$2n$)なら、異なる2つの量子ビットに同じデータを埋め込んでも良いです。

2 qubits feature map (二次埋め込み)

次は2量子ビットにまたがった埋め込みです。
以下はZZ feature map と呼ばれる例です。

def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        qml.RZ(a[i], wires=i)

    qml.IsingZZ((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

本質的なのは、最後の
qml.IsingZZ((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])
です。
入力データの1次元目と2次元目を同時に取ってきて、2量子ビット間にZZゲートをかけています。
ZZゲートについては、以下を参照。
https://pennylane.readthedocs.io/en/stable/code/api/pennylane.IsingZZ.html
ZZゲートをかけると、1番目の量子ビットの状態と2番目の量子ビットの状態に相関(エンタングルメント)が生まれます。
エンタングルメントがあるのとないのとでは、古典データがアクセスできる量子状態ベクトル空間(正確にはブロッホベクトル空間)の次元の大きさが違います。
https://qiita.com/notori48/items/6367876c3426350fab32
ただ、単にエンタングルメントがあればSVMの性能が必ず良くなるかというと、そうでもないようです。
ここが難しさです。

性能比較

feature map をいろいろ試してみます。
データセットはmoonを用いました。

image.png

実装は過去の記事(以下)と同じです。feature map と kernel だけを差し替えています。
https://qiita.com/notori48/items/a54a5219ffd1ed6666df
https://qiita.com/notori48/items/6367876c3426350fab32

学習は、100データに対して10秒程度で終わります。


def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        qml.RZ(a[i], wires=i)

    qml.IsingZZ((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

@qml.qnode(dev_kernel)
def kernel(x1, x2):
    """The quantum kernel."""
    #S(x)
    my_feature_map(x1)
    #S^{\dagger}(x')
    qml.adjoint(my_feature_map)(x2)
    return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))

RX のみ

def my_feature_map(a):
    AngleEmbedding(a, wires=range(n_qubits), rotation='X') 

accuracy = 0.8
image.png

RY のみ

def my_feature_map(a):
    AngleEmbedding(a, wires=range(n_qubits), rotation='Y') 

0.8

image.png

RZのみ

def my_feature_map(a):
    AngleEmbedding(a, wires=range(n_qubits), rotation='Z') 

0.32

image.png

Hadamard + RZ

def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
    AngleEmbedding(a, wires=range(n_qubits), rotation='Z')

0.8

image.png

Hadamard を入れるとRZがRXと似た性能になっています。
Hadamard で座標変換するとZゲートがXゲートに見えるからだと思います。(X=HZH)

どうやらmoonデータセットに対してはXやYが相性が良さそうです。

XX feature map

def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        qml.RX(a[i], wires=i)

    qml.IsingXX((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

0.32

image.png

Xゲートの系譜なのにだめになっています。
これは、初段に入れているHadamard によってXがZへ変換されているためと考えられます。

XX feature map から Hadamard を引っこ抜く

def my_feature_map(a):
    for i in range(n_qubits):
        qml.RX(a[i], wires=i)

    qml.IsingXX((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

0.96

image.png

Hadamardを引っこ抜くことにより、純粋にXゲートの系譜になっていますので、うまくいっています。
そして、RXのみ(一次)のときより性能が改善しています(0.8→0.96)。
エンタングルメントの効果が出ています。
しかし判定領域に不連続性が出ていたりしますので、扱いづらそう。

YY feature map

def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        qml.RY(a[i], wires=i)

    qml.IsingYY((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

AttributeError: module 'pennylane' has no attribute 'IsingYY'
バグで実行できません。

ZZ feature map

def my_feature_map(a):
    for i in range(n_qubits):
        qml.Hadamard(wires=i)
        qml.RZ(a[i], wires=i)

    qml.IsingZZ((np.pi-a[0])*(np.pi-a[1]),wires=[0,1])

0.96

image.png

Zの系譜ですが性能が良いです。
これは、Hadamard によってZがXに化けているためと考えられます。
やはりXが相性が良さそうです。

古典カーネル(RBFカーネル)

1.0

image.png

古典がベストでした・・・

比較結果

feature map の決め方によって分類精度が全く異なる。
moonデータセットに対してはXゲートやYゲートのfeature map の相性が良いと考えられる。
この例では一次よりも二次のほうが性能が良かった。
が、判定領域に不連続性が入っていたりするので、これが悪さをすることも考えられ、一般に二次のほうがいいとは限らないだろう。
何も考えない古典RBFカーネルだと一発で分類エラー0になるし、学習も200倍ぐらい早い。
量子の表現力、とは。

まとめ

何も考えない古典RBFカーネルが一番いいのでは?という悲しい結果。
なお量子カーネルSVMのほうが性能が良くなるデータセットも存在しますが、そのような例は人為的な場合が多いのが現状と思います。
qiskitチュートリアルの アドホックデータ がその例です。
https://qiskit.org/documentation/stable/0.24/locale/ja_JP/tutorials/machine_learning/01_qsvm_classification.html

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1