-
Notifications
You must be signed in to change notification settings - Fork 329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add QuantumKernelTrainer and KernelLoss classes #244
Add QuantumKernelTrainer and KernelLoss classes #244
Conversation
…o accept QKT as input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank! A couple of questions:
- Are there any papers to reference in the documentation?
- Does QKA works for QSVR?
def test_qkt(self): | ||
"""Test QuantumKernelTrainer""" | ||
self.setUp() | ||
with self.subTest("check default fit"): | ||
qkt = QuantumKernelTrainer(optimizer=self.optimizer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a test where QuantumKernelTrainer
is instantiated with all default values?
@calebj15 Are there any updates on this PR? |
…to quantum-kernel-trainer
… QuantumKernel.assign_user_parameters more robust and add user tests to test parameter expression assignment. Test QKT outputs in tests.
…to quantum-kernel-trainer
…achine-learning into quantum-kernel-trainer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Any plans to add a tutorial on QKT?
super().setUp() | ||
algorithm_globals.random_seed = 10598 | ||
self.optimizer = COBYLA(maxiter=25) | ||
self.backend = Aer.get_backend("statevector_simulator") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed, please replace statevector_simulator
with aer_simulator_statevector
, otherwise there's a deprecation warning.
self.backend = Aer.get_backend("statevector_simulator") | |
self.backend = Aer.get_backend("aer_simulator_statevector") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I left a few minor comments.
# Class fields | ||
self._quantum_kernel = quantum_kernel | ||
self._initial_point = initial_point | ||
self._optimizer = optimizer if optimizer else SPSA() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified:
self._optimizer = optimizer if optimizer else SPSA() | |
self._optimizer = optimizer or SPSA() |
self._loss = loss | ||
else: | ||
raise ValueError(f"Unknown loss {loss}!") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I pass a callable Callable[[Sequence[float]], float]
, I get an exception.
Could you also add a test with a custom loss to check this scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I believe we decided against this usage, so I just need to update type hint. Thanks
return self._loss | ||
|
||
@loss.setter | ||
def loss(self, loss: KernelLoss) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setter type should be the same as in the constructor.
def test_qkt(self): | ||
"""Test QuantumKernelTrainer""" | ||
self.setUp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.setUp()
is not required. Please remove.
|
||
with self.subTest("check fit with params"): | ||
self.setUp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.setUp()
is not required. Please remove.
@calebj15 you have a conflict in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the tutorial!I think we are converging and a few minor things are left in the code and tutorial.
{ | ||
"cells": [ | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename tutorial to 08
. There are already two new tutorials 06 Torch runtime
, 07 PegasosQSVC
.
" x[0]: number of function evaluations\n", | ||
" x[1]: the parameters\n", | ||
" x[2]: the function value\n", | ||
" x[3]: the stepsize\n", | ||
" x[4]: whether the step was accepted\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reformat as a proper docstring. By the way, starting last week, black
should applied on the doc
folder as well.
"source": [ | ||
"### Prepare the Dataset\n", | ||
"\n", | ||
"QKT only provides an advantage over classical counterparts for quantum kernels which are hard to compute classically. Finding quantum kernels which provide an advantage on real world data is a challenge in itself and is outside the scope of this tutorial.\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"QKT only provides an advantage over classical counterparts for quantum kernels which are hard to compute classically. Finding quantum kernels which provide an advantage on real world data is a challenge in itself and is outside the scope of this tutorial.\n", | |
"`QuantumKernelTrainer` only provides an advantage over classical counterparts for quantum kernels which are hard to compute classically. Finding quantum kernels which provide an advantage on real world data is a challenge in itself and is outside the scope of this tutorial.\n", |
"\n", | ||
"QKT only provides an advantage over classical counterparts for quantum kernels which are hard to compute classically. Finding quantum kernels which provide an advantage on real world data is a challenge in itself and is outside the scope of this tutorial.\n", | ||
"\n", | ||
"In this guide, we will use Qiskit Machine Learning's `ad_hoc.py` dataset located [here](../../qiskit_machine_learning/datasets/). Quantum kernel training does not provide a classification advantage on this dataset, but we will use it to demonstrate the kernel training process." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"In this guide, we will use Qiskit Machine Learning's `ad_hoc.py` dataset located [here](../../qiskit_machine_learning/datasets/). Quantum kernel training does not provide a classification advantage on this dataset, but we will use it to demonstrate the kernel training process." | |
"In this guide, we will use Qiskit Machine Learning's `ad_hoc` dataset, see the documentation [here](https://qiskit.org/documentation/machine-learning/stubs/qiskit_machine_learning.datasets.ad_hoc_data.html). Quantum kernel training does not provide a classification advantage on this dataset, but we will use it to demonstrate the kernel training process." |
"\n", | ||
"Additionally, we select SPSA as the optimizer and initialize the trainable parameter to 0.1 with `initial_point`.\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the code initial_point
set as initial_point=[0.0]
, while in the text it is mentioned 0.1
. Please correct.
"# To use the quantum-kernel-trainer runtime client, users should replace\n", | ||
"# QuantumKernelTrainer with the\n", | ||
"# qiskit_machine_learning.runtime.QuantumKernelTrainerClient class.\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather remove this comment about the runtime. Once runtime is out, the tutorial can be extended.
"{ 'optimal_parameters': {ParameterVectorElement(θ[0]): -0.0717475136739174},\n", | ||
" 'optimal_point': array([-0.07174751]),\n", | ||
" 'optimal_value': 6.825533666231239,\n", | ||
" 'optimizer_evals': 30,\n", | ||
" 'optimizer_time': None,\n", | ||
" 'quantum_kernel': <qiskit_machine_learning.kernels.quantum_kernel.QuantumKernel object at 0x7fdda0701b50>}\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a description of what you get in qka_results
?
"From the callback data, we can plot how the loss evolves during the training process. We see it converges rapidly and reaches 100% test accuracy on this dataset with our choice of inputs.\n", | ||
"\n", | ||
"We can also display the final kernel matrix evaluated on the training data." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please a description of what is shown on the kernel matrix plot in various colors?
loss: Union[str, Callable[[Sequence[float]], float]] = "svc_loss", | ||
optimizer: Optional[Optimizer] = None, | ||
initial_point: Optional[Sequence[float]] = None, | ||
): | ||
""" | ||
Args: | ||
quantum_kernel: QuantumKernel to be trained | ||
loss (Callable[[Sequence[float]], float] or str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please update loss type hints to be the same across the code? I guess it should be Union[str, KernelLoss]
now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I hope I left last two comments :)
"source": [ | ||
"### Train the Quantum Kernel\n", | ||
"\n", | ||
"To train the quantum kernel on the dataset (samples and labels), we call the `fit_kernel` method of `QuantumKernelTrainer`.\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"To train the quantum kernel on the dataset (samples and labels), we call the `fit_kernel` method of `QuantumKernelTrainer`.\n", | |
"To train the quantum kernel on the dataset (samples and labels), we call the `fit` method of `QuantumKernelTrainer`.\n", |
loss = loss.lower() | ||
if loss == "svc_loss": | ||
self._loss = self._str_to_loss(loss) | ||
else: | ||
raise ValueError(f"Unknown loss {loss}!") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess a string to loss conversion is done in the _str_to_loss
, so these checks are unnecessary as you mentioned below.
@stefan-woerner Please review as well as you left a change request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would consider renaming user_parameters
to kernel_parameters
but otherwise I am good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
* Add QuantumKernelTrainer class, KernelLoss class, and refactor QSVC to accept QKT as input. * Refactor to unconfuse mypy * Add runtime client for QKA * Remove qka program info from __init__ * Remove vqe language from qka client * Retract changes to QSVC * Address peer review comments. Remove kernels.algorithms package. Make QuantumKernel.assign_user_parameters more robust and add user tests to test parameter expression assignment. Test QKT outputs in tests. * Change SVCAlignment class to SVCLoss and update KernelLoss doc strings. * Fix equation in SVCLoss docstring * Docstring improvements * Add quantum kernel trainer runtime client and unit tests. * Fix spelling errors * Fix spelling errors * Clean up docstring for SVCLoss * Clean up docstring for SVCLoss * Fix spelling errors * Fix equation formatting in docstring * Fix equation formatting in docstring * New spelling errors * New spelling errors * Fix spelling errors. Add 'runtime' to pylint dict * Fix mypy errors * Fix mypy errors * style error * style error * spelling error in docstring * Fix circular imports due to typing. * Fix circular imports due to typing. * Make QuantumKernel class serializable by runtime. * Update quantum_kernel_trainer.py * Update quantum_kernel_trainer.py * Update quantum_kernel_trainer.py * Make KernelLoss.get_variational_callable a base method * Make SVCLoss more efficient by only calculating kernel once * Create kernels.algorithms package for QuantumKernelTrainer. Fix all CI/CD errors * spelling errors * Clean up kernel loss docstring * Create kernels.algorithms package for quantum kernel trainer. Clean up CI/CD errors. Address kernel loss feedback. * spelling errors * spelling errors * spelling errors * Create separate file for kernel loss classes. Fix spelling errors. * add runtime to pylint dict * add vqe to pylint dict * Address peer feedback * html errors * Address peer review comments * Fix mypy errors * Add a quantum kernel training tutorial * Print results of kernel fitting in tutorial * Rename QKT tutorial. Fix bad assertion in qkt test. * Make QKT tests deterministic. Add to pylintdict * Address minor comments in qkt tutorial * Fix spelling errors in QKT tutorial * Clean up docstring for qkt * Fix comment in qkt tutorial. Remove unnecessary type checks from QKT module * Clean up docstring in QKT * Fix mypy error in qkt * Fix mypy errors in qkt * Fix mypy errors in qkt Co-authored-by: Manoel Marques <[email protected]>
Summary
Closes #227
Variational quantum algorithms generally aim to train some quantum circuit parameters using a classical optimizer. To implement this, parameters of a
QuantumCircuit
must be bound and re-bound many times during optimization; however, theQuantumCircuit
API "forgets" the parameter after it is bound, making consecutive binds of aQuantumCircuit
parameter a cumbersome process.The introduction of a
QuantumKernelTrainer (QKT)
class simplifies this process by providing afit_kernel
method, which will return some optimizedQuantumKernel.feature_map
parameter values which can be used to generate an optimized kernel operator.Changes from this PR:
Addition of a
qiskit_machine_learning.kernels.algorithms.QuantumKernelTrainer (QKT)
class which facilitates optimizing a set of a parameters within aQuantumKernel
feature map with regard to a given dataset.Addition of a new
qiskit_machine_learning.utils.loss_functions
base class,KernelLoss
.KernelLoss
functions take a set of circuit parameters to optimize, aQuantumKernel
object, and a labeled dataset as input and provide a loss value as output.Addition of a new
KernelLoss
child class,SVCLoss
.