Run GPU Qiskit on IBM Power

Jan. 5, 2020, 4:41 a.m. edited Jan. 5, 2020, 5:26 a.m.

#Qiskit  #Python 

This is memo. これはメモ.

Final structure 最終的な構成

  • Client-server model. Server is docker container on IBM Power with GPU. Client is docker container on IBM Power without GPU.
  • クライアント-サーバモデルとなる.サーバはIBM Power上でGPUありのdockerコンテナ.クライアントはIBM Power上でGPUなしのdockerコンテナ(nginxとかでリバースプロキシすればクライアントは外に出せるかも).

Method 手順

Server サーバ

  1. Run docker container with GPU. Like below command.
    GPUが使えるdockerコンテナを立ち上げる.例えばこんなコマンド.
    docker run -it -d -e NVIDIA_VISIBLE_DEVICES=all --name server_qiskit -p 8080:80 nvidia/cuda-ppc64le /bin/bash
  2. docker exec -it server_qiskit bash
  3. apt update apt upgrade apt install python3 python3-pip git
  4. Install Advance Toolchain. Read https://developer.ibm.com/linuxonpower/advance-toolchain/advtool-installation/. However, this maybe failed by kernel is too old (but no problem???).
  5. apt install cmake apt install build-essential apt install libopenblas-dev
  6. git clone https://github.com/doichanj/qiskit-aer mkdir out cd out cmake .. make However, this would failed, so fix the source code.
...
/* Around line:110 */
template <typename T>
void add_metadata(const std::string &key, T &&data);
void add_metadata_json(const std::string &key, json_t &&data); // add
void add_metadata_json(const std::string &key, const json_t &data); // add
...
/* Around line:784 */
template <typename T>
void ExperimentData::add_metadata(const std::string &key, T &&data) {
  // Use implicit to_json conversion function for T
  json_t jdata = data;
  add_metadata_json(key, std::move(jdata)); // fix like it
}

void ExperimentData::add_metadata_json(const std::string &key, json_t &&data) { // fix like it
//template <>
//void ExperimentData::add_metadata(const std::string &key, json_t &&data) {
  auto elt = metadata_.find("key");
  if (elt == metadata_.end()) {
    // If key doesn't already exist add new data
    metadata_[key] = std::move(data);
  } else {
    // If key already exists append with additional data
    elt->second.update(data.begin(), data.end());
  }
}

void ExperimentData::add_metadata_json(const std::string &key, const json_t &data) { // fix like it
//template <>
//void ExperimentData::add_metadata(const std::string &key, const json_t &data) {
  auto elt = metadata_.find("key");
  if (elt == metadata_.end()) {
    // If key doesn't already exist add new data
    metadata_[key] = data;
  } else {
    // If key already exists append with additional data
    elt->second.update(data.begin(), data.end());
  }
}
...
/* Around line:49 */
template <typename T>
void add_metadata(const std::string &key, T &&data);
void add_metadata_json(const std::string &key, json_t &&meta); // add
void add_metadata_json(const std::string &key, const json_t &meta); // add
...
/* Around line:62 */
template <typename T>
void ExperimentResult::add_metadata(const std::string &key, T &&meta) {
  // Use implicit to_json conversion function for T
  json_t jdata = meta;
  add_metadata_json(key, std::move(jdata)); // fix like it
}

void ExperimentResult::add_metadata_json(const std::string &key, json_t &&meta) { // fix like it
//template <>
//void ExperimentResult::add_metadata(const std::string &key, json_t &&meta) {
  auto elt = metadata.find("key");
  if (elt == metadata.end()) {
    // If key doesn't already exist add new data
    metadata[key] = std::move(meta);
  } else {
    // If key already exists append with additional data
    elt->second.update(meta.begin(), meta.end());
  }
}

void ExperimentResult::add_metadata_json(const std::string &key, const json_t &meta) { // fix like it
//template <>
//void ExperimentResult::add_metadata(const std::string &key, const json_t &meta) {
  auto elt = metadata.find("key");
  if (elt == metadata.end()) {
    // If key doesn't already exist add new data
    metadata[key] = meta;
  } else {
    // If key already exists append with additional data
    elt->second.update(meta.begin(), meta.end());
  }
}
  1. make mkdir /server-qiskit cd /server-qiskit git clone https://github.com/hitomitak/qiskit-aer cd qiskit-aer git checkout distribute cd server pip install flask cp /qiskit-aer/out/Release/qasm_simulator . Set port 80 in server.ini.
  2. python3 server.py Ctrl-p&Ctrl-q

Client クライアント

  1. docker run -it -d --link server-qiskit:server-qiskit --name client-qiskit python:3.7 /bin/bash docker exec -it client-qiskit bash
  2. apt update apt upgrade apt install git cmake lib
  3. git clone https://github.com/hitomitak/qiskit-aer cd qiskit-aer git checkout distribute apt install build-essential apt install libopenblas-dev apt install gfortran pip install pybind11 Install suitesparce and move headers like cp /usr/include/suitesparse/* /usr/include/..
  4. pip install qiskit-terra pip install qiskit-ibmq-provider pip install -r requirements-dev.txt python ./setup.py bdist_wheel cd dist pip install *.whl
  5. Fix library source code in /usr/local/lib/python3.7/site-packages/qiskit/providers/aer/backends/remote_node.py:113 from qasm_simulator into remote_qasm_simulator.
  6. Make client program.
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, Aer, execute

qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
qc = QuantumCircuit(qubits, clbits)
qc.h(qubits[0])
qc.measure(qubits, clbits)

bkend = Aer.get_backend("remote_simulator", http_hosts=["http://server-qiskit:80"])
job = execute(qc, backend=bkend, shots=1024, run_config={"GPU": True})
result = job.result()
count = result.get_counts()
print(count)
  1. python prog.py Then, if you succeed, you can get like {'00': 507, '01': 517}.

Other 他の方法

https://github.com/qiskit-community/qiskit-qcgpu-providerを頑張ってGoogle Colabとかで動かすのもありかもしれない(私は無理だった.とりあえずGitHubのコミット履歴見た感じqiskit==0.7.0は必要そうだけどまだエラー出た)