qiskit-community / prototype-quantum-kernel-training

Toolkit for training quantum kernels in machine learning applications
https://arxiv.org/abs/2105.03406
Apache License 2.0
39 stars 12 forks source link

Using ZZ_featuremap with QKT #20

Closed dancbeaulieu closed 2 years ago

dancbeaulieu commented 2 years ago

Describe the bug Was trying to test my custom kernel I created vs ZZ_Featuremap circuit as my feature map for my quantum kernel. Could not get the QKT function to work with zz_featuremap. Can you help us figure out how to get binding parameters to work for preconstructed qiskit featuremap circuits?

We tried the method specified in https://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/how_tos/train_kernels_using_qiskit_feature_maps.ipynb, but couldn't get it to work. Two of us tried multiple methods specified in the guide, but none of them worked when we tried to move them over the QKT library, especially qkt.fit(). Can you expand the tutorial to show this actually working?

There are a few problems: 1) Can't bind parameters successfully with ZZ_Featuremap based kernel, returns an error because it doesn not have a 'user_parameter' property. Always have issues with the "qkt_fit" call which expects a "user_parameters" property. en_map = ZZFeatureMap(feature_dimension=12, reps=2, entanglement='linear', data_map_func=None , insert_barriers=True) print(en_map.user_parameters) #.user_parameters)

 AttributeError                            Traceback (most recent call last)
 Input In [148], in <module>
 ----> 1 print(en_map.user_parameters)

 AttributeError: 'ZZFeatureMap' object has no attribute 'user_parameters'

If I try to look at the user_parameters of my kernel I create with zz_featuremap, I get nothing. en_map = ZZFeatureMap(feature_dimension=12, reps=2, entanglement='linear', data_map_func=None , insert_barriers=True) zz_ker = QuantumKernel(feature_map=en_map, quantum_instan

print(zz_ker.user_parameters)
    >None

I can get the properties with en_map.ordered_parameters, however if I do this I get the following error with qkt_fit() call. qkt

Train the kernel using QKT directly

qka_results = qkt.fit(X_train_q, y_train_q)
optimized_kernel = qka_results.quantum_kernel
​
# Use QSVC for classification
qsvc = QSVC(quantum_kernel=zz_qkt_kernel)
​
# Fit the QSVC
qsvc.fit(X_train_q, y_train_q)
​
# Predict the labels
labels_test = qsvc.predict(X_test_pcadf)
​
# Evalaute the test accuracy
accuracy_test = metrics.balanced_accuracy_score(y_true=y_test, y_pred=labels_test)
print(f"accuracy test: {accuracy_test}")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [142], in <module>
      1 # Train the kernel using QKT directly
----> 2 qka_results = qkt.fit(X_train_q, y_train_q)
      3 optimized_kernel = qka_results.quantum_kernel
      5 # Use QSVC for classification

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit_machine_learning/kernels/algorithms/quantum_kernel_trainer.py:189, in QuantumKernelTrainer.fit(self, data, labels)
    173 """
    174 Train the QuantumKernel by minimizing loss over the kernel parameters. The input
    175 quantum kernel will not be altered, and an optimized quantum kernel will be returned.
   (...)
    186     ValueError: No trainable user parameters specified in quantum kernel
    187 """
    188 # Number of parameters to tune
--> 189 num_params = len(self._quantum_kernel.user_parameters)
    190 if num_params == 0:
    191     msg = "Quantum kernel cannot be fit because there are no user parameters specified."

TypeError: object of type 'NoneType' has no len()

To Reproduce To reproduce this try using a ZZ_Featuremap with qkt.fit().

Expected behavior I expect either a way to pass ZZ_Featuremap parameters to qkt.fit(), zz_featuremap doesn't have user_parameters properties.

Any suggestions? Can you figure out a method for getting zz_featuremap properties into QKT? Can you show actually binding parameters and getting it to work in qkt.fit() in the https://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/how_tos/bind_parameters_using_quantum_kernel.ipynb or show the successful integration of a zz_featuremap in the https://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/how_tos/train_kernels_using_qiskit_feature_maps.ipynb? These tutorials seems to end too early.

BryceFuller commented 2 years ago

Hello Dan, do you see the same issue when running the train_kernels_using_qiskit_feature_maps.ipynb notebook?

The ZZ feature map does not have any user_parameters by default. This feature map was introduced in the IBM nature paper which popularized the idea of QSVMs and quantum feature maps. The first quantum feature maps proposed were not trainable.

To be clear, the only practical difference between what I call a trainable feature map and a non-trainable feature map is the existence of parameters which are explicitly set aside for training (and will thus not be bound to input data values). So any non-trainable feature map could still become a trainable one if you as the user split up its input parameters and explicitly set some of them aside as trainable parameters.

In the train_kernels_using_qiskit_feature_maps.ipynb notebook, my goal (in Option 1) was to show how one could do this manual partitioning of parameters to convert a single ZZ FeatureMap into a trainable feature map (but which now has fewer input parameters).

This is sort of a hack which I included to show how one could make this work, but there are downsides of this. One downside of Option 1 (from the notebook) is that the ZZ feature map uses one parameter per qubit. Treating this feature map as a trainable feature map requires re-purposing input parameters to be trainable parameters, so this implies that you will end up needing more qubits than you have features. For this reason, you might be better off going with Option 2, which suggests that you can instead compose two ZZ feature maps into one big feature map and manually define one of the ZZ feature map's params to be trainable (while leaving the other feature map's parameters as regular input parameters). This too has imperfect side-effects. For one, you may end up with a circuit that is deeper than you'd prefer. Also, if you place the trainable parameters as the last block of the circuit, then that entire block will cancel itself out when you compute Kernel entries between data points. There is also theoretical justification for wanting to increase how interleaved the data and input parameters are within the circuit, which Option 2 fails to do.

