common.title
Cloud support

Nobisuke

Dekisugi

RAG


autoQAOA
RAG for dev
Fortune telling app
Annealing
DEEPSCORE
Translation

Overview
Service overview
Terms of service

Privacy policy

Contact
Research

Sign in
Sign up
common.title

PyTorchだけで量子計算!

Yuichiro Minato

2024/01/08 13:25

!pip --no-cache-dir install -U torch
Requirement already satisfied: torch in /opt/conda/lib/python3.10/site-packages (2.1.2)

Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch) (3.13.1)

Requirement already satisfied: typing-extensions in /opt/conda/lib/python3.10/site-packages (from torch) (4.5.0)

Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch) (1.12)

Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch) (3.2.1)

Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch) (3.1.2)

Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch) (2023.5.0)

Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch) (12.1.105)

Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch) (12.1.105)

Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch) (12.1.105)

あんまり詳しくは書かないのですが、PyTorchを使って量子計算や機械学習を進めます。 まずは簡単な量子回路を書いてみますが、基本的には、

    • 量子ビット
    • 量子ゲート
    • 測定
    • 期待値を取るときのハミルトニアン

などあたりで表現が多少これまでの手法と異なります。

説明のためにはこれまでのような量子回路描画用のツールよりも単純にNetworkXのようなものを使ってみます。

import matplotlib.pyplot as plt import networkx as nx import numpy as np G = nx.Graph() nx.add_path(G, ["q0", "H", "C", "M0"]) nx.add_path(G, ["q1", "X", "M1"]) nx.add_path(G, ["C", "X"]) pos = {"q0":[0, 0], "H":[1, 0], "C":[2, 0], "M0":[3, 0], "q1":[0, -1], "X":[2, -1], "M1":[3, -1]} nx.draw(G, pos, with_labels = True) plt.show()
<Figure size 640x480 with 1 Axes>output

q0とq1が量子ビットに対応し、通常は状態ベクトルが個別に|0> = [1,0] として与えられます。

Hゲートは量子ゲートなのでユニタリ行列が。CXゲートに関しては、NetworkX上ではCとXが分離していますが、通常は腕が2本、ノードが点1つの行列になっているはずですが、今回はノードが2つ、それぞれのノードに対して腕が3本ずつになっています。測定もM0とM1でノードが割り振られています。

以前でもどこかで記事を書いた気がしますが、また最初からやってみます。

import torch.optim as optim import torch import numpy as np

q0は|0>なので、 同様に q1も設定します。

q0 = torch.tensor([1.,0]) q1 = torch.tensor([1,0])

次にHゲートです。こちらは行列ですので、素直に行列で実装します。

H = torch.tensor([[1.,1],[1,-1]])/np.sqrt(2)

試しにq0とHを計算するには、q0とHを行列演算すればいいのでした。

M0= torch.matmul(q0,H)
print(M0)
tensor([0.7071, 0.7071])

無事状態ベクトルが取れましたね。

続いてeinsumでも計算してみたいと思います。基本的には同じことなのですが、うまくいきました。

M0 = torch.einsum("a,ab->b", (q0, H)) print(M0)
tensor([0.7071, 0.7071])

おそらくeinsumで計算した方が簡単そうですね。 後ほど変分回路での計算もしてみたいので、勾配情報を含んで量子計算できるかみてみます。 勾配を持たせるには状態ベクトルや量子ゲートをfloatで書き直す必要がありました。

q0 = torch.tensor([1.,0.]) H = torch.tensor([[1.,1],[1,-1]],requires_grad=True)/np.sqrt(2)

計算してみます。

M0 = torch.einsum("a,ab->b", (q0, H)) print(M0)
tensor([0.7071, 0.7071], grad_fn=<ViewBackward0>)

今度はベル状態を作ってみます。 量子ビットを二つとHゲート、CXゲートを準備します。

q0 = torch.tensor([1.,0]) q1 = torch.tensor([1.,0]) H = torch.tensor([[1.,1],[1,-1]])/np.sqrt(2) CX = torch.tensor([[1.,0,0,0],[0,1,0,0],[0,0,0,1],[0,0,1,0]])

