コンテンツにスキップ

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/