QURI PARTS
QURI PARTSについて
ABCIQ 上では、量子計算ライブラリ QURI Parts をマルチGPUに対応したライブラリが使用可能となっています。 ここでは、cuQuantum Appliance イメージをベースとして QURI Parts を追加インストールして、使用する方法について説明します。
Caution
現在、QURI-PARTS はマルチノードには対応しておりません。
Singularityイメージの作成
NVIDIA NGC(以下「NGC」という)で公開されているcuQuantum ApplianceのDockerイメージからSingularityイメージを作成します。 (現在サポートしているのは、cuQuantum appliance version 24.08 です。)
最初に、コンテナを作成するためのDefinition fileを用意します。(以下、ファイル名の qc は、任意の名前で構いません)
[username@qes01 ~]$ cat qc.def
Bootstrap: docker
From: nvcr.io/nvidia/cuquantum-appliance:24.08-x86_64
%environment
source /etc/bashrc
export CONDA_ENV_NAME=cuquantum-24.08
conda info -e
%post -c /bin/bash
chmod -R o+rX /home/cuquantum
chmod -R o+rX /root
mkdir -p /opt/etc
echo -e "#!/bin/bash\n\n# script to activate the conda environment" > ~/.bashrc \
&& conda init bash \
&& echo -e "\nconda activate cuquantum-24.08" >> ~/.bashrc \
&& conda clean -a \
&& cp ~/.bashrc /etc/bashrc
mkdir -p /opt/src
cd /opt/src
git clone https://github.com/G-QuAT-ABCIQ/quri-parts-cuquantum.git
git init
/bin/bash -rcfile /opt/etc/bashrc -c "pip install -r /opt/src/quri-parts-cuquantum/requirements.txt"
/bin/bash -rcfile /opt/etc/bashrc -c "pip install -e /opt/src/quri-parts-cuquantum/"
次に、インタラクティブジョブを投入し計算ノードにログインし、コンテナを作成します。
[username@qes01 ~]$ qsub -I -W group_list=your_group_name -l rt_QG=1 -l walltime=1:00:00
.
.
[username@qh001 ~]$ SINGULARITY_TMPDIR=$PBS_LOCALDIR singularity build --fakeroot qc.sif qc.def
.
.
INFO: Creating SIF file...
INFO: Build complete: qc.sif
singularity build/pullコマンドは一時ファイルの作成場所として/tmpを使用します。
cuQuantum Applianceは、イメージサイズの大きいコンテナで、計算ノード上でsingularity build/pullする際に/tmpの容量が足りずエラーになる場合があります。
そこで、ローカルスクラッチを使用するようSINGULARITY_TMPDIR環境変数を設定しています。
作成したSingularityイメージqc.sifを利用する方法は以下のとおりです。
[username@hnode001 ~]$ singularity run --nv ./qc.sif
以下のように、cuQuantum Applianceが起動します。
.
.
==========================================================================
=== NVIDIA CUQUANTUM APPLIANCE v24.08 ===
==========================================================================
=== COPYRIGHT © NVIDIA CORPORATION & AFFILIATES. All rights reserved. ===
==========================================================================
WARNING: no nvidia devices were detected
WARNING: gpu functionality will not be available
Singularity>
Sampler の作成・実行
QURI Parts のSampler は量子コンピュータ実機の「測定」に対応するインターフェースであり、量子回路とショット数を受け取り、ショット数分の測定を行ったサンプリング結果を返します。
ここでは、QURI-PARTS のサイトにあるSampler を実行するプログラム例( https://quri-sdk.qunasys.com/docs/tutorials/quri-parts/basics/sampler/ )を変更して、使用するGPUの数に応じて定義された量子回路を transpile して、sampler でサンプリングするように変更してみます。
サイトの例では、4 qubit の量子回路を定義し、バックエンドとして QULACS を使用してサンプリングを行っていますが、cuQuantum の状態ヘクトルシュミレータを用いてサンプリングを行うPython スクリプトに変更する例を示します。
下記の Python スクリプトを sampling.py というファイル名で保存します。(回路の定義までは、サイトの例と同じです)
python スクリプト内の、n_global_qubits=2 、つまり 2の2乗=4 個の GPU を用いて、回路をtranspile したのち、sampler を実行しています。 ( n_global_qubits=1 で 2GPU を使用、n_global_qubits=0 で 1GPU を使用することになります。)
# sampling.py
from math import pi
from quri_parts.circuit import QuantumCircuit
from quri_parts.circuit.utils.circuit_drawer import draw_circuit
# A circuit with 4 qubits
circuit = QuantumCircuit(4)
circuit.add_X_gate(0)
circuit.add_H_gate(1)
circuit.add_Y_gate(2)
circuit.add_CNOT_gate(1, 2)
circuit.add_RX_gate(3, pi/4)
print("original circuit")
draw_circuit( circuit )
import time
from quri_parts.core.state import ComputationalBasisState
from quri_parts.qulacs.simulator import evaluate_state_to_vector
from quri_parts.circuit import QuantumCircuit
from quri_parts.circuit.utils.circuit_drawer import draw_circuit
from quri_parts.qulacs.sampler import create_qulacs_vector_sampler
from quri_parts.circuit.transpile import (
CircuitTranspiler,
ParallelDecomposer,
PauliDecomposeTranspiler,
PauliRotationDecomposeTranspiler,
SequentialTranspiler,
)
from quri_parts.cuquantum.custatevec.transpiler import MultiGPUReorderingTranspiler
from quri_parts.cuquantum.custatevec.sampler import (
create_cuquantum_vector_sampler,
)
import seaborn as sns
import matplotlib.pyplot as plt
import pdb
# number of GPU = n_global_qbits **2, below means we will use 4 GPU
n_global_qubits = 2
n_qubits = circuit.qubit_count
n_local_qubits = n_qubits - n_global_qubits
transpiler = SequentialTranspiler([
ParallelDecomposer([PauliDecomposeTranspiler(), PauliRotationDecomposeTranspiler()]),
MultiGPUReorderingTranspiler(n_local_qubits)
])
sampler = create_cuquantum_vector_sampler(precision="complex64", n_global_qubits=n_global_qubits, transpiler=(lambda a: a))
transpiled = transpiler(circuit)
sampling_result = sampler(transpiled, shots=1000)
print("")
print("transpiled circuit")
draw_circuit( transpiled )
print("sampling result")
print(sampling_result)
バッチジョブの実行
バッチスクリプト job.sh (名前は任意)を用意し、ジョブを投入します。
[username@es1 ~]$ cat job.sh
#PBS -l rt_QF=1
#PBS -l walltime=1:00:00
#PBS -W group_list=your_group_name
cd ${Your_working_directory}
singularity exec --nv ./qc.sif python3 sampling.py
結果は以下の通りです。
original circuit
___
| X |
--|0 |---------
|___|
___
| H |
--|1 |-----●---
|___| |
___ _|_
| Y | |CX |
--|2 |---|3 |-
|___| |___|
___
|RX |
--|4 |---------
|___|
transpiled circuit
___ ___ ___ ___
| X | 2 | Y | |CX | 5 |RX | 7
--|0 |-----x-----|3 |---|4 |-----x-----|6 |-----x-----------
|___| | |___| |___| | |___| |
___ | | | |
| H | | | | |
--|1 |-----|---------------●-------|---------------|-----------
|___| | | |
| | |
| | | 8
------------x-----------------------|---------------x-------x---
| |
| |
| |
------------------------------------x-----------------------x---
sampling result
Counter({5: 430, 3: 423, 11: 85, 13: 62})
defaultdict(<class 'int'>, {3: 423, 11: 85, 13: 62, 5: 430})
参考
QURISDK QURI Parts Basics Sampler https://quri-sdk.qunasys.com/docs/tutorials/quri-parts/basics/sampler/