Issue with QNSPSA Optimizer and Qiskit's Fake Backend Noise Model

Dear PennyLane Team,

I was following the tutorial on the PennyLane website, “How to import noise models from Qiskit”, and I’m really excited about using noise models from Qiskit’s FakeBackend in my experiments. While the SPSA optimizer works perfectly, I encountered an issue when trying to use the QNSPSA optimizer.

I’m getting the following error:
IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed

I’d greatly appreciate any guidance or suggestions on how to resolve this issue. Thanks a lot in advance for your help!

Best regards,

# import pennylane as qml
from pennylane import numpy as np

from qiskit_aer.noise import NoiseModel
from qiskit.providers.fake_provider import GenericBackendV2

# ====================
# Qiskit Noise Model
# ====================
n_qubits = 2
shots = 8192

# Create a fake backend with noise
backend = GenericBackendV2(num_qubits=n_qubits, seed=42)
noise_model = NoiseModel.from_backend(backend)
print("Qiskit Noise Model:\n", noise_model)

# PennyLane device with Qiskit noise
dev_noisy = qml.device("qiskit.aer", wires=n_qubits, shots=shots, noise_model=noise_model)

# ============================
# Define Hamiltonian (VQE)
# ============================

# Simple Ising Hamiltonian: H = Z0 Z1 + X0 + X1
H = qml.Hamiltonian(
    [1.0, 1.0, 1.0],
    [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0), qml.PauliX(1)]
)

# ================================
# Variational Ansatz Circuit
# ================================

def variational_ansatz(params, wires):
    for i in range(len(wires)):
        qml.RY(params[i], wires=wires[i])
    qml.CNOT(wires=[0, 1])

# ===============================
# Cost Function (VQE Expectation)
# ===============================

@qml.qnode(dev_noisy)
def cost_fn(params):
    variational_ansatz(params, wires=range(n_qubits))
    return qml.expval(H)

# ===========================
# Run VQE with SPSA and QNSPSA
# ===========================

# Initialize random parameters
np.random.seed(42)
params_spsa = np.random.uniform(-np.pi, np.pi, n_qubits)
params_qnspsa = np.copy(params_spsa)

# SPSA Optimizer
opt1 = qml.SPSAOptimizer(maxiter=100)
# QNSPSA Optimizer
opt2 = qml.QNSPSAOptimizer(stepsize=0.01)

# Track energy
energy_spsa = []
energy_qnspsa = []

# Run SPSA Optimization
print("\nRunning SPSA Optimization:")
for i in range(100):
    params_spsa = opt1.step(cost_fn, params_spsa)
    curr_energy = cost_fn(params_spsa)
    energy_spsa.append(curr_energy)
    if i % 10 == 0:
        print(f"SPSA Iteration {i}: Energy = {curr_energy:.6f}")

# Run QNSPSA Optimization
print("\nRunning QNSPSA Optimization:")
for i in range(100):
    params_qnspsa = opt2.step(cost_fn, params_qnspsa)
    curr_energy = cost_fn(params_qnspsa)
    energy_qnspsa.append(curr_energy)
    if i % 10 == 0:
        print(f"QNSPSA Iteration {i}: Energy = {curr_energy:.6f}")

# Final results
print("\nFinal Energies:")
print(f"SPSA Final Energy: {energy_spsa[-1]:.6f}")
print(f"QNSPSA Final Energy: {energy_qnspsa[-1]:.6f}")

Hi @QuantumH ,

Unfortunately QNSPSA works by calculating a metric tensor, and this doesn’t work together with noise models. Are you able to use other differentiation methods, different from QNSPSA or QNGO?

Thanks, CatalinaAlbornoz. In my project, I should use QNG and QNSPSA.

I see @QuantumH .

There may be a way to hack this into working, but this isn’t straightforward.

You can define a custom gradient transform (e.g., by inheriting from the param-shift transform) that returns quantum_gradient(tape) * metric_tensor(tape). Then, in your QNode you can set diff_method=custom_qngrad , and use standard GradientDescent optimization.

If you haven’t worked with metric tensors before then you may want to start by looking at qml.metric_tensor and testing how to use it for simple circuits before trying to use it for more complicated ones.

If you test this out please let us know if it works!