新しいblueqatでは量子機械学習が以前よりもやりやすいです。今後はツールも充実していきますが、まずは量子機械学習のフローをVQEを使ってやってみます。まずはツールを導入。
pip install --no-deps -U git+https://github.com/jcmgray/quimb.git@develop autoray blueqat
Collecting git+https://github.com/jcmgray/quimb.git@develop
Cloning https://github.com/jcmgray/quimb.git (to revision develop) to /tmp/pip-req-build-kwso_y_4
Running command git clone -q https://github.com/jcmgray/quimb.git /tmp/pip-req-build-kwso_y_4
Requirement already satisfied: autoray in /opt/conda/lib/python3.8/site-packages (0.3.1)
Requirement already satisfied: blueqat in /opt/conda/lib/python3.8/site-packages (1.0.0)
Note: you may need to restart the kernel to use updated packages.
新しいblueqatではハミルトニアンの期待値を簡単に出せます。ハミルトニアンをパウリ行列で作り、実行時に指定するだけです。
from blueqat import Circuit
from blueqat.pauli import Z
hamiltonian = 1*Z[0]+1*Z[1]
Circuit(4).x[:].run(backend="quimb", hamiltonian=hamiltonian)
-2.0
最近の量子コンピュータの計算では、状態ベクトルよりも期待値のほうが重要です。機械学習や離散最適化、VQEではよく使います。ハミルトニアンはパウリ行列を組合わせて行列を作ります。その行列と、量子状態から期待値を出すことができます。この期待値を小さくする方向に学習が進むように量子回路を作って最適化してみます。
100量子ビット回路で、回路を1回だけ繰り返し、パラメータを最適化してみます。
#量子ビット数
n = 100
#回路の繰り返し回数
p = 1
#必要なパラメータ数、(NN回路n*6)*繰り返し回数
n_params = (n * 6)*p
print("number of parameters=", n_params)
number of parameters= 600
回路を作ります。任意回転のRX/RY/RZをつなぎ、その後もつれをCZでループ状につなぎます。
#NN回路
def nn(params, n_qubits):
c = Circuit()
#1量子ビット任意回転
for i in range(n_qubits):
c.rx(params[i*3])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]
#2量子ビットクラスタ用CZ
for i in range(n_qubits):
c.cz[i, (i+1) % n_qubits]
return c
#後処理
def post_process(params, n_qubits):
c = Circuit()
#1量子ビット任意回転
for i in range(n_qubits):
c.rx(params[i*3])[i].ry(params[i*3+1])[i].rz(params[i*3+2])[i]
return c
#1サイクル分
def one_cycle(params, n_qubits):
return nn(params[:3*n_qubits], n_qubits) + post_process(params[3*n_qubits:], n_qubits)
これらをつなぎます。ハミルトニアンは最後の量子ビット一つの期待値を取ります。期待値は軸を選びますが、普通にZにします。
def all_cycle(params, n_qubits, n_cycle):
circuit = Circuit()
for i in range(n_cycle):
circuit += one_cycle(params[i*6*n:(i+1)*6*n], n_qubits)
hamiltonian = 1*Z[n_qubits-1]
return circuit.run(backend="quimb", hamiltonian=hamiltonian)
これで回路は完了です。さっそくループを回してみます。パラメータはランダムスタート、学習率などは適当です。計算が重たいのでループは10回にします。今回は期待値を小さくする方に向かいますので、VQEですが、量子機械学習はここに損失関数を使ってデータを評価しますが、今回は簡略化のためにVQEをやります。最終的には期待値は-1へ向かうはずです。
%%time
import copy
import numpy as np
from blueqat.pauli import Z
import matplotlib.pyplot as plt
#ランダムパラメータ初期化
param = np.random.rand(n_params)*2*np.pi
#loss格納用のarray
arr = []
#学習率
e = 0.5
#微分
h = 0.1
loop = 10
for k in range(loop):
#損失関数の代わりにハミルトニアン期待値をそのまま使う
loss = all_cycle(param, n , p)
arr.append(loss)
#勾配法を実装します。
loss_arr = np.zeros(n_params)
for i in range(n_params):
param_tmp = copy.copy(param)
param_tmp[i] += h
loss_arr[i] = all_cycle(param_tmp, n , p)
param -= (loss_arr - loss)*e
print("epoch:", k)
print("loss:",loss)
epoch: 0
loss: -0.14999994171919007
epoch: 1
loss: -0.2052320943073752
epoch: 2
loss: -0.25918263117240925
epoch: 3
loss: -0.31147714744371785
epoch: 4
loss: -0.36178139986149566
epoch: 5
loss: -0.40981065300989966
epoch: 6
loss: -0.4553364135063569
epoch: 7
loss: -0.49819016389283727
epoch: 8
loss: -0.5382640048638467
epoch: 9
loss: -0.5755084062582768
plt.plot(arr)
plt.show()
<Figure size 432x288 with 1 Axes>
かなり重たいですが、止まることなく計算ができます。損失関数(今回は期待値ですが)の値がきちんと下がっていくのが見て取れます。きちんと100量子ビットのもつれ回路を学習できています。このサイズになってくると接続などどのようにすればよいかなど、新しく検討する事項が極端に増えます。高性能なマシンを使えばより高速に計算ができると思いますので、引き続きやっていきたいですね。以上です。