コンテンツにスキップ

cuQuantum Appliance

cuQuantum Applianceについて

NVIDIA cuQuantumは、量子回路シミュレーションをGPUで加速できるソフトウェア開発キットです。 量子回路シミュレーションとしては、IBM Qiskit Aer、Google Cirq qsimに対応しています。

NVIDIA cuQuantum Applianceは、NVIDIA cuQuantumを簡単に利用できるようデプロイ可能なソフトウェアとしてコンテナ化されたもので、複数のGPUと複数のノードを活用して量子回路シミュレーションを実行することができます。

本ドキュメントでは、次の流れに沿ってcuQuantum Applianceの使い方について説明します。

  1. cuQuantum ApplianceをABCIで実行可能なSingularityイメージに変換する。
  2. IBM Qiskit Aerの状態ベクトルシミュレーションをシングルノード・マルチGPUで実行する。
  3. Open MPIを用いて、状態ベクトルシミュレーションをマルチノード・マルチGPUで実行する。

cuQuantum ApplianceをSingularityイメージに変換する

NVIDIA NGC(以下「NGC」という)で公開されているcuQuantum ApplianceのDockerイメージからSingularityイメージを作成します。

最初に、コンテナを作成するためのDefinition fileを用意します。(以下、ファイル名の cuquantum-appliance は、任意の名前で構いません)

[username@qes01 ~]$ cat cuquantum-appliance.def
Bootstrap: docker
From: nvcr.io/nvidia/cuquantum-appliance:24.08-cuda12.2.2-devel-ubuntu22.04-x86_64
%environment
    source /opt/etc/bashrc
    export CONDA_ENV_NAME=cuquantum-24.08
    conda info -e >> /dev/stderr

%post -c /bin/bash
    chmod -R o+rX /home/cuquantum
    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 \
    && echo "echo \"Hello World\" >>/dev/stderr " >>  ~/.bashrc \
    && conda clean -a \
    && cp ~/.bashrc /opt/etc/bashrc

次に、インタラクティブジョブを投入し計算ノードにログインし、コンテナを作成します。

