Training#
This section describes how to use the model provided with this package, using a simple training scenario as an example.
We consider a Fourier series with \(n\) frequencies defined as follows:
Here, \(\omega \in \boldsymbol{\Omega}\) are the frequencies in the spectrum with the Fourier coefficients \(c_{\omega}(\boldsymbol{\theta})\), parameterized by the set of trainable parameters \(\boldsymbol{\theta}\).
As shown by Schuld et al. (2020), a quantum circuit, parametrised by \(\boldsymbol{\theta}\) and input \(x\) and is equivalent to the Fourier series representation. Such circuits must be of the following form:
Therefore, training such a model on a Fourier series is a proof-of-concept which we want to demonstrate here.
Let's start with building our dataset. A Fourier series with \(4\) frequencies:
import pennylane.numpy as np
import matplotlib.pyplot as plt
domain = [-np.pi, np.pi]
omegas = np.array([1, 2, 3, 4])
coefficients = np.array([0.5, 0.5, 0.5, 0.5])
# Calculate the number of required samples to satisfy the Nyquist criterium
n_d = int(np.ceil(2 * np.max(np.abs(domain)) * np.max(omegas)))
# Sample the domain linearly
x = np.linspace(domain[0], domain[1], num=n_d)
# define our Fourier series f(x)
def f(x):
return 1 / np.linalg.norm(omegas) * np.sum(coefficients * np.cos(omegas.T * x))
# evaluate f(x) on the domain samples
y = np.stack([f(sample) for sample in x])
plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.show()
Note that we chose the coefficients to be all \(0.5\). Play around with those values to change the magnitude of each frequency component. Also note that we're using the Pennylane version of Numpy, which is required because of the optimizer that we will be using later. Now that we have our "dataset", let's move on and build a model:
from qml_essentials.model import Model
model = Model(
n_qubits=4,
n_layers=1,
circuit_type="Circuit_19",
)
This is the minimal amout of information needed. According to the work referenced above, a model with \(4\) qubits should be capable of learning a Fourier series with \(4\) frequencies, considering single qubit Pauli encoding (which we have by default).
Now, let's train our model:
import pennylane as qml
opt = qml.AdamOptimizer(stepsize=0.01)
def cost_fct(params):
y_hat = model(params=params, inputs=x, force_mean=True)
return np.mean((y_hat - y) ** 2)
for epoch in range(1, 1001):
model.params, cost_val = opt.step_and_cost(cost_fct, model.params)
if epoch % 100 == 0:
print(f"Epoch: {epoch}, Cost: {cost_val:.4f}")
plt.plot(x, y, label="True function")
plt.plot(x, model(params=model.params, inputs=x, force_mean=True), label="Model prediction")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.show()
Epoch: 100, Cost: 0.0081
Epoch: 200, Cost: 0.0073
Epoch: 300, Cost: 0.0051
Epoch: 400, Cost: 0.0043
Epoch: 500, Cost: 0.0036
Epoch: 600, Cost: 0.0022
Epoch: 700, Cost: 0.0014
Epoch: 800, Cost: 0.0008
Epoch: 900, Cost: 0.0006
Epoch: 1000, Cost: 0.0001
As you can see, the model is able to learn the Fourier series with the \(4\) frequencies.
Btw. if you're in a hurry, we have a Jupyter notebook with the exact same example here .
Wondering what to do next? You can try a few different models, and see how they perform. If you're curious, checkout how this correlates with the Entanglement and Expressibility of the model.