The main takeaway from train_kernels_using_qiskit_feature_maps.ipynb is that you will have to take special care if you wish to treat existing (nontrainable) feature maps as though they are trainable.

Using the ZZ Feature map may still be desirable though, as a first sanity check to get things running. But I expect you will see shorter circuits and more efficient use of qubits by using quantum feature maps that were intended for training, or by building a trainable feature map from scratch.

Let me know if this helps clear up your questions.

dancbeaulieu commented 2 years ago

Hi Bryce,

I did try applying the techniques from the train_kernels_using_qiskit_feature_maps.ipynbhttps://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/how_tos/train_kernels_using_qiskit_feature_maps.ipynb in the kernel_optimization_using_qkt.ipynbhttps://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/tutorials/kernel_optimization_using_qkt.ipynb tutorial notebook. I attached my notebook where I tried to implement the parameter binding. Can you provide guidance based on my code as to how to get this working? It just won’t work for us.

Daniel Beaulieu Specialist Master @.**@.>

From: Bryce Fuller @.> Reply-To: IBM-Quantum-Prototypes/quantum-kernel-training @.> Date: Thursday, February 24, 2022 at 12:03 PM To: IBM-Quantum-Prototypes/quantum-kernel-training @.> Cc: "Beaulieu, Daniel" @.>, Author @.***> Subject: [EXT] Re: [IBM-Quantum-Prototypes/quantum-kernel-training] Using ZZ_featuremap with QKT (Issue #20)

Hello Dan, do you see the same issue when running the train_kernels_using_qiskit_feature_maps.ipynbhttps://secure-web.cisco.com/16Moh3DoBstUlyMsxD5jxt1OJy348psj4Dmjy8m5TUnuHEJy888iJbbZyPEuJML9yUvFDFpzojZYBOHBqU_2VJqO_BavutNW6vwswJWCgfIqbTABIBWUdU7kbkymYiB8G6-0mJYTQTya762gKHA2njjuMBvZVvLb0Lpfpfl0WNafsn9Cp3FLuxC5m3FZB0ksZ7NtfQsfUH_F98X1hXb4vXoEloqJlvfkBFnv1sxMOnMGeikNI4OAscM5HKDW2AlIvrOUIjFR2weeCTH5Ys6B5HbGBF2QnSnhhJ_K9SKyk2pAegBYTjs3F9Ss6FRlxYL67VsKq3wZefBQN1Ie6dDNWln53Ha_NnDSHOtkTJmEX256_ZJSTR-fq4xUzUb-dQh618gNWOU3lfvhWQPbXpaIUmaYErKz8sbjLSextjGXzsn-w1dEiXjXY6V0jjn7ecKHTOAcmmnOM_106A25ur7PnQq6CnJWnpeTHX08gvvFLds7dPIDOcudrXSPn4BIroNG8vxpLZ3aa9cgjyfrMQEs7zg/https%3A%2F%2Fgithub.com%2FIBM-Quantum-Prototypes%2Fquantum-kernel-training%2Fblob%2Fmain%2Fdocs%2Fhow_tos%2Ftrain_kernels_using_qiskit_feature_maps.ipynb notebook?

The ZZ feature map does not have any user_parameters by default. This feature map was introduced in the IBM nature paperhttps://secure-web.cisco.com/1JEuXu1yBGvGBO7pafUVR4xmJAmteppiisl4EsKspCSZqz-wXC2Sb4EYQDsZiZ-0cAiimazk6ZlTRYekhd9yyv1OvwksxpErO3I797t9BsDMeXydVsMHexhoRhJnlY0d-zHKV8VnxoNLJbZh7dAloaQjQR-yYe4QSPwhKMyac_io57mg0g4eOTYXQ8YO1nj3Ulx8bZqGjSNOJOlGVzA6HE9CcWLluZfzR_BUcBJMftE6M7w6CZ6pQ1GY5BEaL5FKO_NzKe1PX67fJPpiz-RFtmb5EC9LchjkQv_8qgGgyI37RxxhaRAh5XWD1m-tu9Hwkt3Pun2OP2xWcsPAPrFOqekfImEzwIr6Exi_k3s9CeYzteQIEsS-Z5bm3J99wRae6CRV2BRfHr5NxNNknrCYlKKPgISE4xHiKplS9b6jOImHSv6CPcM0HMAa32O-T6cpo6n4QWzs2efebPM3RvSvlJUcE0zJ4MVAMnwd7lqaTsqw8d_4wxcn_Ow-7hioY3OMCdaixrRQ45Ce_z1hQPBSGHA/https%3A%2F%2Farxiv.org%2Fabs%2F1804.11326 which popularized the idea of QSVMs and quantum feature maps. The first quantum feature maps proposed were not trainable.

To be clear, the only practical difference between what I call a trainable feature map and a non-trainable feature map is the existence of parameters which are explicitly set aside for training (and will thus not be bound to input data values). So any non-trainable feature map could still become a trainable one if you as the user split up its input parameters and explicitly set some of them aside as trainable parameters.

In the train_kernels_using_qiskit_feature_maps.ipynbhttps://secure-web.cisco.com/16Moh3DoBstUlyMsxD5jxt1OJy348psj4Dmjy8m5TUnuHEJy888iJbbZyPEuJML9yUvFDFpzojZYBOHBqU_2VJqO_BavutNW6vwswJWCgfIqbTABIBWUdU7kbkymYiB8G6-0mJYTQTya762gKHA2njjuMBvZVvLb0Lpfpfl0WNafsn9Cp3FLuxC5m3FZB0ksZ7NtfQsfUH_F98X1hXb4vXoEloqJlvfkBFnv1sxMOnMGeikNI4OAscM5HKDW2AlIvrOUIjFR2weeCTH5Ys6B5HbGBF2QnSnhhJ_K9SKyk2pAegBYTjs3F9Ss6FRlxYL67VsKq3wZefBQN1Ie6dDNWln53Ha_NnDSHOtkTJmEX256_ZJSTR-fq4xUzUb-dQh618gNWOU3lfvhWQPbXpaIUmaYErKz8sbjLSextjGXzsn-w1dEiXjXY6V0jjn7ecKHTOAcmmnOM_106A25ur7PnQq6CnJWnpeTHX08gvvFLds7dPIDOcudrXSPn4BIroNG8vxpLZ3aa9cgjyfrMQEs7zg/https%3A%2F%2Fgithub.com%2FIBM-Quantum-Prototypes%2Fquantum-kernel-training%2Fblob%2Fmain%2Fdocs%2Fhow_tos%2Ftrain_kernels_using_qiskit_feature_maps.ipynb notebook, my goal (in Option 1) was to show how one could do this manual partitioning of parameters to convert a single ZZ FeatureMap into a trainable feature map (but which now has fewer input parameters).

This is sort of a hack which I included to show how one could make this work, but there are downsides of this. One downside of Option 1 (from the notebook) is that the ZZ feature map uses one parameter per qubit. Treating this feature map as a trainable feature map requires re-purposing input parameters to be trainable parameters, so this implies that you will end up needing more qubits than you have features. For this reason, you might be better off going with Option 2, which suggests that you can instead compose two ZZ feature maps into one big feature map and manually define one of the ZZ feature map's params to be trainable (while leaving the other feature map's parameters as regular input parameters). This too has imperfect side-effects. For one, you may end up with a circuit that is deeper than you'd prefer. Also, if you place the trainable parameters as the last block of the circuit, then that entire block will cancel itself out when you compute Kernel entries between data points. There is also theoretical justification for wanting to increase how interleaved the data and input parameters are within the circuit, which Option 2 fails to do.

