--- a +++ b/Code/All Qiskit, PennyLane QML Nov 23/24a2 Kernels 50% No Train kkawchak.ipynb @@ -0,0 +1,1175 @@ +{ + "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 +}