• Docs >
  • Module code >
  • qiskit_machine_learning.kernels.algorithms.quantum_kernel_trainer

Source code for qiskit_machine_learning.kernels.algorithms.quantum_kernel_trainer

# This code is part of Qiskit.
# (C) Copyright IBM 2021.
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Quantum Kernel Trainer"""
import copy
from functools import partial
from typing import Union, Optional, Sequence

import numpy as np

from qiskit.utils.algorithm_globals import algorithm_globals
from qiskit.algorithms.optimizers import Optimizer, SPSA
from qiskit.algorithms.variational_algorithm import VariationalResult
from qiskit_machine_learning.utils.loss_functions import KernelLoss, SVCLoss

from qiskit_machine_learning.kernels import QuantumKernel

[docs]class QuantumKernelTrainerResult(VariationalResult): """Quantum Kernel Trainer Result.""" def __init__(self) -> None: super().__init__() self._quantum_kernel: QuantumKernel = None @property def quantum_kernel(self) -> Optional[QuantumKernel]: """Return the optimized quantum kernel object.""" return self._quantum_kernel @quantum_kernel.setter def quantum_kernel(self, quantum_kernel: QuantumKernel) -> None: self._quantum_kernel = quantum_kernel
[docs]class QuantumKernelTrainer: """ Quantum Kernel Trainer. This class provides utility to train ``QuantumKernel`` feature map parameters. **Example** .. code-block:: # Create 2-qubit feature map qc = QuantumCircuit(2) # Vectors of input and trainable user parameters input_params = ParameterVector("x_par", 2) user_params = ParameterVector("θ_par", 2) # Create an initial rotation layer of trainable parameters for i, param in enumerate(user_params): qc.ry(param, qc.qubits[i]) # Create a rotation layer of input parameters for i, param in enumerate(input_params): qc.rz(param, qc.qubits[i]) quant_kernel = QuantumKernel( feature_map=qc, user_parameters=user_params, quantum_instance=... ) loss_func = ... optimizer = ... initial_point = ... qk_trainer = QuantumKernelTrainer( quantum_kernel=quant_kernel, loss=loss_func, optimizer=optimizer, initial_point=initial_point, ) qkt_results = qk_trainer.fit(X_train, y_train) optimized_kernel = qkt_results.quantum_kernel """ def __init__( self, quantum_kernel: QuantumKernel, loss: Optional[Union[str, KernelLoss]] = None, optimizer: Optional[Optimizer] = None, initial_point: Optional[Sequence[float]] = None, ): """ Args: quantum_kernel: QuantumKernel to be trained loss (str or KernelLoss): Loss functions available via string: {'svc_loss': SVCLoss()}. If a string is passed as the loss function, then the underlying KernelLoss object will exhibit default behavior. optimizer: An instance of ``Optimizer`` to be used in training. Since no analytical gradient is defined for kernel loss functions, gradient-based optimizers are not recommended for training kernels. initial_point: Initial point from which the optimizer will begin. Raises: ValueError: unknown loss function """ # Class fields self._quantum_kernel = quantum_kernel self._initial_point = initial_point self._optimizer = optimizer or SPSA() # Loss setter self._set_loss(loss) @property def quantum_kernel(self) -> QuantumKernel: """Return the quantum kernel object.""" return self._quantum_kernel @quantum_kernel.setter def quantum_kernel(self, quantum_kernel: QuantumKernel) -> None: """Set the quantum kernel.""" self._quantum_kernel = quantum_kernel @property def loss(self) -> KernelLoss: """Return the loss object.""" return self._loss @loss.setter def loss(self, loss: Optional[Union[str, KernelLoss]]) -> None: """ Set the loss. Args: loss: a loss function to set Raises: ValueError: Unknown loss function """ self._set_loss(loss) @property def optimizer(self) -> Optimizer: """Return an optimizer to be used in training.""" return self._optimizer @optimizer.setter def optimizer(self, optimizer: Optimizer) -> None: """Set the optimizer.""" self._optimizer = optimizer @property def initial_point(self) -> Optional[Sequence[float]]: """Return initial point""" return self._initial_point @initial_point.setter def initial_point(self, initial_point: Optional[Sequence[float]]) -> None: """Set the initial point""" self._initial_point = initial_point
[docs] def fit( self, data: np.ndarray, labels: np.ndarray, ) -> QuantumKernelTrainerResult: """ Train the QuantumKernel by minimizing loss over the kernel parameters. The input quantum kernel will not be altered, and an optimized quantum kernel will be returned. Args: data (numpy.ndarray): ``(N, D)`` array of training data, where ``N`` is the number of samples and ``D`` is the feature dimension labels (numpy.ndarray): ``(N, 1)`` array of target values for the training samples Returns: QuantumKernelTrainerResult: the results of kernel training Raises: ValueError: No trainable user parameters specified in quantum kernel """ # Number of parameters to tune num_params = len(self._quantum_kernel.user_parameters) if num_params == 0: msg = "Quantum kernel cannot be fit because there are no user parameters specified." raise ValueError(msg) # Bind inputs to objective function output_kernel = copy.deepcopy(self._quantum_kernel) # Randomly initialize the initial point if one was not passed if self._initial_point is None: self._initial_point = algorithm_globals.random.random(num_params) # Perform kernel optimization loss_function = partial( self._loss.evaluate, quantum_kernel=self.quantum_kernel, data=data, labels=labels ) opt_results = self._optimizer.minimize( fun=loss_function, x0=self._initial_point, ) # Return kernel training results result = QuantumKernelTrainerResult() result.optimizer_evals = opt_results.nfev result.optimal_value = opt_results.fun result.optimal_point = opt_results.x result.optimal_parameters = dict(zip(output_kernel.user_parameters, opt_results.x)) # Return the QuantumKernel in optimized state output_kernel.assign_user_parameters(result.optimal_parameters) result.quantum_kernel = output_kernel return result
def _set_loss(self, loss: Optional[Union[str, KernelLoss]]) -> None: """Internal setter.""" if loss is None: loss = SVCLoss() elif isinstance(loss, str): loss = self._str_to_loss(loss) self._loss = loss def _str_to_loss(self, loss_str: str) -> KernelLoss: """Function which maps strings to default KernelLoss objects.""" if loss_str == "svc_loss": loss_obj = SVCLoss() else: raise ValueError(f"Unknown loss {loss_str}!") return loss_obj

© Copyright 2018, 2021, Qiskit Machine Learning Development Team.

Built with Sphinx using a theme provided by Read the Docs.