The main takeaway from train_kernels_using_qiskit_feature_maps.ipynbhttps://secure-web.cisco.com/16Moh3DoBstUlyMsxD5jxt1OJy348psj4Dmjy8m5TUnuHEJy888iJbbZyPEuJML9yUvFDFpzojZYBOHBqU_2VJqO_BavutNW6vwswJWCgfIqbTABIBWUdU7kbkymYiB8G6-0mJYTQTya762gKHA2njjuMBvZVvLb0Lpfpfl0WNafsn9Cp3FLuxC5m3FZB0ksZ7NtfQsfUH_F98X1hXb4vXoEloqJlvfkBFnv1sxMOnMGeikNI4OAscM5HKDW2AlIvrOUIjFR2weeCTH5Ys6B5HbGBF2QnSnhhJ_K9SKyk2pAegBYTjs3F9Ss6FRlxYL67VsKq3wZefBQN1Ie6dDNWln53Ha_NnDSHOtkTJmEX256_ZJSTR-fq4xUzUb-dQh618gNWOU3lfvhWQPbXpaIUmaYErKz8sbjLSextjGXzsn-w1dEiXjXY6V0jjn7ecKHTOAcmmnOM_106A25ur7PnQq6CnJWnpeTHX08gvvFLds7dPIDOcudrXSPn4BIroNG8vxpLZ3aa9cgjyfrMQEs7zg/https%3A%2F%2Fgithub.com%2FIBM-Quantum-Prototypes%2Fquantum-kernel-training%2Fblob%2Fmain%2Fdocs%2Fhow_tos%2Ftrain_kernels_using_qiskit_feature_maps.ipynb is that you will have to take special care if you wish to treat existing (nontrainable) feature maps as though they are trainable.

