講義内容
2、テンソルネットワークと量子計算と深層学習 (本講義)
3、パラメータ化量子回路と量子機械学習、SGDと古典最適化処理
5、量子機械学習を利用したOpenAI Gymでの量子強化学習
前回は量子計算をテンソルとして扱うという話をしました。量子計算では、状態ベクトルをユニタリゲートで操作しますが、テンソルとして扱う場合には、そういうルールはあまり考えずに機械的に処理をします。メリットは、
1、近年の実用的な量子計算に対して100-1000量子ビット単位の大きな量子ビットサイズが扱える。
2、近似を導入することで計算の高速化やサイズアップがさらに実現できる。
3、機械学習でも利用されるテンソルを利用することで量子計算がすぐに仕事にならなくても潰しがきく。
あたりです。ユニタリ計算という制約を外すことで多くの計算を高速化できるようになってきました。そのため量子コンピュータを使えばかなり高速な計算ができるという都市伝説はなくなりつつありますが、代わりに現実的な開発ができるようになります。
量子コンピュータ実機
その前に量子コンピュータを使ってみたいという要望がありましたので、インターンの方にいろいろ使ってもらいます。blueqat.comからアカウントを作って、各種設定からAPIキーのページに行くとパスワードのようなものがあります。そのキーを利用することで量子コンピュータに値を投げて計算ができます。最新版はgithubからインストールをお願いします。
!pip install -U git+https://github.com/Blueqat/bqcloud.git
実行は簡単です。
import bqcloud
from blueqat import Circuit
from bqcloud import load_api, Device
api = bqcloud.api.Api("Your API key here")
circ = Circuit().h[0].cx[0, 1]
#リーズナブル
task = api.execute(circ, Device.AspenM3, 10)
#値段が高い!
#task = api.execute(circ, Device.IonQDevice, 10)
これで実行できます。上記のYour API key hereのところには、自分のキーを入れます。キーを毎回指定しないで保存する方法もあります。
https://github.com/Blueqat/bqcloud
量子コンピュータは計算時間は一定ではないのでジョブのキューが指定されます。なので、投げてすぐに戻ってこない場合には、終わりそうな時に計算結果をとりに行く必要があります。
# Wait 10 sec. If complete, result is returned, otherwise, None is returned.
result = task.wait(timeout=10)
if result:
print(result.shots())
else:
print("timeout")
上記はIonQに投げています。とりあえず今は一番安定しているので。実行にはクレジットが必要ですが、インターンには十分実行できるクレジットを提供しています。
cuQuantum
ついでにcuQuantumを見ます。NVIDIA GPUを使った量子コンピュータのシミュレータです。ハイブリッドで利用したりしたらかなり便利です。二種類のSDKが搭載されています。GPUが搭載されていて、cuQuantumが入っていると実行できます。cuQuantumのインストールは、
pip install -U blueqat cuquantum-python-cu11
状態ベクトルシミュレータcuStateVec
従来型の状態ベクトルシミュレータです。使いやすいです。
from blueqat import Circuit
Circuit(28).h[:].cx[0,1].cx[26,27].run(backend="cusv")
を実行してください。
テンソルネットワークシミュレータcuTensorNet
from blueqat import Circuit
import numpy
N = 10
c = Circuit(N)
#loop1
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(0, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(1, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
#loop2
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(0, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(1, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
#loop3
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(0, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
for i in range(1, N-1, 2):
c.cx[i, i+1]
for i in range(N):
c.ry(np.random.rand())[i]
c.run(backend="cutn")
このような感じで実行すると利用できます。今後はもちょっと簡単にしようと思います。。。
テンソルとテンソルネットワーク
上記のうち、ベクトルと行列が普通の量子計算で使われますがここでは、腕三本以上のテンソルも活用します。
GoogleのTensornetworkツール
テンソルネットワークの計算は実際はツール経由で行います。ここではGoogleからでたTensornetworkをnumpyバックエンドとして使って見たいと思います。
https://github.com/google/TensorNetwork
上記のように腕一本のベクトル同士を計算するとスカラー量になります。
!pip install tensornetwork
そして、
import numpy as np
import tensornetwork as tn
#腕が一本で要素が10このベクトル
a = tn.Node(np.ones((10,)))
#腕が一本で要素が10このベクトル
b = tn.Node(np.ones((10,)))
#二つをつける
edge = a[0] ^ b[0]
#計算する
c = tn.contract(edge)
#答えを得る
print(c.tensor)
10.0
量子回路の場合には、これらを連続して行なってコンパクトにすると答えが出ます。従来手法よりも順番が自由なので、早い順番を探すと従来の方式よりも大規模なものを扱うことができます。
[基礎]テンソルネットワークで量子もつれ回路をCNOT回路の分析
https://blueqat.com/yuichiro_minato2/40ddea8b-fbe6-4e8c-958a-d03d82c1ed39
テンソルネットワークと深層学習
テンソルネットワークを上記のように量子計算に応用するだけでなく、SVDなどでテンソルの軽量化を通じてパラメータ圧縮ができます。
Speeding up neural networks using TensorNetwork in Kerasと組み合わせてできるそうです。やってみたい。例題動かすだけで申し訳ないですが、 https://blog.tensorflow.org/2020/02/speeding-up-neural-networks-using-tensornetwork-in-keras.html を見てみます。
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensornetwork as tn
#デフォルトのバックエンドをnumpyからtensorflowに変更
tn.set_default_backend("tensorflow")
次に、ネットワークを作ります。
class TNLayer(tf.keras.layers.Layer):
def __init__(self):
super(TNLayer, self).__init__()
# 各層の変数を決めます。
self.a_var = tf.Variable(tf.random.normal(
shape=(32, 32, 2), stddev=1.0/32.0),
name="a", trainable=True)
self.b_var = tf.Variable(tf.random.normal(shape=(32, 32, 2), stddev=1.0/32.0),
name="b", trainable=True)
self.bias = tf.Variable(tf.zeros(shape=(32, 32)), name="bias", trainable=True)
def call(self, inputs):
# 縮約を定義し、並列計算を可能にする
def f(input_vec, a_var, b_var, bias_var):
# ベクトルの代わりに行列に
input_vec = tf.reshape(input_vec, (32,32))
# ネットワークを決める
a = tn.Node(a\_var)
b = tn.Node(b\_var)
x\_node = tn.Node(input\_vec)
a\[1\] ^ x\_node\[0\]
b\[1\] ^ x\_node\[1\]
a\[2\] ^ b\[2\]
# 行列をaとbに分解
# | |
# a --- b
# \\ /
# x
# 縮約実行
c = a @ x\_node
result = (c @ b).tensor
# バイアスを付加
return result + bias\_var
# バッチ処理に tf.vectorized\_map を利用する
result = tf.vectorized\_map(
lambda vec: f(vec, self.a\_var, self.b\_var, self.bias), inputs)
return tf.nn.relu(tf.reshape(result, (-1, 1024)))
圧縮前のネットワーク
Dense = tf.keras.layers.Dense
fc_model = tf.keras.Sequential(
[
tf.keras.Input(shape=(2,)),
Dense(1024, activation=tf.nn.relu),
Dense(1024, activation=tf.nn.relu),
Dense(1, activation=None)])
fc_model.summary()
パラメータ数は100万前後です。
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 1024) 3072
dense_1 (Dense) (None, 1024) 1049600
dense_2 (Dense) (None, 1) 1025
=================================================================
Total params: 1,053,697
Trainable params: 1,053,697
Non-trainable params: 0
圧縮後は、
tn_model = tf.keras.Sequential(
[
tf.keras.Input(shape=(2,)),
Dense(1024, activation=tf.nn.relu),
# MPSで書き換えた結果
TNLayer(),
Dense(1, activation=None)])
tn_model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_3 (Dense) (None, 1024) 3072
tn_layer (TNLayer) (None, 1024) 5120
dense_4 (Dense) (None, 1) 1025
=================================================================
Total params: 9,217
Trainable params: 9,217
Non-trainable params: 0
1/100になりました。モデルを学習させてみます。
X = np.concatenate([np.random.randn(20, 2) + np.array([3, 3]),
np.random.randn(20, 2) + np.array([-3, -3]),
np.random.randn(20, 2) + np.array([-3, 3]),
np.random.randn(20, 2) + np.array([3, -3]),])
Y = np.concatenate([np.ones((40)), -np.ones((40))])
tn_model.compile(optimizer="adam", loss="mean_squared_error")
tn_model.fit(X, Y, epochs=300, verbose=1)
Plotting code, feel free to ignore.
h = 1.0
x_min, x_max = X[:, 0].min() - 5, X[:, 0].max() + 5
y_min, y_max = X[:, 1].min() - 5, X[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
here "model" is your model's prediction (classification) function
Z = tn_model.predict(np.c_[xx.ravel(), yy.ravel()])
Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z)
plt.axis('off')
Plot also the training points
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired)
Torch.Tensorでの量子計算
最後にpyTorchです。YゲートやZゲートの行列をPyTorchで実装してみて、それを実行します。ansatzはYZで、期待値はZをとっています。アルゴリズムはVQEです。実行するとハミルトニアンの期待値はきちんと-1になっているのがみれます。
import matplotlib.pyplot as plt
import torch.optim as optim
import torch
import numpy as np
%matplotlib inline
x = torch.tensor([1., 0.])
a = torch.tensor([0.2],requires_grad=True)
arr = []
#the first variable is list of paramters.
op = optim.Adam([a],lr=0.05)
for _ in range(100):
y = [[torch.cos(a/2),-torch.sin(a/2)],[torch.sin(a/2),torch.cos(a/2)]]
z = [x[0]*y[0][0]+x[1]*y[0][1],x[0]*y[1][0]+x[1]*y[1][1]]
expt = torch.abs(z\[0\])\*\*2 - torch.abs(z\[1\])\*\*2
arr.append(expt.item()) # Add the item to the arr list
op.zero\_grad()
expt.backward()
op.step()
plt.plot(arr)
plt.show()
このように量子計算や深層学習を行ったり来たりしながら行えるのがテンソルネットワークの特徴です。
インターンの方に紹介いただいた参考資料を貼っておきます。
テンソル分解の基礎と応用(MIRU2022チュートリアル)
https://speakerdeck.com/yokotatsuya/tensorufen-jie-falseji-chu-toying-yong-miru2022tiyutoriaru
Tensor Networks Meet Neural Networks: A Survey