[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 cuquantum-appliance.img cuquantum-appliance.def
.
.
INFO:    Creating SIF file...
INFO:    Build complete: cuquantum-appliance.img

singularity build/pullコマンドは一時ファイルの作成場所として/tmpを使用します。 cuQuantum Applianceは、イメージサイズの大きいコンテナで、計算ノード上でsingularity build/pullする際に/tmpの容量が足りずエラーになる場合があります。 そこで、ローカルスクラッチを使用するようSINGULARITY_TMPDIR環境変数を設定しています。

作成したSingularityイメージcuquantum-appliance.imgを利用する方法は以下のとおりです。

[username@hnode001 ~]$ singularity run --nv ./cuquantum-appliance.img

以下のように、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>

シングルノード・マルチGPUで実行する

バッチジョブでの実行

cuQuantum Applianceのコンテナイメージでは、インストールされているOpen MPIを使用して、マルチGPUでシミュレーションが実行可能です。 また、Google の qsimcirq ではマルチGPUの使用をサポートしています。アプライアンス内のサンプルプログラム(/home/cuquantum/examples/ghz.py)を参照ください。 (割り当てるGPUの数をオプションで指定可能です。)

ここでは、cuQuantum Appliance内に用意されているサンプルプログラム(/home/cuquantum/examples/qiskit_ghz.py)にMPI関連の情報を出力するよう、変更したものを実行してみます。 (ご自分の home direcotry に、"singularity run --nv ./cuquantum-appliance.img" を実行した際に、コピーしてください。)

# Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES
#
# SPDX-License-Identifier: BSD-3-Clause

from qiskit import QuantumCircuit, transpile
from qiskit_aer import Aer
from mpi4py import MPI
import argparse
from socket import gethostname                                      # 追加

def create_ghz_circuit(n_qubits):
    circuit = QuantumCircuit(n_qubits)
    circuit.h(0)
    for qubit in range(n_qubits - 1):
        circuit.cx(qubit, qubit + 1)
    return circuit


def run(n_qubits, precision, use_cusvaer):
    simulator = Aer.get_backend('aer_simulator_statevector')
    simulator.set_option('cusvaer_enable', use_cusvaer)
    simulator.set_option('precision', precision)
    circuit = create_ghz_circuit(n_qubits)
    circuit.measure_all()
    circuit = transpile(circuit, simulator)
    job = simulator.run(circuit)
    result = job.result()

    h=gethostname()                                                 # 追加
    print(f"host: {h}, Result: rank: {result.mpi_rank}, size: {result.num_mpi_processes}")       # 追加

    if MPI.COMM_WORLD.Get_rank() == 0:
        print(f'precision: {precision}')
        print(result.get_counts())
        print(f'backend: {result.backend_name}')


parser = argparse.ArgumentParser(description="Qiskit ghz.")
parser.add_argument('--nbits', type=int, default=20, help='the number of qubits')
parser.add_argument('--precision', type=str, default='single', choices=['single', 'double'], help='numerical precision')
parser.add_argument('--disable-cusvaer', default=False, action='store_true', help='disable cusvaer')

args = parser.parse_args()

run(args.nbits, args.precision, not args.disable_cusvaer)

バッチスクリプトjob.sh(名前は任意)を用意し、ジョブを投入します。

[username@qes01 ~]$ cat job.sh
#!/bin/sh
#PBS -W group_list=your_groupname
#PBS -l rt_QF=1
#PBS -l walltime=00:10:00

module load openmpi/4.1.7
cd /home/your_home_directory/your_work_directory
singularity exec --nv cuquantum-appliance.img mpiexec -np 4 python3 qiskit_ghz.py --nbits 30 --precision double

[username@qes01 ~]$ qsub job.sh

結果は、以下の様に、1ノード上に8プロセスが起動されていることがわかります。

host: qh500, Result: rank: 3, size: 4
host: qh500, Result: rank: 2, size: 4
host: qh500, Result: rank: 1, size: 4
host: qh500, Result: rank: 0, size: 4
precision: double
{'111111111111111111111111111111': 518, '000000000000000000000000000000': 506}
backend: cusvaer_simulator_statevector

マルチノード・マルチGPUで実行する

マルチノードでの実行を行うには、ABCI-Q で提供されている Open MPIを使用して、実行が可能です。

バッチジョブでの実行

シングルノード、マルチGPUで使用したサンプルと同じpython スクリプトを使用し、計算ノード4台を用いたジョブスクリプト job.sh を用意し、ジョブを投入します。 (mpirun のオプション --display-allocationは、確保されたリソースの状況を表示するためのオプションで、なくても構いません。)

[username@qes01 ~]$ cat jobm.sh
#!/bin/sh
#PBS -W group_list=your_group
#PBS -l rt_QF=8:mpiprocs=32
#PBS -l walltime=00:30:00

source /etc/profile.d/modules.sh
module load openmpi/4.1.7
export MPIOPTS="-np 32 -map-by ppr:4:node --mca pml ucx -x UCX_TLS=^cma --mca coll_hcoll_enabel 0 -x OMPI_MCA_coll_hcoll_enable=0 "
export MPIENVS="--env OPAL_PREFIX=/usr/local/mpi --env PMIX_INSTALL_PREFIX=/usr/local/mpi"
export PMIX_MCA_gsd=^ds12

cd /home/your_home_directory/your_work_directory
MPIRUN=`which mpirun`
$MPIRUN -v $MPIOPTS --display-allocation  singularity exec --nv $MPIENVS cuquantum-appliance.img python3 ./qiskit_ghz.py --nbits 20 --precision double

[username@qes01 ~]$ qsub jobm.sh

結果は、以下の様になります。

======================   ALLOCATED NODES   ======================
    qh481: flags=0x11 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh482: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh483: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh484: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh485: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh487: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh488: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
    qh489: flags=0x13 slots=32 max_slots=0 slots_inuse=0 state=UP
=================================================================
host: qh481, Result: rank: 0, size: 32
precision: double
host: qh481, Result: rank: 1, size: 32
{'11111111111111111111': 519, '00000000000000000000': 505}
backend: cusvaer_simulator_statevector
host: qh484, Result: rank: 13, size: 32
host: qh485, Result: rank: 16, size: 32
host: qh483, Result: rank: 11, size: 32
host: qh488, Result: rank: 25, size: 32
host: qh489, Result: rank: 30, size: 32
host: qh482, Result: rank: 4, size: 32
host: qh487, Result: rank: 22, size: 32
host: qh484, Result: rank: 14, size: 32
host: qh485, Result: rank: 17, size: 32
host: qh483, Result: rank: 10, size: 32
host: qh489, Result: rank: 28, size: 32
host: qh482, Result: rank: 5, size: 32
host: qh487, Result: rank: 23, size: 32
host: qh484, Result: rank: 12, size: 32
host: qh483, Result: rank: 9, size: 32
host: qh482, Result: rank: 6, size: 32
host: qh487, Result: rank: 21, size: 32
host: qh485, Result: rank: 19, size: 32
host: qh489, Result: rank: 31, size: 32
host: qh481, Result: rank: 3, size: 32
host: qh488, Result: rank: 27, size: 32
host: qh481, Result: rank: 2, size: 32
host: qh488, Result: rank: 26, size: 32
host: qh489, Result: rank: 29, size: 32
host: qh483, Result: rank: 8, size: 32
host: qh485, Result: rank: 18, size: 32
host: qh487, Result: rank: 20, size: 32
host: qh488, Result: rank: 24, size: 32
host: qh482, Result: rank: 7, size: 32
host: qh484, Result: rank: 15, size: 32

PBS のジョブのリソースとして、"rt_QF=8:mpiprocs=32" を指定し、計算ノードを資源タイプrt_QFで8ノードで起動しています。

mpirun のオプションで、"-np 32 -map-by ppr:4:node" で、プロセス数32、ノード当たり4プロセスを指定しています。

上記の出力から、8ノードが割り当てられ、それぞれに4プロセスづつ割り当てられていることと、それぞれにMPIのランクが割り当てられていることがわかります。

オプションの詳細は、cuQuantum Applianceのドキュメントを参照してください。

参考

  1. NVIDIA cuQuantum Appliance
  2. NVIDIA cuQuantum Appliance で大規模にクラス最高の量子回路シミュレーションを実現