Using the ZZ Feature map may still be desirable though, as a first sanity check to get things running. But I expect you will see shorter circuits and more efficient use of qubits by using quantum feature maps that were intended for training, or by building a trainable feature map from scratch.

Let me know if this helps clear up your questions.

— Reply to this email directly, view it on GitHubhttps://secure-web.cisco.com/1ML0TFMWpgDKoCHqfDVRMULPzVLePlPY-syfOW-0yVXVJbfr-qViZO7_d-s8niJEDPJBYRjuSZlAX4qMUgp_YK3FyII2UkKiXSKjKWQk95B0Pdt8D-hUNJIzYyIrCdz1M04oX1Jsc6IeaH8MgiV7vkDRYkKtlbZdH9UWPJmUGDT4QGAACPInz8vj48MewY5Yj0Ba9WnXONwvhaM9KcrlhbCo57LUFHetFK69gvQ3GaeD756kO98ZwUCg3Mdiifz-SN5Tv7j_t8xWWahU73nJqBs9HABD6uMgNjTGgl5sj_kifaflADvz-N_YJp6xlBfvg8We-QdEmvuQsNj8568V9qz56VmI157WxXYkrFj2rh45okAZPlJSg1wr4wSJChvxfiISB-KkpsVlMIF7BFcX44tKL4cV8JzMZ2l6z7gonxxluKV8F0Z7Qpnm1sygHHDv5WU5k0bWhnRr83uotBvd32S342ZCd2Ioj9tp43R6_BIGeXkyvlya_tZoMjEGIR5dQCpDOVXB6VDg2YT7DvQhVHg/https%3A%2F%2Fgithub.com%2FIBM-Quantum-Prototypes%2Fquantum-kernel-training%2Fissues%2F20%23issuecomment-1050063871, or unsubscribehttps://secure-web.cisco.com/1kY-z03SR5vHdfw40eojlJ0sFIT0TaEa60rLn0b-VPpXH7MeLqGeH--633_K4Y-oUqNWkrFosmF2CZJP-tgweNSBcYo8qJ-0AQAMr9YN9cIk_rnDDH-3IJ-5GOUz9D8gIivHDYfiNBEU85wtQmT_W0uUgKUgfrfvHHZXCGvFcCRUwdcOgl1Id4pxW7LWVN1R7RpEo2Hs8qLy6Y5BhAae7uM5ebKLVa1csWWSYV9nlVr0BO_fKismx_8x3IEQvJdtQKHtBSDZ-k8pmauhlNXn63L1FAzHeI3ddNhqUU0CzNis_wVFAYTHx7cslLs8q2LZaqoWP23fB03IYuzLq10Cem2OyzgxL86piapphOSfx6N4X3c2eWdH41HsY0MbVvAmqr4L0CjiKFBp9anQon_63KcgnqFTHPKEsQXxTFZe7A4pcGyoeu9xKG-DX3PH2yRFsGLdZi47pAKLwaLtmvTo1HOexGEcee4FKYXuC6vN2zdWIZbMkK17NlpZjXzaEwjpmVo51WsIuynqqLUVVNfPaTQ/https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FATJ35MK5Z3DSQUMTTYSDRP3U4ZP7LANCNFSM5PHXWQUQ. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you authored the thread.Message ID: @.***>

