qiskit-machine-learning
qiskit-machine-learning copied to clipboard
SamplerQNN: TypeError: run() takes 2 positional arguments but 3 were given
Environment
- Qiskit Machine Learning version: Name: qiskit-machine-learning Version: 0.8.0 (I have tried 0.7, 0.5 ...)
- Python version: Python 3.9.20
- Operating system: MacOS
What is happening?
Hello,
I am trying to run a SamplerQNN but since new version of qiskit I am not able to run it on real hardware (on local machine it works).
I have the following code that I run with my local machine and that works perfectly:
# Import necessary libraries
import warnings
import numpy as np
from sklearn.datasets import load_iris
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score, KFold
from sklearn.preprocessing import LabelEncoder
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.primitives import Sampler
from qiskit_machine_learning.neural_networks import SamplerQNN
from qiskit_machine_learning.algorithms.classifiers import NeuralNetworkClassifier
from qiskit_algorithms.optimizers import COBYLA
# Configure the logging levels and suppress warnings
warnings.filterwarnings("ignore")
# Set random seed for reproducibility
np.random.seed(42)
# Parameters
feature_dimensions = [2] # We will use 2 features for binary classification
number_classes = 2 # We'll work with binary classification
# Load a standard dataset (Iris)
iris = load_iris()
X, y = iris.data, iris.target
# Filter to keep only two classes for binary classification
binary_class_indices = y < 2
X = X[binary_class_indices]
y = y[binary_class_indices]
# Use only the first 2 features (reduce the dimensionality)
X = X[:, :2]
# Initialize results list
results = []
# Define the Interpret Function
def parity(x):
return '{:b}'.format(x).count('1') % 2
# Use a predefined QNNCircuit with 2 qubits (for 2 features)
from qiskit_machine_learning.circuit.library import QNNCircuit
qc = QNNCircuit(2)
# Extract input and weight parameters
input_params = qc.input_parameters
weight_params = qc.weight_parameters
sampler = Sampler()
sampler_qnn = SamplerQNN(
circuit=qc,
input_params=input_params,
weight_params=weight_params,
interpret=parity,
output_shape=2, # Number of classes
sampler=sampler
)
# Define the optimizer
optimizer = COBYLA(maxiter=50)
# Rescale the data
rescale_pipeline = make_pipeline(StandardScaler())
X_rescaled = rescale_pipeline.fit_transform(X)
# Cross-validation setup
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores_train = []
scores_test = []
# Label encoding for binary classification
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)
for train_index, test_index in kf.split(X_rescaled):
X_train, X_test = X_rescaled[train_index], X_rescaled[test_index]
y_train, y_test = y_encoded[train_index], y_encoded[test_index]
# Create a new instance of the classifier for each fold
quantum_classifier = NeuralNetworkClassifier(
neural_network=sampler_qnn,
optimizer=optimizer
)
# Fit the classifier
quantum_classifier.fit(X_train, y_train)
training_accuracy = quantum_classifier.score(X_train, y_train)
scores_train.append(training_accuracy)
# Evaluate the classifier
testing_accuracy = quantum_classifier.score(X_test, y_test)
scores_test.append(testing_accuracy)
mean_score = np.mean(scores_test)
print(f"Rescaling method: StandardScaler, Feature Dimension: {feature_dimensions}")
print("Training scores:", scores_train)
print("Cross-validation scores:", scores_test)
print(f"Mean cross-validation score: {mean_score}")
# Store the results
results.append({
'Rescaling Method': 'StandardScaler',
'Feature Dimension': feature_dimensions,
'Scores train': scores_train,
'Scores test': scores_test,
'Mean Score': mean_score
})
# Convert results to DataFrame for analysis
import pandas as pd
results_df = pd.DataFrame(results)
print(results_df)
results_df.to_csv(f'results_quantum_iris.csv')
When I want to run it on real hardware, I did the following modifications and doesn't work:
# Import necessary libraries
import warnings
import numpy as np
from sklearn.datasets import load_iris
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score, KFold
from sklearn.preprocessing import LabelEncoder
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.primitives import Sampler
from qiskit_machine_learning.neural_networks import SamplerQNN
from qiskit_machine_learning.algorithms.classifiers import NeuralNetworkClassifier
from qiskit_algorithms.optimizers import COBYLA
# Configure the logging levels and suppress warnings
warnings.filterwarnings("ignore")
# Set random seed for reproducibility
np.random.seed(42)
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator, SamplerV2 as Sampler
# Initialize the Qiskit Runtime Service
service = QiskitRuntimeService(channel="ibm_quantum", instance="ibm-q/open/main", token="IBM_QUANTUM_TOKEN")
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# Parameters
feature_dimensions = [2] # We will use 2 features for binary classification
number_classes = 2 # We'll work with binary classification
# Load a standard dataset (Iris)
iris = load_iris()
X, y = iris.data, iris.target
# Filter to keep only two classes for binary classification
binary_class_indices = y < 2
X = X[binary_class_indices]
y = y[binary_class_indices]
# Use only the first 2 features (reduce the dimensionality)
X = X[:, :2]
# Initialize results list
results = []
# Define the Interpret Function
def parity(x):
return '{:b}'.format(x).count('1') % 2
# Use a predefined QNNCircuit with 2 qubits (for 2 features)
from qiskit_machine_learning.circuit.library import QNNCircuit
qc = QNNCircuit(2)
# Extract input and weight parameters
input_params = qc.input_parameters
weight_params = qc.weight_parameters
sampler = Sampler(backend)
sampler_qnn = SamplerQNN(
circuit=qc,
input_params=input_params,
weight_params=weight_params,
interpret=parity,
output_shape=2, # Number of classes
sampler=sampler
)
# Define the optimizer
optimizer = COBYLA(maxiter=50)
# Rescale the data
rescale_pipeline = make_pipeline(StandardScaler())
X_rescaled = rescale_pipeline.fit_transform(X)
# Cross-validation setup
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores_train = []
scores_test = []
# Label encoding for binary classification
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)
for train_index, test_index in kf.split(X_rescaled):
X_train, X_test = X_rescaled[train_index], X_rescaled[test_index]
y_train, y_test = y_encoded[train_index], y_encoded[test_index]
# Create a new instance of the classifier for each fold
quantum_classifier = NeuralNetworkClassifier(
neural_network=sampler_qnn,
optimizer=optimizer
)
# Fit the classifier
quantum_classifier.fit(X_train, y_train)
training_accuracy = quantum_classifier.score(X_train, y_train)
scores_train.append(training_accuracy)
# Evaluate the classifier
testing_accuracy = quantum_classifier.score(X_test, y_test)
scores_test.append(testing_accuracy)
mean_score = np.mean(scores_test)
print(f"Rescaling method: StandardScaler, Feature Dimension: {feature_dimensions}")
print("Training scores:", scores_train)
print("Cross-validation scores:", scores_test)
print(f"Mean cross-validation score: {mean_score}")
# Store the results
results.append({
'Rescaling Method': 'StandardScaler',
'Feature Dimension': feature_dimensions,
'Scores train': scores_train,
'Scores test': scores_test,
'Mean Score': mean_score
})
# Convert results to DataFrame for analysis
import pandas as pd
results_df = pd.DataFrame(results)
print(results_df)
results_df.to_csv(f'results_quantum_iris.csv')
I get the following error message:
(quantum_hw) xavi@MacBook-Air-de-Xavier Desktop % python code_hw.py
Traceback (most recent call last):
File "/Users/xavi/Desktop/code_hw.py", line 97, in <module>
quantum_classifier.fit(X_train, y_train)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/algorithms/trainable_model.py", line 199, in fit
self._fit_result = self._fit_internal(X, y)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/algorithms/classifiers/neural_network_classifier.py", line 116, in _fit_internal
return self._minimize(function)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/algorithms/trainable_model.py", line 295, in _minimize
optimizer_result = self._optimizer.minimize(
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/qiskit_algorithms/optimizers/scipy_optimizer.py", line 148, in minimize
raw_result = minimize(
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_minimize.py", line 719, in minimize
res = _minimize_cobyla(fun, x0, args, constraints, callback=callback,
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_cobyla_py.py", line 35, in wrapper
return func(*args, **kwargs)
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_cobyla_py.py", line 278, in _minimize_cobyla
sf = _prepare_scalar_function(fun, x0, args=args, jac=_jac)
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_optimize.py", line 288, in _prepare_scalar_function
sf = ScalarFunction(fun, x0, args, grad, hess,
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_differentiable_functions.py", line 166, in __init__
self._update_fun()
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_differentiable_functions.py", line 262, in _update_fun
self._update_fun_impl()
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_differentiable_functions.py", line 163, in update_fun
self.f = fun_wrapped(self.x)
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/scipy/optimize/_differentiable_functions.py", line 145, in fun_wrapped
fx = fun(np.copy(x), *args)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/algorithms/objective_functions.py", line 152, in objective
probs = self._neural_network_forward(weights)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/algorithms/objective_functions.py", line 102, in _neural_network_forward
self._last_forward = self._neural_network.forward(self._X, weights)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/neural_networks/neural_network.py", line 229, in forward
output_data = self._forward(input_, weights_)
File "/Users/xavi/Desktop/qiskit-machine-learning/qiskit_machine_learning/neural_networks/sampler_qnn.py", line 391, in _forward
job = self.sampler.run([self._circuit] * num_samples, parameter_values)
TypeError: run() takes 2 positional arguments but 3 were given
If I change
from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2 as Estimator, SamplerV2 as Sampler
to
from qiskit.primitives import Sampler
I have the following error message:
(quantum_hw) xavi@MacBook-Air-de-Xavier Desktop % python code_hw.py
Traceback (most recent call last):
File "/Users/xavi/Desktop/code_hw.py", line 59, in <module>
sampler = Sampler(backend)
File "/opt/anaconda3/envs/quantum_hw/lib/python3.9/site-packages/qiskit/utils/deprecation.py", line 97, in wrapper
return func(*args, **kwargs)
TypeError: __init__() takes 1 positional argument but 2 were given
Can you please help me ?
Thank you in advance
How can we reproduce the issue?
I provided the code above
What should happen?
The output should be something like:
Rescaling method: StandardScaler, Feature Dimension: [2]
Training scores: [0.6125, 0.5375, 0.5375, 0.575, 0.625]
Cross-validation scores: [0.6, 0.3, 0.5, 0.35, 0.55]
Mean cross-validation score: 0.45999999999999996
Rescaling Method Feature Dimension Scores train Scores test Mean Score
0 StandardScaler [2] [0.6125, 0.5375, 0.5375, 0.575, 0.625] [0.6, 0.3, 0.5, 0.35, 0.55] 0.46
Any suggestions?
No response
Hi @xaviervasques, thanks for raising this issue. It appears because V2 primitives are not supported in Qiskit Machine Learning 0.7.2 ( see https://github.com/qiskit-community/qiskit-machine-learning/issues/742 and https://github.com/qiskit-community/qiskit-machine-learning/issues/786) but are the only type that Qiskit IBM Runtime supports for running jobs on real backends.
The upcoming 0.8.0 version includes support for V2 primitives, so this error should disappear after you run with upgraded Qiskit Machine Learning (pip install -U qiskit-machine-learning). We expect the 0.8.0 version to come out at the end of October 2024.
More details on this error
- When using
{Sampler,Estimator}V2and call.run(...)the arguments must be structured as a Primitive Unified Bloc (PUB) which is of typetuple, or a list of PUBs (list[tuple]). This structure is different from that of the V1 primitives and leads to the error above (TypeError: run() takes 2 positional arguments but 3 were given) when V1-like arguments are used in V2 primitives..run(...)is triggered in your code when you callSamplerQNN(...).fit(...). - When using
from qiskit.primitives import Sampleryou are implicitly using V1 Base primitives, which do not have the additional functionality to be run on hardware directly and also returns an argument mismatch error fromSamplerQNN(...).fit(...). Qiskit IBM Runtime has derived primitives that do just that, however, V1 primitives can no longer run on real backends.
Proposed temporary solution
We should expect your experiment to run on hardware with the upcoming 0.8.0 version and V2 primitive support. Until then, you may run simulations of SamplerQNN in local testing mode with Qiskit Aer backends and the V1 primitives as
from qiskit_ibm_runtime import EstimatorV1 as Estimator, SamplerV1 as Sampler
sampler = Sampler(backend)
sampler_qnn = SamplerQNN(
circuit=qc,
input_params=input_params,
weight_params=weight_params,
interpret=parity,
output_shape=2, # Number of classes
sampler=sampler
)
With this setup, you will be able to switch to submitting to the real device just by changing the definitions of backend and restoring from qiskit_ibm_runtime import EstimatorV2 as Estimator, SamplerV2 as Sampler as you originally had. I hope this helps!
Thank you Edoardo. I will wait for the 0.8.0, hope it is coming soon :)
Yes indeed, we are looking forward to it! The feature will be in the main branch as soon as the PR is merged, but live from pip install --update once 0.8.0 is released.
Looking forward to the 0.8.0.