├── LICENSE.md ├── Notebooks ├── CIFAR_Hybrid_QNN.ipynb ├── CIFAR_Hybrid_QNN_1_with_accuracy.ipynb ├── CIFAR_Hybrid_QNN_2_comparing_optimizers_Adam,_SGD,_RMSprop.ipynb ├── CIFAR_Hybrid_QNN_3_hyperparameter_tuning.ipynb ├── CIFAR_Hybrid_QNN_Checkpoint_3_comparing_optimizers_Adam,_SGD,_RMSprop.ipynb ├── CIFAR_Hybrid_QNN_till_the_training_convergence.ipynb ├── CIFAR_QNN.ipynb ├── CIFAR_QNN2.ipynb ├── CPU_Changing_QCNN_layers.ipynb ├── Changing_QCNN_layers.ipynb ├── Checkpoint2.ipynb ├── GPU_Changing_QCNN_layers.ipynb ├── Hybrid_MNIST_ZZ.ipynb ├── QCNN_using_Validation_set.ipynb ├── Using_validation.ipynb ├── Using_validation_ex1.ipynb ├── Using_validation_loss.ipynb ├── Using_validation_loss_3.ipynb ├── Using_validation_loss_4.ipynb └── Using_validation_loss_5.ipynb ├── README.md └── paper.md.zip /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rita Abani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Notebooks/CIFAR_QNN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "CIFAR QNN.ipynb", 7 | "provenance": [], 8 | "authorship_tag": "ABX9TyNiD9H7hVIgb9AnF1ulvz94", 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | }, 15 | "language_info": { 16 | "name": "python" 17 | }, 18 | "widgets": { 19 | "application/vnd.jupyter.widget-state+json": { 20 | "9942406645bd4fbf9c7bfa3d79a6abd5": { 21 | "model_module": "@jupyter-widgets/controls", 22 | "model_name": "HBoxModel", 23 | "state": { 24 | "_view_name": "HBoxView", 25 | "_dom_classes": [], 26 | "_model_name": "HBoxModel", 27 | "_view_module": "@jupyter-widgets/controls", 28 | "_model_module_version": "1.5.0", 29 | "_view_count": null, 30 | "_view_module_version": "1.5.0", 31 | "box_style": "", 32 | "layout": "IPY_MODEL_cfbc065d109148b588d47238166c63c8", 33 | "_model_module": "@jupyter-widgets/controls", 34 | "children": [ 35 | "IPY_MODEL_e91c1de864c846bdbd79d88aba3216d4", 36 | "IPY_MODEL_5b108a6c97ef4baebb8d0d26436ffca6" 37 | ] 38 | } 39 | }, 40 | "cfbc065d109148b588d47238166c63c8": { 41 | "model_module": "@jupyter-widgets/base", 42 | "model_name": "LayoutModel", 43 | "state": { 44 | "_view_name": "LayoutView", 45 | "grid_template_rows": null, 46 | "right": null, 47 | "justify_content": null, 48 | "_view_module": "@jupyter-widgets/base", 49 | "overflow": null, 50 | "_model_module_version": "1.2.0", 51 | "_view_count": null, 52 | "flex_flow": null, 53 | "width": null, 54 | "min_width": null, 55 | "border": null, 56 | "align_items": null, 57 | "bottom": null, 58 | "_model_module": "@jupyter-widgets/base", 59 | "top": null, 60 | "grid_column": null, 61 | "overflow_y": null, 62 | "overflow_x": null, 63 | "grid_auto_flow": null, 64 | "grid_area": null, 65 | "grid_template_columns": null, 66 | "flex": null, 67 | "_model_name": "LayoutModel", 68 | "justify_items": null, 69 | "grid_row": null, 70 | "max_height": null, 71 | "align_content": null, 72 | "visibility": null, 73 | "align_self": null, 74 | "height": null, 75 | "min_height": null, 76 | "padding": null, 77 | "grid_auto_rows": null, 78 | "grid_gap": null, 79 | "max_width": null, 80 | "order": null, 81 | "_view_module_version": "1.2.0", 82 | "grid_template_areas": null, 83 | "object_position": null, 84 | "object_fit": null, 85 | "grid_auto_columns": null, 86 | "margin": null, 87 | "display": null, 88 | "left": null 89 | } 90 | }, 91 | "e91c1de864c846bdbd79d88aba3216d4": { 92 | "model_module": "@jupyter-widgets/controls", 93 | "model_name": "FloatProgressModel", 94 | "state": { 95 | "_view_name": "ProgressView", 96 | "style": "IPY_MODEL_ccf7167b19cb4321bebc78eb23522af6", 97 | "_dom_classes": [], 98 | "description": "", 99 | "_model_name": "FloatProgressModel", 100 | "bar_style": "success", 101 | "max": 170498071, 102 | "_view_module": "@jupyter-widgets/controls", 103 | "_model_module_version": "1.5.0", 104 | "value": 170498071, 105 | "_view_count": null, 106 | "_view_module_version": "1.5.0", 107 | "orientation": "horizontal", 108 | "min": 0, 109 | "description_tooltip": null, 110 | "_model_module": "@jupyter-widgets/controls", 111 | "layout": "IPY_MODEL_a84646e520e64288a5ac88c051f7ea41" 112 | } 113 | }, 114 | "5b108a6c97ef4baebb8d0d26436ffca6": { 115 | "model_module": "@jupyter-widgets/controls", 116 | "model_name": "HTMLModel", 117 | "state": { 118 | "_view_name": "HTMLView", 119 | "style": "IPY_MODEL_e444098210404cae8b961ff0970fb367", 120 | "_dom_classes": [], 121 | "description": "", 122 | "_model_name": "HTMLModel", 123 | "placeholder": "​", 124 | "_view_module": "@jupyter-widgets/controls", 125 | "_model_module_version": "1.5.0", 126 | "value": " 170499072/? [00:18<00:00, 9314699.72it/s]", 127 | "_view_count": null, 128 | "_view_module_version": "1.5.0", 129 | "description_tooltip": null, 130 | "_model_module": "@jupyter-widgets/controls", 131 | "layout": "IPY_MODEL_48015e9c118e44b9a3780f60e2eef6f5" 132 | } 133 | }, 134 | "ccf7167b19cb4321bebc78eb23522af6": { 135 | "model_module": "@jupyter-widgets/controls", 136 | "model_name": "ProgressStyleModel", 137 | "state": { 138 | "_view_name": "StyleView", 139 | "_model_name": "ProgressStyleModel", 140 | "description_width": "initial", 141 | "_view_module": "@jupyter-widgets/base", 142 | "_model_module_version": "1.5.0", 143 | "_view_count": null, 144 | "_view_module_version": "1.2.0", 145 | "bar_color": null, 146 | "_model_module": "@jupyter-widgets/controls" 147 | } 148 | }, 149 | "a84646e520e64288a5ac88c051f7ea41": { 150 | "model_module": "@jupyter-widgets/base", 151 | "model_name": "LayoutModel", 152 | "state": { 153 | "_view_name": "LayoutView", 154 | "grid_template_rows": null, 155 | "right": null, 156 | "justify_content": null, 157 | "_view_module": "@jupyter-widgets/base", 158 | "overflow": null, 159 | "_model_module_version": "1.2.0", 160 | "_view_count": null, 161 | "flex_flow": null, 162 | "width": null, 163 | "min_width": null, 164 | "border": null, 165 | "align_items": null, 166 | "bottom": null, 167 | "_model_module": "@jupyter-widgets/base", 168 | "top": null, 169 | "grid_column": null, 170 | "overflow_y": null, 171 | "overflow_x": null, 172 | "grid_auto_flow": null, 173 | "grid_area": null, 174 | "grid_template_columns": null, 175 | "flex": null, 176 | "_model_name": "LayoutModel", 177 | "justify_items": null, 178 | "grid_row": null, 179 | "max_height": null, 180 | "align_content": null, 181 | "visibility": null, 182 | "align_self": null, 183 | "height": null, 184 | "min_height": null, 185 | "padding": null, 186 | "grid_auto_rows": null, 187 | "grid_gap": null, 188 | "max_width": null, 189 | "order": null, 190 | "_view_module_version": "1.2.0", 191 | "grid_template_areas": null, 192 | "object_position": null, 193 | "object_fit": null, 194 | "grid_auto_columns": null, 195 | "margin": null, 196 | "display": null, 197 | "left": null 198 | } 199 | }, 200 | "e444098210404cae8b961ff0970fb367": { 201 | "model_module": "@jupyter-widgets/controls", 202 | "model_name": "DescriptionStyleModel", 203 | "state": { 204 | "_view_name": "StyleView", 205 | "_model_name": "DescriptionStyleModel", 206 | "description_width": "", 207 | "_view_module": "@jupyter-widgets/base", 208 | "_model_module_version": "1.5.0", 209 | "_view_count": null, 210 | "_view_module_version": "1.2.0", 211 | "_model_module": "@jupyter-widgets/controls" 212 | } 213 | }, 214 | "48015e9c118e44b9a3780f60e2eef6f5": { 215 | "model_module": "@jupyter-widgets/base", 216 | "model_name": "LayoutModel", 217 | "state": { 218 | "_view_name": "LayoutView", 219 | "grid_template_rows": null, 220 | "right": null, 221 | "justify_content": null, 222 | "_view_module": "@jupyter-widgets/base", 223 | "overflow": null, 224 | "_model_module_version": "1.2.0", 225 | "_view_count": null, 226 | "flex_flow": null, 227 | "width": null, 228 | "min_width": null, 229 | "border": null, 230 | "align_items": null, 231 | "bottom": null, 232 | "_model_module": "@jupyter-widgets/base", 233 | "top": null, 234 | "grid_column": null, 235 | "overflow_y": null, 236 | "overflow_x": null, 237 | "grid_auto_flow": null, 238 | "grid_area": null, 239 | "grid_template_columns": null, 240 | "flex": null, 241 | "_model_name": "LayoutModel", 242 | "justify_items": null, 243 | "grid_row": null, 244 | "max_height": null, 245 | "align_content": null, 246 | "visibility": null, 247 | "align_self": null, 248 | "height": null, 249 | "min_height": null, 250 | "padding": null, 251 | "grid_auto_rows": null, 252 | "grid_gap": null, 253 | "max_width": null, 254 | "order": null, 255 | "_view_module_version": "1.2.0", 256 | "grid_template_areas": null, 257 | "object_position": null, 258 | "object_fit": null, 259 | "grid_auto_columns": null, 260 | "margin": null, 261 | "display": null, 262 | "left": null 263 | } 264 | } 265 | } 266 | } 267 | }, 268 | "cells": [ 269 | { 270 | "cell_type": "markdown", 271 | "metadata": { 272 | "id": "view-in-github", 273 | "colab_type": "text" 274 | }, 275 | "source": [ 276 | "\"Open" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "metadata": { 282 | "colab": { 283 | "base_uri": "https://localhost:8080/" 284 | }, 285 | "id": "mlYRr1NTuUCq", 286 | "outputId": "0bfcceb7-4de2-4264-f148-cf4050df60ec" 287 | }, 288 | "source": [ 289 | "!pip install qiskit" 290 | ], 291 | "execution_count": 2, 292 | "outputs": [ 293 | { 294 | "output_type": "stream", 295 | "text": [ 296 | "Collecting qiskit\n", 297 | " Downloading https://files.pythonhosted.org/packages/6f/61/cb7506e17a2566dc8a31a3e1924d91ac0bdd8ff07c71ec698c06647b6306/qiskit-0.26.2.tar.gz\n", 298 | "Collecting qiskit-terra==0.17.4\n", 299 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/b3/0c/3c7a8dd451dae0907263e9de9e3e34909e15e18c88a589b44581972c8511/qiskit_terra-0.17.4-cp37-cp37m-manylinux2010_x86_64.whl (6.0MB)\n", 300 | "\u001b[K |████████████████████████████████| 6.0MB 5.1MB/s \n", 301 | "\u001b[?25hCollecting qiskit-aer==0.8.2\n", 302 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/c2/d2/6ff15c370b5465b32529b528bf3f4ce1e01f74498be16203aa1c04b67022/qiskit_aer-0.8.2-cp37-cp37m-manylinux2010_x86_64.whl (18.0MB)\n", 303 | "\u001b[K |████████████████████████████████| 18.0MB 154kB/s \n", 304 | "\u001b[?25hCollecting qiskit-ibmq-provider==0.13.1\n", 305 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/be/99/74bbb901f88603a7d850d4889abc06d81ba702e4227151f4a5b66f2631fe/qiskit_ibmq_provider-0.13.1-py3-none-any.whl (228kB)\n", 306 | "\u001b[K |████████████████████████████████| 235kB 50.7MB/s \n", 307 | "\u001b[?25hCollecting qiskit-ignis==0.6.0\n", 308 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/54/be/a13c828e457e09d979667a61bddbd8c7246aafa94e2501b6a9154429cbea/qiskit_ignis-0.6.0-py3-none-any.whl (207kB)\n", 309 | "\u001b[K |████████████████████████████████| 215kB 51.0MB/s \n", 310 | "\u001b[?25hCollecting qiskit-aqua==0.9.1\n", 311 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/88/79/392c57b978decbb24b902344b536af52c40a751aed0ebbaefa8bc2964cb5/qiskit_aqua-0.9.1-py3-none-any.whl (2.1MB)\n", 312 | "\u001b[K |████████████████████████████████| 2.1MB 33.6MB/s \n", 313 | "\u001b[?25hRequirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (2.6.0)\n", 314 | "Collecting retworkx>=0.8.0\n", 315 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/9e/cd/70d436f170aa1ead2ac9e4c19c8838633355d48b530f09455eab0af2f98e/retworkx-0.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.4MB)\n", 316 | "\u001b[K |████████████████████████████████| 1.5MB 36.7MB/s \n", 317 | "\u001b[?25hRequirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (5.4.8)\n", 318 | "Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (0.3.3)\n", 319 | "Requirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (2.8.1)\n", 320 | "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.19.5)\n", 321 | "Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.7.1)\n", 322 | "Collecting fastjsonschema>=2.10\n", 323 | " Downloading https://files.pythonhosted.org/packages/d1/fb/ea090e917b18320f79be31d754bbe496b715175e865603cfce1eaed2e774/fastjsonschema-2.15.1-py3-none-any.whl\n", 324 | "Collecting python-constraint>=1.4\n", 325 | " Downloading https://files.pythonhosted.org/packages/37/8b/5f1bc2734ca611943e1d6733ee244238679f6410a10cd45ede55a61a8402/python-constraint-1.4.0.tar.bz2\n", 326 | "Requirement already satisfied: scipy>=1.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.4.1)\n", 327 | "Collecting ply>=3.10\n", 328 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl (49kB)\n", 329 | "\u001b[K |████████████████████████████████| 51kB 5.8MB/s \n", 330 | "\u001b[?25hCollecting pybind11>=2.6\n", 331 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/8d/43/7339dbabbc2793718d59703aace4166f53c29ee1c202f6ff5bf8a26c4d91/pybind11-2.6.2-py2.py3-none-any.whl (191kB)\n", 332 | "\u001b[K |████████████████████████████████| 194kB 52.4MB/s \n", 333 | "\u001b[?25hRequirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.13.1->qiskit) (1.24.3)\n", 334 | "Collecting requests-ntlm>=1.1.0\n", 335 | " Downloading https://files.pythonhosted.org/packages/03/4b/8b9a1afde8072c4d5710d9fa91433d504325821b038e00237dc8d6d833dc/requests_ntlm-1.1.0-py2.py3-none-any.whl\n", 336 | "Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.13.1->qiskit) (2.23.0)\n", 337 | "Requirement already satisfied: nest-asyncio!=1.1.0,>=1.0.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.13.1->qiskit) (1.5.1)\n", 338 | "Collecting websockets>=8\n", 339 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/84/64/78c2b3fe37730b30dca3c93d1f7f4a4286767f86e7c04cf3571b39bc2fb7/websockets-9.1-cp37-cp37m-manylinux2010_x86_64.whl (103kB)\n", 340 | "\u001b[K |████████████████████████████████| 112kB 44.4MB/s \n", 341 | "\u001b[?25hRequirement already satisfied: setuptools>=40.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ignis==0.6.0->qiskit) (57.0.0)\n", 342 | "Requirement already satisfied: scikit-learn<=0.24.1,>=0.20.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.1->qiskit) (0.22.2.post1)\n", 343 | "Collecting docplex<=2.20.204; sys_platform != \"darwin\"\n", 344 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/87/99/6f7c219b39fd58c84688ad0713eb932bfcf6be81fc74519e43ea9c915b56/docplex-2.20.204.tar.gz (611kB)\n", 345 | "\u001b[K |████████████████████████████████| 614kB 27.2MB/s \n", 346 | "\u001b[?25hCollecting quandl<=3.6.0\n", 347 | " Downloading https://files.pythonhosted.org/packages/c2/58/9f0e69d836045e3865d263e9ed49f42b23a58526fdabb30f74c430baee3f/Quandl-3.6.0-py2.py3-none-any.whl\n", 348 | "Collecting yfinance<=0.1.55\n", 349 | " Downloading https://files.pythonhosted.org/packages/7a/e8/b9d7104d3a4bf39924799067592d9e59119fcfc900a425a12e80a3123ec8/yfinance-0.1.55.tar.gz\n", 350 | "Requirement already satisfied: pandas<=1.2.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.1->qiskit) (1.1.5)\n", 351 | "Collecting dlx<=1.0.4\n", 352 | " Downloading https://files.pythonhosted.org/packages/54/c0/b8fb5bb727e983b6f5251433ef941b48f38c65bb0bd6ec509e9185bcd406/dlx-1.0.4.tar.gz\n", 353 | "Requirement already satisfied: h5py<=3.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.1->qiskit) (3.1.0)\n", 354 | "Requirement already satisfied: fastdtw<=0.3.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.1->qiskit) (0.3.4)\n", 355 | "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.8.0->qiskit-terra==0.17.4->qiskit) (1.15.0)\n", 356 | "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-terra==0.17.4->qiskit) (1.2.1)\n", 357 | "Collecting cryptography>=1.3\n", 358 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/b2/26/7af637e6a7e87258b963f1731c5982fb31cd507f0d90d91836e446955d02/cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl (3.2MB)\n", 359 | "\u001b[K |████████████████████████████████| 3.2MB 37.1MB/s \n", 360 | "\u001b[?25hCollecting ntlm-auth>=1.0.2\n", 361 | " Downloading https://files.pythonhosted.org/packages/ff/84/97c550164b54942b0e908c31ef09d9469f3ba4cd7332a671e2125732f63b/ntlm_auth-1.5.0-py2.py3-none-any.whl\n", 362 | "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.13.1->qiskit) (3.0.4)\n", 363 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.13.1->qiskit) (2020.12.5)\n", 364 | "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.13.1->qiskit) (2.10)\n", 365 | "Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn<=0.24.1,>=0.20.0->qiskit-aqua==0.9.1->qiskit) (1.0.1)\n", 366 | "Collecting inflection>=0.3.1\n", 367 | " Downloading https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl\n", 368 | "Requirement already satisfied: more-itertools in /usr/local/lib/python3.7/dist-packages (from quandl<=3.6.0->qiskit-aqua==0.9.1->qiskit) (8.7.0)\n", 369 | "Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.7/dist-packages (from yfinance<=0.1.55->qiskit-aqua==0.9.1->qiskit) (0.0.9)\n", 370 | "Collecting lxml>=4.5.1\n", 371 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/30/c0/d0526314971fc661b083ab135747dc68446a3022686da8c16d25fcf6ef07/lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl (6.3MB)\n", 372 | "\u001b[K |████████████████████████████████| 6.3MB 34.3MB/s \n", 373 | "\u001b[?25hRequirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/dist-packages (from pandas<=1.2.3->qiskit-aqua==0.9.1->qiskit) (2018.9)\n", 374 | "Requirement already satisfied: cached-property; python_version < \"3.8\" in /usr/local/lib/python3.7/dist-packages (from h5py<=3.1.0->qiskit-aqua==0.9.1->qiskit) (1.5.2)\n", 375 | "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.13.1->qiskit) (1.14.5)\n", 376 | "Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.13.1->qiskit) (2.20)\n", 377 | "Building wheels for collected packages: qiskit, python-constraint, docplex, yfinance, dlx\n", 378 | " Building wheel for qiskit (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 379 | " Created wheel for qiskit: filename=qiskit-0.26.2-cp37-none-any.whl size=10506 sha256=12f51dc2d377a6044ff38d97d797ca61b1047760ecd2ce0e6114cc12c4fe2642\n", 380 | " Stored in directory: /root/.cache/pip/wheels/89/89/34/524839952d5a58a7be9789e580bfc1ca883bf6579152444568\n", 381 | " Building wheel for python-constraint (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 382 | " Created wheel for python-constraint: filename=python_constraint-1.4.0-py2.py3-none-any.whl size=24079 sha256=ae1a2e58e7f4c70f00b38333cfcc79fd765a5e41913e32f973e1dffeef67c586\n", 383 | " Stored in directory: /root/.cache/pip/wheels/34/31/15/7b070b25d0a549d20ce2e9fe6d727471c2c61ef904720fd40c\n", 384 | " Building wheel for docplex (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 385 | " Created wheel for docplex: filename=docplex-2.20.204-cp37-none-any.whl size=675396 sha256=1c65cc23e3254d87ce484b7dba5a34470bceb90614d4ff7084a3ff2465991e18\n", 386 | " Stored in directory: /root/.cache/pip/wheels/ae/2c/e2/a099ebb6fda8adeba9c5fc2e25659d195ad2f5c6cc5fb75fd4\n", 387 | " Building wheel for yfinance (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 388 | " Created wheel for yfinance: filename=yfinance-0.1.55-py2.py3-none-any.whl size=22627 sha256=35dc3ccee8d98cabcc6909a266effae76b1ad814b0836a2d8a13700998708541\n", 389 | " Stored in directory: /root/.cache/pip/wheels/04/98/cc/2702a4242d60bdc14f48b4557c427ded1fe92aedf257d4565c\n", 390 | " Building wheel for dlx (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 391 | " Created wheel for dlx: filename=dlx-1.0.4-cp37-none-any.whl size=5720 sha256=8ef543ca246bfac210870c429a104410bd89c89d602f678be6c41f2473061d1e\n", 392 | " Stored in directory: /root/.cache/pip/wheels/bb/ba/15/fdd0deb104df3254912998150ba9245668db06b00af5912d1a\n", 393 | "Successfully built qiskit python-constraint docplex yfinance dlx\n", 394 | "\u001b[31mERROR: qiskit-aqua 0.9.1 has requirement retworkx<=0.8.0,>=0.7.0, but you'll have retworkx 0.9.0 which is incompatible.\u001b[0m\n", 395 | "Installing collected packages: retworkx, fastjsonschema, python-constraint, ply, qiskit-terra, pybind11, qiskit-aer, cryptography, ntlm-auth, requests-ntlm, websockets, qiskit-ibmq-provider, qiskit-ignis, docplex, inflection, quandl, lxml, yfinance, dlx, qiskit-aqua, qiskit\n", 396 | " Found existing installation: lxml 4.2.6\n", 397 | " Uninstalling lxml-4.2.6:\n", 398 | " Successfully uninstalled lxml-4.2.6\n", 399 | "Successfully installed cryptography-3.4.7 dlx-1.0.4 docplex-2.20.204 fastjsonschema-2.15.1 inflection-0.5.1 lxml-4.6.3 ntlm-auth-1.5.0 ply-3.11 pybind11-2.6.2 python-constraint-1.4.0 qiskit-0.26.2 qiskit-aer-0.8.2 qiskit-aqua-0.9.1 qiskit-ibmq-provider-0.13.1 qiskit-ignis-0.6.0 qiskit-terra-0.17.4 quandl-3.6.0 requests-ntlm-1.1.0 retworkx-0.9.0 websockets-9.1 yfinance-0.1.55\n" 400 | ], 401 | "name": "stdout" 402 | } 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "metadata": { 408 | "id": "VYBMeYOGuuN9" 409 | }, 410 | "source": [ 411 | "import numpy as np\n", 412 | "import matplotlib.pyplot as plt\n", 413 | "\n", 414 | "import torch\n", 415 | "from torch.autograd import Function\n", 416 | "from torchvision import datasets, transforms\n", 417 | "import torch.optim as optim\n", 418 | "import torch.nn as nn\n", 419 | "import torch.nn.functional as F\n", 420 | "\n", 421 | "import qiskit\n", 422 | "from qiskit import transpile, assemble\n", 423 | "from qiskit.visualization import *" 424 | ], 425 | "execution_count": 3, 426 | "outputs": [] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "metadata": { 431 | "id": "zNivTot8fdU5" 432 | }, 433 | "source": [ 434 | "def to_numbers(tensor_list):\n", 435 | " num_list = []\n", 436 | " for tensor in tensor_list:\n", 437 | " num_list += [tensor.item()]\n", 438 | " return num_list" 439 | ], 440 | "execution_count": 4, 441 | "outputs": [] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "metadata": { 446 | "id": "nIxXTsQp3zN_" 447 | }, 448 | "source": [ 449 | "class QiskitCircuit():\n", 450 | " \n", 451 | " # Specify initial parameters and the quantum circuit\n", 452 | " \n", 453 | " def __init__(self,shots):\n", 454 | " self.theta = Parameter('Theta')\n", 455 | " self.shots = shots\n", 456 | " \n", 457 | " def create_circuit():\n", 458 | " qr = QuantumRegister(1,'q')\n", 459 | " cr = ClassicalRegister(1,'c')\n", 460 | " ckt = QuantumCircuit(qr,cr)\n", 461 | " ckt.h(qr[0])\n", 462 | " ckt.barrier()\n", 463 | " ckt.ry(self.theta,qr[0])\n", 464 | " ckt.barrier()\n", 465 | " ckt.measure(qr,cr)\n", 466 | " return ckt\n", 467 | " \n", 468 | " self.circuit = create_circuit()\n", 469 | " \n", 470 | " def N_qubit_expectation_Z(self,counts, shots, nr_qubits):\n", 471 | " expects = np.zeros(nr_qubits)\n", 472 | " for key in counts.keys():\n", 473 | " perc = counts[key]/shots\n", 474 | " check = np.array([(float(key[i])-1/2)*2*perc for i in range(nr_qubits)])\n", 475 | " expects += check \n", 476 | " return expects \n", 477 | " \n", 478 | " def bind(self, parameters):\n", 479 | " [self.theta] = to_numbers(parameters)\n", 480 | " self.circuit.data[2][0]._params = to_numbers(parameters)\n", 481 | " \n", 482 | " def run(self, i):\n", 483 | " self.bind(i)\n", 484 | " backend = Aer.get_backend('qasm_simulator')\n", 485 | " job_sim = execute(self.circuit,backend,shots=self.shots)\n", 486 | " result_sim = job_sim.result()\n", 487 | " counts = result_sim.get_counts(self.circuit)\n", 488 | " return self.N_qubit_expectation_Z(counts,self.shots,1)" 489 | ], 490 | "execution_count": 5, 491 | "outputs": [] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "metadata": { 496 | "id": "FHJQ4B-z34Yf" 497 | }, 498 | "source": [ 499 | "class TorchCircuit(Function): \n", 500 | "\n", 501 | " @staticmethod\n", 502 | " def forward(ctx, i):\n", 503 | " if not hasattr(ctx, 'QiskitCirc'):\n", 504 | " ctx.QiskitCirc = QiskitCircuit(shots=100)\n", 505 | " \n", 506 | " exp_value = ctx.QiskitCirc.run(i[0])\n", 507 | " \n", 508 | " result = torch.tensor([exp_value]) # store the result as a torch tensor\n", 509 | " \n", 510 | " ctx.save_for_backward(result, i)\n", 511 | " \n", 512 | " return result\n", 513 | " \n", 514 | " @staticmethod\n", 515 | " def backward(ctx, grad_output):\n", 516 | " s = np.pi/2\n", 517 | " \n", 518 | " forward_tensor, i = ctx.saved_tensors \n", 519 | " \n", 520 | " # Obtain paramaters \n", 521 | " input_numbers = to_numbers(i[0])\n", 522 | " \n", 523 | " gradient = []\n", 524 | " \n", 525 | " for k in range(len(input_numbers)):\n", 526 | " input_plus_s = input_numbers\n", 527 | " input_plus_s[k] = input_numbers[k] + s # Shift up by s\n", 528 | " \n", 529 | " exp_value_plus = ctx.QiskitCirc.run(torch.tensor(input_plus_s))[0]\n", 530 | " result_plus_s = torch.tensor([exp_value_plus])\n", 531 | " \n", 532 | " input_minus_s = input_numbers\n", 533 | " input_minus_s[k] = input_numbers[k] - s # Shift down by s\n", 534 | " \n", 535 | " exp_value_minus = ctx.QiskitCirc.run(torch.tensor(input_minus_s))[0]\n", 536 | " result_minus_s = torch.tensor([exp_value_minus])\n", 537 | "\n", 538 | " gradient_result = (result_plus_s - result_minus_s)\n", 539 | "\n", 540 | " gradient.append(gradient_result)\n", 541 | " \n", 542 | " result = torch.tensor([gradient])\n", 543 | " \n", 544 | " return result.float() * grad_output.float()" 545 | ], 546 | "execution_count": 6, 547 | "outputs": [] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "metadata": { 552 | "colab": { 553 | "base_uri": "https://localhost:8080/", 554 | "height": 246 555 | }, 556 | "id": "O0NOffGU39h7", 557 | "outputId": "f8971cec-3907-4de3-de1a-434673008b5f" 558 | }, 559 | "source": [ 560 | "#import torchvision\n", 561 | "#transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()]) # transform images to tensors/vectors\n", 562 | "#cifar_trainset = datasets.CIFAR10(root='./data1', train=True, download=True, transform=transform)\n", 563 | "\n", 564 | "#labels = cifar_trainset.targets # get the labels for the data\n", 565 | "#labels = labels.numpy()\n", 566 | "\n", 567 | "#idx1 = np.where(labels == 0) # filter on aeroplanes\n", 568 | "#idx2 = np.where(labels == 1) # filter on automobiles\n", 569 | "\n", 570 | "# Specify number of datapoints per class (i.e. there will be n pictures of automobiles and n pictures of aeroplanes in the training set)\n", 571 | "#n=100\n", 572 | "\n", 573 | "# concatenate the data indices\n", 574 | "#idx = np.concatenate((idx1[0][0:n],idx2[0][0:n])) \n", 575 | "\n", 576 | "# create the filtered dataset for our training set\n", 577 | "#cifar_trainset.targets = labels[idx] \n", 578 | "#cifar_trainset.data = cifar_trainset.data[idx]\n", 579 | "\n", 580 | "#train_loader = torch.utils.data.DataLoader(cifar_trainset, batch_size=1, shuffle=True)" 581 | ], 582 | "execution_count": 25, 583 | "outputs": [ 584 | { 585 | "output_type": "stream", 586 | "text": [ 587 | "Files already downloaded and verified\n" 588 | ], 589 | "name": "stdout" 590 | }, 591 | { 592 | "output_type": "error", 593 | "ename": "AttributeError", 594 | "evalue": "ignored", 595 | "traceback": [ 596 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 597 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", 598 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mlabels\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcifar_trainset\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtargets\u001b[0m \u001b[0;31m# get the labels for the data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mlabels\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlabels\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnumpy\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 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0midx1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwhere\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlabels\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# filter on aeroplanes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 599 | "\u001b[0;31mAttributeError\u001b[0m: 'list' object has no attribute 'numpy'" 600 | ] 601 | } 602 | ] 603 | }, 604 | { 605 | "cell_type": "code", 606 | "metadata": { 607 | "id": "Rpb9LrNzhVMW" 608 | }, 609 | "source": [ 610 | "import tensorflow\n", 611 | "import torchvision" 612 | ], 613 | "execution_count": 15, 614 | "outputs": [] 615 | }, 616 | { 617 | "cell_type": "code", 618 | "metadata": { 619 | "id": "MXdFx30u5PwY" 620 | }, 621 | "source": [ 622 | "def to_numbers(tensor_list):\n", 623 | " num_list = []\n", 624 | " for tensor in tensor_list:\n", 625 | " num_list += [tensor.item()]\n", 626 | " return num_list" 627 | ], 628 | "execution_count": 26, 629 | "outputs": [] 630 | }, 631 | { 632 | "cell_type": "code", 633 | "metadata": { 634 | "colab": { 635 | "base_uri": "https://localhost:8080/", 636 | "height": 99, 637 | "referenced_widgets": [ 638 | "9942406645bd4fbf9c7bfa3d79a6abd5", 639 | "cfbc065d109148b588d47238166c63c8", 640 | "e91c1de864c846bdbd79d88aba3216d4", 641 | "5b108a6c97ef4baebb8d0d26436ffca6", 642 | "ccf7167b19cb4321bebc78eb23522af6", 643 | "a84646e520e64288a5ac88c051f7ea41", 644 | "e444098210404cae8b961ff0970fb367", 645 | "48015e9c118e44b9a3780f60e2eef6f5" 646 | ] 647 | }, 648 | "id": "C8GWLzXk5Q-i", 649 | "outputId": "9bbcf3d0-8649-4cba-85a1-98ed2e2a6ac0" 650 | }, 651 | "source": [ 652 | "\n", 653 | "import torchvision\n", 654 | "transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()]) # transform images to tensors/vectors\n", 655 | "cifar_trainset = datasets.CIFAR10(root='./data1', train=True, download=True, transform=transform)\n", 656 | "\n", 657 | "labels = cifar_trainset.targets # get the labels for the data\n", 658 | "labels = np.array(labels)\n", 659 | "\n", 660 | "idx1 = np.where(labels == 0) # filter on aeroplanes\n", 661 | "idx2 = np.where(labels == 1) # filter on automobiles\n", 662 | "\n", 663 | "# Specify number of datapoints per class (i.e. there will be n pictures of automobiles and n pictures of aeroplanes in the training set)\n", 664 | "n=100\n", 665 | "\n", 666 | "# concatenate the data indices\n", 667 | "idx = np.concatenate((idx1[0][0:n],idx2[0][0:n])) \n", 668 | "\n", 669 | "# create the filtered dataset for our training set\n", 670 | "cifar_trainset.targets = labels[idx] \n", 671 | "cifar_trainset.data = cifar_trainset.data[idx]\n", 672 | "\n", 673 | "train_loader = torch.utils.data.DataLoader(cifar_trainset, batch_size=1, shuffle=True)" 674 | ], 675 | "execution_count": 8, 676 | "outputs": [ 677 | { 678 | "output_type": "stream", 679 | "text": [ 680 | "Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data1/cifar-10-python.tar.gz\n" 681 | ], 682 | "name": "stdout" 683 | }, 684 | { 685 | "output_type": "display_data", 686 | "data": { 687 | "application/vnd.jupyter.widget-view+json": { 688 | "model_id": "9942406645bd4fbf9c7bfa3d79a6abd5", 689 | "version_minor": 0, 690 | "version_major": 2 691 | }, 692 | "text/plain": [ 693 | "HBox(children=(FloatProgress(value=0.0, max=170498071.0), HTML(value='')))" 694 | ] 695 | }, 696 | "metadata": { 697 | "tags": [] 698 | } 699 | }, 700 | { 701 | "output_type": "stream", 702 | "text": [ 703 | "\n", 704 | "Extracting ./data1/cifar-10-python.tar.gz to ./data1\n" 705 | ], 706 | "name": "stdout" 707 | } 708 | ] 709 | }, 710 | { 711 | "cell_type": "markdown", 712 | "metadata": { 713 | "id": "9wxOOuQQDjDP" 714 | }, 715 | "source": [ 716 | "Now creating the hybrid neural network." 717 | ] 718 | }, 719 | { 720 | "cell_type": "code", 721 | "metadata": { 722 | "id": "7Chcmm8xem-5" 723 | }, 724 | "source": [ 725 | "\n", 726 | "qc = TorchCircuit.apply \n", 727 | "\n", 728 | "class Net(nn.Module):\n", 729 | " def __init__(self):\n", 730 | " super(Net, self).__init__()\n", 731 | " self.conv1 = nn.Conv2d(3, 10, kernel_size=5)\n", 732 | " self.conv2 = nn.Conv2d(10, 20, kernel_size=5)\n", 733 | " self.conv2_drop = nn.Dropout2d()\n", 734 | " self.h1 = nn.Linear(500, 500)\n", 735 | " self.h2 = nn.Linear(500, 1)\n", 736 | "\n", 737 | " def forward(self,x):\n", 738 | " x = F.relu(F.max_pool2d(self.conv1(x), 2))\n", 739 | " x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))\n", 740 | " x = x.view(-1, 500)\n", 741 | " x = F.relu(self.h1(x))\n", 742 | " x = F.dropout(x, training=self.training)\n", 743 | " x = self.h2(x)\n", 744 | " x = qc(x)\n", 745 | " x = (x+1)/2 # Normalise the inputs to 1 or 0\n", 746 | " x = torch.cat((x, 1-x), -1)\n", 747 | " return x" 748 | ], 749 | "execution_count": 31, 750 | "outputs": [] 751 | }, 752 | { 753 | "cell_type": "code", 754 | "metadata": { 755 | "colab": { 756 | "base_uri": "https://localhost:8080/", 757 | "height": 450 758 | }, 759 | "id": "41oqcpbJe2W5", 760 | "outputId": "042a47a2-bddd-4246-fa80-dd30104edec3" 761 | }, 762 | "source": [ 763 | "network = Net()\n", 764 | "#input = input.permute(1,0,2,3)\n", 765 | "optimizer = optim.Adam(network.parameters(), lr=0.001)\n", 766 | "\n", 767 | "epochs = 10\n", 768 | "loss_list = []\n", 769 | "for epoch in range(epochs):\n", 770 | " total_loss = []\n", 771 | " target_list = []\n", 772 | " for batch_idx, (data, target) in enumerate(train_loader):\n", 773 | " target_list.append(target.item())\n", 774 | " optimizer.zero_grad()\n", 775 | " output = network(data)\n", 776 | " loss = F.nll_loss(output, target)\n", 777 | " loss.backward()\n", 778 | " optimizer.step()\n", 779 | " total_loss.append(loss.item())\n", 780 | " loss_list.append(sum(total_loss)/len(total_loss))\n", 781 | " print(loss_list[-1])\n", 782 | "\n", 783 | "# Normalise the loss between 0 and 1\n", 784 | "for i in range(len(loss_list)):\n", 785 | " loss_list[i] += 1\n", 786 | "\n", 787 | "# Plot the loss per epoch\n", 788 | "plt.plot(loss_list)" 789 | ], 790 | "execution_count": 32, 791 | "outputs": [ 792 | { 793 | "output_type": "stream", 794 | "text": [ 795 | "-0.5160500000000002\n", 796 | "-0.5147499999999998\n", 797 | "-0.4957500000000001\n", 798 | "-0.5060999999999997\n", 799 | "-0.5278\n", 800 | "-0.5152499999999998\n", 801 | "-0.5463500000000002\n", 802 | "-0.6112999999999998\n", 803 | "-0.6389999999999998\n", 804 | "-0.6592499999999994\n" 805 | ], 806 | "name": "stdout" 807 | }, 808 | { 809 | "output_type": "execute_result", 810 | "data": { 811 | "text/plain": [ 812 | "[]" 813 | ] 814 | }, 815 | "metadata": { 816 | "tags": [] 817 | }, 818 | "execution_count": 32 819 | }, 820 | { 821 | "output_type": "display_data", 822 | "data": { 823 | "image/png": "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\n", 824 | "text/plain": [ 825 | "
" 826 | ] 827 | }, 828 | "metadata": { 829 | "tags": [], 830 | "needs_background": "light" 831 | } 832 | } 833 | ] 834 | }, 835 | { 836 | "cell_type": "code", 837 | "metadata": { 838 | "id": "Ve0YtqV2REFJ" 839 | }, 840 | "source": [ 841 | "\n", 842 | "import numpy as np\n", 843 | "import torch\n", 844 | "from torch.autograd import Function\n", 845 | "import torch.optim as optim\n", 846 | "import torch.nn as nn\n", 847 | "import torch.nn.functional as F\n", 848 | "import torchvision\n", 849 | "from torchvision import datasets, transforms\n", 850 | "from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, execute\n", 851 | "from qiskit.circuit import Parameter\n", 852 | "from qiskit import Aer\n", 853 | "from tqdm import tqdm\n", 854 | "from matplotlib import pyplot as plt\n", 855 | "%matplotlib inline" 856 | ], 857 | "execution_count": 18, 858 | "outputs": [] 859 | } 860 | ] 861 | } 862 | -------------------------------------------------------------------------------- /Notebooks/Using_validation_loss.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Using validation loss.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "authorship_tag": "ABX9TyMpLt2O9bHGcU7CHCM7h8Ef", 10 | "include_colab_link": true 11 | }, 12 | "kernelspec": { 13 | "name": "python3", 14 | "display_name": "Python 3" 15 | }, 16 | "language_info": { 17 | "name": "python" 18 | }, 19 | "widgets": { 20 | "application/vnd.jupyter.widget-state+json": { 21 | "6b21baa29bbf408d96883c52c578d25e": { 22 | "model_module": "@jupyter-widgets/controls", 23 | "model_name": "HBoxModel", 24 | "state": { 25 | "_view_name": "HBoxView", 26 | "_dom_classes": [], 27 | "_model_name": "HBoxModel", 28 | "_view_module": "@jupyter-widgets/controls", 29 | "_model_module_version": "1.5.0", 30 | "_view_count": null, 31 | "_view_module_version": "1.5.0", 32 | "box_style": "", 33 | "layout": "IPY_MODEL_c0afc2958d7f4cb6ad5fa7df3127b838", 34 | "_model_module": "@jupyter-widgets/controls", 35 | "children": [ 36 | "IPY_MODEL_97126e60fd414c0ca90bcf1090f159e0", 37 | "IPY_MODEL_61bcf60fe4cc4dc7bebc1215bf6c27f7" 38 | ] 39 | } 40 | }, 41 | "c0afc2958d7f4cb6ad5fa7df3127b838": { 42 | "model_module": "@jupyter-widgets/base", 43 | "model_name": "LayoutModel", 44 | "state": { 45 | "_view_name": "LayoutView", 46 | "grid_template_rows": null, 47 | "right": null, 48 | "justify_content": null, 49 | "_view_module": "@jupyter-widgets/base", 50 | "overflow": null, 51 | "_model_module_version": "1.2.0", 52 | "_view_count": null, 53 | "flex_flow": null, 54 | "width": null, 55 | "min_width": null, 56 | "border": null, 57 | "align_items": null, 58 | "bottom": null, 59 | "_model_module": "@jupyter-widgets/base", 60 | "top": null, 61 | "grid_column": null, 62 | "overflow_y": null, 63 | "overflow_x": null, 64 | "grid_auto_flow": null, 65 | "grid_area": null, 66 | "grid_template_columns": null, 67 | "flex": null, 68 | "_model_name": "LayoutModel", 69 | "justify_items": null, 70 | "grid_row": null, 71 | "max_height": null, 72 | "align_content": null, 73 | "visibility": null, 74 | "align_self": null, 75 | "height": null, 76 | "min_height": null, 77 | "padding": null, 78 | "grid_auto_rows": null, 79 | "grid_gap": null, 80 | "max_width": null, 81 | "order": null, 82 | "_view_module_version": "1.2.0", 83 | "grid_template_areas": null, 84 | "object_position": null, 85 | "object_fit": null, 86 | "grid_auto_columns": null, 87 | "margin": null, 88 | "display": null, 89 | "left": null 90 | } 91 | }, 92 | "97126e60fd414c0ca90bcf1090f159e0": { 93 | "model_module": "@jupyter-widgets/controls", 94 | "model_name": "FloatProgressModel", 95 | "state": { 96 | "_view_name": "ProgressView", 97 | "style": "IPY_MODEL_2fe1f152bcf7413cae42224d18d44fd7", 98 | "_dom_classes": [], 99 | "description": "", 100 | "_model_name": "FloatProgressModel", 101 | "bar_style": "success", 102 | "max": 170498071, 103 | "_view_module": "@jupyter-widgets/controls", 104 | "_model_module_version": "1.5.0", 105 | "value": 170498071, 106 | "_view_count": null, 107 | "_view_module_version": "1.5.0", 108 | "orientation": "horizontal", 109 | "min": 0, 110 | "description_tooltip": null, 111 | "_model_module": "@jupyter-widgets/controls", 112 | "layout": "IPY_MODEL_20cfd8834a4548e993b60bce5a119264" 113 | } 114 | }, 115 | "61bcf60fe4cc4dc7bebc1215bf6c27f7": { 116 | "model_module": "@jupyter-widgets/controls", 117 | "model_name": "HTMLModel", 118 | "state": { 119 | "_view_name": "HTMLView", 120 | "style": "IPY_MODEL_755a675c4f374bd0a427143b783eb6b7", 121 | "_dom_classes": [], 122 | "description": "", 123 | "_model_name": "HTMLModel", 124 | "placeholder": "​", 125 | "_view_module": "@jupyter-widgets/controls", 126 | "_model_module_version": "1.5.0", 127 | "value": " 170499072/? [00:02<00:00, 58654212.03it/s]", 128 | "_view_count": null, 129 | "_view_module_version": "1.5.0", 130 | "description_tooltip": null, 131 | "_model_module": "@jupyter-widgets/controls", 132 | "layout": "IPY_MODEL_661d394b279547e197586c2e7ed91993" 133 | } 134 | }, 135 | "2fe1f152bcf7413cae42224d18d44fd7": { 136 | "model_module": "@jupyter-widgets/controls", 137 | "model_name": "ProgressStyleModel", 138 | "state": { 139 | "_view_name": "StyleView", 140 | "_model_name": "ProgressStyleModel", 141 | "description_width": "initial", 142 | "_view_module": "@jupyter-widgets/base", 143 | "_model_module_version": "1.5.0", 144 | "_view_count": null, 145 | "_view_module_version": "1.2.0", 146 | "bar_color": null, 147 | "_model_module": "@jupyter-widgets/controls" 148 | } 149 | }, 150 | "20cfd8834a4548e993b60bce5a119264": { 151 | "model_module": "@jupyter-widgets/base", 152 | "model_name": "LayoutModel", 153 | "state": { 154 | "_view_name": "LayoutView", 155 | "grid_template_rows": null, 156 | "right": null, 157 | "justify_content": null, 158 | "_view_module": "@jupyter-widgets/base", 159 | "overflow": null, 160 | "_model_module_version": "1.2.0", 161 | "_view_count": null, 162 | "flex_flow": null, 163 | "width": null, 164 | "min_width": null, 165 | "border": null, 166 | "align_items": null, 167 | "bottom": null, 168 | "_model_module": "@jupyter-widgets/base", 169 | "top": null, 170 | "grid_column": null, 171 | "overflow_y": null, 172 | "overflow_x": null, 173 | "grid_auto_flow": null, 174 | "grid_area": null, 175 | "grid_template_columns": null, 176 | "flex": null, 177 | "_model_name": "LayoutModel", 178 | "justify_items": null, 179 | "grid_row": null, 180 | "max_height": null, 181 | "align_content": null, 182 | "visibility": null, 183 | "align_self": null, 184 | "height": null, 185 | "min_height": null, 186 | "padding": null, 187 | "grid_auto_rows": null, 188 | "grid_gap": null, 189 | "max_width": null, 190 | "order": null, 191 | "_view_module_version": "1.2.0", 192 | "grid_template_areas": null, 193 | "object_position": null, 194 | "object_fit": null, 195 | "grid_auto_columns": null, 196 | "margin": null, 197 | "display": null, 198 | "left": null 199 | } 200 | }, 201 | "755a675c4f374bd0a427143b783eb6b7": { 202 | "model_module": "@jupyter-widgets/controls", 203 | "model_name": "DescriptionStyleModel", 204 | "state": { 205 | "_view_name": "StyleView", 206 | "_model_name": "DescriptionStyleModel", 207 | "description_width": "", 208 | "_view_module": "@jupyter-widgets/base", 209 | "_model_module_version": "1.5.0", 210 | "_view_count": null, 211 | "_view_module_version": "1.2.0", 212 | "_model_module": "@jupyter-widgets/controls" 213 | } 214 | }, 215 | "661d394b279547e197586c2e7ed91993": { 216 | "model_module": "@jupyter-widgets/base", 217 | "model_name": "LayoutModel", 218 | "state": { 219 | "_view_name": "LayoutView", 220 | "grid_template_rows": null, 221 | "right": null, 222 | "justify_content": null, 223 | "_view_module": "@jupyter-widgets/base", 224 | "overflow": null, 225 | "_model_module_version": "1.2.0", 226 | "_view_count": null, 227 | "flex_flow": null, 228 | "width": null, 229 | "min_width": null, 230 | "border": null, 231 | "align_items": null, 232 | "bottom": null, 233 | "_model_module": "@jupyter-widgets/base", 234 | "top": null, 235 | "grid_column": null, 236 | "overflow_y": null, 237 | "overflow_x": null, 238 | "grid_auto_flow": null, 239 | "grid_area": null, 240 | "grid_template_columns": null, 241 | "flex": null, 242 | "_model_name": "LayoutModel", 243 | "justify_items": null, 244 | "grid_row": null, 245 | "max_height": null, 246 | "align_content": null, 247 | "visibility": null, 248 | "align_self": null, 249 | "height": null, 250 | "min_height": null, 251 | "padding": null, 252 | "grid_auto_rows": null, 253 | "grid_gap": null, 254 | "max_width": null, 255 | "order": null, 256 | "_view_module_version": "1.2.0", 257 | "grid_template_areas": null, 258 | "object_position": null, 259 | "object_fit": null, 260 | "grid_auto_columns": null, 261 | "margin": null, 262 | "display": null, 263 | "left": null 264 | } 265 | } 266 | } 267 | }, 268 | "accelerator": "GPU" 269 | }, 270 | "cells": [ 271 | { 272 | "cell_type": "markdown", 273 | "metadata": { 274 | "id": "view-in-github", 275 | "colab_type": "text" 276 | }, 277 | "source": [ 278 | "\"Open" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "metadata": { 284 | "colab": { 285 | "base_uri": "https://localhost:8080/" 286 | }, 287 | "id": "4BE4HL0SJrYa", 288 | "outputId": "6614b473-7668-4c7f-f46d-fc9f8b427e93" 289 | }, 290 | "source": [ 291 | "!pip install qiskit" 292 | ], 293 | "execution_count": 1, 294 | "outputs": [ 295 | { 296 | "output_type": "stream", 297 | "text": [ 298 | "Collecting qiskit\n", 299 | " Downloading https://files.pythonhosted.org/packages/79/19/44f002f6633c64b4ab88d274dd036857624e4ba8b701cd90a408103a3791/qiskit-0.27.0.tar.gz\n", 300 | "Collecting qiskit-terra==0.17.4\n", 301 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/b3/0c/3c7a8dd451dae0907263e9de9e3e34909e15e18c88a589b44581972c8511/qiskit_terra-0.17.4-cp37-cp37m-manylinux2010_x86_64.whl (6.0MB)\n", 302 | "\u001b[K |████████████████████████████████| 6.0MB 5.1MB/s \n", 303 | "\u001b[?25hCollecting qiskit-aer==0.8.2\n", 304 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/c2/d2/6ff15c370b5465b32529b528bf3f4ce1e01f74498be16203aa1c04b67022/qiskit_aer-0.8.2-cp37-cp37m-manylinux2010_x86_64.whl (18.0MB)\n", 305 | "\u001b[K |████████████████████████████████| 18.0MB 120kB/s \n", 306 | "\u001b[?25hCollecting qiskit-ibmq-provider==0.14.0\n", 307 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/83/2f/6f3b53b633cc477dbe601728c8c3fc8674441cb9554d14517254a52d0c8a/qiskit_ibmq_provider-0.14.0-py3-none-any.whl (229kB)\n", 308 | "\u001b[K |████████████████████████████████| 235kB 24.2MB/s \n", 309 | "\u001b[?25hCollecting qiskit-ignis==0.6.0\n", 310 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/54/be/a13c828e457e09d979667a61bddbd8c7246aafa94e2501b6a9154429cbea/qiskit_ignis-0.6.0-py3-none-any.whl (207kB)\n", 311 | "\u001b[K |████████████████████████████████| 215kB 47.6MB/s \n", 312 | "\u001b[?25hCollecting qiskit-aqua==0.9.2\n", 313 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/81/00/1f71631bbc3fd24537d7ec1c52adfcf4fa0851c13fefc05d6babcb11a1f8/qiskit_aqua-0.9.2-py3-none-any.whl (2.1MB)\n", 314 | "\u001b[K |████████████████████████████████| 2.1MB 34.2MB/s \n", 315 | "\u001b[?25hRequirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (2.6.0)\n", 316 | "Collecting python-constraint>=1.4\n", 317 | " Downloading https://files.pythonhosted.org/packages/37/8b/5f1bc2734ca611943e1d6733ee244238679f6410a10cd45ede55a61a8402/python-constraint-1.4.0.tar.bz2\n", 318 | "Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (0.3.4)\n", 319 | "Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (5.4.8)\n", 320 | "Collecting retworkx>=0.8.0\n", 321 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/9e/cd/70d436f170aa1ead2ac9e4c19c8838633355d48b530f09455eab0af2f98e/retworkx-0.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.4MB)\n", 322 | "\u001b[K |████████████████████████████████| 1.5MB 35.3MB/s \n", 323 | "\u001b[?25hRequirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.19.5)\n", 324 | "Collecting ply>=3.10\n", 325 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl (49kB)\n", 326 | "\u001b[K |████████████████████████████████| 51kB 6.6MB/s \n", 327 | "\u001b[?25hRequirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (2.8.1)\n", 328 | "Collecting fastjsonschema>=2.10\n", 329 | " Downloading https://files.pythonhosted.org/packages/d1/fb/ea090e917b18320f79be31d754bbe496b715175e865603cfce1eaed2e774/fastjsonschema-2.15.1-py3-none-any.whl\n", 330 | "Requirement already satisfied: scipy>=1.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.4.1)\n", 331 | "Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit) (1.7.1)\n", 332 | "Collecting pybind11>=2.6\n", 333 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/8d/43/7339dbabbc2793718d59703aace4166f53c29ee1c202f6ff5bf8a26c4d91/pybind11-2.6.2-py2.py3-none-any.whl (191kB)\n", 334 | "\u001b[K |████████████████████████████████| 194kB 46.1MB/s \n", 335 | "\u001b[?25hCollecting websocket-client>=1.0.1\n", 336 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/ca/5f/3c211d168b2e9f9342cfb53bcfc26aab0eac63b998015e7af7bcae66119d/websocket_client-1.1.0-py2.py3-none-any.whl (68kB)\n", 337 | "\u001b[K |████████████████████████████████| 71kB 9.8MB/s \n", 338 | "\u001b[?25hCollecting requests-ntlm>=1.1.0\n", 339 | " Downloading https://files.pythonhosted.org/packages/03/4b/8b9a1afde8072c4d5710d9fa91433d504325821b038e00237dc8d6d833dc/requests_ntlm-1.1.0-py2.py3-none-any.whl\n", 340 | "Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.14.0->qiskit) (2.23.0)\n", 341 | "Requirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.14.0->qiskit) (1.24.3)\n", 342 | "Requirement already satisfied: setuptools>=40.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ignis==0.6.0->qiskit) (57.0.0)\n", 343 | "Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit) (1.1.5)\n", 344 | "Collecting quandl\n", 345 | " Downloading https://files.pythonhosted.org/packages/8b/2b/feefb36015beaecc5c0f9f2533e815b409621d9fa7b50b2aac621796f828/Quandl-3.6.1-py2.py3-none-any.whl\n", 346 | "Requirement already satisfied: scikit-learn>=0.20.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit) (0.22.2.post1)\n", 347 | "Collecting docplex<=2.20.204; sys_platform != \"darwin\"\n", 348 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/87/99/6f7c219b39fd58c84688ad0713eb932bfcf6be81fc74519e43ea9c915b56/docplex-2.20.204.tar.gz (611kB)\n", 349 | "\u001b[K |████████████████████████████████| 614kB 34.3MB/s \n", 350 | "\u001b[?25hCollecting dlx<=1.0.4\n", 351 | " Downloading https://files.pythonhosted.org/packages/54/c0/b8fb5bb727e983b6f5251433ef941b48f38c65bb0bd6ec509e9185bcd406/dlx-1.0.4.tar.gz\n", 352 | "Collecting yfinance\n", 353 | " Downloading https://files.pythonhosted.org/packages/a7/ee/315752b9ef281ba83c62aa7ec2e2074f85223da6e7e74efb4d3e11c0f510/yfinance-0.1.59.tar.gz\n", 354 | "Requirement already satisfied: fastdtw<=0.3.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit) (0.3.4)\n", 355 | "Requirement already satisfied: h5py in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit) (3.1.0)\n", 356 | "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.8.0->qiskit-terra==0.17.4->qiskit) (1.15.0)\n", 357 | "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-terra==0.17.4->qiskit) (1.2.1)\n", 358 | "Collecting ntlm-auth>=1.0.2\n", 359 | " Downloading https://files.pythonhosted.org/packages/ff/84/97c550164b54942b0e908c31ef09d9469f3ba4cd7332a671e2125732f63b/ntlm_auth-1.5.0-py2.py3-none-any.whl\n", 360 | "Collecting cryptography>=1.3\n", 361 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/b2/26/7af637e6a7e87258b963f1731c5982fb31cd507f0d90d91836e446955d02/cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl (3.2MB)\n", 362 | "\u001b[K |████████████████████████████████| 3.2MB 38.7MB/s \n", 363 | "\u001b[?25hRequirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.14.0->qiskit) (2.10)\n", 364 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.14.0->qiskit) (2021.5.30)\n", 365 | "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.14.0->qiskit) (3.0.4)\n", 366 | "Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/dist-packages (from pandas->qiskit-aqua==0.9.2->qiskit) (2018.9)\n", 367 | "Collecting inflection>=0.3.1\n", 368 | " Downloading https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl\n", 369 | "Requirement already satisfied: more-itertools in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.2->qiskit) (8.8.0)\n", 370 | "Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.2->qiskit) (1.0.1)\n", 371 | "Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.7/dist-packages (from yfinance->qiskit-aqua==0.9.2->qiskit) (0.0.9)\n", 372 | "Collecting lxml>=4.5.1\n", 373 | "\u001b[?25l Downloading https://files.pythonhosted.org/packages/30/c0/d0526314971fc661b083ab135747dc68446a3022686da8c16d25fcf6ef07/lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl (6.3MB)\n", 374 | "\u001b[K |████████████████████████████████| 6.3MB 37.0MB/s \n", 375 | "\u001b[?25hRequirement already satisfied: cached-property; python_version < \"3.8\" in /usr/local/lib/python3.7/dist-packages (from h5py->qiskit-aqua==0.9.2->qiskit) (1.5.2)\n", 376 | "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit) (1.14.5)\n", 377 | "Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit) (2.20)\n", 378 | "Building wheels for collected packages: qiskit, python-constraint, docplex, dlx, yfinance\n", 379 | " Building wheel for qiskit (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 380 | " Created wheel for qiskit: filename=qiskit-0.27.0-cp37-none-any.whl size=10505 sha256=10f30fdea9e877bba66706286d60e00ce2419baec4b6a3d13cb59ef21c70de7e\n", 381 | " Stored in directory: /root/.cache/pip/wheels/c6/54/d9/f0f711dc20aff31947456951374132d0e23ec527da8c15295d\n", 382 | " Building wheel for python-constraint (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 383 | " Created wheel for python-constraint: filename=python_constraint-1.4.0-py2.py3-none-any.whl size=24079 sha256=f0142898cfdc812b42ff7a8b39c4d0900e5ecc9ab1b8f6edd4ab543330a3cbad\n", 384 | " Stored in directory: /root/.cache/pip/wheels/34/31/15/7b070b25d0a549d20ce2e9fe6d727471c2c61ef904720fd40c\n", 385 | " Building wheel for docplex (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 386 | " Created wheel for docplex: filename=docplex-2.20.204-cp37-none-any.whl size=675396 sha256=cef4ea2bfe0d0fed41c12d081c9d51081851ed7e458abca71fad98df682e0b89\n", 387 | " Stored in directory: /root/.cache/pip/wheels/ae/2c/e2/a099ebb6fda8adeba9c5fc2e25659d195ad2f5c6cc5fb75fd4\n", 388 | " Building wheel for dlx (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 389 | " Created wheel for dlx: filename=dlx-1.0.4-cp37-none-any.whl size=5720 sha256=2c9ed4f40018720ce9d87f03b00e6d73db9e9a4d9bfb80ef53ba1539b080bfc8\n", 390 | " Stored in directory: /root/.cache/pip/wheels/bb/ba/15/fdd0deb104df3254912998150ba9245668db06b00af5912d1a\n", 391 | " Building wheel for yfinance (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 392 | " Created wheel for yfinance: filename=yfinance-0.1.59-py2.py3-none-any.whl size=23455 sha256=ce19493c31bc6d04244cdfe9f90530568180522ef682e39cdde433f60513cf40\n", 393 | " Stored in directory: /root/.cache/pip/wheels/f8/2a/0f/4b5a86e1d52e451757eb6bc17fd899629f0925c777741b6d04\n", 394 | "Successfully built qiskit python-constraint docplex dlx yfinance\n", 395 | "Installing collected packages: python-constraint, retworkx, ply, fastjsonschema, qiskit-terra, pybind11, qiskit-aer, websocket-client, ntlm-auth, cryptography, requests-ntlm, qiskit-ibmq-provider, qiskit-ignis, inflection, quandl, docplex, dlx, lxml, yfinance, qiskit-aqua, qiskit\n", 396 | " Found existing installation: lxml 4.2.6\n", 397 | " Uninstalling lxml-4.2.6:\n", 398 | " Successfully uninstalled lxml-4.2.6\n", 399 | "Successfully installed cryptography-3.4.7 dlx-1.0.4 docplex-2.20.204 fastjsonschema-2.15.1 inflection-0.5.1 lxml-4.6.3 ntlm-auth-1.5.0 ply-3.11 pybind11-2.6.2 python-constraint-1.4.0 qiskit-0.27.0 qiskit-aer-0.8.2 qiskit-aqua-0.9.2 qiskit-ibmq-provider-0.14.0 qiskit-ignis-0.6.0 qiskit-terra-0.17.4 quandl-3.6.1 requests-ntlm-1.1.0 retworkx-0.9.0 websocket-client-1.1.0 yfinance-0.1.59\n" 400 | ], 401 | "name": "stdout" 402 | } 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "metadata": { 408 | "colab": { 409 | "base_uri": "https://localhost:8080/" 410 | }, 411 | "id": "mPVMDRDsPS58", 412 | "outputId": "c8fe66ba-cda7-4c5b-ead1-a16dd8b0e181" 413 | }, 414 | "source": [ 415 | "# check if CUDA is available\n", 416 | "import torch\n", 417 | "train_on_gpu = torch.cuda.is_available()\n", 418 | "\n", 419 | "if not train_on_gpu:\n", 420 | " print('CUDA is not available. Training on CPU ...')\n", 421 | "else:\n", 422 | " print('CUDA is available! Training on GPU ...')" 423 | ], 424 | "execution_count": 3, 425 | "outputs": [ 426 | { 427 | "output_type": "stream", 428 | "text": [ 429 | "CUDA is available! Training on GPU ...\n" 430 | ], 431 | "name": "stdout" 432 | } 433 | ] 434 | }, 435 | { 436 | "cell_type": "code", 437 | "metadata": { 438 | "id": "cen8pzlVbzDF" 439 | }, 440 | "source": [ 441 | "\n", 442 | "import numpy as np\n", 443 | "import matplotlib.pyplot as plt\n", 444 | "\n", 445 | "import torch\n", 446 | "from torch.autograd import Function\n", 447 | "from torchvision import datasets, transforms\n", 448 | "import torch.optim as optim\n", 449 | "import torch.nn as nn\n", 450 | "import torch.nn.functional as F\n", 451 | "\n", 452 | "import qiskit\n", 453 | "from qiskit import transpile, assemble\n", 454 | "from qiskit.visualization import *" 455 | ], 456 | "execution_count": 4, 457 | "outputs": [] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "metadata": { 462 | "id": "pYRqHiA4J_yw" 463 | }, 464 | "source": [ 465 | "import numpy as np\n", 466 | "import torch\n", 467 | "from torch.autograd import Function\n", 468 | "import torch.optim as optim\n", 469 | "import torch.nn as nn\n", 470 | "import torch.nn.functional as F\n", 471 | "import torchvision\n", 472 | "from torchvision import datasets, transforms\n", 473 | "from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, execute\n", 474 | "from qiskit.circuit import Parameter\n", 475 | "from qiskit import Aer\n", 476 | "from tqdm import tqdm\n", 477 | "from matplotlib import pyplot as plt\n", 478 | "%matplotlib inline" 479 | ], 480 | "execution_count": 5, 481 | "outputs": [] 482 | }, 483 | { 484 | "cell_type": "code", 485 | "metadata": { 486 | "id": "uS6nwoWxdqQT" 487 | }, 488 | "source": [ 489 | "def to_numbers(tensor_list):\n", 490 | " num_list = []\n", 491 | " for tensor in tensor_list:\n", 492 | " num_list += [tensor.item()]\n", 493 | " return num_list" 494 | ], 495 | "execution_count": 6, 496 | "outputs": [] 497 | }, 498 | { 499 | "cell_type": "code", 500 | "metadata": { 501 | "id": "9Zxv2aYdJ_7W" 502 | }, 503 | "source": [ 504 | "class QuantumCircuit:\n", 505 | " \"\"\" \n", 506 | " This class provides a simple interface for interaction \n", 507 | " with the quantum circuit \n", 508 | " \"\"\"\n", 509 | " \n", 510 | " def __init__(self, n_qubits, backend, shots):\n", 511 | " # --- Circuit definition ---\n", 512 | " self._circuit = qiskit.QuantumCircuit(n_qubits)\n", 513 | " \n", 514 | " all_qubits = [i for i in range(n_qubits)]\n", 515 | " self.theta = qiskit.circuit.Parameter('theta')\n", 516 | " \n", 517 | " self._circuit.h(all_qubits)\n", 518 | " self._circuit.barrier()\n", 519 | " self._circuit.ry(self.theta, all_qubits)\n", 520 | " \n", 521 | " self._circuit.measure_all()\n", 522 | " # ---------------------------\n", 523 | "\n", 524 | " self.backend = backend\n", 525 | " self.shots = shots\n", 526 | " \n", 527 | " def run(self, thetas):\n", 528 | " t_qc = transpile(self._circuit,\n", 529 | " self.backend)\n", 530 | " qobj = assemble(t_qc,\n", 531 | " shots=self.shots,\n", 532 | " parameter_binds = [{self.theta: theta} for theta in thetas])\n", 533 | " job = self.backend.run(qobj)\n", 534 | " result = job.result().get_counts()\n", 535 | " \n", 536 | " counts = np.array(list(result.values()))\n", 537 | " states = np.array(list(result.keys())).astype(float)\n", 538 | " \n", 539 | " # Compute probabilities for each state\n", 540 | " probabilities = counts / self.shots\n", 541 | " # Get state expectation\n", 542 | " expectation = np.sum(states * probabilities)\n", 543 | " \n", 544 | " return np.array([expectation])" 545 | ], 546 | "execution_count": 7, 547 | "outputs": [] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "metadata": { 552 | "id": "jcTJjA7aKVT-" 553 | }, 554 | "source": [ 555 | "class HybridFunction(Function):\n", 556 | " \"\"\" Hybrid quantum - classical function definition \"\"\"\n", 557 | " \n", 558 | " @staticmethod\n", 559 | " def forward(ctx, input, quantum_circuit, shift):\n", 560 | " \"\"\" Forward pass computation \"\"\"\n", 561 | " ctx.shift = shift\n", 562 | " ctx.quantum_circuit = quantum_circuit\n", 563 | "\n", 564 | " expectation_z = ctx.quantum_circuit.run(input[0].tolist())\n", 565 | " result = torch.tensor([expectation_z])\n", 566 | " ctx.save_for_backward(input, result)\n", 567 | "\n", 568 | " return result\n", 569 | " \n", 570 | " @staticmethod\n", 571 | " def backward(ctx, grad_output):\n", 572 | " \"\"\" Backward pass computation \"\"\"\n", 573 | " input, expectation_z = ctx.saved_tensors\n", 574 | " input_list = np.array(input.tolist())\n", 575 | " \n", 576 | " shift_right = input_list + np.ones(input_list.shape) * ctx.shift\n", 577 | " shift_left = input_list - np.ones(input_list.shape) * ctx.shift\n", 578 | " \n", 579 | " gradients = []\n", 580 | " for i in range(len(input_list)):\n", 581 | " expectation_right = ctx.quantum_circuit.run(shift_right[i])\n", 582 | " expectation_left = ctx.quantum_circuit.run(shift_left[i])\n", 583 | " \n", 584 | " gradient = torch.tensor([expectation_right]) - torch.tensor([expectation_left])\n", 585 | " gradients.append(gradient)\n", 586 | " gradients = np.array([gradients]).T\n", 587 | " return torch.tensor([gradients]).float() * grad_output.float(), None, None\n", 588 | "\n", 589 | "class Hybrid(nn.Module):\n", 590 | " \"\"\" Hybrid quantum - classical layer definition \"\"\"\n", 591 | " \n", 592 | " def __init__(self, backend, shots, shift):\n", 593 | " super(Hybrid, self).__init__()\n", 594 | " self.quantum_circuit = QuantumCircuit(1, backend, shots)\n", 595 | " self.shift = shift\n", 596 | " \n", 597 | " def forward(self, input):\n", 598 | " return HybridFunction.apply(input, self.quantum_circuit, self.shift)" 599 | ], 600 | "execution_count": 8, 601 | "outputs": [] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "metadata": { 606 | "colab": { 607 | "base_uri": "https://localhost:8080/", 608 | "height": 99, 609 | "referenced_widgets": [ 610 | "6b21baa29bbf408d96883c52c578d25e", 611 | "c0afc2958d7f4cb6ad5fa7df3127b838", 612 | "97126e60fd414c0ca90bcf1090f159e0", 613 | "61bcf60fe4cc4dc7bebc1215bf6c27f7", 614 | "2fe1f152bcf7413cae42224d18d44fd7", 615 | "20cfd8834a4548e993b60bce5a119264", 616 | "755a675c4f374bd0a427143b783eb6b7", 617 | "661d394b279547e197586c2e7ed91993" 618 | ] 619 | }, 620 | "id": "jF_gcTnMKXNs", 621 | "outputId": "7da967d2-5363-4827-ca25-1120191d130a" 622 | }, 623 | "source": [ 624 | "import torchvision\n", 625 | "transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()]) # transform images to tensors/vectors\n", 626 | "cifar_trainset = datasets.CIFAR10(root='./data1', train=True, download=True, transform=transform)" 627 | ], 628 | "execution_count": 9, 629 | "outputs": [ 630 | { 631 | "output_type": "stream", 632 | "text": [ 633 | "Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data1/cifar-10-python.tar.gz\n" 634 | ], 635 | "name": "stdout" 636 | }, 637 | { 638 | "output_type": "display_data", 639 | "data": { 640 | "application/vnd.jupyter.widget-view+json": { 641 | "model_id": "6b21baa29bbf408d96883c52c578d25e", 642 | "version_minor": 0, 643 | "version_major": 2 644 | }, 645 | "text/plain": [ 646 | "HBox(children=(FloatProgress(value=0.0, max=170498071.0), HTML(value='')))" 647 | ] 648 | }, 649 | "metadata": { 650 | "tags": [] 651 | } 652 | }, 653 | { 654 | "output_type": "stream", 655 | "text": [ 656 | "\n", 657 | "Extracting ./data1/cifar-10-python.tar.gz to ./data1\n" 658 | ], 659 | "name": "stdout" 660 | } 661 | ] 662 | }, 663 | { 664 | "cell_type": "code", 665 | "metadata": { 666 | "colab": { 667 | "base_uri": "https://localhost:8080/" 668 | }, 669 | "id": "LleGzzGrKjmY", 670 | "outputId": "9f0dcc2a-3ca4-43ae-a3d9-14b88b6e7282" 671 | }, 672 | "source": [ 673 | "len(cifar_trainset)" 674 | ], 675 | "execution_count": 10, 676 | "outputs": [ 677 | { 678 | "output_type": "execute_result", 679 | "data": { 680 | "text/plain": [ 681 | "50000" 682 | ] 683 | }, 684 | "metadata": { 685 | "tags": [] 686 | }, 687 | "execution_count": 10 688 | } 689 | ] 690 | }, 691 | { 692 | "cell_type": "code", 693 | "metadata": { 694 | "id": "wLYWsG_zKnyI" 695 | }, 696 | "source": [ 697 | "from torch.utils.data import DataLoader, random_split" 698 | ], 699 | "execution_count": 11, 700 | "outputs": [] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "metadata": { 705 | "id": "51xN5aJDKo1S" 706 | }, 707 | "source": [ 708 | "#cifar_trainset = datasets.CIFAR10(root='./data1', train=True, download=True, transform=transform)\n", 709 | "\n", 710 | "\n", 711 | "labels = cifar_trainset.targets # get the labels for the data\n", 712 | "labels = np.array(labels)\n", 713 | "\n", 714 | "idx1 = np.where(labels == 0) # filter on aeroplanes\n", 715 | "idx2 = np.where(labels == 1) # filter on automobiles\n", 716 | "\n", 717 | "# Specify number of datapoints per class (i.e. there will be n pictures of automobiles and n pictures of aeroplanes in the training set)\n", 718 | "n=100\n", 719 | "\n", 720 | "# concatenate the data indices\n", 721 | "idx = np.concatenate((idx1[0][0:n],idx2[0][0:n])) \n", 722 | "\n", 723 | "# create the filtered dataset for our training set\n", 724 | "cifar_trainset.targets = labels[idx] \n", 725 | "cifar_trainset.data = cifar_trainset.data[idx]\n", 726 | "\n", 727 | "cifar_trainset, valid = random_split(cifar_trainset,[150,50])\n", 728 | "\n", 729 | "train_loader = torch.utils.data.DataLoader(cifar_trainset, batch_size=1, shuffle=True)\n", 730 | "valid_loader = torch.utils.data.DataLoader(valid, batch_size=1, shuffle=True)" 731 | ], 732 | "execution_count": 12, 733 | "outputs": [] 734 | }, 735 | { 736 | "cell_type": "code", 737 | "metadata": { 738 | "id": "pZtFi8B9LmvE" 739 | }, 740 | "source": [ 741 | "@torch.no_grad()\n", 742 | "def get_all_preds(model, train_loader):\n", 743 | " all_preds = torch.tensor([])\n", 744 | " for batch in train_loader:\n", 745 | " images, labels = batch\n", 746 | "\n", 747 | " preds = model(images)\n", 748 | " all_preds = torch.cat(\n", 749 | " (all_preds, preds)\n", 750 | " ,dim=0\n", 751 | " )\n", 752 | " return all_preds" 753 | ], 754 | "execution_count": 13, 755 | "outputs": [] 756 | }, 757 | { 758 | "cell_type": "code", 759 | "metadata": { 760 | "colab": { 761 | "base_uri": "https://localhost:8080/", 762 | "height": 130 763 | }, 764 | "id": "_wUCuMmHLowP", 765 | "outputId": "062b0dd5-d53c-4f92-8483-5f136f23dfe8" 766 | }, 767 | "source": [ 768 | "import numpy as np \n", 769 | "import matplotlib.pyplot as plt\n", 770 | "\n", 771 | "n_samples_show = 6\n", 772 | "\n", 773 | "data_iter = iter(train_loader)\n", 774 | "fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 2))\n", 775 | "\n", 776 | "while n_samples_show > 0:\n", 777 | " images, targets = data_iter.__next__()\n", 778 | " images=images.squeeze()\n", 779 | " \n", 780 | " axes[n_samples_show - 1].imshow(images[0].numpy(), cmap='gray')\n", 781 | " axes[n_samples_show - 1].set_xticks([])\n", 782 | " axes[n_samples_show - 1].set_yticks([])\n", 783 | " axes[n_samples_show - 1].set_title(\"Labeled: {}\".format(targets.item()))\n", 784 | " \n", 785 | " n_samples_show -= 1" 786 | ], 787 | "execution_count": 14, 788 | "outputs": [ 789 | { 790 | "output_type": "display_data", 791 | "data": { 792 | "image/png": "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\n", 793 | "text/plain": [ 794 | "
" 795 | ] 796 | }, 797 | "metadata": { 798 | "tags": [] 799 | } 800 | } 801 | ] 802 | }, 803 | { 804 | "cell_type": "code", 805 | "metadata": { 806 | "id": "tsft9NG8MZZG" 807 | }, 808 | "source": [ 809 | "" 810 | ], 811 | "execution_count": null, 812 | "outputs": [] 813 | }, 814 | { 815 | "cell_type": "code", 816 | "metadata": { 817 | "colab": { 818 | "base_uri": "https://localhost:8080/" 819 | }, 820 | "id": "GGbi3LCbu48T", 821 | "outputId": "fdb2fbc4-db41-4f0a-ee9b-e672cf1c4076" 822 | }, 823 | "source": [ 824 | "import torchvision\n", 825 | "transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()]) # transform images to tensors/vectors\n", 826 | "cifar_testset = datasets.CIFAR10(root='./data1', train=False, download=True, transform=transform)\n", 827 | "\n", 828 | "labels = cifar_testset.targets # get the labels for the data\n", 829 | "labels = np.array(labels)\n", 830 | "\n", 831 | "idx1 = np.where(labels == 0) # filter on aeroplanes\n", 832 | "idx2 = np.where(labels == 1) # filter on automobiles\n", 833 | "\n", 834 | "# Specify number of datapoints per class (i.e. there will be n pictures of automobiles and n pictures of aeroplanes in the training set)\n", 835 | "n=100\n", 836 | "\n", 837 | "# concatenate the data indices\n", 838 | "idx = np.concatenate((idx1[0][0:n],idx2[0][0:n])) \n", 839 | "\n", 840 | "# create the filtered dataset for our training set\n", 841 | "cifar_testset.targets = labels[idx] \n", 842 | "cifar_testset.data = cifar_testset.data[idx]\n", 843 | "\n", 844 | "test_loader = torch.utils.data.DataLoader(cifar_testset, batch_size=1, shuffle=False)" 845 | ], 846 | "execution_count": 15, 847 | "outputs": [ 848 | { 849 | "output_type": "stream", 850 | "text": [ 851 | "Files already downloaded and verified\n" 852 | ], 853 | "name": "stdout" 854 | } 855 | ] 856 | }, 857 | { 858 | "cell_type": "code", 859 | "metadata": { 860 | "colab": { 861 | "base_uri": "https://localhost:8080/" 862 | }, 863 | "id": "6EepnrZFBtZ6", 864 | "outputId": "e9903bd8-bd38-4bab-a2c1-b4161f0c6147" 865 | }, 866 | "source": [ 867 | "len(cifar_testset)" 868 | ], 869 | "execution_count": 16, 870 | "outputs": [ 871 | { 872 | "output_type": "execute_result", 873 | "data": { 874 | "text/plain": [ 875 | "200" 876 | ] 877 | }, 878 | "metadata": { 879 | "tags": [] 880 | }, 881 | "execution_count": 16 882 | } 883 | ] 884 | }, 885 | { 886 | "cell_type": "code", 887 | "metadata": { 888 | "id": "_xmz9iOuvfAh" 889 | }, 890 | "source": [ 891 | "class Net(nn.Module):\n", 892 | " def __init__(self):\n", 893 | " super(Net, self).__init__()\n", 894 | " self.conv1 = nn.Conv2d(3, 10, kernel_size=5)\n", 895 | " self.conv2 = nn.Conv2d(10, 20, kernel_size=5)\n", 896 | " self.dropout = nn.Dropout2d()\n", 897 | " self.fc1 = nn.Linear(500, 500)\n", 898 | " self.fc2 = nn.Linear(500, 1)\n", 899 | " self.hybrid = Hybrid(qiskit.Aer.get_backend('qasm_simulator'), 100, np.pi / 2)\n", 900 | "\n", 901 | " def forward(self, x):\n", 902 | " x = F.relu(self.conv1(x))\n", 903 | " x = F.max_pool2d(x, 2)\n", 904 | " x = F.relu(self.conv2(x))\n", 905 | " x = F.max_pool2d(x, 2)\n", 906 | " x = self.dropout(x)\n", 907 | " x = x.view(1, -1)\n", 908 | " x = F.relu(self.fc1(x))\n", 909 | " x = self.fc2(x)\n", 910 | " x = self.hybrid(x)\n", 911 | " return torch.cat((x, 1 - x), -1)" 912 | ], 913 | "execution_count": 17, 914 | "outputs": [] 915 | }, 916 | { 917 | "cell_type": "code", 918 | "metadata": { 919 | "id": "OpOsgNA1OFjq" 920 | }, 921 | "source": [ 922 | "" 923 | ], 924 | "execution_count": null, 925 | "outputs": [] 926 | }, 927 | { 928 | "cell_type": "code", 929 | "metadata": { 930 | "colab": { 931 | "base_uri": "https://localhost:8080/", 932 | "height": 349 933 | }, 934 | "id": "Ur6t9UeqMlpa", 935 | "outputId": "cc8428bf-997f-4fc0-ecc1-ade926685aac" 936 | }, 937 | "source": [ 938 | "%matplotlib inline\n", 939 | "import matplotlib.pyplot as plt\n", 940 | "model = Net()\n", 941 | "optimizer = optim.Adam(model.parameters(), lr=0.001)\n", 942 | "loss_func = nn.NLLLoss()\n", 943 | "\n", 944 | "epochs = 5\n", 945 | "loss_list = []\n", 946 | "loss_list_V = []\n", 947 | "\n", 948 | "#training the model\n", 949 | "model.train()\n", 950 | "for epoch in range(epochs):\n", 951 | " train_loss = []\n", 952 | " for batch_idx, (data, target) in enumerate(train_loader):\n", 953 | " optimizer.zero_grad()\n", 954 | " # Forward pass\n", 955 | " output = model(data)\n", 956 | " # Calculating loss\n", 957 | " loss = loss_func(output, target)\n", 958 | " # Backward pass\n", 959 | " loss.backward()\n", 960 | " # Optimize the weights\n", 961 | " optimizer.step()\n", 962 | " \n", 963 | " train_loss.append(loss.item())\n", 964 | " loss_list.append(sum(train_loss)/len(train_loss))\n", 965 | " #print('Training [{:.0f}%]\\tLoss: {:.4f}'.format(100. * (epoch + 1) / epochs, loss_list[-1]))\n", 966 | "\n", 967 | "\n", 968 | "#Validate the model\n", 969 | "\n", 970 | "model.eval()\n", 971 | "for epoch in range(epochs):\n", 972 | " valid_loss = []\n", 973 | " for batch_idx, (data, target) in enumerate(valid_loader):\n", 974 | " optimizer.zero_grad()\n", 975 | " # Forward pass\n", 976 | " output = model(data)\n", 977 | " # Calculating loss\n", 978 | " validation_loss = loss_func(output, target)\n", 979 | " # Backward pass\n", 980 | " validation_loss.backward()\n", 981 | " # Optimize the weights\n", 982 | " optimizer.step()\n", 983 | " \n", 984 | " valid_loss.append(validation_loss.item())\n", 985 | " loss_list_V.append(sum(valid_loss)/len(valid_loss))\n", 986 | " #print('Training [{:.0f}%]\\tLoss: {:.4f}'.format(100. * (epoch + 1) / epochs, loss_list_V[-1]))\n", 987 | " print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n", 988 | " epoch, loss_list[-1], loss_list_V[-1]))\n", 989 | "\n", 990 | "\n", 991 | "\n", 992 | "\n", 993 | "#Now plotting the training graph\n", 994 | "plt.plot(loss_list,label='Training Loss') \n", 995 | "plt.plot(loss_list_V,label='Validation Loss') \n", 996 | "plt.legend() \n", 997 | "plt.show() \n" 998 | ], 999 | "execution_count": 34, 1000 | "outputs": [ 1001 | { 1002 | "output_type": "stream", 1003 | "text": [ 1004 | "Epoch: 0 \tTraining Loss: -0.670600 \tValidation Loss: -0.759400\n", 1005 | "Epoch: 1 \tTraining Loss: -0.670600 \tValidation Loss: -0.803600\n", 1006 | "Epoch: 2 \tTraining Loss: -0.670600 \tValidation Loss: -0.847600\n", 1007 | "Epoch: 3 \tTraining Loss: -0.670600 \tValidation Loss: -0.831200\n", 1008 | "Epoch: 4 \tTraining Loss: -0.670600 \tValidation Loss: -0.897600\n" 1009 | ], 1010 | "name": "stdout" 1011 | }, 1012 | { 1013 | "output_type": "display_data", 1014 | "data": { 1015 | "image/png": "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\n", 1016 | "text/plain": [ 1017 | "
" 1018 | ] 1019 | }, 1020 | "metadata": { 1021 | "tags": [], 1022 | "needs_background": "light" 1023 | } 1024 | } 1025 | ] 1026 | }, 1027 | { 1028 | "cell_type": "code", 1029 | "metadata": { 1030 | "colab": { 1031 | "base_uri": "https://localhost:8080/" 1032 | }, 1033 | "id": "bo6vTTvimIj4", 1034 | "outputId": "5a30f0fd-2014-4e28-91ea-d693f78b3dcb" 1035 | }, 1036 | "source": [ 1037 | "total_loss=[]\n", 1038 | "model.eval()\n", 1039 | "with torch.no_grad():\n", 1040 | " \n", 1041 | " correct = 0\n", 1042 | " for batch_idx, (data, target) in enumerate(test_loader):\n", 1043 | " output = model(data)\n", 1044 | " \n", 1045 | " pred = output.argmax(dim=1, keepdim=True) \n", 1046 | " correct += pred.eq(target.view_as(pred)).sum().item()\n", 1047 | " \n", 1048 | " loss = loss_func(output, target)\n", 1049 | " total_loss.append(loss.item())\n", 1050 | " \n", 1051 | " print('Performance on train data:\\n\\tLoss: {:.4f}\\n\\tAccuracy: {:.1f}%'.format(\n", 1052 | " sum(total_loss) / len(total_loss),\n", 1053 | " correct / len(test_loader) * 100)\n", 1054 | " )\n" 1055 | ], 1056 | "execution_count": 36, 1057 | "outputs": [ 1058 | { 1059 | "output_type": "stream", 1060 | "text": [ 1061 | "Performance on train data:\n", 1062 | "\tLoss: -0.7634\n", 1063 | "\tAccuracy: 81.5%\n" 1064 | ], 1065 | "name": "stdout" 1066 | } 1067 | ] 1068 | } 1069 | ] 1070 | } 1071 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quantum-Classical Hyrid Neural Network for binary image classification using PyTorch-Qiskit pipeline 2 | 3 | This project involved developing a Hybrid Quantum Neural Network using the amalgamation of PyTorch and Qiskit , i.e intergrating the classical ML tools and features of PyTorch with the Quantum Computing framework of Qiskit. Hold-out validation was carried out, the model was tested on a validation set before noting the test accuracy. Hyperparameter tuning , effect of changing learning rates, optimizer and loss function on the model and Layer architectures were studied. The Quantum Layer involved a Parametrized Quantum circuit analogous to using a Variational Circuit as a classifier. This project was carried out under the guidance of Dr Elias F Combarro, Professor of Computer Science at Universidad de Oviedo, Spain and Advisor CERN QTI to whom I am extremely indebted to for his help and mentorship. 4 | 5 | 6 | ## Pre-requisites 7 | The following are the pre-requisites for running the notebook on a local machine (Google Colab was used throughout this project along with IBM Quantum Experience owing to the ease in integrating PyTorch and Qiskit without the local installation of additional dependencies). 8 | 9 | * Python3 10 | * Qiskit 11 | * PyTorch 12 | * Matplotlib 13 | * Numpy 14 | * torchvision 15 | 16 | The Google Colab notebooks can be accessed under the [Notebook](https://github.com/DRA-chaos/Quantum-Convolutional-Neural-Network/tree/main/Notebooks) folder of this repository. 17 | 18 | ## Dataset: 19 | The CIFAR-10 dataset outsourced from the torchvision datasets under PyTorch has been used for this project. 20 | The CIFAR-10 dataset that can be accessed [here](https://www.cs.toronto.edu/~kriz/cifar.html) consists of 60000 32x32 colour images in 10 classes, with 6000 images per class. There are 50000 training images and 10000 test images. 21 | 22 | The dataset is divided into five training batches and one test batch, each with 10000 images. The test batch contains exactly 1000 randomly-selected images from each class. The training batches contain the remaining images in random order, but some training batches may contain more images from one class than another. Between them, the training batches contain exactly 5000 images from each class. 23 | The project encompassed building a variational classifier to distinguish between Aeroplanes and Automobiles. 24 | ![image](https://user-images.githubusercontent.com/68393451/127451266-36669b90-bacb-4c38-afb5-ee2d2199d9f9.png) 25 | 26 | [image source](https://www.cs.toronto.edu/~kriz/cifar.html) 27 | 28 | Here are a few sample observations from the study : 29 | ![image](https://user-images.githubusercontent.com/68393451/127451652-5e70a45d-80c9-4c1e-b51d-09bb34fa8ed9.png) 30 | 31 | ## Flowchart depicting the Quantum Layer 32 | 33 | ![image](https://user-images.githubusercontent.com/68393451/127452166-2361aad8-817d-4fbb-a626-01086588ee8c.png) 34 | 35 | 36 | ## References: 37 | [1]Crooks, Gavin. (2019). Gradients of parameterized quantum gates using the parameter-shift rule and gate decomposition. 38 | 39 | [2]A. Asfaw, L. Bello, Y. Ben-Haim, S. Bravyi, L. Capelluto, A. C. Vazquez, J. Ceroni, J. Gambetta, S. Garion, L. Gil, et al., Learn quantum computation using qiskit (2020), 40 | URL:https://qiskit.org/textbook/ch-machine-learning/machine-learning-qiskit-pytorch.html 41 | 42 | [3]Krizhevsky, Alex. (2012). Learning Multiple Layers of Features from Tiny Images. University of Toronto. 43 | 44 | [4]Oh, Seunghyeok & Choi, Jaeho & Kim, Joongheon. (2020). A Tutorial on Quantum Convolutional Neural Networks (QCNN). 45 | 46 | [5]Farhi, Edward & Neven, Hartmut. (2018). Classification with Quantum Neural Networks on Near Term Processors. 47 | 48 | [6]Kulkarni, Viraj & Kulkarni, Milind & Pant, Aniruddha. (2020). Quantum Computing Methods for Supervised Learning. 49 | 50 | [7]Beer, K., Bondarenko, D., Farrelly, T. et al. Training deep quantum neural networks. Nat Commun 11, 808 (2020). https://doi.org/10.1038/s41467-020-14454-2 51 | 52 | Enjoy your journey through the quantum realm !! 53 | 54 | Rita Abani 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /paper.md.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DRA-chaos/Quantum-Classical-Hyrid-Neural-Network-for-binary-image-classification-using-PyTorch-Qiskit-pipeline/07c99915851af71584ebcf700c16c60d713ad81a/paper.md.zip --------------------------------------------------------------------------------