This message (including any attachments) contains confidential information intended for a specific individual and purpose, and is protected by law. If you are not the intended recipient, you should delete this message and any disclosure, copying, or distribution of this message, or the taking of any action based on it, by you is strictly prohibited.

Deloitte refers to a Deloitte member firm, one of its related entities, or Deloitte Touche Tohmatsu Limited ("DTTL"). Each Deloitte member firm is a separate legal entity and a member of DTTL. DTTL does not provide services to clients. Please see www.deloitte.com/about to learn more.

v.E.1

jenglick commented 2 years ago

Hi Dan, could you include a snippet of working code directly into this issue that reproduces the error you're seeing? As well as the version of python and OS you're using? That will help us troubleshoot what might be going on. Thanks!

I did try applying the techniques from the train_kernels_using_qiskit_feature_maps.ipynbhttps://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/how_tos/train_kernels_using_qiskit_feature_maps.ipynb in the kernel_optimization_using_qkt.ipynbhttps://github.com/IBM-Quantum-Prototypes/quantum-kernel-training/blob/main/docs/tutorials/kernel_optimization_using_qkt.ipynb tutorial notebook. I attached my notebook where I tried to implement the parameter binding.

dancbeaulieu commented 2 years ago

Here is a code snippet: !python --version -> Python 3.9.7

Define two circuits

circ1 = ZZFeatureMap(12) circ2 = ZZFeatureMap(12) input_params = circ1.parameters user_params = ParameterVector('θ', 12)

Reassign new parameters to circ2 so there are no name collisions

circ2.assign_parameters(user_params, inplace=True)

Compose to build a parameterized feature map

fm = circ2.compose(circ1) print("input_params:", list(input_params)) print("user_params:", user_params) fm.draw()

Use the qasm simulator backend

backend = BasicAer.get_backend('statevector_simulator')

Instantiate quantum kernel

quant_kernel = QuantumKernel(fm, user_parameters=fm.parameters, quantum_instance=backend)

Set up the optimizer

cb_qkt = QKTCallback() spsa_opt = SPSA(maxiter=5, callback=cb_qkt.callback, learning_rate=0.1, perturbation=0.1 )

Instantiate a quantum kernel trainer.

