{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "xLOXFOT5Q40E" }, "source": [ "##### Copyright 2020 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:21:56.424869Z", "iopub.status.busy": "2024-05-18T11:21:56.424462Z", "iopub.status.idle": "2024-05-18T11:21:56.428553Z", "shell.execute_reply": "2024-05-18T11:21:56.427858Z" }, "id": "iiQkM5ZgQ8r2", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "j6331ZSsQGY3" }, "source": [ "# Hello, many worlds" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "i9Jcnb8bQQyd" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", " View on TensorFlow.org\n", " \n", " Run in Google Colab\n", " \n", " View source on GitHub\n", " \n", " Download notebook\n", "
" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "6tYn2HaAUgH0" }, "source": [ "This tutorial shows how a classical neural network can learn to correct qubit calibration errors. It introduces Cirq, a Python framework to create, edit, and invoke Noisy Intermediate Scale Quantum (NISQ) circuits, and demonstrates how Cirq interfaces with TensorFlow Quantum." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "sPZoNKvpUaqa" }, "source": [ "## Setup" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:21:56.432179Z", "iopub.status.busy": "2024-05-18T11:21:56.431763Z", "iopub.status.idle": "2024-05-18T11:22:26.273998Z", "shell.execute_reply": "2024-05-18T11:22:26.273066Z" }, "id": "TorxE5tnkvb2", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting tensorflow==2.15.0\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Downloading tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.4 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: absl-py>=1.0.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (2.1.0)\r\n", "Requirement already satisfied: astunparse>=1.6.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (1.6.3)\r\n", "Requirement already satisfied: flatbuffers>=23.5.26 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (24.3.25)\r\n", "Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (0.5.4)\r\n", "Requirement already satisfied: google-pasta>=0.1.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (0.2.0)\r\n", "Requirement already satisfied: h5py>=2.9.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (3.11.0)\r\n", "Requirement already satisfied: libclang>=13.0.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (18.1.1)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting ml-dtypes~=0.2.0 (from tensorflow==2.15.0)\r\n", " Downloading ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (20 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: numpy<2.0.0,>=1.23.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (1.26.4)\r\n", "Requirement already satisfied: opt-einsum>=2.3.2 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (3.3.0)\r\n", "Requirement already satisfied: packaging in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (24.0)\r\n", "Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<5.0.0dev,>=3.20.3 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (3.20.3)\r\n", "Requirement already satisfied: setuptools in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (69.5.1)\r\n", "Requirement already satisfied: six>=1.12.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (1.16.0)\r\n", "Requirement already satisfied: termcolor>=1.1.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (2.4.0)\r\n", "Requirement already satisfied: typing-extensions>=3.6.6 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (4.12.0rc1)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting wrapt<1.15,>=1.11.0 (from tensorflow==2.15.0)\r\n", " Downloading wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.7 kB)\r\n", "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (0.37.0)\r\n", "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorflow==2.15.0) (1.64.0rc1)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting tensorboard<2.16,>=2.15 (from tensorflow==2.15.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Downloading tensorboard-2.15.2-py3-none-any.whl.metadata (1.7 kB)\r\n", "Collecting tensorflow-estimator<2.16,>=2.15.0 (from tensorflow==2.15.0)\r\n", " Downloading tensorflow_estimator-2.15.0-py2.py3-none-any.whl.metadata (1.3 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting keras<2.16,>=2.15.0 (from tensorflow==2.15.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Downloading keras-2.15.0-py3-none-any.whl.metadata (2.4 kB)\r\n", "Requirement already satisfied: wheel<1.0,>=0.23.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from astunparse>=1.6.0->tensorflow==2.15.0) (0.41.2)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting google-auth<3,>=1.6.3 (from tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Using cached google_auth-2.29.0-py2.py3-none-any.whl.metadata (4.7 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting google-auth-oauthlib<2,>=0.5 (from tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Downloading google_auth_oauthlib-1.2.0-py2.py3-none-any.whl.metadata (2.7 kB)\r\n", "Requirement already satisfied: markdown>=2.6.8 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorboard<2.16,>=2.15->tensorflow==2.15.0) (3.6)\r\n", "Requirement already satisfied: requests<3,>=2.21.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorboard<2.16,>=2.15->tensorflow==2.15.0) (2.31.0)\r\n", "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorboard<2.16,>=2.15->tensorflow==2.15.0) (0.7.2)\r\n", "Requirement already satisfied: werkzeug>=1.0.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from tensorboard<2.16,>=2.15->tensorflow==2.15.0) (3.0.3)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-auth<3,>=1.6.3->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (5.3.3)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting pyasn1-modules>=0.2.1 (from google-auth<3,>=1.6.3->tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Using cached pyasn1_modules-0.4.0-py3-none-any.whl.metadata (3.4 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting rsa<5,>=3.1.4 (from google-auth<3,>=1.6.3->tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Using cached rsa-4.9-py3-none-any.whl.metadata (4.2 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting requests-oauthlib>=0.7.0 (from google-auth-oauthlib<2,>=0.5->tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Downloading requests_oauthlib-2.0.0-py2.py3-none-any.whl.metadata (11 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: importlib-metadata>=4.4 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from markdown>=2.6.8->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (7.1.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: charset-normalizer<4,>=2 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3,>=2.21.0->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (3.3.2)\r\n", "Requirement already satisfied: idna<4,>=2.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3,>=2.21.0->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (3.7)\r\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3,>=2.21.0->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (2.2.1)\r\n", "Requirement already satisfied: certifi>=2017.4.17 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3,>=2.21.0->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (2024.2.2)\r\n", "Requirement already satisfied: MarkupSafe>=2.1.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from werkzeug>=1.0.1->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (2.1.5)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: zipp>=0.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from importlib-metadata>=4.4->markdown>=2.6.8->tensorboard<2.16,>=2.15->tensorflow==2.15.0) (3.18.2)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting pyasn1<0.7.0,>=0.4.6 (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Using cached pyasn1-0.6.0-py2.py3-none-any.whl.metadata (8.3 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting oauthlib>=3.0.0 (from requests-oauthlib>=0.7.0->google-auth-oauthlib<2,>=0.5->tensorboard<2.16,>=2.15->tensorflow==2.15.0)\r\n", " Downloading oauthlib-3.2.2-py3-none-any.whl.metadata (7.5 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Downloading tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (475.2 MB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Downloading keras-2.15.0-py3-none-any.whl (1.7 MB)\r\n", "Downloading ml_dtypes-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.0 MB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Downloading tensorboard-2.15.2-py3-none-any.whl (5.5 MB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Downloading tensorflow_estimator-2.15.0-py2.py3-none-any.whl (441 kB)\r\n", "Downloading wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (77 kB)\r\n", "Using cached google_auth-2.29.0-py2.py3-none-any.whl (189 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Downloading google_auth_oauthlib-1.2.0-py2.py3-none-any.whl (24 kB)\r\n", "Using cached pyasn1_modules-0.4.0-py3-none-any.whl (181 kB)\r\n", "Downloading requests_oauthlib-2.0.0-py2.py3-none-any.whl (24 kB)\r\n", "Using cached rsa-4.9-py3-none-any.whl (34 kB)\r\n", "Downloading oauthlib-3.2.2-py3-none-any.whl (151 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Using cached pyasn1-0.6.0-py2.py3-none-any.whl (85 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Installing collected packages: wrapt, tensorflow-estimator, pyasn1, oauthlib, ml-dtypes, keras, rsa, requests-oauthlib, pyasn1-modules, google-auth, google-auth-oauthlib, tensorboard, tensorflow\r\n", " Attempting uninstall: wrapt\r\n", " Found existing installation: wrapt 1.16.0\r\n", " Uninstalling wrapt-1.16.0:\r\n", " Successfully uninstalled wrapt-1.16.0\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Attempting uninstall: ml-dtypes\r\n", " Found existing installation: ml-dtypes 0.3.2\r\n", " Uninstalling ml-dtypes-0.3.2:\r\n", " Successfully uninstalled ml-dtypes-0.3.2\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Attempting uninstall: keras\r\n", " Found existing installation: keras 3.3.3\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uninstalling keras-3.3.3:\r\n", " Successfully uninstalled keras-3.3.3\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Attempting uninstall: tensorboard\r\n", " Found existing installation: tensorboard 2.16.2\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uninstalling tensorboard-2.16.2:\r\n", " Successfully uninstalled tensorboard-2.16.2\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Attempting uninstall: tensorflow\r\n", " Found existing installation: tensorflow 2.16.1\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Uninstalling tensorflow-2.16.1:\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Successfully uninstalled tensorflow-2.16.1\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\r\n", "tf-keras 2.16.0 requires tensorflow<2.17,>=2.16, but you have tensorflow 2.15.0 which is incompatible.\u001b[0m\u001b[31m\r\n", "\u001b[0mSuccessfully installed google-auth-2.29.0 google-auth-oauthlib-1.2.0 keras-2.15.0 ml-dtypes-0.2.0 oauthlib-3.2.2 pyasn1-0.6.0 pyasn1-modules-0.4.0 requests-oauthlib-2.0.0 rsa-4.9 tensorboard-2.15.2 tensorflow-2.15.0 tensorflow-estimator-2.15.0 wrapt-1.14.1\r\n" ] } ], "source": [ "!pip install tensorflow==2.15.0" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "FxkQA6oblNqI" }, "source": [ "Install TensorFlow Quantum:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:26.278714Z", "iopub.status.busy": "2024-05-18T11:22:26.278117Z", "iopub.status.idle": "2024-05-18T11:22:38.442683Z", "shell.execute_reply": "2024-05-18T11:22:38.441732Z" }, "id": "saFHsRDpkvkH", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting tensorflow-quantum==0.7.3\r\n", " Using cached tensorflow_quantum-0.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.7 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting cirq-core==1.3.0 (from tensorflow-quantum==0.7.3)\r\n", " Using cached cirq_core-1.3.0-py3-none-any.whl.metadata (1.9 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting cirq-google==1.3.0 (from tensorflow-quantum==0.7.3)\r\n", " Using cached cirq_google-1.3.0-py3-none-any.whl.metadata (2.0 kB)\r\n", "Collecting sympy==1.12 (from tensorflow-quantum==0.7.3)\r\n", " Using cached sympy-1.12-py3-none-any.whl.metadata (12 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting duet~=0.2.8 (from cirq-core==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached duet-0.2.9-py3-none-any.whl.metadata (2.3 kB)\r\n", "Requirement already satisfied: matplotlib~=3.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (3.9.0)\r\n", "Requirement already satisfied: networkx>=2.4 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (3.2.1)\r\n", "Requirement already satisfied: numpy~=1.16 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (1.26.4)\r\n", "Requirement already satisfied: pandas in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (2.2.2)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting sortedcontainers~=2.0 (from cirq-core==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached sortedcontainers-2.4.0-py2.py3-none-any.whl.metadata (10 kB)\r\n", "Requirement already satisfied: scipy in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (1.13.0)\r\n", "Requirement already satisfied: typing-extensions>=4.2 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (4.12.0rc1)\r\n", "Requirement already satisfied: tqdm in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-core==1.3.0->tensorflow-quantum==0.7.3) (4.66.4)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting google-api-core>=1.14.0 (from google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Using cached google_api_core-2.19.0-py3-none-any.whl.metadata (2.7 kB)\r\n", "Collecting proto-plus>=1.20.0 (from cirq-google==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached proto_plus-1.23.0-py3-none-any.whl.metadata (2.2 kB)\r\n", "Requirement already satisfied: protobuf>=3.15.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from cirq-google==1.3.0->tensorflow-quantum==0.7.3) (3.20.3)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting mpmath>=0.19 (from sympy==1.12->tensorflow-quantum==0.7.3)\r\n", " Using cached mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting googleapis-common-protos<2.0.dev0,>=1.56.2 (from google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached googleapis_common_protos-1.63.0-py2.py3-none-any.whl.metadata (1.5 kB)\r\n", "Requirement already satisfied: google-auth<3.0.dev0,>=2.14.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (2.29.0)\r\n", "Requirement already satisfied: requests<3.0.0.dev0,>=2.18.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (2.31.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: grpcio<2.0dev,>=1.33.2 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (1.64.0rc1)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting grpcio-status<2.0.dev0,>=1.33.2 (from google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached grpcio_status-1.63.0-py3-none-any.whl.metadata (1.1 kB)\r\n", "Requirement already satisfied: contourpy>=1.0.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (1.2.1)\r\n", "Requirement already satisfied: cycler>=0.10 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (0.12.1)\r\n", "Requirement already satisfied: fonttools>=4.22.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (4.51.0)\r\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (1.4.5)\r\n", "Requirement already satisfied: packaging>=20.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (24.0)\r\n", "Requirement already satisfied: pillow>=8 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (10.3.0)\r\n", "Requirement already satisfied: pyparsing>=2.3.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (3.1.2)\r\n", "Requirement already satisfied: python-dateutil>=2.7 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (2.9.0.post0)\r\n", "Requirement already satisfied: importlib-resources>=3.2.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (6.4.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: pytz>=2020.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from pandas->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (2024.1)\r\n", "Requirement already satisfied: tzdata>=2022.7 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from pandas->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (2024.1)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (5.3.3)\r\n", "Requirement already satisfied: pyasn1-modules>=0.2.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (0.4.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: rsa<5,>=3.1.4 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (4.9)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "INFO: pip is looking at multiple versions of grpcio-status to determine which version is compatible with other requirements. This could take a while.\r\n", " Using cached grpcio_status-1.62.2-py3-none-any.whl.metadata (1.3 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting protobuf>=3.15.0 (from cirq-google==1.3.0->tensorflow-quantum==0.7.3)\r\n", " Using cached protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl.metadata (541 bytes)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: zipp>=3.1.0 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from importlib-resources>=3.2.0->matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (3.18.2)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: six>=1.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from python-dateutil>=2.7->matplotlib~=3.0->cirq-core==1.3.0->tensorflow-quantum==0.7.3) (1.16.0)\r\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (3.3.2)\r\n", "Requirement already satisfied: idna<4,>=2.5 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (3.7)\r\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (2.2.1)\r\n", "Requirement already satisfied: certifi>=2017.4.17 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (2024.2.2)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /tmpfs/src/tf_docs_env/lib/python3.9/site-packages (from pyasn1-modules>=0.2.1->google-auth<3.0.dev0,>=2.14.1->google-api-core>=1.14.0->google-api-core[grpc]>=1.14.0->cirq-google==1.3.0->tensorflow-quantum==0.7.3) (0.6.0)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Using cached tensorflow_quantum-0.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.8 MB)\r\n", "Using cached cirq_core-1.3.0-py3-none-any.whl (1.8 MB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Using cached cirq_google-1.3.0-py3-none-any.whl (598 kB)\r\n", "Using cached sympy-1.12-py3-none-any.whl (5.7 MB)\r\n", "Using cached duet-0.2.9-py3-none-any.whl (29 kB)\r\n", "Using cached google_api_core-2.19.0-py3-none-any.whl (139 kB)\r\n", "Using cached mpmath-1.3.0-py3-none-any.whl (536 kB)\r\n", "Using cached proto_plus-1.23.0-py3-none-any.whl (48 kB)\r\n", "Using cached sortedcontainers-2.4.0-py2.py3-none-any.whl (29 kB)\r\n", "Using cached googleapis_common_protos-1.63.0-py2.py3-none-any.whl (229 kB)\r\n", "Using cached grpcio_status-1.62.2-py3-none-any.whl (14 kB)\r\n", "Using cached protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl (294 kB)\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Installing collected packages: sortedcontainers, mpmath, sympy, protobuf, duet, proto-plus, googleapis-common-protos, grpcio-status, google-api-core, cirq-core, cirq-google, tensorflow-quantum\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Attempting uninstall: protobuf\r\n", " Found existing installation: protobuf 3.20.3\r\n", " Uninstalling protobuf-3.20.3:\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " Successfully uninstalled protobuf-3.20.3\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\r\n", "tensorflow-metadata 1.15.0 requires protobuf<4.21,>=3.20.3; python_version < \"3.11\", but you have protobuf 4.25.3 which is incompatible.\r\n", "tf-keras 2.16.0 requires tensorflow<2.17,>=2.16, but you have tensorflow 2.15.0 which is incompatible.\u001b[0m\u001b[31m\r\n", "\u001b[0mSuccessfully installed cirq-core-1.3.0 cirq-google-1.3.0 duet-0.2.9 google-api-core-2.19.0 googleapis-common-protos-1.63.0 grpcio-status-1.62.2 mpmath-1.3.0 proto-plus-1.23.0 protobuf-4.25.3 sortedcontainers-2.4.0 sympy-1.12 tensorflow-quantum-0.7.3\r\n" ] } ], "source": [ "!pip install tensorflow-quantum==0.7.3" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:38.446880Z", "iopub.status.busy": "2024-05-18T11:22:38.446273Z", "iopub.status.idle": "2024-05-18T11:22:38.546372Z", "shell.execute_reply": "2024-05-18T11:22:38.545749Z" }, "id": "4Ql5PW-ACO0J", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/tmpfs/tmp/ipykernel_11114/1875984233.py:2: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html\n", " import importlib, pkg_resources\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Update package resources to account for version changes.\n", "import importlib, pkg_resources\n", "importlib.reload(pkg_resources)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "F1L8h1YKUvIO" }, "source": [ "Now import TensorFlow and the module dependencies:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:38.550276Z", "iopub.status.busy": "2024-05-18T11:22:38.549705Z", "iopub.status.idle": "2024-05-18T11:22:42.763362Z", "shell.execute_reply": "2024-05-18T11:22:42.762232Z" }, "id": "enZ300Bflq80", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2024-05-18 11:22:39.011840: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", "2024-05-18 11:22:39.011885: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", "2024-05-18 11:22:39.013339: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2024-05-18 11:22:42.671821: E external/local_xla/xla/stream_executor/cuda/cuda_driver.cc:274] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected\n" ] } ], "source": [ "import tensorflow as tf\n", "import tensorflow_quantum as tfq\n", "\n", "import cirq\n", "import sympy\n", "import numpy as np\n", "\n", "# visualization tools\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "from cirq.contrib.svg import SVGCircuit" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "b08Mmbs8lr81" }, "source": [ "## 1. The Basics" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "y31qSRCczI-L" }, "source": [ "### 1.1 Cirq and parameterized quantum circuits\n", "\n", "Before exploring TensorFlow Quantum (TFQ), let's look at some Cirq basics. Cirq is a Python library for quantum computing from Google. You use it to define circuits, including static and parameterized gates.\n", "\n", "Cirq uses SymPy symbols to represent free parameters." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.768714Z", "iopub.status.busy": "2024-05-18T11:22:42.767299Z", "iopub.status.idle": "2024-05-18T11:22:42.772520Z", "shell.execute_reply": "2024-05-18T11:22:42.771607Z" }, "id": "2yQdmhQLCrzQ", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "a, b = sympy.symbols('a b')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "itUlpbKmDYNW" }, "source": [ "The following code creates a two-qubit circuit using your parameters:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.776287Z", "iopub.status.busy": "2024-05-18T11:22:42.775741Z", "iopub.status.idle": "2024-05-18T11:22:42.905476Z", "shell.execute_reply": "2024-05-18T11:22:42.904624Z" }, "id": "Ps-pd2mndXs7", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "data": { "image/svg+xml": [ "(0, 0): (0, 1): Rx(a)Ry(b)X" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create two qubits\n", "q0, q1 = cirq.GridQubit.rect(1, 2)\n", "\n", "# Create a circuit on these qubits using the parameters you created above.\n", "circuit = cirq.Circuit(\n", " cirq.rx(a).on(q0),\n", " cirq.ry(b).on(q1), cirq.CNOT(q0, q1))\n", "\n", "SVGCircuit(circuit)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zcCX109cJUaz" }, "source": [ "To evaluate circuits, you can use the `cirq.Simulator` interface. You replace free parameters in a circuit with specific numbers by passing in a `cirq.ParamResolver` object. The following code calculates the raw state vector output of your parameterized circuit:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.909245Z", "iopub.status.busy": "2024-05-18T11:22:42.908694Z", "iopub.status.idle": "2024-05-18T11:22:42.919043Z", "shell.execute_reply": "2024-05-18T11:22:42.918141Z" }, "id": "VMq7EayNRyQb", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "array([ 0.9387913 +0.j , -0.23971277+0.j ,\n", " 0. +0.06120872j, 0. -0.23971277j], dtype=complex64)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Calculate a state vector with a=0.5 and b=-0.5.\n", "resolver = cirq.ParamResolver({a: 0.5, b: -0.5})\n", "output_state_vector = cirq.Simulator().simulate(circuit, resolver).final_state_vector\n", "output_state_vector" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-SUlLpXBeicF" }, "source": [ "State vectors are not directly accessible outside of simulation (notice the complex numbers in the output above). To be physically realistic, you must specify a measurement, which converts a state vector into a real number that classical computers can understand. Cirq specifies measurements using combinations of the Pauli operators $\\hat{X}$, $\\hat{Y}$, and $\\hat{Z}$. As illustration, the following code measures $\\hat{Z}_0$ and $\\frac{1}{2}\\hat{Z}_0 + \\hat{X}_1$ on the state vector you just simulated:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.922776Z", "iopub.status.busy": "2024-05-18T11:22:42.922235Z", "iopub.status.idle": "2024-05-18T11:22:42.928140Z", "shell.execute_reply": "2024-05-18T11:22:42.927305Z" }, "id": "hrSnOCi3ehr_", "scrolled": true, "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "0.8775825500488281" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z0 = cirq.Z(q0)\n", "\n", "qubit_map={q0: 0, q1: 1}\n", "\n", "z0.expectation_from_state_vector(output_state_vector, qubit_map).real" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.931758Z", "iopub.status.busy": "2024-05-18T11:22:42.931215Z", "iopub.status.idle": "2024-05-18T11:22:42.937266Z", "shell.execute_reply": "2024-05-18T11:22:42.936423Z" }, "id": "OZ0lWFXv6pII", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "-0.04063427448272705" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z0x1 = 0.5 * z0 + cirq.X(q1)\n", "\n", "z0x1.expectation_from_state_vector(output_state_vector, qubit_map).real" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bkC-yjIolDNr" }, "source": [ "### 1.2 Quantum circuits as tensors\n", "\n", "TensorFlow Quantum (TFQ) provides `tfq.convert_to_tensor`, a function that converts Cirq objects into tensors. This allows you to send Cirq objects to our quantum layers and quantum ops. The function can be called on lists or arrays of Cirq Circuits and Cirq Paulis:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.941110Z", "iopub.status.busy": "2024-05-18T11:22:42.940559Z", "iopub.status.idle": "2024-05-18T11:22:42.950240Z", "shell.execute_reply": "2024-05-18T11:22:42.949355Z" }, "id": "1gLQjA02mIyy", "scrolled": true, "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1,)\n", "\n" ] } ], "source": [ "# Rank 1 tensor containing 1 circuit.\n", "circuit_tensor = tfq.convert_to_tensor([circuit])\n", "\n", "print(circuit_tensor.shape)\n", "print(circuit_tensor.dtype)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "SJy6AkbU6pIP" }, "source": [ "This encodes the Cirq objects as `tf.string` tensors that `tfq` operations decode as needed." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.953820Z", "iopub.status.busy": "2024-05-18T11:22:42.953545Z", "iopub.status.idle": "2024-05-18T11:22:42.959356Z", "shell.execute_reply": "2024-05-18T11:22:42.958382Z" }, "id": "aX_vEmCKmpQS", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "TensorShape([2])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Rank 1 tensor containing 2 Pauli operators.\n", "pauli_tensor = tfq.convert_to_tensor([z0, z0x1])\n", "pauli_tensor.shape" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "FI1JLWe6m8JF" }, "source": [ "### 1.3 Batching circuit simulation\n", "\n", "TFQ provides methods for computing expectation values, samples, and state vectors. For now, let's focus on *expectation values*.\n", "\n", "The highest-level interface for calculating expectation values is the `tfq.layers.Expectation` layer, which is a `tf.keras.Layer`. In its simplest form, this layer is equivalent to simulating a parameterized circuit over many `cirq.ParamResolvers`; however, TFQ allows batching following TensorFlow semantics, and circuits are simulated using efficient C++ code.\n", "\n", "Create a batch of values to substitute for our `a` and `b` parameters:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.963204Z", "iopub.status.busy": "2024-05-18T11:22:42.962538Z", "iopub.status.idle": "2024-05-18T11:22:42.966496Z", "shell.execute_reply": "2024-05-18T11:22:42.965687Z" }, "id": "1fsVZhF5lIXp", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "batch_vals = np.array(np.random.uniform(0, 2 * np.pi, (5, 2)), dtype=float)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Ip7jlGXIf22u" }, "source": [ "Batching circuit execution over parameter values in Cirq requires a loop:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.970183Z", "iopub.status.busy": "2024-05-18T11:22:42.969547Z", "iopub.status.idle": "2024-05-18T11:22:42.985292Z", "shell.execute_reply": "2024-05-18T11:22:42.984626Z" }, "id": "RsfF53UCJtr9", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cirq batch results: \n", " [[ 0.91391081]\n", " [-0.99317902]\n", " [ 0.97061282]\n", " [-0.1768328 ]\n", " [-0.97718316]]\n" ] } ], "source": [ "cirq_results = []\n", "cirq_simulator = cirq.Simulator()\n", "\n", "for vals in batch_vals:\n", " resolver = cirq.ParamResolver({a: vals[0], b: vals[1]})\n", " final_state_vector = cirq_simulator.simulate(circuit, resolver).final_state_vector\n", " cirq_results.append(\n", " [z0.expectation_from_state_vector(final_state_vector, {\n", " q0: 0,\n", " q1: 1\n", " }).real])\n", "\n", "print('cirq batch results: \\n {}'.format(np.array(cirq_results)))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "W0JlZEu-f9Ac" }, "source": [ "The same operation is simplified in TFQ:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:42.988698Z", "iopub.status.busy": "2024-05-18T11:22:42.988178Z", "iopub.status.idle": "2024-05-18T11:22:43.016194Z", "shell.execute_reply": "2024-05-18T11:22:43.015511Z" }, "id": "kGZVdcZ6y9lC", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tfq.layers.Expectation()(circuit,\n", " symbol_names=[a, b],\n", " symbol_values=batch_vals,\n", " operators=z0)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wppQ3TJ23mWC" }, "source": [ "## 2. Hybrid quantum-classical optimization\n", "\n", "Now that you've seen the basics, let's use TensorFlow Quantum to construct a *hybrid quantum-classical neural net*. You will train a classical neural net to control a single qubit. The control will be optimized to correctly prepare the qubit in the `0` or `1` state, overcoming a simulated systematic calibration error. This figure shows the architecture:\n", "\n", "\n", "\n", "Even without a neural network this is a straightforward problem to solve, but the theme is similar to the real quantum control problems you might solve using TFQ. It demonstrates an end-to-end example of a quantum-classical computation using the `tfq.layers.ControlledPQC` (Parametrized Quantum Circuit) layer inside of a `tf.keras.Model`." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NlyxF3Q-6pIe" }, "source": [ "For the implementation of this tutorial, this architecture is split into 3 parts:\n", "\n", "- The *input circuit* or *datapoint circuit*: The first three $R$ gates.\n", "- The *controlled circuit*: The other three $R$ gates.\n", "- The *controller*: The classical neural-network setting the parameters of the controlled circuit." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "VjDf-nTM6ZSs" }, "source": [ "### 2.1 The controlled circuit definition\n", "\n", "Define a learnable single bit rotation, as indicated in the figure above. This will correspond to our controlled circuit." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:43.019902Z", "iopub.status.busy": "2024-05-18T11:22:43.019224Z", "iopub.status.idle": "2024-05-18T11:22:43.136572Z", "shell.execute_reply": "2024-05-18T11:22:43.135947Z" }, "id": "N-j7SCl-51-q", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "findfont: Font family 'Arial' not found.\n" ] }, { "data": { "image/svg+xml": [ "(0, 0): Rz(theta_1)Ry(theta_2)Rx(theta_3)" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Parameters that the classical NN will feed values into.\n", "control_params = sympy.symbols('theta_1 theta_2 theta_3')\n", "\n", "# Create the parameterized circuit.\n", "qubit = cirq.GridQubit(0, 0)\n", "model_circuit = cirq.Circuit(\n", " cirq.rz(control_params[0])(qubit),\n", " cirq.ry(control_params[1])(qubit),\n", " cirq.rx(control_params[2])(qubit))\n", "\n", "SVGCircuit(model_circuit)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wfjSbsvb7g9f" }, "source": [ "### 2.2 The controller\n", "\n", "Now define controller network: " ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:43.140017Z", "iopub.status.busy": "2024-05-18T11:22:43.139397Z", "iopub.status.idle": "2024-05-18T11:22:43.152650Z", "shell.execute_reply": "2024-05-18T11:22:43.152000Z" }, "id": "1v4CK2jD6pIj", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# The classical neural network layers.\n", "controller = tf.keras.Sequential([\n", " tf.keras.layers.Dense(10, activation='elu'),\n", " tf.keras.layers.Dense(3)\n", "])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "QNimbsAt6pIm" }, "source": [ "Given a batch of commands, the controller outputs a batch of control signals for the controlled circuit. \n", "\n", "The controller is randomly initialized so these outputs are not useful, yet." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:43.155964Z", "iopub.status.busy": "2024-05-18T11:22:43.155422Z", "iopub.status.idle": "2024-05-18T11:22:43.214942Z", "shell.execute_reply": "2024-05-18T11:22:43.214288Z" }, "id": "kZbYRTe16pIm", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0. , 0. , 0. ],\n", " [-0.1500438 , -0.2821513 , -0.12589622]], dtype=float32)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "controller(tf.constant([[0.0],[1.0]])).numpy()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "XizLExg56pIp" }, "source": [ "### 2.3 Connect the controller to the circuit" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "I5Pmy5-V6pIq" }, "source": [ "Use `tfq` to connect the controller to the controlled circuit, as a single `keras.Model`. \n", "\n", "See the [Keras Functional API guide](https://www.tensorflow.org/guide/keras/functional) for more about this style of model definition.\n", "\n", "First define the inputs to the model: " ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:43.218510Z", "iopub.status.busy": "2024-05-18T11:22:43.217885Z", "iopub.status.idle": "2024-05-18T11:22:43.223988Z", "shell.execute_reply": "2024-05-18T11:22:43.223347Z" }, "id": "UfHF8NNE6pIr", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# This input is the simulated miscalibration that the model will learn to correct.\n", "circuits_input = tf.keras.Input(shape=(),\n", " # The circuit-tensor has dtype `tf.string` \n", " dtype=tf.string,\n", " name='circuits_input')\n", "\n", "# Commands will be either `0` or `1`, specifying the state to set the qubit to.\n", "commands_input = tf.keras.Input(shape=(1,),\n", " dtype=tf.dtypes.float32,\n", " name='commands_input')\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "y9xN2mNl6pIu" }, "source": [ "Next apply operations to those inputs, to define the computation." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:43.227442Z", "iopub.status.busy": "2024-05-18T11:22:43.226796Z", "iopub.status.idle": "2024-05-18T11:22:44.433490Z", "shell.execute_reply": "2024-05-18T11:22:44.432716Z" }, "id": "Zvt2YGmZ6pIu", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "dense_2 = controller(commands_input)\n", "\n", "# TFQ layer for classically controlled circuits.\n", "expectation_layer = tfq.layers.ControlledPQC(model_circuit,\n", " # Observe Z\n", " operators = cirq.Z(qubit))\n", "expectation = expectation_layer([circuits_input, dense_2])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Ip2jNA9h6pIy" }, "source": [ "Now package this computation as a `tf.keras.Model`:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.437809Z", "iopub.status.busy": "2024-05-18T11:22:44.437212Z", "iopub.status.idle": "2024-05-18T11:22:44.443934Z", "shell.execute_reply": "2024-05-18T11:22:44.443250Z" }, "id": "Xs6EMhah6pIz", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# The full Keras model is built from our layers.\n", "model = tf.keras.Model(inputs=[circuits_input, commands_input],\n", " outputs=expectation)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "w7kgqm3t6pI3" }, "source": [ "The network architecture is indicated by the plot of the model below.\n", "Compare this model plot to the architecture diagram to verify correctness.\n", "\n", "Note: May require a system install of the `graphviz` package." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.447363Z", "iopub.status.busy": "2024-05-18T11:22:44.446807Z", "iopub.status.idle": "2024-05-18T11:22:44.557756Z", "shell.execute_reply": "2024-05-18T11:22:44.556860Z" }, "id": "ERXNPe4F6pI4", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.keras.utils.plot_model(model, show_shapes=True, dpi=70)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "-Pbemgww6pI7" }, "source": [ "This model takes two inputs: The commands for the controller, and the input-circuit whose output the controller is attempting to correct. " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "hpnIBK916pI8" }, "source": [ "### 2.4 The dataset" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yJSC9qH76pJA" }, "source": [ "The model attempts to output the correct correct measurement value of $\\hat{Z}$ for each command. The commands and correct values are defined below." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.561961Z", "iopub.status.busy": "2024-05-18T11:22:44.561309Z", "iopub.status.idle": "2024-05-18T11:22:44.565813Z", "shell.execute_reply": "2024-05-18T11:22:44.565163Z" }, "id": "ciMIJAuH6pJA", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# The command input values to the classical NN.\n", "commands = np.array([[0], [1]], dtype=np.float32)\n", "\n", "# The desired Z expectation value at output of quantum circuit.\n", "expected_outputs = np.array([[1], [-1]], dtype=np.float32)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "kV1LM_hZ6pJD" }, "source": [ "This is not the entire training dataset for this task. \n", "Each datapoint in the dataset also needs an input circuit." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bbiVHvSYVW4H" }, "source": [ "### 2.4 Input circuit definition\n", "\n", "The input-circuit below defines the random miscalibration the model will learn to correct." ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.569267Z", "iopub.status.busy": "2024-05-18T11:22:44.568760Z", "iopub.status.idle": "2024-05-18T11:22:44.575904Z", "shell.execute_reply": "2024-05-18T11:22:44.575253Z" }, "id": "_VYfzHffWo7n", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "random_rotations = np.random.uniform(0, 2 * np.pi, 3)\n", "noisy_preparation = cirq.Circuit(\n", " cirq.rx(random_rotations[0])(qubit),\n", " cirq.ry(random_rotations[1])(qubit),\n", " cirq.rz(random_rotations[2])(qubit)\n", ")\n", "datapoint_circuits = tfq.convert_to_tensor([\n", " noisy_preparation\n", "] * 2) # Make two copied of this circuit" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "FvOkMyKI6pJI" }, "source": [ "There are two copies of the circuit, one for each datapoint." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.579179Z", "iopub.status.busy": "2024-05-18T11:22:44.578639Z", "iopub.status.idle": "2024-05-18T11:22:44.583321Z", "shell.execute_reply": "2024-05-18T11:22:44.582681Z" }, "id": "6nk2Yr3e6pJJ", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "TensorShape([2])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "datapoint_circuits.shape" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "gB--UhZZYgVY" }, "source": [ "### 2.5 Training" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "jATjqUIv6pJM" }, "source": [ "With the inputs defined you can test-run the `tfq` model." ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.586729Z", "iopub.status.busy": "2024-05-18T11:22:44.586117Z", "iopub.status.idle": "2024-05-18T11:22:44.598968Z", "shell.execute_reply": "2024-05-18T11:22:44.598337Z" }, "id": "Lwphqvs96pJO", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "array([[-0.13725013],\n", " [-0.13366866]], dtype=float32)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model([datapoint_circuits, commands]).numpy()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "9gyg5qSL6pJR" }, "source": [ "Now run a standard training process to adjust these values towards the `expected_outputs`." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:44.602251Z", "iopub.status.busy": "2024-05-18T11:22:44.601736Z", "iopub.status.idle": "2024-05-18T11:22:45.368111Z", "shell.execute_reply": "2024-05-18T11:22:45.367276Z" }, "id": "dtPYqbNi8zeZ", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)\n", "loss = tf.keras.losses.MeanSquaredError()\n", "model.compile(optimizer=optimizer, loss=loss)\n", "history = model.fit(x=[datapoint_circuits, commands],\n", " y=expected_outputs,\n", " epochs=30,\n", " verbose=0)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.372313Z", "iopub.status.busy": "2024-05-18T11:22:45.371631Z", "iopub.status.idle": "2024-05-18T11:22:45.561589Z", "shell.execute_reply": "2024-05-18T11:22:45.560941Z" }, "id": "azE-qV0OaC1o", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "image/png": "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TGJiotX+APD999/Xuz8RERF5Jtm7q1JSUjBmzBjcdNNNuOWWW7B48WKUlJRg3LhxAIDRo0ejRYsWSEtLAwBMmzYN/fr1w8KFC3H33Xdj7dq12LNnD95991053wYRERE1MrKHnBEjRiAvLw9z5sxBdnY2evTogc2bN1sGF585cwYKxeUGp169euGTTz7B888/j2effRbt27fHxo0beY0cIiIisiL7dXJcjdfJISIianoa8v3Ny5MSERGRW2LIISIiIrfEkENERERuiSGHiIiI3BJDDhEREbklhhwiIiJySww5RERE5JYYcoiIiMgtMeQQERGRW5J9WQdXM1/gWafTyVwJERER2cr8vW3PQg0eF3KKi4sBANHR0TJXQkRERPYqLi5GUFCQTft63NpVRqMR58+fR0BAACRJcuhz63Q6REdH4+zZs1wXyw48b/bjOWsYnreG4XlrGJ43+13tnAkhUFxcjKioKKuFu6/G41pyFAoFWrZs6dTXCAwM5Ae6AXje7Mdz1jA8bw3D89YwPG/2q++c2dqCY8aBx0REROSWGHKIiIjILTHkOJBGo0Fqaio0Go3cpTQpPG/24zlrGJ63huF5axieN/s5+px53MBjIiIi8gxsySEiIiK3xJBDREREbokhh4iIiNwSQw4RERG5JYYcB1m2bBliYmLg7e2NhIQE7N69W+6SGrW5c+dCkiSrW6dOneQuq9H58ccfMWTIEERFRUGSJGzcuNHqcSEE5syZg+bNm8PHxwdJSUk4duyYPMU2Itc6b2PHjq31+Rs4cKA8xTYSaWlpuPnmmxEQEICIiAgMGzYMmZmZVvuUl5djypQpaNasGfz9/XH//fcjJydHpoobB1vO2+23317r8zZp0iSZKm4c3nnnHXTv3t1y0b/ExER8++23lscd9VljyHGAdevWISUlBampqdi3bx/i4uKQnJyM3NxcuUtr1Lp06YKsrCzL7aeffpK7pEanpKQEcXFxWLZsWZ2Pv/rqq3jzzTexfPly/Prrr/Dz80NycjLKy8tdXGnjcq3zBgADBw60+vytWbPGhRU2Pjt27MCUKVPwyy+/4Pvvv0dVVRXuuusulJSUWPaZMWMG/vvf/+Kzzz7Djh07cP78edx3330yVi0/W84bAEyYMMHq8/bqq6/KVHHj0LJlSyxYsAB79+7Fnj170L9/f9xzzz34888/ATjw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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.plot(history.history['loss'])\n", "plt.title(\"Learning to Control a Qubit\")\n", "plt.xlabel(\"Iterations\")\n", "plt.ylabel(\"Error in Control\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "GTd5DGcRmmOK" }, "source": [ "From this plot you can see that the neural network has learned to overcome the systematic miscalibration." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "C2RfWismj66S" }, "source": [ "### 2.6 Verify outputs\n", "Now use the trained model, to correct the qubit calibration errors. With Cirq:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.565300Z", "iopub.status.busy": "2024-05-18T11:22:45.564636Z", "iopub.status.idle": "2024-05-18T11:22:45.579427Z", "shell.execute_reply": "2024-05-18T11:22:45.578735Z" }, "id": "RoIlb7r7j5SY", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For a desired output (expectation) of [1.] with noisy preparation, the controller\n", "network found the following values for theta: [ 1.1249783 1.6464207 -2.502687 ]\n", "Which gives an actual expectation of: 0.9762285351753235\n", "\n", "For a desired output (expectation) of [-1.] with noisy preparation, the controller\n", "network found the following values for theta: [-1.0330195 -1.6024671 0.2864415]\n", "Which gives an actual expectation of: -0.9853028655052185\n", "\n" ] } ], "source": [ "def check_error(command_values, desired_values):\n", " \"\"\"Based on the value in `command_value` see how well you could prepare\n", " the full circuit to have `desired_value` when taking expectation w.r.t. Z.\"\"\"\n", " params_to_prepare_output = controller(command_values).numpy()\n", " full_circuit = noisy_preparation + model_circuit\n", "\n", " # Test how well you can prepare a state to get expectation the expectation\n", " # value in `desired_values`\n", " for index in [0, 1]:\n", " state = cirq_simulator.simulate(\n", " full_circuit,\n", " {s:v for (s,v) in zip(control_params, params_to_prepare_output[index])}\n", " ).final_state_vector\n", " expt = cirq.Z(qubit).expectation_from_state_vector(state, {qubit: 0}).real\n", " print(f'For a desired output (expectation) of {desired_values[index]} with'\n", " f' noisy preparation, the controller\\nnetwork found the following '\n", " f'values for theta: {params_to_prepare_output[index]}\\nWhich gives an'\n", " f' actual expectation of: {expt}\\n')\n", "\n", "\n", "check_error(commands, expected_outputs)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wvW_ZDwmsws6" }, "source": [ "The value of the loss function during training provides a rough idea of how well the model is learning. The lower the loss, the closer the expectation values in the above cell is to `desired_values`. If you aren't as concerned with the parameter values, you can always check the outputs from above using `tfq`:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.582700Z", "iopub.status.busy": "2024-05-18T11:22:45.582248Z", "iopub.status.idle": "2024-05-18T11:22:45.593038Z", "shell.execute_reply": "2024-05-18T11:22:45.591315Z" }, "id": "aYskLTacs8Ku", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model([datapoint_circuits, commands])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "jNrW0NXR-lDC" }, "source": [ "## 3 Learning to prepare eigenstates of different operators\n", "\n", "The choice of the $\\pm \\hat{Z}$ eigenstates corresponding to 1 and 0 was arbitrary. You could have just as easily wanted 1 to correspond to the $+ \\hat{Z}$ eigenstate and 0 to correspond to the $-\\hat{X}$ eigenstate. One way to accomplish this is by specifying a different measurement operator for each command, as indicated in the figure below:\n", "\n", "\n", "\n", "This requires use of tfq.layers.Expectation. Now your input has grown to include three objects: circuit, command, and operator. The output is still the expectation value." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Ci3WMZ9CjEM1" }, "source": [ "### 3.1 New model definition\n", "\n", "Lets take a look at the model to accomplish this task:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.596499Z", "iopub.status.busy": "2024-05-18T11:22:45.595981Z", "iopub.status.idle": "2024-05-18T11:22:45.603556Z", "shell.execute_reply": "2024-05-18T11:22:45.602864Z" }, "id": "hta0G3Nc6pJY", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Define inputs.\n", "commands_input = tf.keras.layers.Input(shape=(1),\n", " dtype=tf.dtypes.float32,\n", " name='commands_input')\n", "circuits_input = tf.keras.Input(shape=(),\n", " # The circuit-tensor has dtype `tf.string` \n", " dtype=tf.dtypes.string,\n", " name='circuits_input')\n", "operators_input = tf.keras.Input(shape=(1,),\n", " dtype=tf.dtypes.string,\n", " name='operators_input')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dtdnkrZm6pJb" }, "source": [ "Here is the controller network:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.606900Z", "iopub.status.busy": "2024-05-18T11:22:45.606336Z", "iopub.status.idle": "2024-05-18T11:22:45.614290Z", "shell.execute_reply": "2024-05-18T11:22:45.613623Z" }, "id": "n_aTG4g3-y0F", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Define classical NN.\n", "controller = tf.keras.Sequential([\n", " tf.keras.layers.Dense(10, activation='elu'),\n", " tf.keras.layers.Dense(3)\n", "])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "q9aN2ciy6pJf" }, "source": [ "Combine the circuit and the controller into a single `keras.Model` using `tfq`:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.617612Z", "iopub.status.busy": "2024-05-18T11:22:45.617083Z", "iopub.status.idle": "2024-05-18T11:22:45.670303Z", "shell.execute_reply": "2024-05-18T11:22:45.669621Z" }, "id": "IMHjiKit6pJg", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "dense_2 = controller(commands_input)\n", "\n", "# Since you aren't using a PQC or ControlledPQC you must append\n", "# your model circuit onto the datapoint circuit tensor manually.\n", "full_circuit = tfq.layers.AddCircuit()(circuits_input, append=model_circuit)\n", "expectation_output = tfq.layers.Expectation()(full_circuit,\n", " symbol_names=control_params,\n", " symbol_values=dense_2,\n", " operators=operators_input)\n", "\n", "# Contruct your Keras model.\n", "two_axis_control_model = tf.keras.Model(\n", " inputs=[circuits_input, commands_input, operators_input],\n", " outputs=[expectation_output])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "VQTM6CCiD4gU" }, "source": [ "### 3.2 The dataset\n", "\n", "Now you will also include the operators you wish to measure for each datapoint you supply for `model_circuit`:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.673702Z", "iopub.status.busy": "2024-05-18T11:22:45.673116Z", "iopub.status.idle": "2024-05-18T11:22:45.677817Z", "shell.execute_reply": "2024-05-18T11:22:45.677157Z" }, "id": "4gw_L3JG0_G0", "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# The operators to measure, for each command.\n", "operator_data = tfq.convert_to_tensor([[cirq.X(qubit)], [cirq.Z(qubit)]])\n", "\n", "# The command input values to the classical NN.\n", "commands = np.array([[0], [1]], dtype=np.float32)\n", "\n", "# The desired expectation value at output of quantum circuit.\n", "expected_outputs = np.array([[1], [-1]], dtype=np.float32)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ALCKSvwh0_G2" }, "source": [ "### 3.3 Training\n", "\n", "Now that you have your new inputs and outputs you can train once again using keras." ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:45.681007Z", "iopub.status.busy": "2024-05-18T11:22:45.680561Z", "iopub.status.idle": "2024-05-18T11:22:46.389830Z", "shell.execute_reply": "2024-05-18T11:22:46.389096Z" }, "id": "nFuGA73MAA4p", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 1.0518" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 482ms/step - loss: 1.0518\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.6841" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.6841\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.4386" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.4386\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.2500" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.2500\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.1179" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.1179\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0456" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0456\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 7/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0172" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0172\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 8/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0077" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0077\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 9/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0035" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0035\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 10/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0026" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0026\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 11/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0060" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0060\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 12/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0142" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0142\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 13/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0256" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0256\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 14/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0361" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0361\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 15/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0430" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0430\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 16/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0437" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0437\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 17/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0359" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0359\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 18/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0244" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0244\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 19/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0146" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0146\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 20/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0079" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0079\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 21/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0038" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0038\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 22/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 0.0016" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 0.0016\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 23/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 6.0264e-04" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 6.0264e-04\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 24/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 1.8856e-04" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 1.8856e-04\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 25/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 5.0837e-05" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 5.0837e-05\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 26/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 1.5398e-05" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 1.5398e-05\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 27/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 1.2333e-05" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 1.2333e-05\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 28/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 2.5812e-05" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 2.5812e-05\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 29/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 6.2401e-05" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 6.2401e-05\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 30/30\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s - loss: 1.3390e-04" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 4ms/step - loss: 1.3390e-04\n" ] } ], "source": [ "optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)\n", "loss = tf.keras.losses.MeanSquaredError()\n", "\n", "two_axis_control_model.compile(optimizer=optimizer, loss=loss)\n", "\n", "history = two_axis_control_model.fit(\n", " x=[datapoint_circuits, commands, operator_data],\n", " y=expected_outputs,\n", " epochs=30,\n", " verbose=1)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:46.393475Z", "iopub.status.busy": "2024-05-18T11:22:46.392849Z", "iopub.status.idle": "2024-05-18T11:22:46.531648Z", "shell.execute_reply": "2024-05-18T11:22:46.530878Z" }, "id": "Cf_G-GdturLL", "vscode": { "languageId": "python" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.plot(history.history['loss'])\n", "plt.title(\"Learning to Control a Qubit\")\n", "plt.xlabel(\"Iterations\")\n", "plt.ylabel(\"Error in Control\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "sdCPDH9NlJBl" }, "source": [ "The loss function has dropped to zero." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NzY8eSVm6pJs" }, "source": [ "The `controller` is available as a stand-alone model. Call the controller, and check its response to each command signal. It would take some work to correctly compare these outputs to the contents of `random_rotations`." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "colab": {}, "colab_type": "code", "execution": { "iopub.execute_input": "2024-05-18T11:22:46.535508Z", "iopub.status.busy": "2024-05-18T11:22:46.535231Z", "iopub.status.idle": "2024-05-18T11:22:46.650586Z", "shell.execute_reply": "2024-05-18T11:22:46.649869Z" }, "id": "uXmH0TQ76pJt", "vscode": { "languageId": "python" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r", "1/1 [==============================] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "1/1 [==============================] - 0s 67ms/step\n" ] }, { "data": { "text/plain": [ "array([[ 1.6641312 , -0.06845868, -0.00440133],\n", " [ 0.59975535, -1.9673042 , 1.7837791 ]], dtype=float32)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "controller.predict(np.array([0,1]))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "n2WtXnsxubD2" }, "source": [ "Success: See if you can adapt the `check_error` function from your first model to work with this new model architecture." ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "hello_many_worlds.ipynb", "private_outputs": true, "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "language": "python", "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.19" } }, "nbformat": 4, "nbformat_minor": 0 }