量子コンピュータの得意分野にサンプリングがありますが、データの分布を学習し、その分布に沿ったサンプリングを返してくれる生成モデルについて紹介をします。
今回は量子コンピュータの生成モデルでQCBMと呼ばれるモデルを紹介します。まずツールを読み込みます。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
次に今回学ぶ分布を作ってみます。
#num of qubits
N = 4
#num of bins
n_bins = 2**N
print(n_bins)
samples = np.random.normal(0, 1, 1000)
hist = plt.hist(samples, bins = n_bins)
data_prob = hist[0]
print(data_prob)
16
[ 3. 8. 14. 27. 65. 94. 125. 141. 160. 134. 96. 58. 39. 28.
6. 2.]
<Figure size 432x288 with 1 Axes>
今回は一般的な量ニューラルネット回路を使います。ランダムシードを固定し、今回のNN回路の繰り返し回数を決めます。
パラメータ数は繰り返し回数と量子ビット数が決まると決まります。
from blueqat import Circuit
import time
np.random.seed(30)
#num of circuit repeat
n_repeat = 3
#num of params
n_params = N*3*n_repeat
print(n_params)
#initial parameters
param_init = [np.random.rand()*np.pi*2 for i in range(n_params)]
36
#任意回転回路
def arbi(para):
circ1 = Circuit()
for i in range(N):
circ1.rx(para[0+i*3])[i].ry(para[1+i*3])[i].rz(para[2+i*3])[i]
return circ1
#接続
def loop():
circ2 = Circuit()
for i in range(N):
circ2.cx[i, (i+1)%N]
return circ2
#QCBMの回路全体
def qcbm(a):
u = Circuit()
for i in range(n_repeat):
s_param = i*3*N
e_param = (i+1)*3*N
u += arbi(a[s_param:e_param])
u += loop()
return u
#サンプリングから損失を計算
def nnl_loss(data, sampled, shots):
D = np.sum(data)
nnl_cost = 0
eps = (1/shots)
for i in range(n_bins):
key = format(i, '04b')
prob = sampled[key] / shots
cost = - np.log(max(eps, prob)) / D
nnl_cost += cost * data[i]
return nnl_cost
#initial parameters
param = param_init.copy()
#result list
loss_hist = []
h = 0.01
e = 0.01
#iterations
nsteps = 100
start = time.time()
shots = 4096
さっそく計算をしてみます。
for i in range(nsteps):
c = qcbm(param)
res = c.m[:].run(shots = shots)
loss = nnl_loss(data_prob, res, shots)
if i%10 == 0:
print(loss)
loss_hist.append(loss)
new_param = [0 for i in range(len(param))]
for j in range(len(param)):
_param = param.copy()
_param[j] += h
c = qcbm(_param)
res = c.m[:].run(shots = shots)
_loss = nnl_loss(data_prob, res, shots)
new_param[j] = param[j] - e*(_loss - loss)/h
param = new_param
plt.plot(loss_hist)
plt.show()
print(time.time() - start)
3.080950736331575
2.997602031143021
2.931538621183997
2.796660192315474
2.78776062008557
2.762643180497116
2.696617208035424
2.6903078473919115
2.6783984056098062
2.658556654441279
<Figure size 432x288 with 1 Axes>
1189.0689253807068
結果が出ましたので、最初のランダムにスタートした分布とちょっと学習された分布の違いを見てみます。
c = qcbm(param_init)
res = c.m[:].run(shots = shots)
before_learning = []
for i in range(n_bins):
key = format(i, '04b')
before_learning.append(res[key])
plt.bar([i for i in range(n_bins)], before_learning, 1)
plt.title("Output distribusion from parameters before learning")
Text(0.5, 1.0, 'Output distribusion from parameters before learning')
<Figure size 432x288 with 1 Axes>
c = qcbm(param)
res = c.m[:].run(shots = shots)
after_learning = []
for i in range(n_bins):
key = format(i, '04b')
after_learning.append(res[key])
plt.bar([i for i in range(n_bins)], after_learning, 1)
plt.title("Output distribusion from parameters after learning")
Text(0.5, 1.0, 'Output distribusion from parameters after learning')
<Figure size 432x288 with 1 Axes>
見た目にもある程度学習が進んだことが確認できたかと思います。以上です。