qkt = QuantumKernelTrainer( quantum_kernel=quant_kernel, loss="svc_loss", optimizer=spsa_opt, initial_point=[0.1]*len(fm.parameters) )

Train the kernel using QKT directly

qka_results = qkt.fit(X_train, y_train) optimized_kernel = qka_results.quantum_kernel


CircuitError Traceback (most recent call last) Input In [34], in 1 # Train the kernel using QKT directly ----> 2 qka_results = qkt.fit(X_train_q, y_train_q) 3 optimized_kernel = qka_results.quantum_kernel

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit_machine_learning/kernels/algorithms/quantum_kernel_trainer.py:205, in QuantumKernelTrainer.fit(self, data, labels) 201 # Perform kernel optimization 202 loss_function = partial( 203 self._loss.evaluate, quantum_kernel=self.quantum_kernel, data=data, labels=labels 204 ) --> 205 opt_results = self._optimizer.minimize( 206 fun=loss_function, 207 x0=self._initial_point, 208 ) 210 # Return kernel training results 211 result = QuantumKernelTrainerResult()

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:551, in SPSA.minimize(self, fun, x0, jac, bounds) 549 iteration_start = time() 550 # compute update --> 551 fx_estimate, update = self._compute_update(fun, x, k, next(eps), lse_solver) 553 # trust region 554 if self.trust_region:

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:486, in SPSA._compute_update(self, loss, x, k, eps, lse_solver) 483 num_samples = self.resamplings 485 # accumulate the number of samples --> 486 value, gradient, hessian = self._point_estimate(loss, x, eps, num_samples) 488 # precondition gradient with inverse Hessian, if specified 489 if self.second_order:

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:463, in SPSA._point_estimate(self, loss, x, eps, num_samples) 460 delta1 = deltas1[i] 461 delta2 = deltas2[i] if self.second_order else None --> 463 value_sample, gradient_sample, hessian_sample = self._point_sample( 464 loss, x, eps, delta1, delta2 465 ) 466 value_estimate += value_sample 467 gradient_estimate += gradient_sample

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:424, in SPSA._point_sample(self, loss, x, eps, delta1, delta2) 421 self._nfev += 2 423 # batch evaluate the points (if possible) --> 424 values = _batch_evaluate(loss, points, self._max_evals_grouped) 426 plus = values[0] 427 minus = values[1]

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:691, in _batch_evaluate(function, points, max_evals_grouped) 687 def _batch_evaluate(function, points, max_evals_grouped): 688 # if the function cannot handle lists of points as input, cover this case immediately 689 if max_evals_grouped == 1: 690 # support functions with multiple arguments where the points are given in a tuple --> 691 return [ 692 function(*point) if isinstance(point, tuple) else function(point) for point in points 693 ] 695 num_points = len(points) 697 # get the number of batches

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/algorithms/optimizers/spsa.py:692, in (.0) 687 def _batch_evaluate(function, points, max_evals_grouped): 688 # if the function cannot handle lists of points as input, cover this case immediately 689 if max_evals_grouped == 1: 690 # support functions with multiple arguments where the points are given in a tuple 691 return [ --> 692 function(*point) if isinstance(point, tuple) else function(point) for point in points 693 ] 695 num_points = len(points) 697 # get the number of batches

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit_machine_learning/utils/loss_functions/kernel_loss_functions.py:109, in SVCLoss.evaluate(self, parameter_values, quantum_kernel, data, labels) 106 quantum_kernel.assign_user_parameters(parameter_values) 108 # Get estimated kernel matrix --> 109 kmatrix = quantum_kernel.evaluate(np.array(data)) 111 # Train a quantum support vector classifier 112 svc = SVC(kernel="precomputed", **self.kwargs)

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit_machine_learning/kernels/quantum_kernel.py:486, in QuantumKernel.evaluate(self, x_vec, y_vec) 484 for min_idx in range(0, len(to_be_computed_data), self._batch_size): 485 max_idx = min(min_idx + self._batch_size, len(to_be_computed_data)) --> 486 circuits = [ 487 parameterized_circuit.assign_parameters({feature_map_params: x}) 488 for x in to_be_computed_data[min_idx:max_idx] 489 ] 490 results = self._quantum_instance.execute(circuits, had_transpiled=True) 491 for j in range(max_idx - min_idx):

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit_machine_learning/kernels/quantum_kernel.py:487, in (.0) 484 for min_idx in range(0, len(to_be_computed_data), self._batch_size): 485 max_idx = min(min_idx + self._batch_size, len(to_be_computed_data)) 486 circuits = [ --> 487 parameterized_circuit.assign_parameters({feature_map_params: x}) 488 for x in to_be_computed_data[min_idx:max_idx] 489 ] 490 results = self._quantum_instance.execute(circuits, had_transpiled=True) 491 for j in range(max_idx - min_idx):

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/circuit/quantumcircuit.py:2494, in QuantumCircuit.assign_parameters(self, parameters, inplace) 2490 bound_circuit._name_update() 2492 if isinstance(parameters, dict): 2493 # unroll the parameter dictionary (needed if e.g. it contains a ParameterVector) -> 2494 unrolled_param_dict = self._unroll_param_dict(parameters) 2495 unsorted_parameters = self._unsorted_parameters() 2497 # check that all param_dict items are in the _parameter_table for this circuit

