こんにちは。GPUを使った量子コンピューティングの中でもcuQuantumは少し特殊です。複数のGPUやマシンを使う場合にはcuQuantum Applianceと言うものをインストール必要があります。今回少し質問をもらいましたので、いつもはcuStateVecの方を行っていましたが、今回はcuTensorNetの方をフォローしたいと思います。
マルチGPU / マルチノード版cuQuantum
https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuquantum-appliance
cuStateVecは伝統的な状態ベクトルシミュレータで王道です。一方cuTensorNetは開発中の新型シミュレータです。
cuTensorNetはテンソルネットワークと呼ばれる手法で実装されたシミュレータです。Google CirqやIBM Qiskitなどの量子回路を一度テンソルネットワーク方式に変換し、それをcuTensorNetに入力することで計算がされます。
コードはこちらを利用します。
NVIDIA cuQuantum / cuTensorNet + Google Cirq で状態ベクトルの求め方
https://blueqat.com/yuichiro_minato2/9907c9bb-f337-453a-86f3-173d5db5f78f
cuStateVecはQiskitやCirq内部から呼び出して使いますが、cuTensorNetは普通は一度量子回路を変換してcuTensorNetで計算します。
import cirq
from cirq.testing import random_circuit
import cupy as cp
import numpy as np
from cuquantum import contract, CircuitToEinsum
num_qubits = 10
n_moments = 6
op_density = 0.9
gate_domain = {cirq.H: 1,
cirq.S: 1,
cirq.T: 1,
cirq.CNOT: 2,
cirq.CZ: 2}
circuit = random_circuit(num_qubits, n_moments, op_density=op_density, gate_domain=gate_domain, random_state=6)
print(circuit)
myconverter = CircuitToEinsum(circuit, dtype='complex128', backend=cp)
expression, operands = myconverter.state_vector()
sv = contract(expression, *operands)
sv.reshape(1, 2**num_qubits)
ランダムサーキットを入れています。CircuitToEinsumというのが変換になります。コンバーターで量子化色を変換したのち、計算を決めます。今回は状態ベクトルを求めてみるので、状態ベクトルようの変換がさらに入ります。量子回路そのままで計算できない場合があるので、目的に応じてそこからさらに量子回路を使って求めたい値が得られるようにグラフを変換するのがcuTensorNetです。
最終的に計算はcontractというところで、expressionとoperandsの組み合わせによって実行されます。縮約という操作をしますが、順番やその縮約に対応する演算子が記述されています。
今回はcuTensorNetのシングルノードマルチGPUでベンチマークをとってみます。
singularity exec --nv cuquantum-appliance.img mpiexec -n 8 python3 tn.py
量子回路は、
┌──┐ ┌───┐ ┌───┐ ┌────┐ ┌──┐ ┌────┐
0: ───────────H───────H────────────────T──────X───────
│
1: ─────@───────@──────@───────@────────@─────┼──@────
│ │ │ │ │ │ │
2: ─────┼───────┼─────T┼───────┼@──────T┼─────┼@─┼────
│ │ │ ││ │ ││ │
3: ────@┼─────X─┼──────┼@──────┼┼@─────T┼─────┼┼@┼────
││ │ │ ││ │││ │ ││││
4: ────┼┼─────┼S┼─────T┼┼─────S┼┼┼─────@┼─────@┼┼┼────
││ │ │ ││ │││ ││ │││
5: ────@┼─────┼T┼──────┼@──────┼┼@─────@┼──────@┼┼────
│ │ │ │ ││ │ ││
6: ────H┼─────@─┼─────X┼──────@┼┼──────T┼─────@─┼┼────
│ │ ││ │││ │ │ ││
7: ────T┼───────@─────┼┼──────┼X┼──────H┼─────┼─┼X────
│ ││ │ │ │ │ │
8: ────H┼─────T───────┼X──────@─┼───────@─────┼─@─────
│ │ │ │
9: ─────@─────────────@─────────@─────────────X───────
└──┘ └───┘ └───┘ └────┘ └──┘ └────┘
速度は、
1GPU - NVIDIA V100 * 1
8並列
0.99s
でした。-n 8というオプションで計算したらよかったのですが、これは並列数はGPU数と対応しているわけではなさそうですよね???
メモリ不足にならない程度に計算しました。
順調に早いですね。
4GPU - NVIDIA V100 * 4
8並列
0.83s
これくらいのサイズだと1GPUでも早いです。もちょい大きさを大きくしてみます。
num_qubits = 20
n_moments = 10
にしてみました。
1GPU - NVIDIA V100 * 1
8並列
1.22s
4GPU - NVIDIA V100 * 4
8並列
1.00s
まぁ、なんというか十分早い気がします。
テンソルネットワークの場合には、量子ビット数だけでなく、深さ方向のパラメータも聞いてきますので、全体の回路のサイズを推定して計算しましょう。以上です。