インターン4回目です。今回はQAOAから離れて量子機械学習をやります。
一般的な最近のNISQ量子計算における機械学習は、
1.量子回路を1量子ビット(バイアス?)と2量子ビット(ウェイト?)のゲートで記述する。
2.量子回路の測定結果からハミルトニアンの期待値を求めて損失関数に入れる。
3.角度を変化させて微分を使って最適化をする。
の3ステップですね。早速これまでのインターンの知識を使って実装します。
今回はデータを連続値で入力するモデルを使います。
モデル
今回はちょっと変わったモデルですが、NN回路の層を先に持ってきて、データを入力する回路を使います。データは連続値として量子ゲートの角度として入れられます。
|0> = RX-RY-RZ-CZ-------CZ---RX(a)-RX-RY-RZ-M
|0> = RX-RY-RZ-CZ-CZ----|----RX(b)-RX-RY-RZ-M
|0> = RX-RY-RZ----CZ-CZ-|----RX(c)-RX-RY-RZ-M
|0> = RX-RY-RZ-------CZ-CZ---RX(d)-RX-RY-RZ-M
一番最初の三つが1量子ビット、その次のループが2量子ビット。そしてRXはデータ入力。abcdにデータが入ります。そのあとにはデータ調整レイヤーが続き、最後に測定です。
!pip install sklearn
Requirement already satisfied: sklearn in /opt/conda/lib/python3.10/site-packages (0.0)
Requirement already satisfied: scikit-learn in /opt/conda/lib/python3.10/site-packages (from sklearn) (1.1.2)
Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/lib/python3.10/site-packages (from scikit-learn->sklearn) (3.1.0)
Requirement already satisfied: scipy>=1.3.2 in /opt/conda/lib/python3.10/site-packages (from scikit-learn->sklearn) (1.8.1)
Requirement already satisfied: numpy>=1.17.3 in /opt/conda/lib/python3.10/site-packages (from scikit-learn->sklearn) (1.21.0)
Requirement already satisfied: joblib>=1.0.0 in /opt/conda/lib/python3.10/site-packages (from scikit-learn->sklearn) (1.1.0)
まずはいつも通りたまプラーザの家賃でやってみます。
from blueqat import Circuit
from blueqat.pauli import Z
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
#data
data = np.array([[8,3,83.74,18,22],[5,2,75.72,19,19],[7,2,31.47,46,7.8],[18,2,46.62,36,8],[8,3,41.02,49,8],[8,1,70.43,25,15.8],[8,1,70.43,25,15.8],[12,1,48.02,3,12.5],[10,4,58.57,36,11.8]])
df = pd.DataFrame(data,columns=['walk','floor','area','age','rent'])
#rent data
y = df["rent"]
#others
X = df.drop(columns=["rent"], axis=1)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=1)
早速回路の準備です。今回はデータ入力が4なので、4量子ビット用意します。
N = 4
初期パラメータは今回の量子回路のために24個準備します。
np.random.seed = 1
params = [np.random.rand() for _ in range(N*6)]
次ですが、測定は今回は回路が短く量子もつれが少ないと予測されますので、全量子ビットの測定結果を利用します。
hamiltonian = 1*Z[0]*Z[1]*Z[2]*Z[3]
数値微分用の誤差を用意し、学習率を設定します。
h = 1e-6
e = 0.1
早速学習のループを回します。微分をとって学習をさせています。
arr_loss = []
for k in range(100):
for item, answer in zip(X_train.values, y_train.values):
circuit = Circuit()
for i in range(N):
circuit.rx(params[i*3+0])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]
circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]
for i in range(N):
circuit.rx(np.pi*2*item[i]/100)[i]
for i in range(N):
circuit.rx(params[i*3+N*3])[i].ry(params[i*3+N*3+1])[i].rz(params[i*3+N*3+2])[i]
expt = circuit.run(hamiltonian = hamiltonian)
loss = (expt - answer/100)**2
grad_temp = np.zeros(N*6)
for j in range(N*6):
params_temp = params[:]
angle_temp = params_temp[j]
params_temp[j] += h
circuit = Circuit()
for i in range(N):
circuit.rx(params_temp[i*3+0])[i].ry(params_temp[i*3+1])[i].rz(params_temp[i*3+2])[i]
circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]
for i in range(N):
circuit.rx(np.pi*2*item[i]/100)[i]
for i in range(N):
circuit.rx(params_temp[i*3+N*3])[i].ry(params_temp[i*3+N*3+1])[i].rz(params_temp[i*3+N*3+2])[i]
expt_temp = circuit.run(hamiltonian = hamiltonian)
loss_temp = (expt_temp - answer/100)**2
grad_temp[j] = (loss_temp - loss)/h
params -= grad_temp*e
arr_loss.append(loss)
print(loss)
0.001577203663075372
0.0007165704545317504
0.0002809029251319455
7.355935852208767e-05
2.9763030383136872e-06
1.642636807862093e-05
7.95173678087693e-05
0.00016849754348836188
0.00026670905041771613
0.00036256946944902266
0.000448213059770772
0.0005184845398007335
0.0005701684632815868
0.0006014058018807433
0.0006112789294864486
0.0005995655690962452
0.0005666803354738703
0.0005138369963023882
0.0004434589244460393
0.00035979970382171646
0.000269548727719499
0.0001818622242898542
0.00010697162506458079
5.29082586126033e-05
2.1639026807316774e-05
8.06187315775453e-06
4.150924182040881e-06
4.724299826516526e-06
8.612997200515925e-06
1.545910716608489e-05
2.3653652603744314e-05
3.11250835124644e-05
3.6581792551948374e-05
3.975330607788671e-05
4.098945417437523e-05
4.083340177249112e-05
3.9785204696098836e-05
3.822324949766464e-05
3.640477500154372e-05
3.4492663245156144e-05
3.25842700314512e-05
3.073437517292059e-05
2.897130679148397e-05
2.7307533007140955e-05
2.5746335089391056e-05
2.428589059790032e-05
2.2921713615497196e-05
2.1648080675656754e-05
2.0458843023532834e-05
1.9347873619451794e-05
1.8309300253507726e-05
1.7337615574706094e-05
1.6427717878060952e-05
1.557491413144111e-05
1.4774903473248573e-05
1.4023751532834228e-05
1.3317861319307516e-05
1.26539437677275e-05
1.202898954970464e-05
1.1440242889206561e-05
1.088517759083214e-05
1.0361475340937574e-05
9.867006184792064e-06
9.399810950251608e-06
8.958085508983957e-06
8.540166608173312e-06
8.144519202255013e-06
7.769725033642873e-06
7.414472365376004e-06
7.077546754451503e-06
6.7578227080321065e-06
6.454256163630758e-06
6.165877689312029e-06
5.891786322447297e-06
5.631143996902736e-06
5.383170467347504e-06
5.147138722576583e-06
4.922370793971091e-06
4.7082339399208735e-06
4.504137183793707e-06
4.309528127926532e-06
4.123890065091571e-06
3.946739327610578e-06
3.7776228578513544e-06
3.616115982504449e-06
3.4618203750953856e-06
3.3143621781767777e-06
3.1733902833635893e-06
3.0385747445611063e-06
2.909605318358167e-06
2.7861901187741153e-06
2.6680543762649036e-06
2.5549392858613317e-06
2.4466009569456027e-06
2.342809427783482e-06
2.2433477617532733e-06
2.148011202809607e-06
2.0566064037875907e-06
1.9689506963788495e-06
1.8848714272386881e-06
誤差を図示してみます。
import matplotlib.pyplot as plt
plt.plot(arr_loss)
plt.show()
<Figure size 432x288 with 1 Axes>
最後にテスト用のデータを使って予測をしてみます。
X_test = [9,5,58.3,34]
circuit = Circuit()
for i in range(N):
circuit.rx(params[i*3+0])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]
circuit.cz[0,1].cz[1,2].cz[2,3].cz[3,0]
for i in range(N):
circuit.rx(np.pi*2*X_test[i]/100)[i]
for i in range(N):
circuit.rx(params[i*3+N*3])[i].ry(params[i*3+N*3+1])[i].rz(params[i*3+N*3+2])[i]
expt = circuit.run(hamiltonian = hamiltonian)
print(expt*100)
12.649119097171557
12.6万円と出ました。実際には量子の回路は複数の層を重ねたほうがいいのですが、今回は一層でやってみました。以上です。