File ~/opt/anaconda3/envs/qkt/lib/python3.9/site-packages/qiskit/circuit/quantumcircuit.py:2564, in QuantumCircuit._unroll_param_dict(self, value_dict) 2562 if isinstance(param, ParameterVector): 2563 if not len(param) == len(value): -> 2564 raise CircuitError( 2565 "ParameterVector {} has length {}, which " 2566 "differs from value list {} of " 2567 "len {}".format(param, len(param), value, len(value)) 2568 ) 2569 unrolled_value_dict.update(zip(param, value)) 2570 # pass anything else except number through. error checking is done in assign_parameter

CircuitError: 'ParameterVector par_x, [] has length 0, which differs from value list [-0.19416302 0.42604558 0.04101789 0.03351072 -0.3293413 -0.1803665 ] of len 6'

jenglick commented 2 years ago

Thanks for the code! I took a look and the way you built the custom feature map using two ZZFeatureMaps from Qiskit is correct (which you can check by visualizing the circuit, as you did). It's when you later set up the QuantumKernel and QuantumKernelTrainer objects that two small (but important!) errors were introduced with the parameters. Since we're interested in trainable quantum kernels for QKT, we distinguish between the parameters that encode the input data and those that are trainable (called user_parameters). When we instantiate the QuantumKernel and QuantumKernelTrainer, we need to be careful to give them the trainable parameters (user_parameters):

  1. Instantiate the quantum kernel
# original version
quant_kernel = QuantumKernel(fm,
                             user_parameters=fm.parameters,
                             quantum_instance=backend) 

In the above code, the argument user_parameters is set to fm.parameters. This tells the quantum kernel that all of our circuit parameters are trainable (x[0], x[1], ... and θ[0], θ[1], ...). Instead, we only want to pass it the trainable parameters you defined earlier, user_params. So the correct code block would be:

# correct version
quant_kernel = QuantumKernel(fm,
                             user_parameters=user_params,
                             quantum_instance=backend) 
  1. Instantiate the quantum kernel trainer
# original version
qkt = QuantumKernelTrainer(
    quantum_kernel=quant_kernel,
    loss="svc_loss",
    optimizer=spsa_opt,
    initial_point=[0.1]*len(fm.parameters)
)

Here, the issue is how initial_point is specified. This argument tells the optimizer what values to start the trainable parameters at -- in your case at 0.1. So, similar to the first point, instead of using all the circuit parameters (via fm.parameters), we should only use those that are trainable (user_params). The correct code block would be:

# correct version
qkt = QuantumKernelTrainer(
    quantum_kernel=quant_kernel,
    loss="svc_loss",
    optimizer=spsa_opt,
    initial_point=[0.1]*len(user_params)
)

Hope this helps!

dancbeaulieu commented 2 years ago

Hi Jen,

I made the change you suggested, and am getting the error "AttributeError: 'ZZFeatureMap' object has no attribute 'user_params'"

Define two circuits

circ1 = ZZFeatureMap(col_dim_pca) circ2 = ZZFeatureMap(col_dim_pca) input_params = circ1.parameters user_params = ParameterVector('θ', col_dim_pca)

