量子のディープな回路を見てみる
量子回路もディープになると表現力が増して複雑な関数を表現できるようになります。ざっくりと計算をしましょう。
参考
The effect of data encoding on the expressive power of variational quantum machine learning models
Maria Schuld, Ryan Sweke, Johannes Jakob Meyer
Parametrized Quantum Circuits for Reinforcement Learning
前の記事
連続量の入力データから連続量の出力を取る方法を確認しました。
https://blueqat.com/yuichiro_minato2/ae406141-506a-46d7-82e5-2e4bd8520f6a
さっそくつくってみましょう
量子NN回路は1量子ビット任意回転と2量子ビットゲートを利用します。データ入力はRXゲートで行いますが、NN回路の後に入力をします。
NN回路
NN回路はRX/RY/RZ回路とCZで作っているのがありますのでその通りやります。まずはパラメータの準備。ランダムで準備します。
from blueqat import Circuit
import numpy as np
#量子ビット数はデータ数に対応する
data = np.random.rand(3)
n_qubits = len(data)
print("量子ビット数:", n_qubits)
#繰り返し回数
repeat = 3
#パラメータ数は量子ビット数*6*繰り返し回数
param = np.random.rand(n_qubits,6,repeat)
print(param)
#取り出すときは量子回路と対応させて、(量子ビット番号,前から順番に0から5まで,繰り返しの回数)
param[1][2][0]
量子ビット数: 3
[[[0.573855 0.9526361 0.69315057]
[0.73581044 0.52612109 0.7327389 ]
[0.33582046 0.25711508 0.48902524]
[0.10345856 0.94387657 0.72513279]
[0.03514019 0.28619167 0.60001793]
[0.01670859 0.56616799 0.80697452]]
[[0.00487255 0.5280308 0.72116262]
[0.53322813 0.57016325 0.01625977]
[0.5094934 0.51912137 0.41566823]
[0.43009867 0.99786402 0.43780676]
[0.62635794 0.11739202 0.39638664]
[0.33771516 0.49713497 0.12768475]]
[[0.70259739 0.9432878 0.2837218 ]
[0.54095693 0.69813221 0.75333507]
[0.83868782 0.6475195 0.34269556]
[0.7225571 0.29044654 0.78981082]
[0.77494212 0.05484443 0.34439639]
[0.45561803 0.19601488 0.44281144]]]
0.509493401819594
次に回路を構築してみます
回路は関数として実装し、繰り返しに対応できるようにします。2量子ビットにはパラメータを含まないCZを採用し、簡略化します。
#回路を初期化
a = Circuit()
for j in range(repeat):
#1量子ビット任意回転
for i in range(n_qubits):
a.rx(param[i][0][j])[i].ry(param[i][1][j])[i].rz(param[i][2][j])[i]
#2量子ビットクラスタ
for i in range(n_qubits):
a.cz[i, (i+1)%n_qubits]
#データ入力&調整
for i in range(n_qubits):
a.rx(data[i])[i]
a.rx(param[i][3][j])[i].ry(param[i][4][j])[i].rz(param[i][5][j])[i]
a.run_with_ibmq(returns='draw', output='mpl')
<Figure size 1591.6x565.88 with 1 Axes>
ちなみに単一のレイヤーは、
c = Circuit()
for j in range(1):
#1量子ビット任意回転
for i in range(n_qubits):
c.rx(param[i][0][j])[i].ry(param[i][1][j])[i].rz(param[i][2][j])[i]
#2量子ビットクラスタ
for i in range(n_qubits):
c.cz[i, (i+1)%n_qubits]
#データ入力&調整
for i in range(n_qubits):
c.rx(data[i])[i]
c.rx(param[i][3][j])[i].ry(param[i][4][j])[i].rz(param[i][5][j])[i]
c.run_with_ibmq(returns='draw', output='mpl')
<Figure size 748.797x264.88 with 1 Axes>
とても分かりやすいです。
測定
試しに計算結果を取り出してみます。期待値計算をします。ハミルトニアンはテンソル積を取ります。今回は0番目の量子ビットの値をZ測定してみます。
#単位行列
I = np.eye(2)
#PauliZ行列
Z = np.array([[1,0],[0,-1]])
#今回使用するハミルトニアン
H = np.kron(np.kron(Z,I),I)
print(H)
[[ 1. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 1. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. -1. -0. -0. -0.]
[ 0. 0. 0. 0. -0. -1. -0. -0.]
[ 0. 0. 0. 0. -0. -0. -1. -0.]
[ 0. 0. 0. 0. -0. -0. -0. -1.]]
ハミルトニアンの行列が得られました。回路を実行して状態ベクトルを確認してみます。
result = a.run()
print(result)
[ 0.27848219-0.15831003j 0.36903509+0.12461934j 0.32041438-0.11691289j
0.0430183 -0.14253776j 0.19055126-0.29968832j -0.30323604+0.2686931j
0.14179012+0.34405978j 0.40476593-0.12074421j]
そして、期待値計算をします。状態ベクトルとハミルトニアンから期待値が出ました。
exptZ0 = result.conj()@H@result
print(exptZ0.real)
-0.21433428173335783
せっかくですのですべての量子ビットを測定した期待値を求めたいと思います。ZZZにします。
#今回使用するハミルトニアン
H2 = np.kron(np.kron(Z,Z),Z)
print(H2)
[[ 1 0 0 0 0 0 0 0]
[ 0 -1 0 0 0 0 0 0]
[ 0 0 -1 0 0 0 0 0]
[ 0 0 0 1 0 0 0 0]
[ 0 0 0 0 -1 0 0 0]
[ 0 0 0 0 0 1 0 0]
[ 0 0 0 0 0 0 1 0]
[ 0 0 0 0 0 0 0 -1]]
exptZZZ = result.conj()@H2@result
print(exptZZZ.real)
-0.1451767385597242
今回は3つの量子ビットをすべて使って期待値を出してみました。この値をラベルと照合し損失関数を用いて最適化すれば量子ディープ回路を学習させられます。以上です。