1176 lines (1175 with data), 100.0 kB
{
"cells": [
{
"cell_type": "code",
"execution_count": 122,
"metadata": {
"id": "IZi5TUAp-1Lt",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"outputId": "1b8c7132-47e7-445b-a4bd-56ca35c5ecb6"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Time in seconds since beginning of run: 1700544102.175086\n",
"Tue Nov 21 05:21:42 2023\n"
]
}
],
"source": [
"# This cell is added by sphinx-gallery\n",
"# It can be customized to whatever you like\n",
"%matplotlib inline\n",
"# !pip install pennylane\n",
"import time\n",
"seconds = time.time()\n",
"print(\"Time in seconds since beginning of run:\", seconds)\n",
"local_time = time.ctime(seconds)\n",
"print(local_time)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "yx4UlxKp-1Lu"
},
"source": [
"Training and evaluating quantum kernels\n",
"=======================================\n",
"\n",
"::: {.meta}\n",
":property=\\\"og:description\\\": Kernels and alignment training with\n",
"Pennylane. :property=\\\"og:image\\\":\n",
"<https://pennylane.ai/qml/_images/QEK_thumbnail.png>\n",
":::\n",
"\n",
"::: {.related}\n",
"tutorial\\_kernel\\_based\\_training Kernel-based training with\n",
"scikit-learn tutorial\\_data\\_reuploading\\_classifier Data-reuploading\n",
"classifier\n",
":::\n",
"\n",
"*Authors: Peter-Jan Derks, Paul K. Faehrmann, Elies Gil-Fuster, Tom\n",
"Hubregtsen, Johannes Jakob Meyer and David Wierichs --- Posted: 24 June\n",
"2021. Last updated: 18 November 2021.*\n",
"\n",
"Kernel methods are one of the cornerstones of classical machine\n",
"learning. Here we are concerned with kernels that can be evaluated on\n",
"quantum computers, *quantum kernels* for short. In this tutorial you\n",
"will learn how to evaluate kernels, use them for classification and\n",
"train them with gradient-based optimization, and all that using the\n",
"functionality of PennyLane\\'s [kernels\n",
"module](https://pennylane.readthedocs.io/en/latest/code/qml_kernels.html).\n",
"The demo is based on Ref., a project from Xanadu\\'s own\n",
"[QHack](https://qhack.ai/) hackathon.\n",
"\n",
"What are kernel methods?\n",
"------------------------\n",
"\n",
"To understand what a kernel method does, let\\'s first revisit one of the\n",
"simplest methods to assign binary labels to datapoints: linear\n",
"classification.\n",
"\n",
"Imagine we want to discern two different classes of points that lie in\n",
"different corners of the plane. A linear classifier corresponds to\n",
"drawing a line and assigning different labels to the regions on opposing\n",
"sides of the line:\n",
"\n",
"{.align-center\n",
"width=\"30.0%\"}\n",
"\n",
"We can mathematically formalize this by assigning the label $y$ via\n",
"\n",
"$$y(\\boldsymbol{x}) = \\operatorname{sgn}(\\langle \\boldsymbol{w}, \\boldsymbol{x}\\rangle + b).$$\n",
"\n",
"The vector $\\boldsymbol{w}$ points perpendicular to the line and thus\n",
"determine its slope. The independent term $b$ specifies the position on\n",
"the plane. In this form, linear classification can also be extended to\n",
"higher dimensional vectors $\\boldsymbol{x}$, where a line does not\n",
"divide the entire space into two regions anymore. Instead one needs a\n",
"*hyperplane*. It is immediately clear that this method is not very\n",
"powerful, as datasets that are not separable by a hyperplane can\\'t be\n",
"classified without error.\n",
"\n",
"We can actually sneak around this limitation by performing a neat trick:\n",
"if we define some map $\\phi(\\boldsymbol{x})$ that *embeds* our\n",
"datapoints into a larger *feature space* and then perform linear\n",
"classification there, we could actually realise non-linear\n",
"classification in our original space!\n",
"\n",
"{.align-center\n",
"width=\"65.0%\"}\n",
"\n",
"If we go back to the expression for our prediction and include the\n",
"embedding, we get\n",
"\n",
"$$y(\\boldsymbol{x}) = \\operatorname{sgn}(\\langle \\boldsymbol{w}, \\phi(\\boldsymbol{x})\\rangle + b).$$\n",
"\n",
"We will forgo one tiny step, but it can be shown that for the purpose of\n",
"optimal classification, we can choose the vector defining the decision\n",
"boundary as a linear combination of the embedded datapoints\n",
"$\\boldsymbol{w} = \\sum_i \\alpha_i \\phi(\\boldsymbol{x}_i)$. Putting this\n",
"into the formula yields\n",
"\n",
"$$y(\\boldsymbol{x}) = \\operatorname{sgn}\\left(\\sum_i \\alpha_i \\langle \\phi(\\boldsymbol{x}_i), \\phi(\\boldsymbol{x})\\rangle + b\\right).$$\n",
"\n",
"This rewriting might not seem useful at first, but notice the above\n",
"formula only contains inner products between vectors in the embedding\n",
"space:\n",
"\n",
"$$k(\\boldsymbol{x}_i, \\boldsymbol{x}_j) = \\langle \\phi(\\boldsymbol{x}_i), \\phi(\\boldsymbol{x}_j)\\rangle.$$\n",
"\n",
"We call this function the *kernel*. It provides the advantage that we\n",
"can often find an explicit formula for the kernel $k$ that makes it\n",
"superfluous to actually perform the (potentially expensive) embedding\n",
"$\\phi$. Consider for example the following embedding and the associated\n",
"kernel:\n",
"\n",
"$$\\begin{aligned}\n",
"\\phi((x_1, x_2)) &= (x_1^2, \\sqrt{2} x_1 x_2, x_2^2) \\\\\n",
"k(\\boldsymbol{x}, \\boldsymbol{y}) &= x_1^2 y_1^2 + 2 x_1 x_2 y_1 y_2 + x_2^2 y_2^2 = \\langle \\boldsymbol{x}, \\boldsymbol{y} \\rangle^2.\n",
"\\end{aligned}$$\n",
"\n",
"This means by just replacing the regular scalar product in our linear\n",
"classification with the map $k$, we can actually express much more\n",
"intricate decision boundaries!\n",
"\n",
"This is very important, because in many interesting cases the embedding\n",
"$\\phi$ will be much costlier to compute than the kernel $k$.\n",
"\n",
"In this demo, we will explore one particular kind of kernel that can be\n",
"realized on near-term quantum computers, namely *Quantum Embedding\n",
"Kernels (QEKs)*. These are kernels that arise from embedding data into\n",
"the space of quantum states. We formalize this by considering a\n",
"parameterised quantum circuit $U(\\boldsymbol{x})$ that maps a datapoint\n",
"$\\boldsymbol{x}$ to the state\n",
"\n",
"$$|\\psi(\\boldsymbol{x})\\rangle = U(\\boldsymbol{x}) |0 \\rangle.$$\n",
"\n",
"The kernel value is then given by the *overlap* of the associated\n",
"embedded quantum states\n",
"\n",
"$$k(\\boldsymbol{x}_i, \\boldsymbol{x}_j) = | \\langle\\psi(\\boldsymbol{x}_i)|\\psi(\\boldsymbol{x}_j)\\rangle|^2.$$\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YFfhnwX7-1Lv"
},
"source": [
"A toy problem\n",
"=============\n",
"\n",
"In this demo, we will treat a toy problem that showcases the inner\n",
"workings of classification with quantum embedding kernels, training\n",
"variational embedding kernels and the available functionalities to do\n",
"both in PennyLane. We of course need to start with some imports:\n"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"id": "_0dLIZDi-1Lv"
},
"outputs": [],
"source": [
"from pennylane import numpy as np\n",
"import matplotlib as mpl\n",
"\n",
"np.random.seed(1359)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rxY0RHIl-1Lv"
},
"source": [
"And we proceed right away to create a dataset to work with, the\n",
"`DoubleCake` dataset. Firstly, we define two functions to enable us to\n",
"generate the data. The details of these functions are not essential for\n",
"understanding the demo, so don\\'t mind them if they are confusing.\n"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {
"id": "-MlPehLl-1Lw"
},
"outputs": [],
"source": [
"def _make_circular_data(num_sectors):\n",
" \"\"\"Generate datapoints arranged in an even circle.\"\"\"\n",
" center_indices = np.array(range(0, 2 * num_sectors))\n",
" sector_angle = 2 * np.pi / (2 * num_sectors)\n",
" angles = (center_indices + 0.5) * sector_angle\n",
" x = 0.7 * np.cos(angles)\n",
" y = 0.7 * np.sin(angles)\n",
" labels = 2 * np.remainder(np.floor_divide(angles, sector_angle), 2) - 1\n",
"\n",
" return x, y, labels\n",
"\n",
"\n",
"def make_double_cake_data(num_sectors):\n",
" x1, y1, labels1 = _make_circular_data(num_sectors)\n",
" x2, y2, labels2 = _make_circular_data(num_sectors)\n",
"\n",
" # x and y coordinates of the datapoints\n",
" x = np.hstack([x1, 0.5 * x2])\n",
" y = np.hstack([y1, 0.5 * y2])\n",
"\n",
" # Canonical form of dataset\n",
" X = np.vstack([x, y]).T\n",
"\n",
" labels = np.hstack([labels1, -1 * labels2])\n",
"\n",
" # Canonical form of labels\n",
" Y = labels.astype(int)\n",
"\n",
" return X, Y"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sE-g9OvE-1Lw"
},
"source": [
"Next, we define a function to help plot the `DoubleCake` data:\n"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"id": "dTzNJQG2-1Lw"
},
"outputs": [],
"source": [
"def plot_double_cake_data(X, Y, ax, num_sectors=None):\n",
" \"\"\"Plot double cake data and corresponding sectors.\"\"\"\n",
" x, y = X.T\n",
" cmap = mpl.colors.ListedColormap([\"#FF0000\", \"#0000FF\"])\n",
" ax.scatter(x, y, c=Y, cmap=cmap, s=25, marker=\"s\")\n",
"\n",
" if num_sectors is not None:\n",
" sector_angle = 360 / num_sectors\n",
" for i in range(num_sectors):\n",
" color = [\"#FF0000\", \"#0000FF\"][(i % 2)]\n",
" other_color = [\"#FF0000\", \"#0000FF\"][((i + 1) % 2)]\n",
" ax.add_artist(\n",
" mpl.patches.Wedge(\n",
" (0, 0),\n",
" 1,\n",
" i * sector_angle,\n",
" (i + 1) * sector_angle,\n",
" lw=0,\n",
" color=color,\n",
" alpha=0.1,\n",
" width=0.5,\n",
" )\n",
" )\n",
" ax.add_artist(\n",
" mpl.patches.Wedge(\n",
" (0, 0),\n",
" 0.5,\n",
" i * sector_angle,\n",
" (i + 1) * sector_angle,\n",
" lw=0,\n",
" color=other_color,\n",
" alpha=0.1,\n",
" )\n",
" )\n",
" ax.set_xlim(-1, 1)\n",
"\n",
" ax.set_ylim(-1, 1)\n",
" ax.set_aspect(\"equal\")\n",
" ax.axis(\"off\")\n",
"\n",
" return ax"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5W9DtU_s-1Lw"
},
"source": [
"Let\\'s now have a look at our dataset. In our example, we will work with\n",
"3 sectors:\n"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 406
},
"id": "9fVgxo-2-1Lw",
"outputId": "0f735fd0-c459-4e61-ac47-1f4d79ce56be"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {}
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"num_sectors = 3\n",
"X, Y = make_double_cake_data(num_sectors)\n",
"\n",
"ax = plot_double_cake_data(X, Y, plt.gca(), num_sectors=num_sectors)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YiOE-Kte-1Lw"
},
"source": [
"Defining a Quantum Embedding Kernel\n",
"===================================\n",
"\n",
"PennyLane\\'s [kernels\n",
"module](https://pennylane.readthedocs.io/en/latest/code/qml_kernels.html)\n",
"allows for a particularly simple implementation of Quantum Embedding\n",
"Kernels. The first ingredient we need for this is an *ansatz*, which we\n",
"will construct by repeating a layer as building block. Let\\'s start by\n",
"defining this layer:\n"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"id": "HoxftykS-1Lw"
},
"outputs": [],
"source": [
"import pennylane as qml\n",
"\n",
"\n",
"def layer(x, params, wires, i0=0, inc=1):\n",
" \"\"\"Building block of the embedding ansatz\"\"\"\n",
" i = i0\n",
" for j, wire in enumerate(wires):\n",
" qml.Hadamard(wires=[wire])\n",
" qml.RZ(x[i % len(x)], wires=[wire])\n",
" i += inc\n",
" qml.RY(params[0, j], wires=[wire])\n",
"\n",
" qml.broadcast(unitary=qml.CNOT, pattern=\"ring\", wires=wires) #, parameters=params[1])"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Vz-Xc85B-1Lx"
},
"source": [
"To construct the ansatz, this layer is repeated multiple times, reusing\n",
"the datapoint `x` but feeding different variational parameters `params`\n",
"into each of them. Together, the datapoint and the variational\n",
"parameters fully determine the embedding ansatz $U(\\boldsymbol{x})$. In\n",
"order to construct the full kernel circuit, we also require its adjoint\n",
"$U(\\boldsymbol{x})^\\dagger$, which we can obtain via `qml.adjoint`.\n"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {
"id": "0u3Ie4pX-1Lx"
},
"outputs": [],
"source": [
"def ansatz(x, params, wires):\n",
" \"\"\"The embedding ansatz\"\"\"\n",
" for j, layer_params in enumerate(params):\n",
" layer(x, layer_params, wires, i0=j * len(wires))\n",
"\n",
"\n",
"adjoint_ansatz = qml.adjoint(ansatz)\n",
"\n",
"\n",
"def random_params(num_wires, num_layers):\n",
" \"\"\"Generate random variational parameters in the shape for the ansatz.\"\"\"\n",
" return np.random.uniform(0, 2 * np.pi, (num_layers, 2, num_wires), requires_grad=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "-3A0BtiZ-1Lx"
},
"source": [
"Together with the ansatz we only need a device to run the quantum\n",
"circuit on. For the purpose of this tutorial we will use PennyLane\\'s\n",
"`default.qubit` device with 5 wires in analytic mode.\n"
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {
"id": "VajRrjnM-1Lx"
},
"outputs": [],
"source": [
"dev = qml.device(\"lightning.qubit\", wires=5, shots=None)\n",
"wires = dev.wires.tolist()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LBQiS_k5-1Lx"
},
"source": [
"Let us now define the quantum circuit that realizes the kernel. We will\n",
"compute the overlap of the quantum states by first applying the\n",
"embedding of the first datapoint and then the adjoint of the embedding\n",
"of the second datapoint. We finally extract the probabilities of\n",
"observing each basis state.\n"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"id": "YUoDYzxl-1Lx"
},
"outputs": [],
"source": [
"@qml.qnode(dev, interface=\"autograd\")\n",
"def kernel_circuit(x1, x2, params):\n",
" ansatz(x1, params, wires=wires)\n",
" adjoint_ansatz(x2, params, wires=wires)\n",
" return qml.probs(wires=wires)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vp3JMl6k-1Lx"
},
"source": [
"The kernel function itself is now obtained by looking at the probability\n",
"of observing the all-zero state at the end of the kernel circuit --\n",
"because of the ordering in `qml.probs`, this is the first entry:\n"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"id": "FzkdR5rH-1Lx"
},
"outputs": [],
"source": [
"def kernel(x1, x2, params):\n",
" return kernel_circuit(x1, x2, params)[0]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "v8d7TzEV-1Lx"
},
"source": [
"::: {.note}\n",
"::: {.title}\n",
"Note\n",
":::\n",
"\n",
"An alternative way to set up the kernel circuit in PennyLane would be to\n",
"use the observable type\n",
"[Projector](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.Projector.html).\n",
"This is shown in the [demo on kernel-based training of quantum\n",
"models](https://pennylane.ai/qml/demos/tutorial_kernel_based_training.html),\n",
"where you will also find more background information on the kernel\n",
"circuit structure itself.\n",
":::\n",
"\n",
"Before focusing on the kernel values we have to provide values for the\n",
"variational parameters. At this point we fix the number of layers in the\n",
"ansatz circuit to $6$.\n"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {
"id": "XND4t8Re-1Lx"
},
"outputs": [],
"source": [
"init_params = random_params(num_wires=5, num_layers=6)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "D13009dA-1Lx"
},
"source": [
"Now we can have a look at the kernel value between the first and the\n",
"second datapoint:\n"
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "EPIxD8tx-1Lx",
"outputId": "e29bfa05-23d9-4e0b-ad33-c2bf73dec787"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"The kernel value between the first and second datapoint is 0.139\n"
]
}
],
"source": [
"kernel_value = kernel(X[0], X[1], init_params)\n",
"print(f\"The kernel value between the first and second datapoint is {kernel_value:.3f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "zftXzrUX-1Lx"
},
"source": [
"The mutual kernel values between all elements of the dataset form the\n",
"*kernel matrix*. We can inspect it via the\n",
"`qml.kernels.square_kernel_matrix` method, which makes use of symmetry\n",
"of the kernel,\n",
"$k(\\boldsymbol{x}_i,\\boldsymbol{x}_j) = k(\\boldsymbol{x}_j, \\boldsymbol{x}_i)$.\n",
"In addition, the option `assume_normalized_kernel=True` ensures that we\n",
"do not calculate the entries between the same datapoints, as we know\n",
"them to be 1 for our noiseless simulation. Overall this means that we\n",
"compute $\\frac{1}{2}(N^2-N)$ kernel values for $N$ datapoints. To\n",
"include the variational parameters, we construct a `lambda` function\n",
"that fixes them to the values we sampled above.\n"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "EJ6j5XF1-1Lx",
"outputId": "55be5477-faab-41db-eccd-4aa46a4b7690"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[[1. 0.139 0.089 0.009 0.012 0.156 0.562 0.216 0.084 0.056 0.03 0.166]\n",
" [0.139 1. 0.049 0.012 0.123 0.02 0.226 0.59 0.161 0.023 0.053 0.059]\n",
" [0.089 0.049 1. 0.156 0.02 0.158 0.11 0.177 0.608 0.283 0.086 0.104]\n",
" [0.009 0.012 0.156 1. 0.139 0.089 0.056 0.03 0.166 0.562 0.216 0.084]\n",
" [0.012 0.123 0.02 0.139 1. 0.049 0.023 0.053 0.059 0.226 0.59 0.161]\n",
" [0.156 0.02 0.158 0.089 0.049 1. 0.283 0.086 0.104 0.11 0.177 0.608]\n",
" [0.562 0.226 0.11 0.056 0.023 0.283 1. 0.618 0.262 0.157 0.184 0.598]\n",
" [0.216 0.59 0.177 0.03 0.053 0.086 0.618 1. 0.559 0.184 0.123 0.25 ]\n",
" [0.084 0.161 0.608 0.166 0.059 0.104 0.262 0.559 1. 0.598 0.25 0.224]\n",
" [0.056 0.023 0.283 0.562 0.226 0.11 0.157 0.184 0.598 1. 0.618 0.262]\n",
" [0.03 0.053 0.086 0.216 0.59 0.177 0.184 0.123 0.25 0.618 1. 0.559]\n",
" [0.166 0.059 0.104 0.084 0.161 0.608 0.598 0.25 0.224 0.262 0.559 1. ]]\n"
]
}
],
"source": [
"init_kernel = lambda x1, x2: kernel(x1, x2, init_params)\n",
"K_init = qml.kernels.square_kernel_matrix(X, init_kernel, assume_normalized_kernel=True)\n",
"\n",
"with np.printoptions(precision=3, suppress=True):\n",
" print(K_init)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nRfsymWl-1Lx"
},
"source": [
"Using the Quantum Embedding Kernel for predictions\n",
"==================================================\n",
"\n",
"The quantum kernel alone can not be used to make predictions on a\n",
"dataset, becaues it is essentially just a tool to measure the similarity\n",
"between two datapoints. To perform an actual prediction we will make use\n",
"of scikit-learn\\'s Support Vector Classifier (SVC).\n"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {
"id": "k6YZKy7J-1Lx"
},
"outputs": [],
"source": [
"from sklearn.svm import SVC"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "s3GDnc3R-1Ly"
},
"source": [
"To construct the SVM, we need to supply `sklearn.svm.SVC` with a\n",
"function that takes two sets of datapoints and returns the associated\n",
"kernel matrix. We can make use of the function\n",
"`qml.kernels.kernel_matrix` that provides this functionality. It expects\n",
"the kernel to not have additional parameters besides the datapoints,\n",
"which is why we again supply the variational parameters via the `lambda`\n",
"function from above. Once we have this, we can let scikit-learn adjust\n",
"the SVM from our Quantum Embedding Kernel.\n",
"\n",
"::: {.note}\n",
"::: {.title}\n",
"Note\n",
":::\n",
"\n",
"This step does *not* modify the variational parameters in our circuit\n",
"ansatz. What it does is solving a different optimization task for the\n",
"$\\alpha$ and $b$ vectors we introduced in the beginning.\n",
":::\n"
]
},
{
"cell_type": "code",
"execution_count": 136,
"metadata": {
"id": "irVOPzix-1Ly"
},
"outputs": [],
"source": [
"svm = SVC(kernel=lambda X1, X2: qml.kernels.kernel_matrix(X1, X2, init_kernel)).fit(X, Y)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "I4xR2Txu-1Ly"
},
"source": [
"To see how well our classifier performs we will measure which percentage\n",
"of the dataset it classifies correctly.\n"
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "ZDX6Qvwk-1Ly",
"outputId": "3b735d02-6e70-4f0f-d30d-6fa212a896f9"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"The accuracy of the kernel with random parameters is 0.500\n"
]
}
],
"source": [
"def accuracy(classifier, X, Y_target):\n",
" return 1 - np.count_nonzero(classifier.predict(X) - Y_target) / len(Y_target)\n",
"\n",
"\n",
"accuracy_init = accuracy(svm, X, Y)\n",
"print(f\"The accuracy of the kernel with random parameters is {accuracy_init:.3f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PPB_3tDn-1Ly"
},
"source": [
"We are also interested in seeing what the decision boundaries in this\n",
"classification look like. This could help us spotting overfitting issues\n",
"visually in more complex data sets. To this end we will introduce a\n",
"second helper method.\n"
]
},
{
"cell_type": "code",
"execution_count": 138,
"metadata": {
"id": "EQZNfZjQ-1Ly"
},
"outputs": [],
"source": [
"def plot_decision_boundaries(classifier, ax, N_gridpoints=14):\n",
" _xx, _yy = np.meshgrid(np.linspace(-1, 1, N_gridpoints), np.linspace(-1, 1, N_gridpoints))\n",
"\n",
" _zz = np.zeros_like(_xx)\n",
" for idx in np.ndindex(*_xx.shape):\n",
" _zz[idx] = classifier.predict(np.array([_xx[idx], _yy[idx]])[np.newaxis, :])\n",
"\n",
" plot_data = {\"_xx\": _xx, \"_yy\": _yy, \"_zz\": _zz}\n",
" ax.contourf(\n",
" _xx,\n",
" _yy,\n",
" _zz,\n",
" cmap=mpl.colors.ListedColormap([\"#FF0000\", \"#0000FF\"]),\n",
" alpha=0.2,\n",
" levels=[-1, 0, 1],\n",
" )\n",
" plot_double_cake_data(X, Y, ax)\n",
"\n",
" return plot_data"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "26F1Bqg9-1Ly"
},
"source": [
"With that done, let\\'s have a look at the decision boundaries for our\n",
"initial classifier:\n"
]
},
{
"cell_type": "code",
"execution_count": 139,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 406
},
"id": "JQ33viIF-1Ly",
"outputId": "1a1f2ff4-871a-4db6-9b51-2723dba46585"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {}
}
],
"source": [
"init_plot_data = plot_decision_boundaries(svm, plt.gca())"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "TLeU4kMX-1Ly"
},
"source": [
"We see the outer points in the dataset can be correctly classified, but\n",
"we still struggle with the inner circle. But remember we have a circuit\n",
"with many free parameters! It is reasonable to believe we can give\n",
"values to those variational parameters which improve the overall\n",
"accuracy of our SVC.\n",
"\n",
"Training the Quantum Embedding Kernel\n",
"=====================================\n",
"\n",
"To be able to train the Quantum Embedding Kernel we need some measure of\n",
"how well it fits the dataset in question. Performing an exhaustive\n",
"search in parameter space is not a good solution because it is very\n",
"resource intensive, and since the accuracy is a discrete quantity we\n",
"would not be able to detect small improvements.\n",
"\n",
"We can, however, resort to a more specialized measure, the\n",
"*kernel-target alignment*. The kernel-target alignment compares the\n",
"similarity predicted by the quantum kernel to the actual labels of the\n",
"training data. It is based on *kernel alignment*, a similiarity measure\n",
"between two kernels with given kernel matrices $K_1$ and $K_2$:\n",
"\n",
"$$\\operatorname{KA}(K_1, K_2) = \\frac{\\operatorname{Tr}(K_1 K_2)}{\\sqrt{\\operatorname{Tr}(K_1^2)\\operatorname{Tr}(K_2^2)}}.$$\n",
"\n",
"::: {.note}\n",
"::: {.title}\n",
"Note\n",
":::\n",
"\n",
"Seen from a more theoretical side, $\\operatorname{KA}$ is nothing else\n",
"than the cosine of the angle between the kernel matrices $K_1$ and $K_2$\n",
"if we see them as vectors in the space of matrices with the\n",
"Hilbert-Schmidt (or Frobenius) scalar product\n",
"$\\langle A, B \\rangle = \\operatorname{Tr}(A^T B)$. This reinforces the\n",
"geometric picture of how this measure relates to objects, namely two\n",
"kernels, being aligned in a vector space.\n",
":::\n",
"\n",
"The training data enters the picture by defining an *ideal* kernel\n",
"function that expresses the original labelling in the vector\n",
"$\\boldsymbol{y}$ by assigning to two datapoints the product of the\n",
"corresponding labels:\n",
"\n",
"$$k_{\\boldsymbol{y}}(\\boldsymbol{x}_i, \\boldsymbol{x}_j) = y_i y_j.$$\n",
"\n",
"The assigned kernel is thus $+1$ if both datapoints lie in the same\n",
"class and $-1$ otherwise and its kernel matrix is simply given by the\n",
"outer product $\\boldsymbol{y}\\boldsymbol{y}^T$. The kernel-target\n",
"alignment is then defined as the kernel alignment of the kernel matrix\n",
"$K$ generated by the quantum kernel and\n",
"$\\boldsymbol{y}\\boldsymbol{y}^T$:\n",
"\n",
"$$\\operatorname{KTA}_{\\boldsymbol{y}}(K)\n",
"= \\frac{\\operatorname{Tr}(K \\boldsymbol{y}\\boldsymbol{y}^T)}{\\sqrt{\\operatorname{Tr}(K^2)\\operatorname{Tr}((\\boldsymbol{y}\\boldsymbol{y}^T)^2)}}\n",
"= \\frac{\\boldsymbol{y}^T K \\boldsymbol{y}}{\\sqrt{\\operatorname{Tr}(K^2)} N}$$\n",
"\n",
"where $N$ is the number of elements in $\\boldsymbol{y}$, that is the\n",
"number of datapoints in the dataset.\n",
"\n",
"In summary, the kernel-target alignment effectively captures how well\n",
"the kernel you chose reproduces the actual similarities of the data. It\n",
"does have one drawback, however: having a high kernel-target alignment\n",
"is only a necessary but not a sufficient condition for a good\n",
"performance of the kernel. This means having good alignment is\n",
"guaranteed for good performance, but optimal alignment will not always\n",
"bring optimal training accuracy with it.\n",
"\n",
"Let\\'s now come back to the actual implementation. PennyLane\\'s\n",
"`kernels` module allows you to easily evaluate the kernel target\n",
"alignment:\n"
]
},
{
"cell_type": "code",
"execution_count": 140,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "N1sKPuO3-1Ly",
"outputId": "de815f87-f17f-477d-fee5-5bcf6924ea77"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"The kernel-target alignment for our dataset and random parameters is 0.041\n"
]
}
],
"source": [
"kta_init = qml.kernels.target_alignment(X, Y, init_kernel, assume_normalized_kernel=True)\n",
"\n",
"print(f\"The kernel-target alignment for our dataset and random parameters is {kta_init:.3f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "eOZMWm-p-1Ly"
},
"source": [
"Now let\\'s code up an optimization loop and improve the kernel-target\n",
"alignment!\n",
"\n",
"We will make use of regular gradient descent optimization. To speed up\n",
"the optimization we will not use the entire training set to compute\n",
"$\\operatorname{KTA}$ but rather sample smaller subsets of the data at\n",
"each step, we choose $4$ datapoints at random. Remember that\n",
"PennyLane\\'s built-in optimizer works to *minimize* the cost function\n",
"that is given to it, which is why we have to multiply the kernel target\n",
"alignment by $-1$ to actually *maximize* it in the process.\n",
"\n",
"::: {.note}\n",
"::: {.title}\n",
"Note\n",
":::\n",
"\n",
"Currently, the function `qml.kernels.target_alignment` is not\n",
"differentiable yet, making it unfit for gradient descent optimization.\n",
"We therefore first define a differentiable version of this function.\n",
":::\n"
]
},
{
"cell_type": "code",
"execution_count": 141,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 405
},
"id": "o8BNL8bP-1Ly",
"outputId": "ff07a1be-aa75-4f35-fa7c-3f5c3650ea52"
},
"outputs": [
{
"output_type": "error",
"ename": "KeyboardInterrupt",
"evalue": "ignored",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-141-2d12ece3dd74>\u001b[0m in \u001b[0;36m<cell line: 34>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 43\u001b[0m )\n\u001b[1;32m 44\u001b[0m \u001b[0;31m# Optimization step\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 45\u001b[0;31m \u001b[0mparams\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcost\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 46\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[0;31m# Report the alignment on the full dataset every 50 steps.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/optimize/gradient_descent.py\u001b[0m in \u001b[0;36mstep\u001b[0;34m(self, objective_fn, grad_fn, *args, **kwargs)\u001b[0m\n\u001b[1;32m 86\u001b[0m \"\"\"\n\u001b[1;32m 87\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 88\u001b[0;31m \u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcompute_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobjective_fn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgrad_fn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mgrad_fn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 89\u001b[0m \u001b[0mnew_args\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mapply_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/optimize/gradient_descent.py\u001b[0m in \u001b[0;36mcompute_grad\u001b[0;34m(objective_fn, args, kwargs, grad_fn)\u001b[0m\n\u001b[1;32m 115\u001b[0m \"\"\"\n\u001b[1;32m 116\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_gradient\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobjective_fn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mgrad_fn\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mgrad_fn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 117\u001b[0;31m \u001b[0mgrad\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 118\u001b[0m \u001b[0mforward\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"forward\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 119\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/_grad.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 116\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 118\u001b[0;31m \u001b[0mgrad_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mans\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgrad_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# pylint: disable=not-callable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 119\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_forward\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mans\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 120\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autograd/wrap_util.py\u001b[0m in \u001b[0;36mnary_f\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0munary_operator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0munary_f\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mnary_op_args\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mnary_op_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnary_f\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnary_operator\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/_grad.py\u001b[0m in \u001b[0;36m_grad_with_forward\u001b[0;34m(fun, x)\u001b[0m\n\u001b[1;32m 142\u001b[0m )\n\u001b[1;32m 143\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 144\u001b[0;31m \u001b[0mgrad_value\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvjp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvspace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mans\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mones\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 145\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mgrad_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mans\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 146\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autograd/core.py\u001b[0m in \u001b[0;36mvjp\u001b[0;34m(g)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvjp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvspace\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mvjp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mbackward_pass\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend_node\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mvjp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend_value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autograd/core.py\u001b[0m in \u001b[0;36mbackward_pass\u001b[0;34m(g, end_node)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mnode\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtoposort\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mend_node\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0moutgrad\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0moutgrads\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 21\u001b[0;31m \u001b[0mingrads\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvjp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutgrad\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 22\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mparent\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mingrad\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparents\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mingrads\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0moutgrads\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mparent\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madd_outgrads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutgrads\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mingrad\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autograd/core.py\u001b[0m in \u001b[0;36m<lambda>\u001b[0;34m(g)\u001b[0m\n\u001b[1;32m 65\u001b[0m \"VJP of {} wrt argnum 0 not defined\".format(fun.__name__))\n\u001b[1;32m 66\u001b[0m \u001b[0mvjp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvjpfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mans\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 67\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mvjp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 68\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mL\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 69\u001b[0m \u001b[0margnum_0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margnum_1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margnums\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/interfaces/autograd.py\u001b[0m in \u001b[0;36mgrad_fn\u001b[0;34m(dy)\u001b[0m\n\u001b[1;32m 231\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mgradient_fn\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mgradient_fn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"param_shift\"\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mcomputing_jacobian\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 233\u001b[0;31m \u001b[0mjacs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_jac_with_caching\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 234\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 235\u001b[0m \u001b[0mjacs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mans\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/interfaces/autograd.py\u001b[0m in \u001b[0;36m_get_jac_with_caching\u001b[0;34m()\u001b[0m\n\u001b[1;32m 203\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 204\u001b[0m \u001b[0mg_tapes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransforms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmap_batch_transform\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpartial_gradient_fn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m \u001b[0mres\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mexecute_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg_tapes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mgradient_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 206\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 207\u001b[0m \u001b[0mjacs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mres\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/interfaces/execution.py\u001b[0m in \u001b[0;36minner_execute_with_empty_jac\u001b[0;34m(tapes, **_)\u001b[0m\n\u001b[1;32m 586\u001b[0m \u001b[0;31m# moved to its own explicit step so it will be easier to remove\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 587\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0minner_execute_with_empty_jac\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtapes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0m_\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 588\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0minner_execute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 589\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 590\u001b[0m \u001b[0mexecute_fn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minner_execute_with_empty_jac\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/interfaces/execution.py\u001b[0m in \u001b[0;36minner_execute\u001b[0;34m(tapes, **_)\u001b[0m\n\u001b[1;32m 246\u001b[0m \u001b[0mtapes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexpand_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 247\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mnumpy_only\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 248\u001b[0;31m \u001b[0mtapes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransforms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconvert_to_numpy_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 249\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mcached_device_execution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 250\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/interfaces/execution.py\u001b[0m in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 246\u001b[0m \u001b[0mtapes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexpand_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 247\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mnumpy_only\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 248\u001b[0;31m \u001b[0mtapes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransforms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconvert_to_numpy_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 249\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mcached_device_execution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtapes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 250\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/transforms/convert_to_numpy_parameters.py\u001b[0m in \u001b[0;36mconvert_to_numpy_parameters\u001b[0;34m(circuit)\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0mnew_ops\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_convert_op_to_numpy_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mop\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moperations\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0mnew_measurements\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_convert_measurement_to_numpy_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mm\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmeasurements\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 86\u001b[0;31m \u001b[0mnew_circuit\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnew_ops\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_measurements\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshots\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshots\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 87\u001b[0m \u001b[0;31m# must preserve trainable params as we lose information about the machine learning interface\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[0mnew_circuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrainable_params\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrainable_params\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/tape/qscript.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, ops, measurements, prep, shots, _update)\u001b[0m\n\u001b[1;32m 192\u001b[0m \u001b[0m_update\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 193\u001b[0m ): # pylint: disable=too-many-arguments\n\u001b[0;32m--> 194\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_ops\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mops\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mops\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 195\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mprep\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 196\u001b[0m warnings.warn(\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/transforms/convert_to_numpy_parameters.py\u001b[0m in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \"\"\"\n\u001b[0;32m---> 84\u001b[0;31m \u001b[0mnew_ops\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_convert_op_to_numpy_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mop\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moperations\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 85\u001b[0m \u001b[0mnew_measurements\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0m_convert_measurement_to_numpy_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mm\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmeasurements\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0mnew_circuit\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnew_ops\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_measurements\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshots\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcircuit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshots\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/transforms/convert_to_numpy_parameters.py\u001b[0m in \u001b[0;36m_convert_op_to_numpy_data\u001b[0;34m(op)\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mop\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;31m# Use operator method to change parameters when it become available\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 28\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfunctions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbind_new_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munwrap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 29\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/lib/python3.10/functools.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kw)\u001b[0m\n\u001b[1;32m 887\u001b[0m '1 positional argument')\n\u001b[1;32m 888\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 889\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdispatch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 890\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 891\u001b[0m \u001b[0mfuncname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'__name__'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'singledispatch function'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/ops/functions/bind_new_parameters.py\u001b[0m in \u001b[0;36mbind_new_parameters\u001b[0;34m(op, params)\u001b[0m\n\u001b[1;32m 47\u001b[0m \"\"\"\n\u001b[1;32m 48\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 49\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwires\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwires\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhyperparameters\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 50\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mTypeError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 51\u001b[0m \u001b[0;31m# operation is doing something different with its call signature.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/ops/qubit/parametric_ops_single_qubit.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, phi, wires, id)\u001b[0m\n\u001b[1;32m 168\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 169\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mphi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwires\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 170\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mphi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwires\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwires\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 171\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 172\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mstaticmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/operation.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, wires, id, *params)\u001b[0m\n\u001b[1;32m 1745\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1746\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwires\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1747\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwires\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwires\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1748\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1749\u001b[0m \u001b[0;31m# check the grad_recipe validity\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/operation.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, wires, id, *params)\u001b[0m\n\u001b[1;32m 1050\u001b[0m )\n\u001b[1;32m 1051\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1052\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_check_batching\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1053\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1054\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mlist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/operation.py\u001b[0m in \u001b[0;36m_check_batching\u001b[0;34m(self, params)\u001b[0m\n\u001b[1;32m 1084\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1085\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1086\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0many\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1087\u001b[0m \u001b[0;31m# if the batch dimension is unknown, then skip the validation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1088\u001b[0m \u001b[0;31m# this happens when a tensor with a partially known shape is passed, e.g. (None, 12),\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/pennylane/operation.py\u001b[0m in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 1084\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1085\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1086\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0many\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mqml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mparams\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1087\u001b[0m \u001b[0;31m# if the batch dimension is unknown, then skip the validation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1088\u001b[0m \u001b[0;31m# this happens when a tensor with a partially known shape is passed, e.g. (None, 12),\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autoray/autoray.py\u001b[0m in \u001b[0;36mdo\u001b[0;34m(fn, like, *args, **kwargs)\u001b[0m\n\u001b[1;32m 77\u001b[0m \u001b[0;34m<\u001b[0m\u001b[0mtf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTensor\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m91\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshape\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 78\u001b[0m \"\"\"\n\u001b[0;32m---> 79\u001b[0;31m \u001b[0mbackend\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mchoose_backend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlike\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlike\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 80\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mget_lib_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autoray/autoray.py\u001b[0m in \u001b[0;36mchoose_backend\u001b[0;34m(fn, like, *args, **kwargs)\u001b[0m\n\u001b[1;32m 344\u001b[0m \"\"\"\n\u001b[1;32m 345\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlike\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 346\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m_infer_auto\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 347\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlike\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 348\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mlike\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autoray/autoray.py\u001b[0m in \u001b[0;36m_default_infer_from_sig\u001b[0;34m(fn, *args, **kwargs)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[0mevery\u001b[0m \u001b[0mcall\u001b[0m \u001b[0mto\u001b[0m\u001b[0;31m \u001b[0m\u001b[0;31m`\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0mdo\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0;31m`\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 91\u001b[0m \"\"\"\n\u001b[0;32m---> 92\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m_DISPATCHERS\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 93\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/local/lib/python3.10/dist-packages/autoray/autoray.py\u001b[0m in \u001b[0;36mdefault_dispatcher\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 1283\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1284\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1285\u001b[0;31m \u001b[0;32mdef\u001b[0m \u001b[0mdefault_dispatcher\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1286\u001b[0m \u001b[0;34m\"\"\"Try to infer backend from first argument passed to function.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1287\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0minfer_backend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mKeyboardInterrupt\u001b[0m: "
]
}
],
"source": [
"def target_alignment(\n",
" X,\n",
" Y,\n",
" kernel,\n",
" assume_normalized_kernel=False,\n",
" rescale_class_labels=True,\n",
"):\n",
" \"\"\"Kernel-target alignment between kernel and labels.\"\"\"\n",
"\n",
" K = qml.kernels.square_kernel_matrix(\n",
" X,\n",
" kernel,\n",
" assume_normalized_kernel=assume_normalized_kernel,\n",
" )\n",
"\n",
" if rescale_class_labels:\n",
" nplus = np.count_nonzero(np.array(Y) == 1)\n",
" nminus = len(Y) - nplus\n",
" _Y = np.array([y / nplus if y == 1 else y / nminus for y in Y])\n",
" else:\n",
" _Y = np.array(Y)\n",
"\n",
" T = np.outer(_Y, _Y)\n",
" inner_product = np.sum(K * T)\n",
" norm = np.sqrt(np.sum(K * K) * np.sum(T * T))\n",
" inner_product = inner_product / norm\n",
"\n",
" return inner_product\n",
"\n",
"\n",
"params = init_params\n",
"opt = qml.GradientDescentOptimizer(0.2)\n",
"\n",
"for i in range(500):\n",
" # Choose subset of datapoints to compute the KTA on.\n",
" subset = np.random.choice(list(range(len(X))), 4)\n",
" # Define the cost function for optimization\n",
" cost = lambda _params: -target_alignment(\n",
" X[subset],\n",
" Y[subset],\n",
" lambda x1, x2: kernel(x1, x2, _params),\n",
" assume_normalized_kernel=True,\n",
" )\n",
" # Optimization step\n",
" params = opt.step(cost, params)\n",
"\n",
" # Report the alignment on the full dataset every 50 steps.\n",
" if (i + 1) % 50 == 0:\n",
" current_alignment = target_alignment(\n",
" X,\n",
" Y,\n",
" lambda x1, x2: kernel(x1, x2, params),\n",
" assume_normalized_kernel=True,\n",
" )\n",
" print(f\"Step {i+1} - Alignment = {current_alignment:.3f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "lhbr4YTr-1Lz"
},
"source": [
"We want to assess the impact of training the parameters of the quantum\n",
"kernel. Thus, let\\'s build a second support vector classifier with the\n",
"trained kernel:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vUg8wNDJ-1Lz"
},
"outputs": [],
"source": [
"# First create a kernel with the trained parameter baked into it.\n",
"trained_kernel = lambda x1, x2: kernel(x1, x2, params)\n",
"\n",
"# Second create a kernel matrix function using the trained kernel.\n",
"trained_kernel_matrix = lambda X1, X2: qml.kernels.kernel_matrix(X1, X2, trained_kernel)\n",
"\n",
"# Note that SVC expects the kernel argument to be a kernel matrix function.\n",
"svm_trained = SVC(kernel=trained_kernel_matrix).fit(X, Y)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "LgE9Tcmn-1Lz"
},
"source": [
"We expect to see an accuracy improvement vs. the SVM with random\n",
"parameters:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "SGUIEF1X-1Lz"
},
"outputs": [],
"source": [
"accuracy_trained = accuracy(svm_trained, X, Y)\n",
"print(f\"The accuracy of a kernel with trained parameters is {accuracy_trained:.3f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "N5tAagq1-1Lz"
},
"source": [
"We have now achieved perfect classification! 🎆\n",
"\n",
"Following on the results that SVM\\'s have proven good generalisation\n",
"behavior, it will be interesting to inspect the decision boundaries of\n",
"our classifier:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "CHXRBR7p-1Lz"
},
"outputs": [],
"source": [
"trained_plot_data = plot_decision_boundaries(svm_trained, plt.gca())"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "71P66YVn-1Lz"
},
"source": [
"Indeed, we see that now not only every data instance falls within the\n",
"correct class, but also that there are no strong artifacts that would\n",
"make us distrust the model. In this sense, our approach benefits from\n",
"both: on one hand it can adjust itself to the dataset, and on the other\n",
"hand is not expected to suffer from bad generalisation.\n",
"\n",
"References\n",
"==========\n",
"\n",
"About the authors\n",
"=================\n"
]
},
{
"cell_type": "code",
"source": [
"seconds = time.time()\n",
"print(\"Time in seconds since end of run:\", seconds)\n",
"local_time = time.ctime(seconds)\n",
"print(local_time)"
],
"metadata": {
"id": "e8dvgrE6Ktzf"
},
"execution_count": null,
"outputs": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.17"
},
"colab": {
"provenance": [],
"machine_shape": "hm"
}
},
"nbformat": 4,
"nbformat_minor": 0
}