Circuit simulation on 'ibmq_qasm_simulator' taking a lot of time

Hello, I am experimenting with Pennylane-Qiskit plugin and tried to run a simple quantum circuit on ibmq_qasm_simulator. Following is the code I used.

import pennylane as qml
from pennylane import numpy as np
import time as time
import torch
import torch.nn as nn

dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(theta, inputs):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": (1,)
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

x_train = np.array([0.2, 0.1, 0.2, 0.14, 0.11, 0.41, 0.55, 0.3, 0.31, 0.6])
x_train = torch.tensor(x_train).reshape(10,1)

model = QNet()
t1 = time.time()
out = model(x_train)
print("time taken for batch operations: {} seconds".format(time.time()-t1))

I created a random tensor of size 10 and passed it as an input to the quantum model. I understand that the all the samples in the batch were executed sequentially as total 10 jobs were created. However, what surprised me is the time taken to complete the execution of each job. Following is the output I got.

time taken for batch operations:  59.5023033618927 seconds

As there are total 10 samples in the batch, time taken/job is around about 6 seconds. However, when I checked the details of the job submitted to ’ ibmq_qasm_simulator’, the ‘Total completion time’ is 230 ms/job on an average which is way less compared to actual time taken. I am not sure if I am doing something wrong or this behavior is normal.

Output of qml.about().

qml.about()
Name: PennyLane
Version: 0.28.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: c:\users\aksi01\miniconda3\envs\qns\lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, retworkx, scipy, semantic-version, toml
Required-by: PennyLane-Lightning, PennyLane-qiskit
Platform info:           Windows-10-10.0.19045-SP0
Python version:          3.8.15
Numpy version:           1.22.3
Scipy version:           1.7.3
Installed devices:
- default.gaussian (PennyLane-0.28.0)
- default.mixed (PennyLane-0.28.0)
- default.qubit (PennyLane-0.28.0)
- default.qubit.autograd (PennyLane-0.28.0)
- default.qubit.jax (PennyLane-0.28.0)
- default.qubit.tf (PennyLane-0.28.0)
- default.qubit.torch (PennyLane-0.28.0)
- default.qutrit (PennyLane-0.28.0)
- null.qubit (PennyLane-0.28.0)
- lightning.qubit (PennyLane-Lightning-0.28.1)
- qiskit.aer (PennyLane-qiskit-0.29.0)
- qiskit.basicaer (PennyLane-qiskit-0.29.0)
- qiskit.ibmq (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.29.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.29.0)

Hello @imakash !

As I mentioned in this post reply, I would suggest first updating your PennyLane installed version.

I also did some minor modifications to the code you shared:

import pennylane as qml
from pennylane import numpy as np
import time as time
import torch
import torch.nn as nn

dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev, interface = 'torch')
def simple_qubit_circuit(inputs, theta):
    qml.RX(inputs, wires=0)
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))
class QNet(nn.Module):
    def __init__(self):
        super().__init__()
        shapes = {
            "theta": ()
        }
        self.q = qml.qnn.TorchLayer(simple_qubit_circuit, shapes)
    
    def forward(self, input_value):
        return self.q(input_value)

x_train = np.array([0.2, 0.1, 0.2, 0.14, 0.11, 0.41, 0.55, 0.3, 0.31, 0.6])
x_train = torch.tensor(x_train)

model = QNet()
t1 = time.time()
out = model(x_train)
print("time taken for batch operations: {} seconds".format(time.time()-t1))

and I got:

time taken for batch operations: 0.005563020706176758 seconds

The time seems reasonable to me.

Does it help? :slight_smile:

Hello @ludmilaaasb

But, can you change the device to the following and check if you the time is reasonable?

dev = qml.device("qiskit.ibmq", wires=1, backend='ibmq_qasm_simulator', shots=1000)

I am afraid I can’t. :sweat_smile:

Note that ibmq_qasm_simulator is a cloud-based simulator. Unfortunately, to use the qiskit.ibmq I need an IBM Q experience account, which I don’t have. :face_with_diagonal_mouth:

But if you facing some issues with it, I strongly recommend first taking a look at the documentation here and here.

I hope that can help! :slight_smile:

Hello @imakash, I ran this device with ludmilaaasb’s code and got: 4.01 seconds.

The issue appears to be with differences between Pennylane and Qiskit simulator settings.

Pennylane defaults to “analytical results” if no shots are entered: qml.devices.default_qubit.DefaultQubit — PennyLane 0.31.1 documentation

Perhaps lower the number of ibmq_qasm_simulator shots, or try simulator_statevector.

1 Like

Hi @imakash! I’m curious what your use-case is for the remote simulator? Are you intending to switch to a hardware device?

Yes, that’s right. I wanted to evaluate the performance of my circuit on ibmq-qasm-simulator before trying it out on a real device.

Hi @imakash, this is indeed a good approach.

Maybe you can use the device tracker to get more insights on the time spent in the queue and other parts of the job. Here’s an example code on how to use it. Please note that I haven’t tested this with the latest Qiskit version so please let me know if you run into any errors.

import warnings
warnings.filterwarnings('ignore')

# Import your favourite libraries

import pennylane as qml
import datetime as dt

# Define the backend that you will run on
b = "ibmq_qasm_simulator"
#b = "ibmq_lima"

# Create your device
dev = qml.device(
    "qiskit.ibmq",
    wires=2,
    backend=b,
    shots = 1,
    #ibmqx_token="add_your_token_here"
)

# Activate the device resource tracker
dev.tracker.active = True

# Create your qnode
@qml.qnode(dev)
def circuit():
    qml.Hadamard(wires=0)
    return qml.expval(qml.PauliZ(0))

# Run your circuit
circuit()

# Retrieve your current job
job = dev._current_job

# Print the summary of job time per step
print('Summary: \n',dev.tracker.history)

# Print the time details for each step in running the job
print('Details: \n',job.time_per_step())
2 Likes