試しにちょっとずつ計算してみます。まずは、q0にHゲートをかけてみます。

res1 = torch.einsum("a,ab->b", (q0,H)) print(res1)
tensor([0.7071, 0.7071])

次にこの量子状態とq1をCXに入れてみます。ただ、CXはこのまま使うのではなく、テンソルに変形します。行列からテンソルにします。

CX_four = CX.reshape([2,2,2,2]) print(CX_four)
tensor([[[[1., 0.],

          [0., 0.]],



         [[0., 1.],

          [0., 0.]]],





        [[[0., 0.],

          [0., 1.]],


これでorder-4のテンソルになりました。計算をしてみます。

res2 = torch.einsum("a,b,abcd->cd", (res1, q1, CX_four)).reshape(4) print(res2)
tensor([0.7071, 0.0000, 0.0000, 0.7071])

どうでしょうか、ベル状態ができました。簡単ですね。 もちろんまとめてやっても大丈夫です。

res2 = torch.einsum("a,ab,c,bcde->de", (q0, H, q1, CX_four)).reshape(4) print(res2)
tensor([0.7071, 0.0000, 0.0000, 0.7071])

できました。

せっかくなので量子古典の変分計算もしてみたいと思います。今回はHの代わりにRY(なるべく複素数を使いたくないので、、、)を置いてみて、変分アルゴで|11>を作ってみます。

|11>の判定として、ハミルトニアンの期待値を使ってみたいと思います。Z0+Z1の値が-2になるように学習をしたいと思います。今回は期待値を求めたいので、Zを配置したテンソルを準備します。Z0の期待値を図に書いてみると、

G = nx.Graph() nx.add_path(G, [0,1,2,3,4,5,6]) nx.add_path(G, [7,8,10,11]) nx.add_path(G, [2,8]) nx.add_path(G, [4,10]) pos = {0:[0, 0], 1:[1, 0], 2:[2, 0], 3:[3, 0], 4:[4, 0], 5:[5, 0], 6:[6, 0], 7:[0, -1], 8:[2, -1], 10:[4, -1], 11:[6, -1], } nx.draw(G, pos) plt.show()
<Figure size 640x480 with 1 Axes>output

同様に<psi|Z0+Z1|psi>を求めれば良いことになります。

#パラメータをランダム初期化 a = torch.tensor([np.random.rand()],requires_grad=True) #最適化アルゴリズムを見つけてパラメータを最適化します op = optim.Adam([a],lr=0.05) #量子ビットを準備 q0 = torch.tensor([1.,0]) q1 = torch.tensor([1.,0]) #期待値測定用のZを準備します Z = torch.tensor([[1.,0],[0,-1]]) #計算結果格納用のリスト arr = [] #最適化ループを回します for _ in range(100): #RYゲートですが、aをうまく使って勾配を失わないようにpytorchの関数を使います。 RY = torch.tensor([[1,0],[0,1]])*torch.cos(a/2) + torch.tensor([[0,-1],[-1,0]])*torch.sin(a/2) #途中までテンソルの計算を終わらせておきます。 net1 = torch.einsum("a,ab,c,bcde->de", (q0, RY, q1, CX_four)) net2 = torch.einsum("a,ab,c,bcde->de", (q0, RY, q1, CX_four)) #Z0とZ1の期待値をそれぞれ求めてたし合わせます。期待値が-2になれば両方のビットは1になるはず。 expt = torch.einsum("ab,cb,ac->", (net1, net2, Z)) + torch.einsum("ab,ad,bd->", (net1, net2, Z)) #期待値をリストに格納 arr.append(expt.detach().numpy()) #最適化 op.zero_grad() expt.backward() op.step() #描画 plt.plot(arr) plt.show()
<Figure size 640x480 with 1 Axes>output

PyTorchでVQEができました。aのパラメータが最適化されているかどうかみます。

print(a)
tensor([3.1281], requires_grad=True)

ほぼ3.14になっていて、RYで量子ビットが1に。その後CXで両方1に。|11>が実現できました。 PyTorchの機能だけで量子計算ができました。GPUなどの活用だけでなく、シームレスに古典NNと統合できますね!以上です。

© 2024, blueqat Inc. All rights reserved