Reassign new parameters to circ2 so there are no name collisions

circ2.assign_parameters(user_params, inplace=True)

Compose to build a parameterized feature map

fm = circ2.compose(circ1) print("input_params:", list(input_params)) print("user_params:", user_params) fm.draw()

Use the qasm simulator backend

backend = Aer.get_backend('aer_simulator') ​

Instantiate quantum kernel

quant_kernel = QuantumKernel(fm, user_parameters=fm.user_params, quantum_instance=backend) ​

Set up the optimizer

cb_qkt = QKTCallback() spsa_opt = SPSA(maxiter=5, callback=cb_qkt.callback, learning_rate=0.1, perturbation=0.1 ) ​

Instantiate a quantum kernel trainer.

qkt = QuantumKernelTrainer( quantum_kernel=quant_kernel, loss="svc_loss", optimizer=spsa_opt, initial_point=[0.1]*len(fm.user_params) )

AttributeError Traceback (most recent call last) Input In [25], in 2 backend = Aer.get_backend('aer_simulator') 4 # Instantiate quantum kernel 5 quant_kernel = QuantumKernel(fm, ----> 6 user_parameters=fm.user_params, 7 quantum_instance=backend) 9 # Set up the optimizer 10 cb_qkt = QKTCallback()

AttributeError: 'ZZFeatureMap' object has no attribute 'user_params'

jenglick commented 2 years ago

That's right, this feature map does not have the attribute user_params -- but you don't need it to. You've already defined your own user_params that you can pass to both objects (see also my previous message):

Quantum Kernel: user_parameters=user_params

Quantum Kernel Trainer: initial_point=user_params

caleb-johnson commented 2 years ago

Marking this resolved.

dancbeaulieu commented 2 years ago

Hi, my apologies for the late reply, was pulled onto other work and had to leave this behind for a bit. I still can't figure out what I am doing wrong. I get len(user_params) = 5 when I run that command, so not sure why its reading it as none.

feature_dimension = 10
num_qubits = int(feature_dimension / 2)
user_params = ParameterVector("θ", num_qubits)
print(feature_dimension, num_qubits)

en_map = ZZFeatureMap(feature_dimension=col_dim_pca, 
                      reps=2, 
                      entanglement='linear', 
                      data_map_func=None , 
                      insert_barriers=True)

zz_ker = QuantumKernel(feature_map=en_map, 
                       quantum_instance=simulator, 
                       user_parameters = user_params)

adhoc_backend = QuantumInstance(
    provider_2.get_backend("ibmq_qasm_simulator"), 
                            shots=1024, 
                            seed_simulator=42, 
                            seed_transpiler=42
)

adhoc_kernel = QuantumKernel(feature_map=em, 
                             quantum_instance=adhoc_backend)

cb_qkt = QKTCallback()
spsa_opt = SPSA(maxiter=5,
                callback=cb_qkt.callback,
                learning_rate=0.1,
                perturbation=0.1
           )

qkt = QuantumKernelTrainer(
    quantum_kernel=adhoc_kernel,
    loss="svc_loss",
    optimizer=spsa_opt,
    initial_point=[0.1]*len(user_params)
)
# Train the kernel using QKT directly
qka_results = qkt.fit(X_train_q, y_train_q)
optimized_kernel = qka_results.quantum_kernel

# Use QSVC for classification
qsvc = QSVC(quantum_kernel=optimized_kernel)

# Fit the QSVC
qsvc.fit(X_train_q, y_train_q)

# Predict the labels
labels_test = qsvc.predict(X_test_q)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [89], in <module>
      1 # Train the kernel using QKT directly
----> 2 qka_results = qkt.fit(X_train_q, y_train_q)
TypeError: object of type 'NoneType' has no len()
caleb-johnson commented 2 years ago

Hi Dan, it looks like you may not have set the user_parameters field of your QuantumKernel. Please pass a list of parameters you wish to train from your feature map circuit into the QuantumKernel.user_parameters field before calling the fit method.

This error could certainly be more informative though. We will submit an issue and PR to Qiskit Machine Learning to improve this error. Thanks!