GPU usage for pennylane-qiskit

Dear experts,

I’ve seen that the Qiskit framework allows simulating quantum circuits using GPUs. I was wondering if this is possible also in Pennylane through the pennylane-qiskit plugin.

Thank you very much :slight_smile:

Hi @Davide_Zuliani Thanks for the question.
It is possible to enable the Aer GPU backend, though we currently cannot guarantee it will work across all use-cases.

If you would like to try it out with a supported device and let us know, following https://qiskit.org/documentation/tutorials/simulators/1_aer_provider.html#GPU-Simulation ensure the qiskit-aer-gpu package is installed first. Then we can enable the device with:

dev = qml.device("qiskit.aer", wires=1)
dev.backend.set_options(device='GPU')

Feel free to get in touch if you need any additional assistance. Hope this helps!

Hi @mlxd, thank you for your quick answer :slight_smile:
So I gave it a try but it doesn’t seem to work (the GPU-util is always at 0%).
Here is a simplified version of my code:

import os
import argparse
import qiskit
import pytorch_lightning as pl
import torch.nn as nn
import torch
from torch.functional import F
import pennylane as qml
from data_preprocessing import prepare_data
import torchmetrics
import pandas as pd
import numpy as np

CUDA_VISIBLE_DEVICES=0

#for noise
from qiskit.providers.aer.noise import NoiseModel
from qiskit import IBMQ, Aer

parser = argparse.ArgumentParser()
parser.add_argument("-c", "--city", help="city name for IBM hardware")
args = parser.parse_args()

WantNoise = True


#load ibm account
IBMQ.enable_account('')
provider = IBMQ.get_provider(hub='')
city = args.city

print("hardware selected: ", "ibmq_"+city)
print("possible choices: sydney, toronto, guadalupe, lagos, santiago, manila, bogota, jakarta, quito, belem, lima")


n_qubits = 4
n_QAOA_layers = 1
n_SE_layers = 4

def circuit(inputs,QAOA_weights,SE_weights):
    qml.templates.QAOAEmbedding(inputs,QAOA_weights,wires=range(n_qubits))
    qml.templates.StronglyEntanglingLayers(weights=SE_weights,wires=range(n_qubits))
return qml.expval(qml.PauliZ(0))

class MuonModel(pl.LightningModule):
def __init__(self):
    super().__init__()
    if WantNoise:
        noise_model = NoiseModel.from_backend(provider.get_backend('ibmq_'+city))
        tfdev = qml.device('qiskit.aer',wires=n_qubits,noise_model=noise_model)
        tfdev.backend.set_options(device='GPU')
    else:
        tfdev = qml.device('qiskit.aer',wires=n_qubits)
    
    circ = qml.QNode(circuit,tfdev,interface='torch',diff_method='best')
     
    qlayer = qml.qnn.TorchLayer(circ,{'QAOA_weights': (n_QAOA_layers, 2*n_qubits) , 'SE_weights' : (n_SE_layers,n_qubits,3)})
    self.training_acc = torchmetrics.Accuracy()
    self.validation_acc = torchmetrics.Accuracy()
    self.quantum = qlayer

def forward(self, x):
    return 0.5*(self.quantum(x)+1)
    #return self.output(self.quantum(x))

def training_step(self, batch, batch_idx):
    x, y = batch
    #print(y)
    y_hat = self(x.float())
    #print(y_hat)
    loss = F.mse_loss(y_hat,y.float())
    #print(list(self.parameters()))
     
    return {'loss' : loss, 'preds' : y_hat, 'target' : y}

def training_step_end(self, outputs):
    self.training_acc(outputs['preds'], outputs['target'])
    self.log('train_accuracy', self.training_acc,on_epoch=True,prog_bar=True)
    self.log('train_loss',outputs['loss'],on_epoch=True,sync_dist=True)

    return outputs

def training_epoch_end(self, outputs):
    return None

def validation_step(self, batch, batch_idx):
    x, y = batch
    #print(y)
    y_hat = self(x.float())
    #print(y_hat)
    loss = F.mse_loss(y_hat,y.float())
    #print(list(self.parameters()))
     
    return {'loss' : loss, 'preds' : y_hat, 'target' : y}

def validation_step_end(self, outputs):
    self.validation_acc(outputs['preds'], outputs['target'])
    self.log('val_accuracy', self.validation_acc,on_epoch=True,prog_bar=True)
    self.log('val_loss',outputs['loss'],on_epoch=True)

    return outputs

def validation_epoch_end(self, outputs):
    return None


def configure_optimizers(self):
    return torch.optim.Adam(self.parameters(), lr=0.01)


if __name__ == '__main__':

model = MuonModel()

trainer = pl.Trainer(
                    gpus=1,
                    max_epochs=100,
                    min_epochs=50)

As you can see I’m embedding the quantum circuit into a TorchLayer and then I’m using PyTorch Lightning to perform the training. Hope this helps in clarifying the issue, anyway thank you for your help :slight_smile:

Thanks for the update @Davide_Zuliani
I had trouble running your example code as given. Would it be possible to simplify it further to a minimum working example? That way we can help try to understand if something is going wrong in the pipeline on our side, and hopefully see if we can get it going.

Hi @mlxd I have a similar problem even after setting GPU for the device and installing the GPU support for qiskit pip install qiskit-aer-gpu I do not see any change in GPU usage but I do see a single CPU core running at 100%. Also, pennylane does not raise any error when I request GPU run without any GPU or when I don’t have qiskit-aer-gpu installed. Is there another plugin in pennylane that I should install for GPU support?

System settings:

  • PennyLane-qiskit v0.20.0
  • qiskit v0.34.0
  • qiskit-aer v0.10.1
  • qiskit-aer-gpu v0.10.1
  • PennyLane v0.20.0

Correction: pennylane does give me an error if I don’t have a GPU when I execute the circuit.

Thanks

@jackaraz Thank you for your question, by using pip install qiskit-aer-gpu, you should overwrite the installation of qiskit-aer. There is more information about the package here. Maybe you could try to create a new environment and install it without the qiskit_aer. Could share a minimal example of what you are trying to run such I can potentially help you!