Closed ShikBan closed 1 year ago
Hi -- could you share the code you have written that produces the error (i.e., after translating over to qumodes)? This would be helpful so that we can reproduce the error.
Sure, I tried to put it all together. Also, I just used some gates as an example; I know they won't give good results.
import os import sys import c2qa import qiskit from math import pi import matplotlib.pyplot as plt import numpy as np from IPython.display import clear_output from qiskit import QuantumCircuit from qiskit.algorithms.optimizers import COBYLA, L_BFGS_B from qiskit.circuit import Parameter from qiskit.circuit.library import RealAmplitudes, ZZFeatureMap from qiskit.utils import algorithm_globals
from qiskit_machine_learning.algorithms.classifiers import NeuralNetworkClassifier, VQC from qiskit_machine_learning.algorithms.regressors import NeuralNetworkRegressor, VQR from qiskit_machine_learning.neural_networks import SamplerQNN, EstimatorQNN
algorithm_globals.random_seed = 42
numsamples = 20 eps = 0.2 lb, ub = -np.pi, np.pi X = np.linspace(lb, ub, num=50).reshape(50, 1) f = lambda x: np.sin(x)
X = (ub - lb) algorithm_globals.random.random([num_samples, 1]) + lb y = f(X[:, 0]) + eps (2 * algorithm_globals.random.random(num_samples) - 1)
plt.plot(X, f(X), "r--") plt.plot(X, y, "bo") plt.show()
qmr = c2qa.QumodeRegister(num_qumodes=2, num_qubits_per_qumode=1) qbr = qiskit.QuantumRegister(1)
param_x = Parameter("x") feature_map = c2qa.CVCircuit(qmr, name="fm") feature_map.cv_d(param_x, qmr[0])
param_y = Parameter("y") ansatz = c2qa.CVCircuit(qmr, name="vf") ansatz.cv_d(param_y, qmr[0]) ansatz.cv_r(param_y, qmr[0])
qmr = c2qa.QumodeRegister(num_qumodes=2, num_qubits_per_qumode=1) qbr = qiskit.QuantumRegister(1)
qc = c2qa.CVCircuit(qmr, qbr) qc.compose(feature_map, inplace=True) qc.compose(ansatz, inplace=True) qc.draw()
regression_estimator_qnn = EstimatorQNN( circuit=qc, input_params=feature_map.parameters, weight_params=ansatz.parameters )
def callback_graph(weights, obj_func_eval): clear_output(wait=True) objective_func_vals.append(obj_func_eval) plt.title("Objective function value against iteration") plt.xlabel("Iteration") plt.ylabel("Objective function value") plt.plot(range(len(objective_func_vals)), objective_func_vals) plt.show()
regressor = NeuralNetworkRegressor( neural_network=regression_estimator_qnn, loss="squared_error", optimizer=L_BFGS_B(maxiter=5), callback=callback_graph, )
objective_func_vals = [] plt.rcParams["figure.figsize"] = (12, 6)
regressor.fit(X, y)
plt.rcParams["figure.figsize"] = (6, 4)
regressor.score(X, y)
I'm not too familiar with qiskit-machine-learning
-- I'm guessing at the regressor.fit(X, y)
step you're using the ML model to fit values to the X & y parameters? This call into fit()
is caling into the Qiskit circuit at a point it is expecting bound parameters (at least for the way we've implemented it in bosonic-qiskit), but the parameters aren't actually bound yet.
For example, a call to bind_parameters()
before simulating the quantum circuit as we currently test here: https://github.com/C2QA/bosonic-qiskit/blob/main/tests/test_parameterized.py#L49
As it is implemented now, obviously our parameterized circuit support in bosonic-qiskit doesn't support the ML integration, but I'm interested in helping you out to get it working.
In doing my due diligence to better understand what you're trying to achieve, it looks like you're following this tutorial, but with CVCircuit and our bosonic gates instead of RY? https://qiskit.org/documentation/machine-learning/tutorials/02_neural_network_classifier_and_regressor.html#Regression
EDIT: I see now that you told me this in your original post ... I missed reading that initially.
I was able to get that tutorial working (at least it didn't raise any errors). I'll look more into how bosonic-qiskit handles parameterized circuits vs how Qiskit does by default.
See https://github.com/C2QA/bosonic-qiskit/blob/parameterized-ml/tests/test_ml.py for the code I've been using to test.
Quick update on what I've found:
Thank you so much for your help. I want to share another code of hybrid NN where I saw that if I use the CV gates with fixed parameters, it works fine (training and testing), but when I train on the gate parameters, I get the "complex number" error. This information may be helpful in resolving the issue. Here is the code: https://colab.research.google.com/drive/1CpAAc4C18j63kM8fTQDssgoTWx5jRKUk?usp=sharing It is a long code because I start with qubits, then qumodes with fixed parameters, and finally qumodes with training parameters
Could you try skipping the transpile step in run()
? Since you are using the Aer_simulator, I believe the circuit should run without transpilation. The issue seems to be that transpilation throws an error for a CVCircuit with unbound parameters (whereas a QuantumCircuit does not).
Here is a code snippet which I believe reproduces and clarifies the error in question: `qmr = c2qa.QumodeRegister(num_qumodes=1, num_qubits_per_qumode=2) qbr = qiskit.QuantumRegister(1) circuit = c2qa.CVCircuit(qmr, qbr) theta = qiskit.circuit.Parameter('theta')
circuit.cv_d(theta, qmr[0]) circuit.h(qbr[0]) circuit.ry(theta, qbr[0])
simulator = qiskit.Aer.get_backend('aer_simulator')
simulator.run(circuit.bind_parameters([0.2]),shots=1000)
circuit_transpiled = qiskit.transpile(circuit.bind_parameters([0.2]),simulator) simulator.run(circuit_transpiled,shots=1000)
circuit_transpiled = qiskit.transpile(circuit,simulator) simulator.run(circuit_transpiled.bind_parameters([0.2]),shots=1000)`
This final transpilation throws the error "Error decomposing node D: ParameterExpression with unbound parameters ({Parameter(theta)}) cannot be cast to a complex.’”
The following link removes all context for the full call stack that results from calling regressor.fit(X, y)
. After further debugging the error, I found where in the call stack the fit()
call is simulating the circuit for you -- including calling transpile
. See https://github.com/Qiskit/qiskit-terra/blob/stable/0.22/qiskit/algorithms/gradients/utils.py#L99. Note that this utils.py
changed in the current release, this is the one used with Qiskit 0.39.5 that we're currently targeting for bosonic-qiskit.
I'll still emphasize that in my testing many of the simulator runs/shots from calling regressor.fit(X, y)
successfully bound the parameters. The complex
cast error only happens after an unbound parameter is sent for one of the shots.
This shows where transpile
is called in the Qiskit tutorial example, but I'll still stress that even if you simulate without transpiling in your own code, you'll still need to be sure that all parameters are bound before it will work without errors.
UnitaryGates in Qiskit (on which the bosonic-qiskit parameterized gates depend) require that all parameters have been bound with values before they will work. I'll continue to look at if there is a different approach we can take with our parameterized gates to work around this issue.
Getting deep into the weeds, here's the full stack:
MainThread:
_wait_for_tstate_lock (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\threading.py:1027)
join (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\threading.py:1011)
shutdown (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\concurrent\futures\thread.py:236)
__exit__ (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\concurrent\futures\_base.py:636)
submit (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\primitives\primitive_job.py:44)
run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\gradients\base_estimator_gradient.py:98)
_backward (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit_machine_learning\neural_networks\estimator_qnn.py:245)
backward (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit_machine_learning\neural_networks\neural_network.py:252)
gradient (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit_machine_learning\algorithms\objective_functions.py:129)
wrapped_gradient (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\optimizers\scipy_optimizer.py:172)
grad_wrapped (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_differentiable_functions.py:164)
update_grad (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_differentiable_functions.py:167)
_update_grad (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_differentiable_functions.py:256)
__init__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_differentiable_functions.py:177)
_prepare_scalar_function (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_optimize.py:263)
_minimize_lbfgsb (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_lbfgsb_py.py:306)
minimize (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\scipy\optimize\_minimize.py:699)
minimize (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\optimizers\scipy_optimizer.py:148)
_fit_internal (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit_machine_learning\algorithms\regressors\neural_network_regressor.py:46)
fit (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit_machine_learning\algorithms\trainable_model.py:201)
test_bosnic_qiskit (c:\Users\stav405\git\bosonic-qiskit\tests\test_ml.py:90)
pytest_pyfunc_call (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\python.py:183)
_multicall (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\callers.py:187)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:84)
_hookexec (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:93)
__call__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\hooks.py:286)
runtest (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\python.py:1641)
pytest_runtest_call (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:162)
_multicall (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\callers.py:187)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:84)
_hookexec (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:93)
__call__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\hooks.py:286)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:255)
from_call (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:311)
call_runtest_hook (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:254)
call_and_report (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:215)
runtestprotocol (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:126)
pytest_runtest_protocol (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\runner.py:109)
_multicall (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\callers.py:187)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:84)
_hookexec (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:93)
__call__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\hooks.py:286)
pytest_runtestloop (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\main.py:348)
_multicall (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\callers.py:187)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:84)
_hookexec (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:93)
__call__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\hooks.py:286)
_main (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\main.py:323)
wrap_session (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\main.py:269)
pytest_cmdline_main (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\main.py:316)
_multicall (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\callers.py:187)
<lambda> (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:84)
_hookexec (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\manager.py:93)
__call__ (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\pluggy\hooks.py:286)
main (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\_pytest\config\__init__.py:162)
_run_code (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\runpy.py:87)
_run_module_as_main (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\runpy.py:194)
Individual shot thread:
_define (c:\Users\stav405\git\bosonic-qiskit\c2qa\operators.py:72)
definition (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\circuit\instruction.py:237)
run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\passes\basis\unroll_custom_definitions.py:77)
_run_this_pass (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\runningpassmanager.py:201)
_do_pass (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\runningpassmanager.py:172)
run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\runningpassmanager.py:125)
_run_single_circuit (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\passmanager.py:283)
run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\passmanager.py:228)
run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\transpiler\passmanager.py:528)
_serial_transpile_circuit (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\compiler\transpiler.py:475)
transpile (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\compiler\transpiler.py:382)
_make_param_shift_gradient_circuit_data (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\gradients\utils.py:99)
_param_shift_preprocessing (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\gradients\utils.py:209)
_run (c:\Users\stav405\git\bosonic-qiskit\venv\Lib\site-packages\qiskit\algorithms\gradients\param_shift_estimator_gradient.py:71)
run (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\concurrent\futures\thread.py:57)
_worker (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\concurrent\futures\thread.py:80)
run (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\threading.py:870)
_bootstrap_inner (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\threading.py:932)
_bootstrap (c:\Users\stav405\AppData\Local\Programs\Python\Python38\Lib\threading.py:890)
We haven't forgotten about this -- I'm working with the qiskit-machine-learning devs on a support / feature request ticket to see if we can bypass the transpilation step while using qiskit-machine-learning. Though I wouldn't be surprised if we still run into a problem of the Parameter(x)
being unbound.
See https://github.com/Qiskit/qiskit-machine-learning/issues/567
Still no real resolution on fixing this, but what I do know:
_define()
. I made a workaround/hack in bosonic-qiskit to let us parameterize our unitary gates, but it only works in certain cases.So until Qiskit supports parameterizing unitary gates or until I work out a better way to support it anyway, I don't think this will be resolved unfortunately. Please let me know if you still need the feature, othwise I'll likely close the issue.
Closing for now, please let me know if I need to look into this furhter.
I am trying to work with bosonic qiskit and ML. For example, I tried to convert the qubits in this example to qumodes. But when I try to use the mentioned EstimatorQNN, I get the error “ParameterExpression with unbound parameters ({Parameter(x)}) cannot be cast to a complex.” Do you have any suggestions on how to resolve this? Since we are using CV gates, there will be complex numbers involved.
Is there any other way to do ML using bosonic-qiskit?