Parameter and Gradients#
It can be useful to define custom parameters in an optimization context. For
example, the rotational angles which encodes information in a Quantum Neural Network
are usually built as a combination of features and trainable parameters. For
doing this, the qibo.parameter.Parameter class can be used. It allows
to define custom parameters which can be inserted into a qibo.models.circuit.Circuit.
Moreover, it automatically precomputes the analytical derivative of the parameter
function, which can be used to calculate the derivatives of a variational model
with respect to its parameters.
- qibo.parameter.calculate_derivatives(func)[source]#
Calculates derivatives w.r.t. to all parameters of a target function func.
- class qibo.parameter.Parameter(func, trainable=None, features=None)[source]#
Object which allows for variational gate parameters. Several trainable parameters and possibly features are linked through a lambda function which returns the final gate parameter. All possible analytical derivatives of the lambda function are calculated at the object initialisation using Sympy.
Example:
from qibo.parameter import Parameter param = Parameter( lambda x, th1, th2, th3: x**2 * th1 + th2 * th3**2, features=[7.0], trainable=[1.5, 2.0, 3.0], ) partial_derivative = param.get_partial_derivative(3) param.update_parameters(trainable=[15.0, 10.0, 7.0], feature=[5.0]) param_value = param()
- Parameters:
func (function) – lambda function which builds the gate parameter. If both features and trainable parameters compose the function, it must be passed by first providing the features and then the parameters, as described in the code example above.
features (list or np.ndarray) – array containing possible input features x.
trainable (list or np.ndarray) – array with initial trainable parameters theta.
- property nparams#
Returns the number of trainable parameters
- property nfeat#
Returns the number of features
- property ncomponents#
Return the number of elements which compose the Parameter
- trainable_parameter_indices(start_index)[source]#
Return list of respective indices of trainable parameters within the larger trainable parameter list of a circuit for example
Gradients#
In the context of optimization, particularly when dealing with Quantum Machine Learning problems, it is often necessary to calculate the gradients of functions that are to be minimized (or maximized). Hybrid methods, which are based on the use of classical techniques for the optimization of quantum computation procedures, have been presented in the Optimizers section. This approach is very useful in simulation, but some classical methods cannot be used when using real circuits: for example, in the context of neural networks, the Back-Propagation algorithm is used, where it is necessary to know the value of a target function during the propagation of information within the network. Using a real circuit, we would not be able to access this information without taking a measurement, causing the state of the system to collapse and losing the information accumulated up to that moment. For this reason, in qibo we have also implemented methods for calculating the gradients which can be performed directly on the hardware, such as the Parameter Shift Rule.
- qibo.derivative.parameter_shift(circuit, hamiltonian, parameter_index, initial_state=None, scale_factor=1, nshots=None)[source]#
In this method the parameter shift rule (PSR) is implemented.
Given a circuit \(U\) and an observable \(H\), the PSR allows to calculate the derivative of the expected value of \(H\) on the final state with respect to a variational parameter of the circuit. There is also the possibility of setting a scale factor. It is useful when a circuit’s parameter is obtained by combination of a variational parameter and an external object, such as a training variable in a Quantum Machine Learning problem. For example, performing a re-uploading strategy to embed some data into a circuit, we apply to the quantum state rotations whose angles are in the form \(\theta^{\prime} = x \, \theta\), where \(\theta\) is a variational parameter, and \(x\) an input variable. The PSR allows to calculate the derivative with respect to \(\theta^{\prime}\). However, if we want to optimize a system with respect to its variational parameters, we need to “free” this procedure from the \(x\) depencency. If the
scale_factoris not provided, it is set equal to one and doesn’t affect the calculation. If the PSR is needed to be executed on a real quantum device, it is important to setnshotsto some integer value. This enables the execution on the hardware by calling the proper methods.- Parameters:
circuit (
qibo.models.circuit.Circuit) – custom quantum circuit.hamiltonian (
qibo.hamiltonians.Hamiltonian) – target observable. if you want to execute on hardware, a symbolic hamiltonian must be provided as follows (example with Pauli-\(Z\) and \(n = 1\)):SymbolicHamiltonian(np.prod([ Z(qubit) for qubit in range(1) ])).parameter_index (int) – the index which identifies the target parameter in the
circuit.get_parameters()list.initial_state (ndarray, optional) – initial state on which the circuit acts. If
None, defaults to the zero state \(\ket{\mathbf{0}}\). Defaults toNone.scale_factor (float, optional) – parameter scale factor. Defaults to \(1\).
nshots (int, optional) – number of shots if derivative is evaluated on hardware. If
None, the simulation mode is executed. Defaults toNone.
- Returns:
- Value of the derivative of the expectation value of the hamiltonian
with respect to the target variational parameter.
- Return type:
Example
import numpy as np from qibo import Circuit, gates from qibo.hamiltonians import Hamiltonian, Z from qibo.derivative import parameter_shift # defining an observable def hamiltonian(nqubits = 1): m0 = (1/nqubits)*Z(nqubits).matrix ham = Hamiltonian(nqubits, m0) return ham # defining a dummy circuit def circuit(nqubits = 1): circ = Circuit(nqubits = 1) circ.add(gates.RY(q = 0, theta = 0)) circ.add(gates.RX(q = 0, theta = 0)) circ.add(gates.M(0)) return circ # initializing the circuit circ = circuit(nqubits = 1) # some parameters test_params = np.random.randn(2) circ.set_parameters(test_params) test_hamiltonian = hamiltonian() # running the psr with respect to the two parameters grad_0 = parameter_shift(circuit=circ, hamiltonian=test_hamiltonian, parameter_index=0) grad_1 = parameter_shift(circuit=circ, hamiltonian=test_hamiltonian, parameter_index=1)
- qibo.derivative.finite_differences(circuit, hamiltonian, parameter_index, initial_state=None, step_size=1e-07)[source]#
Calculate derivative of the expectation value of
hamiltonianon the final state obtained by executingcircuitoninitial_statewith respect to the variational parameter identified byparameter_indexin the circuit’s parameters list. This method can be used only in exact simulation mode.- Parameters:
circuit (
qibo.models.circuit.Circuit) – custom quantum circuit.hamiltonian (
qibo.hamiltonians.Hamiltonian) – target observable. To execute on hardware, a symbolic hamiltonian must be provided as follows (example with Pauli-\(Z\) and \(n = 1\)):SymbolicHamiltonian(np.prod([ Z(qubit) for qubit in range(1) ])).parameter_index (int) – the index which identifies the target parameter in the
qibo.models.Circuit.get_parameters()list.initial_state (ndarray, optional) – initial state on which the circuit acts. If
None, defaults to the zero state \(\ket{\mathbf{0}}\). Defaults toNone.step_size (float, optional) – step size used to evaluate the finite difference. Defaults to \(10^{-7}\).
- Returns:
- Value of the derivative of the expectation value of the hamiltonian
with respect to the target variational parameter.
- Return type: