量子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を用いました。
実装は過去の記事(以下)と同じです。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')
RY のみ
def my_feature_map(a):
AngleEmbedding(a, wires=range(n_qubits), rotation='Y')
0.8
RZのみ
def my_feature_map(a):
AngleEmbedding(a, wires=range(n_qubits), rotation='Z')
0.32
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
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
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
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
Zの系譜ですが性能が良いです。
これは、Hadamard によってZがXに化けているためと考えられます。
やはりXが相性が良さそうです。
古典カーネル(RBFカーネル)
1.0
古典がベストでした・・・
比較結果
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