Nobisuke
Dekisugi
RAG
Privacy policy
前回 バレンプラトー — 論文サーベイと簡単な検証 という記事で、blueqat
+ cuQuantum
(cuStateVec) を Google Colab 上で使ったサンプルを記述しましたが、ひょっとしたら需要があったのかな?ということで、Qiskit Aer
+ cuQuantum
について触れたいと思います。なお、qsim
の場合も似たような感じです。手順は
です。なお、以下の手順は WSL2 で cuQuantum (1) を大いに参考にした上で、実際に Colab 上で試して良さそうなやり方を探した内容になります。同記事は WSL2 用ということになっていますので、Windows 上で試したい方は参考になるかもしれません。
以下では Colab 上で試します。順に説明していますが、これを都度実行するのは面倒くさいので一括処理するシェルスクリプトを最後にご案内します。
色々試した結果以下のようになりましたが、多分不要なやつも混じっています。あまり精査できていません。
Copy %%bash sudo apt install -y build-essential libopenblas-dev && cmake && pip install pybind11 pluginbase patch-ng node-semver bottle PyJWT fasteners distro colorama conan
これは、cuQuantum SDK が対応している CUDA のバージョンが 11.x らしいのでそれに従います。今回は 11.2 を使ってみます。基本的には CUDA Toolkit 11.2 Downloads に従うだけです。Colab の OS は Ubuntu 18.04 なので、Linux - x86_64 - Ubuntu - 18.04 を選択します。「Installer Type」は幾つかあるのですが「runfile (local)」を使います。「deb (local)」を試したところ、「CUDA 12」関連のファイルを見に行っている部分があるようでセットアップに難航したので、全部入りのファイルをダウンロードしてセットアップします。
公式の手順のままだと一緒にドライバもインストールしようとするのですが、Colab 上に既にドライバが入っているため警告が出ます。従って、ドライバは入れないように指示します:
Copy %%bash wget https://developer.download.nvidia.com/compute/cuda/11.2.0/local_installers/cuda_11.2.0_460.27.04_linux.run sudo sh cuda_11.2.0_460.27.04_linux.run --toolkit --silent --override
こちらも cuQuantum SDK に従うだけです。Linux - x86_64 - Ubuntu - 18.04 を選択します。「Installer Type」は「deb (local)」を使います。試していないですが、たぶんどちらでも良いと思います。
Copy %%bash export PATH=/usr/local/cuda-11.2/bin${PATH:+:${PATH} } wget https://developer.download.nvidia.com/compute/cuquantum/22.11.0/local_installers/cuquantum-local-repo-ubuntu1804-22.11.0_1.0-1_amd64.deb sudo dpkg -i cuquantum-local-repo-ubuntu1804-22.11.0_1.0-1_amd64.deb sudo cp /var/cuquantum-local-repo-ubuntu1804-22.11.0/cuquantum-*-keyring.gpg /usr/share/keyrings/ sudo apt-get update sudo apt-get -y install cuquantum cuquantum-dev cuquantum-doc
ここまで来ると基本的には難所はないので、後は量子 SDK をビルドするだけです。ここでは Qiskit Aer のみ説明します。具体的な内容は CONTRIBUTING.md に書いてありますが、Colab 上でそのまま実行する場合、適切にパスを通すなどしてあげないと、ランタイム再起動後に cuQuantum の共有ライブラリを見つけられなかったりします。今回は静的リンクをして逃げます。
以下では Qiskit をフルにインストールして、Aer だけアンインストールして差し替えます。
Copy %%bash export PATH=/usr/local/cuda-11.2/bin${PATH:+:${PATH} } export CUQUANTUM_DIR=/opt/nvidia/cuquantum export LD_LIBRARY_PATH=$CUQUANTUM_DIR/lib:$LD_LIBRARY_PATH pip install "qiskit[all]" pip uninstall -y qiskit-aer git clone https://github.com/Qiskit/qiskit-aer/ cd qiskit-aer git checkout 0.11.2 python setup.py bdist_wheel -- -DAER_THRUST_BACKEND=CUDA -DCUSTATEVEC_ROOT=$CUQUANTUM_DIR -DCUSTATEVEC_STATIC=True
以上です。スムーズに実行できても概ね 10 分程度かかります。
実際にはこのような事を毎回やるのは手間なので、シェルスクリプト化しています。
Copy ! curl -sL https://raw.githubusercontent.com/derwind/cuquantum_on_colab/cuquantum-22.11.0/install_qiskit-aer-gpu.bash -o install_qiskit-aer-gpu.bash ! bash install_qiskit-aer-gpu.bash
冒頭で参考にさせていただいた WSL2 で cuQuantum (1) のサンプルコードを拝借して動作検証をしてみたいと思います。Colab 環境でも 29 量子ビットのシミュレーションはできますのでそれで試してみます。
Copy from qiskit import * from qiskit.circuit.library import * from qiskit_aer import * def experiment(qubits=29, device='CPU', cuStateVec_enable=False): sim = AerSimulator(method='statevector', device=device, cuStateVec_enable=cuStateVec_enable) qubits = qubits depth=10 shots = 10 circuit = QuantumVolume(qubits, depth, seed=0) circuit.measure_all() circuit = transpile(circuit, sim) result = sim.run(circuit,sim,shots=shots,seed_simulator=12345).result() print(result) metadata = result.to_dict()['results'][0]['metadata'] if 'cuStateVec_enable' in metadata and metadata['cuStateVec_enable']: print("cuStateVector is used for the simulation") else: print("cuStateVector is not used for the simulation") print("{0} qubits, Time = {1} sec".format(qubits,result.to_dict()['results'][0]['time_taken'])) counts = result.get_counts() print(counts)
以下になります。
Copy %%time experiment(device='CPU')
数回試したことがありますが、10〜20 分かかります。
もともと Qiskit の GPU 実装があるのでそれを試してみます。
Copy %%time experiment(device='GPU')
Copy Result(backend_name='aer_simulator_statevector_gpu', backend_version='0.11.2', qobj_id='ad1bd890-6ca3-4656-98e2-688670f2741a', job_id='7e3fff43-2b87-464d-a02e-502f0f1a6c13', success=True, results=[ExperimentResult(shots=10, success=True, meas_level=2, data=ExperimentResultData(counts={'0xcd34a5e': 1, '0x11f48d98': 1, '0xf0d1544': 1, '0x67ae152': 1, '0xb6ae624': 1, '0xe55747': 1, '0x15f39fff': 1, '0x15f76ce5': 1, '0x1268d390': 1, '0x67f1e4c': 1}), header=QobjExperimentHeader(clbit_labels=[['meas', 0], ['meas', 1], ['meas', 2], ['meas', 3], ['meas', 4], ['meas', 5], ['meas', 6], ['meas', 7], ['meas', 8], ['meas', 9], ['meas', 10], ['meas', 11], ['meas', 12], ['meas', 13], ['meas', 14], ['meas', 15], ['meas', 16], ['meas', 17], ['meas', 18], ['meas', 19], ['meas', 20], ['meas', 21], ['meas', 22], ['meas', 23], ['meas', 24], ['meas', 25], ['meas', 26], ['meas', 27], ['meas', 28]], creg_sizes=[['meas', 29]], global_phase=0.0, memory_slots=29, metadata={}, n_qubits=29, name='quantum_volume_[29,10,0]', qreg_sizes=[['q', 29]], qubit_labels=[['q', 0], ['q', 1], ['q', 2], ['q', 3], ['q', 4], ['q', 5], ['q', 6], ['q', 7], ['q', 8], ['q', 9], ['q', 10], ['q', 11], ['q', 12], ['q', 13], ['q', 14], ['q', 15], ['q', 16], ['q', 17], ['q', 18], ['q', 19], ['q', 20], ['q', 21], ['q', 22], ['q', 23], ['q', 24], ['q', 25], ['q', 26], ['q', 27], ['q', 28]]), status=DONE, seed_simulator=12345, metadata={'parallel_state_update': 2, 'sample_measure_time': 0.079424362, 'noise': 'ideal', 'batched_shots_optimization': False, 'measure_sampling': True, 'device': 'GPU', 'num_qubits': 29, 'parallel_shots': 1, 'cuStateVec_enable': False, 'remapped_qubits': False, 'method': 'statevector', 'active_input_qubits': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], 'num_clbits': 29, 'input_qubit_map': [[28, 28], [27, 27], [26, 26], [25, 25], [24, 24], [23, 23], [22, 22], [21, 21], [20, 20], [19, 19], [18, 18], [17, 17], [16, 16], [5, 5], [4, 4], [3, 3], [2, 2], [0, 0], [1, 1], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15]], 'fusion': {'time_taken': 0.001292759, 'applied': True, 'threshold': 14, 'max_fused_qubits': 5, 'method': 'unitary', 'parallelization': 1, 'enabled': True, 'cost_factor': 1.8}}, time_taken=18.157103944)], date=2023-01-05T13:25:55.767014, status=COMPLETED, header=QobjHeader(backend_name='aer_simulator_statevector_gpu', backend_version='0.11.2'), metadata={'time_taken': 18.158615785, 'time_taken_execute': 18.157172632, 'mpi_rank': 0, 'parallel_experiments': 1, 'omp_enabled': True, 'max_gpu_memory_mb': 15109, 'num_processes_per_experiments': 1, 'num_mpi_processes': 1, 'time_taken_load_qobj': 0.001395827, 'max_memory_mb': 12985}, time_taken=18.160932064056396) cuStateVector is not used for the simulation 29 qubits, Time = 18.157103944 sec {'01100110100110100101001011110': 1, '10001111101001000110110011000': 1, '01111000011010001010101000100': 1, '00110011110101110000101010010': 1, '01011011010101110011000100100': 1, '00000111001010101011101000111': 1, '10101111100111001111111111111': 1, '10101111101110110110011100101': 1, '10010011010001101001110010000': 1, '00110011111110001111001001100': 1} CPU times: user 18.2 s, sys: 65 ms, total: 18.3 s Wall time: 18.3 s
概ね 18 秒前後の事が多かったです。最後に cuQuantum (cuStateVec) をみます。
Copy %%time experiment(device='GPU', cuStateVec_enable=True)
Copy Result(backend_name='aer_simulator_statevector_gpu', backend_version='0.11.2', qobj_id='cc0b71d8-22b1-4d68-9850-43de436bcbc2', job_id='01100a93-ab53-4feb-a25f-c0ea1f410219', success=True, results=[ExperimentResult(shots=10, success=True, meas_level=2, data=ExperimentResultData(counts={'0xcd34a5e': 1, '0x11f48d98': 1, '0xf0d1544': 1, '0x67ae152': 1, '0xb6ae624': 1, '0xe55747': 1, '0x15f39fff': 1, '0x15f76ce5': 1, '0x1268d390': 1, '0x67f1e4c': 1}), header=QobjExperimentHeader(clbit_labels=[['meas', 0], ['meas', 1], ['meas', 2], ['meas', 3], ['meas', 4], ['meas', 5], ['meas', 6], ['meas', 7], ['meas', 8], ['meas', 9], ['meas', 10], ['meas', 11], ['meas', 12], ['meas', 13], ['meas', 14], ['meas', 15], ['meas', 16], ['meas', 17], ['meas', 18], ['meas', 19], ['meas', 20], ['meas', 21], ['meas', 22], ['meas', 23], ['meas', 24], ['meas', 25], ['meas', 26], ['meas', 27], ['meas', 28]], creg_sizes=[['meas', 29]], global_phase=0.0, memory_slots=29, metadata={}, n_qubits=29, name='quantum_volume_[29,10,0]', qreg_sizes=[['q', 29]], qubit_labels=[['q', 0], ['q', 1], ['q', 2], ['q', 3], ['q', 4], ['q', 5], ['q', 6], ['q', 7], ['q', 8], ['q', 9], ['q', 10], ['q', 11], ['q', 12], ['q', 13], ['q', 14], ['q', 15], ['q', 16], ['q', 17], ['q', 18], ['q', 19], ['q', 20], ['q', 21], ['q', 22], ['q', 23], ['q', 24], ['q', 25], ['q', 26], ['q', 27], ['q', 28]]), status=DONE, seed_simulator=12345, metadata={'parallel_state_update': 1, 'sample_measure_time': 0.047699654, 'noise': 'ideal', 'batched_shots_optimization': False, 'measure_sampling': True, 'device': 'GPU', 'num_qubits': 29, 'parallel_shots': 1, 'cuStateVec_enable': True, 'remapped_qubits': False, 'method': 'statevector', 'active_input_qubits': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28], 'num_clbits': 29, 'input_qubit_map': [[28, 28], [27, 27], [26, 26], [25, 25], [24, 24], [23, 23], [22, 22], [21, 21], [20, 20], [19, 19], [18, 18], [17, 17], [16, 16], [5, 5], [4, 4], [3, 3], [2, 2], [0, 0], [1, 1], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15]], 'fusion': {'time_taken': 0.001080673, 'applied': True, 'threshold': 14, 'max_fused_qubits': 5, 'method': 'unitary', 'parallelization': 1, 'enabled': True, 'cost_factor': 1.8}}, time_taken=11.055874399)], date=2023-01-05T12:45:21.744463, status=COMPLETED, header=QobjHeader(backend_name='aer_simulator_statevector_gpu', backend_version='0.11.2'), metadata={'time_taken': 11.056874077, 'time_taken_execute': 11.055901886, 'mpi_rank': 0, 'parallel_experiments': 1, 'omp_enabled': True, 'max_gpu_memory_mb': 15109, 'num_processes_per_experiments': 1, 'num_mpi_processes': 1, 'time_taken_load_qobj': 0.000960355, 'max_memory_mb': 12985}, time_taken=11.058109521865845) cuStateVector is used for the simulation 29 qubits, Time = 11.055874399 sec {'01100110100110100101001011110': 1, '10001111101001000110110011000': 1, '01111000011010001010101000100': 1, '00110011110101110000101010010': 1, '01011011010101110011000100100': 1, '00000111001010101011101000111': 1, '10101111100111001111111111111': 1, '10101111101110110110011100101': 1, '10010011010001101001110010000': 1, '00110011111110001111001001100': 1} CPU times: user 11.1 s, sys: 65.5 ms, total: 11.1 s Wall time: 11.3 s
多少結果にばらつきが出た事もありますが、概ね 11 秒前後のようです。20 秒を超えた事もあったのですがよく分かりません。いずれにせよ CPU とは比較にならない速度です。
駆け足で、Qiskit Aer の cuQuantum 対応版をビルドして走らせてみました。Qiskit と blueqat はベーシックな回路であれば「OpenQASM 2.0」の言葉を介して相互に回路を変換できるはずなので、色々比較してみると面白いかもしれません。
今回 qsim については触れていませんが、CUDA + cuQuantum のインストールを済ませた後は、GPU-based quantum simulation on Google Cloud の通りに、リポジトリを clone して make するだけでいけたと思います。是非試してみてください。
© 2024, blueqat Inc. All rights reserved