From 5ec36093b7a29c6ddbe0018d28ff031afae9a105 Mon Sep 17 00:00:00 2001 From: Leonid Didukh Date: Sun, 20 Apr 2025 00:41:34 +0300 Subject: [PATCH 1/2] Added the Quantum Vision Transformer Implementation --- .../Quantum Vision Transformer.ipynb | 479 ++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 community/paper_implementation_project/Quantum Vision Transformer.ipynb diff --git a/community/paper_implementation_project/Quantum Vision Transformer.ipynb b/community/paper_implementation_project/Quantum Vision Transformer.ipynb new file mode 100644 index 000000000..1b04808d5 --- /dev/null +++ b/community/paper_implementation_project/Quantum Vision Transformer.ipynb @@ -0,0 +1,479 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "fb8f88e1-d493-4473-80cd-00042b61f868", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/opt/anaconda3/envs/baler/lib/python3.11/site-packages/classiq/_internals/authentication/token_manager.py:101: UserWarning: Device is already registered.\n", + "Generating a new refresh token should only be done if the current refresh token is compromised.\n", + "To do so, set the overwrite parameter to true\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "import classiq\n", + "classiq.authenticate()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "20d0b3d8-8de2-460b-93d2-bc805561c0c8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: 'dlopen(/opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/image.so, 0x0006): Symbol not found: __ZN3c1017RegisterOperatorsD1Ev\n", + " Referenced from: /opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/image.so\n", + " Expected in: /opt/anaconda3/envs/baler/lib/python3.11/site-packages/torch/lib/libtorch_cpu.dylib'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?\n", + " warn(\n" + ] + } + ], + "source": [ + "import torch\n", + "import numpy as np\n", + "import torch.nn as nn\n", + "import torch.optim as optim\n", + "from typing import List\n", + "import pdb\n", + "\n", + "from classiq import (\n", + " synthesize,\n", + " qfunc,\n", + " QArray,\n", + " QBit,\n", + " RX,\n", + " CArray,\n", + " Output,\n", + " CReal,\n", + " allocate,\n", + " repeat,\n", + " create_model,\n", + " show\n", + ")\n", + "\n", + "# choosing our data\n", + "import torchvision\n", + "import torchvision.transforms as transforms\n", + "import math\n", + "from classiq.applications.qnn.types import SavedResult\n", + "from classiq.applications.qnn import QLayer\n", + "from classiq.qmod.symbolic import pi\n", + "from classiq.synthesis import SerializedQuantumProgram" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "634a20e6-3b46-4907-84f7-27ab3f473417", + "metadata": {}, + "outputs": [], + "source": [ + "from classiq.execution import (\n", + " ExecutionPreferences,\n", + " execute_qnn,\n", + " set_quantum_program_execution_preferences,\n", + ")\n", + "from classiq.synthesis import SerializedQuantumProgram\n", + "from classiq.applications.qnn.types import (\n", + " MultipleArguments,\n", + " ResultsCollection,\n", + " SavedResult,\n", + ")\n", + "\n", + "\n", + "from classiq.applications.qnn.types import (\n", + " MultipleArguments,\n", + " ResultsCollection,\n", + " SavedResult,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91d168c1-d9da-4c10-a728-a179f3abc9db", + "metadata": {}, + "outputs": [], + "source": [ + "N_QUBITS = 4\n", + "num_shots = 1024" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "5d172b4f-c317-4759-ad63-74b2eb4fa87d", + "metadata": {}, + "outputs": [], + "source": [ + "def execute(\n", + " quantum_program: SerializedQuantumProgram, arguments: MultipleArguments\n", + ") -> ResultsCollection:\n", + " quantum_program = set_quantum_program_execution_preferences(\n", + " quantum_program, preferences=ExecutionPreferences(num_shots=num_shots)\n", + " )\n", + " return execute_qnn(quantum_program, arguments)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b98e5452-3bc8-4aa0-beee-cc6d0c3cb994", + "metadata": {}, + "outputs": [], + "source": [ + "def post_process(result: SavedResult) -> torch.Tensor:\n", + " res = result.value\n", + " yvec = [\n", + " (res.counts_of_qubits(k)[\"1\"] if \"1\" in res.counts_of_qubits(k) else 0)\n", + " / num_shots\n", + " for k in range(N_QUBITS)\n", + " ]\n", + "\n", + " return torch.tensor(yvec)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2bb9e435-d050-468a-a61f-0d14ce16eb9c", + "metadata": {}, + "outputs": [], + "source": [ + "def get_circuit():\n", + "\n", + " @qfunc\n", + " def vqc(input_: CArray[CReal, N_QUBITS], weight_: CArray[CArray[CReal, N_QUBITS], N_QUBITS], res: QArray[QBit]) -> None:\n", + " num_qubits = input_.len\n", + " num_qlayers = weight_.len\n", + " repeat(\n", + " count=num_qlayers,\n", + " iteration=lambda i: repeat(count=num_qubits, \n", + " iteration=lambda j:RX(pi * weight_[i][j], res[j]))\n", + " )\n", + " \n", + " @qfunc\n", + " def angle_embedding(input_: CArray[CReal, N_QUBITS], res: QArray[QBit]) -> None:\n", + " repeat(\n", + " count=input_.len,\n", + " iteration=lambda index: RX(pi * input_[index], res[index]),\n", + " )\n", + "\n", + " @qfunc\n", + " def main(input_: CArray[CReal, N_QUBITS], weight_: CArray[CArray[CReal, N_QUBITS], N_QUBITS], res: Output[QArray[QBit]]) -> None:\n", + " allocate(N_QUBITS, res)\n", + " angle_embedding(input_=input_, res=res)\n", + " vqc(input_=input_, weight_=weight_, res=res)\n", + " \n", + " qmod = create_model(main)\n", + " quantum_program = synthesize(qmod)\n", + " return quantum_program" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "00f92a77-0b94-4fe6-8f9b-2331d4f77939", + "metadata": {}, + "outputs": [], + "source": [ + "class Patchify(torch.nn.Module):\n", + " \"\"\"\n", + " Patchify layer implemented using the Conv2d layer\n", + " \"\"\"\n", + " def __init__(self, patch_size:int, hidden_size:int):\n", + " super(Patchify, self).__init__()\n", + " self.patch_size = patch_size\n", + " self.conv = torch.nn.Conv2d(in_channels=3, out_channels=hidden_size, kernel_size=self.patch_size, stride=self.patch_size)\n", + " self.hidden_size = hidden_size\n", + " \n", + " def forward(self, x:torch.Tensor):\n", + " bs, c, h, w = x.size()\n", + " self.num_patches = (h // self.patch_size) ** 2\n", + "\n", + " x = self.conv(x)\n", + " x = x.view(bs, self.num_patches, self.hidden_size)\n", + " return x\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "2849e3a5-3d01-42bf-ae4b-4c79375e8443", + "metadata": {}, + "outputs": [], + "source": [ + "class RotaryPositionalEmbedding(torch.nn.Module):\n", + " \"\"\"\n", + " Rotary Positional Embedding\n", + " \"\"\"\n", + " def __init__(self, d_model, max_seq_len):\n", + " super(RotaryPositionalEmbedding, self).__init__()\n", + "\n", + " # Create a rotation matrix.\n", + " self.rotation_matrix = torch.zeros(d_model, d_model)\n", + " for i in range(d_model):\n", + " for j in range(d_model):\n", + " self.rotation_matrix[i, j] = math.cos(i * j * 0.01)\n", + "\n", + " # Create a positional embedding matrix.\n", + " self.positional_embedding = torch.zeros(max_seq_len, d_model)\n", + " for i in range(max_seq_len):\n", + " for j in range(d_model):\n", + " self.positional_embedding[i, j] = math.cos(i * j * 0.01)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Args:\n", + " x: A tensor of shape (batch_size, seq_len, d_model).\n", + "\n", + " Returns:\n", + " A tensor of shape (batch_size, seq_len, d_model).\n", + " \"\"\"\n", + "\n", + " # Add the positional embedding to the input tensor.\n", + " x += self.positional_embedding\n", + "\n", + " # Apply the rotation matrix to the input tensor.\n", + " x = torch.matmul(x, self.rotation_matrix)\n", + "\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "19042677-6d63-426c-b12d-9d107b47eecb", + "metadata": {}, + "outputs": [], + "source": [ + "class QuantumLayer(torch.nn.Module):\n", + " \"\"\"\n", + " Quantum Layer\n", + " \"\"\"\n", + " def __init__(self, in_dim, out_dim):\n", + " super(QuantumLayer, self).__init__()\n", + " self.quantum_program = get_circuit()\n", + " self.quantum_layer = QLayer(self.quantum_program, execute, post_process)\n", + "\n", + " def forward(self, x:torch.Tensor):\n", + " size = x.size()\n", + " x = x.view(-1, size[-1])\n", + " x = self.quantum_layer(x)\n", + " x = x.view(size)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "376d717d-76bf-45bc-a90f-67d15a92f33a", + "metadata": {}, + "outputs": [], + "source": [ + "class FFN(torch.nn.Module):\n", + " \"\"\"\n", + " Feed Forward Network\n", + " \"\"\"\n", + " def __init__(self, in_dim, hidden_size):\n", + " super().__init__()\n", + " self.linear_1 = torch.nn.Linear(in_dim, hidden_size)\n", + " self.qlinear_1 = QuantumLayer(hidden_size, hidden_size)\n", + " self.dropout = torch.nn.Dropout(p=0.4)\n", + " self.linear_2 = torch.nn.Linear(hidden_size, in_dim)\n", + " return\n", + " \n", + " def forward(self, x:torch.Tensor):\n", + " x = self.linear_1(x)\n", + " x = self.qlinear_1(x)\n", + " x = self.dropout(x)\n", + " x = torch.nn.functional.gelu(x)\n", + " x = self.linear_2(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f2ffa889-38a6-425b-bf76-c1032406e6e3", + "metadata": {}, + "outputs": [], + "source": [ + "class qMHA(torch.nn.Module):\n", + " \"\"\"\n", + " Quantum Multihead Attention\n", + " \"\"\"\n", + " def __init__(self, in_dim:int, num_heads:int) -> None:\n", + " super().__init__()\n", + "\n", + " self.qK = QuantumLayer(in_dim, in_dim);\n", + " self.qQ = QuantumLayer(in_dim, in_dim);\n", + " self.qV = QuantumLayer(in_dim, in_dim);\n", + " self.dropout = torch.nn.Dropout(p=0.1)\n", + " \n", + " self.final_l = QuantumLayer(in_dim, in_dim)\n", + " self.num_heads = num_heads\n", + " self.in_dim = in_dim\n", + " \n", + " return\n", + "\n", + " def forward(self, X:torch.Tensor):\n", + "\n", + " dim = torch.sqrt(torch.Tensor([X.shape[-1]]))\n", + " attention = torch.nn.functional.softmax((1/dim)*self.qK(X))*self.qQ(X)*self.qV(X)\n", + " x = self.dropout(attention)\n", + " x = self.final_l(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "426e1bed-2197-4d62-ba13-6215c466c97b", + "metadata": {}, + "outputs": [], + "source": [ + "class qTransformerEncoder(torch.nn.Module):\n", + " \"\"\"\n", + " Quantum Transformer Encoder Layer\n", + " \"\"\"\n", + " def __init__(self, in_dim:int, num_heads:int) -> None:\n", + " super().__init__()\n", + " self.layer_norm_1 = torch.nn.LayerNorm(normalized_shape=in_dim)\n", + " self.layer_norm_2 = torch.nn.LayerNorm(normalized_shape=in_dim)\n", + " \n", + " self.qMHA = qMHA(in_dim, num_heads)\n", + " self.qFFN = FFN(in_dim, hidden_size=in_dim)\n", + " self.dropout = torch.nn.Dropout(p=0.3)\n", + " \n", + "\n", + " def forward(self, X:torch.Tensor):\n", + " \n", + " x = self.qMHA(X)\n", + " x = self.layer_norm_1(x)\n", + " x = self.dropout(x) + X\n", + "\n", + " y = self.layer_norm_2(x)\n", + " y = self.qFFN(y)+y\n", + " \n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "e6a37ec6-d82c-4784-aa97-94bf80be78c1", + "metadata": {}, + "outputs": [], + "source": [ + "class QVT(torch.nn.Module):\n", + " \"\"\"\n", + " Quantum Vision Transformer;\n", + " \"\"\"\n", + " def __init__(self, patch_size, in_dim, hidden_size, num_heads, n_classes, n_layers) -> None:\n", + " super().__init__()\n", + " self.patch_formation = Patchify(patch_size=patch_size, hidden_size=hidden_size)\n", + " self.d_model = (in_dim//patch_size)**2\n", + " self.pos_encoding = RotaryPositionalEmbedding(hidden_size, self.d_model)\n", + " self.transformer_blocks = [qTransformerEncoder(hidden_size, num_heads) for i in range(n_layers)]\n", + " \n", + " self.n_classes = n_classes\n", + " self.final_normalization = torch.nn.LayerNorm(hidden_size)\n", + " self.final_layer = torch.nn.Linear(hidden_size, self.n_classes)\n", + "\n", + " def forward(self, x: torch.Tensor) -> torch.Tensor: \n", + " x = self.patch_formation(x)\n", + " x += self.pos_encoding(x)\n", + " for trans_block in self.transformer_blocks:\n", + " x = trans_block(x)\n", + " x = self.final_normalization(x)\n", + " x = x.mean(axis=1)\n", + " x = self.final_layer(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "b57b43fe-0963-4576-95f3-55e7655858e4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/zj/jmm9ywc51bb4p1pn12_23y340000gn/T/ipykernel_4329/535465168.py:22: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " attention = torch.nn.functional.softmax((1/dim)*self.qK(X))*self.qQ(X)*self.qV(X)\n" + ] + } + ], + "source": [ + "x = torch.rand(32, 3, 16, 16)\n", + "qVisTransformer = QVT(patch_size=4, in_dim=16, hidden_size=4, num_heads=1, n_classes=10, n_layers=4)\n", + "res = qVisTransformer(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "86242cc3-2d4d-48e2-83c2-1ea397976faa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([32, 10])" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res.size()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79282b7f-cb02-4b20-a29a-51de390c2d17", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From d5a1f00f3fc573b50b591c4543930938ece5b798 Mon Sep 17 00:00:00 2001 From: Leonid Didukh Date: Wed, 23 Apr 2025 01:25:51 +0300 Subject: [PATCH 2/2] QVT with the MNIST Data for training --- .../Quantum Vision Transformer.ipynb | 211 +++++++++++------- 1 file changed, 130 insertions(+), 81 deletions(-) diff --git a/community/paper_implementation_project/Quantum Vision Transformer.ipynb b/community/paper_implementation_project/Quantum Vision Transformer.ipynb index 1b04808d5..c4e9085fa 100644 --- a/community/paper_implementation_project/Quantum Vision Transformer.ipynb +++ b/community/paper_implementation_project/Quantum Vision Transformer.ipynb @@ -2,21 +2,10 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "fb8f88e1-d493-4473-80cd-00042b61f868", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/opt/anaconda3/envs/baler/lib/python3.11/site-packages/classiq/_internals/authentication/token_manager.py:101: UserWarning: Device is already registered.\n", - "Generating a new refresh token should only be done if the current refresh token is compromised.\n", - "To do so, set the overwrite parameter to true\n", - " warnings.warn(\n" - ] - } - ], + "outputs": [], "source": [ "import classiq\n", "classiq.authenticate()" @@ -24,27 +13,17 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "20d0b3d8-8de2-460b-93d2-bc805561c0c8", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: 'dlopen(/opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/image.so, 0x0006): Symbol not found: __ZN3c1017RegisterOperatorsD1Ev\n", - " Referenced from: /opt/anaconda3/envs/baler/lib/python3.11/site-packages/torchvision/image.so\n", - " Expected in: /opt/anaconda3/envs/baler/lib/python3.11/site-packages/torch/lib/libtorch_cpu.dylib'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?\n", - " warn(\n" - ] - } - ], + "outputs": [], "source": [ "import torch\n", "import numpy as np\n", "import torch.nn as nn\n", "import torch.optim as optim\n", "from typing import List\n", + "import tqdm\n", "import pdb\n", "\n", "from classiq import (\n", @@ -74,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "634a20e6-3b46-4907-84f7-27ab3f473417", "metadata": {}, "outputs": [], @@ -107,12 +86,12 @@ "outputs": [], "source": [ "N_QUBITS = 4\n", - "num_shots = 1024" + "num_shots = 4096" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "5d172b4f-c317-4759-ad63-74b2eb4fa87d", "metadata": {}, "outputs": [], @@ -128,7 +107,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "b98e5452-3bc8-4aa0-beee-cc6d0c3cb994", "metadata": {}, "outputs": [], @@ -146,7 +125,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "2bb9e435-d050-468a-a61f-0d14ce16eb9c", "metadata": {}, "outputs": [], @@ -154,9 +133,10 @@ "def get_circuit():\n", "\n", " @qfunc\n", - " def vqc(input_: CArray[CReal, N_QUBITS], weight_: CArray[CArray[CReal, N_QUBITS], N_QUBITS], res: QArray[QBit]) -> None:\n", + " def vqc(input_: CArray[CReal, N_QUBITS], weight_: CArray[CArray[CReal, N_QUBITS], N_QUBITS], res: Output[QArray[QBit]]) -> None:\n", " num_qubits = input_.len\n", " num_qlayers = weight_.len\n", + " allocate(input_.len, res)\n", " repeat(\n", " count=num_qlayers,\n", " iteration=lambda i: repeat(count=num_qubits, \n", @@ -164,16 +144,18 @@ " )\n", " \n", " @qfunc\n", - " def angle_embedding(input_: CArray[CReal, N_QUBITS], res: QArray[QBit]) -> None:\n", + " def angle_embedding(input_: CArray[CReal, N_QUBITS], qbv: Output[QArray[QBit]]) -> None:\n", + " allocate(input_.len, qbv)\n", + "\n", " repeat(\n", " count=input_.len,\n", - " iteration=lambda index: RX(pi * input_[index], res[index]),\n", + " iteration=lambda index: RX(pi * input_[index], qbv[index]),\n", " )\n", "\n", " @qfunc\n", " def main(input_: CArray[CReal, N_QUBITS], weight_: CArray[CArray[CReal, N_QUBITS], N_QUBITS], res: Output[QArray[QBit]]) -> None:\n", - " allocate(N_QUBITS, res)\n", - " angle_embedding(input_=input_, res=res)\n", + " x = QArray(\"x\")\n", + " angle_embedding(input_=input_, qbv=x)\n", " vqc(input_=input_, weight_=weight_, res=res)\n", " \n", " qmod = create_model(main)\n", @@ -183,7 +165,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "00f92a77-0b94-4fe6-8f9b-2331d4f77939", "metadata": {}, "outputs": [], @@ -192,10 +174,10 @@ " \"\"\"\n", " Patchify layer implemented using the Conv2d layer\n", " \"\"\"\n", - " def __init__(self, patch_size:int, hidden_size:int):\n", + " def __init__(self, in_channels:int, patch_size:int, hidden_size:int):\n", " super(Patchify, self).__init__()\n", " self.patch_size = patch_size\n", - " self.conv = torch.nn.Conv2d(in_channels=3, out_channels=hidden_size, kernel_size=self.patch_size, stride=self.patch_size)\n", + " self.conv = torch.nn.Conv2d(in_channels=in_channels, out_channels=hidden_size, kernel_size=self.patch_size, stride=self.patch_size)\n", " self.hidden_size = hidden_size\n", " \n", " def forward(self, x:torch.Tensor):\n", @@ -210,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "2849e3a5-3d01-42bf-ae4b-4c79375e8443", "metadata": {}, "outputs": [], @@ -254,7 +236,17 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, + "id": "5bbc585c-c3bc-4cbe-b63a-e927577080d8", + "metadata": {}, + "outputs": [], + "source": [ + "quantum_program = get_circuit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "19042677-6d63-426c-b12d-9d107b47eecb", "metadata": {}, "outputs": [], @@ -265,8 +257,7 @@ " \"\"\"\n", " def __init__(self, in_dim, out_dim):\n", " super(QuantumLayer, self).__init__()\n", - " self.quantum_program = get_circuit()\n", - " self.quantum_layer = QLayer(self.quantum_program, execute, post_process)\n", + " self.quantum_layer = QLayer(quantum_program, execute, post_process)\n", "\n", " def forward(self, x:torch.Tensor):\n", " size = x.size()\n", @@ -278,7 +269,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "376d717d-76bf-45bc-a90f-67d15a92f33a", "metadata": {}, "outputs": [], @@ -306,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "f2ffa889-38a6-425b-bf76-c1032406e6e3", "metadata": {}, "outputs": [], @@ -340,7 +331,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "426e1bed-2197-4d62-ba13-6215c466c97b", "metadata": {}, "outputs": [], @@ -373,7 +364,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "e6a37ec6-d82c-4784-aa97-94bf80be78c1", "metadata": {}, "outputs": [], @@ -382,9 +373,9 @@ " \"\"\"\n", " Quantum Vision Transformer;\n", " \"\"\"\n", - " def __init__(self, patch_size, in_dim, hidden_size, num_heads, n_classes, n_layers) -> None:\n", + " def __init__(self, in_channels, patch_size, in_dim, hidden_size, num_heads, n_classes, n_layers) -> None:\n", " super().__init__()\n", - " self.patch_formation = Patchify(patch_size=patch_size, hidden_size=hidden_size)\n", + " self.patch_formation = Patchify(in_channels=in_channels, patch_size=patch_size, hidden_size=hidden_size)\n", " self.d_model = (in_dim//patch_size)**2\n", " self.pos_encoding = RotaryPositionalEmbedding(hidden_size, self.d_model)\n", " self.transformer_blocks = [qTransformerEncoder(hidden_size, num_heads) for i in range(n_layers)]\n", @@ -393,7 +384,7 @@ " self.final_normalization = torch.nn.LayerNorm(hidden_size)\n", " self.final_layer = torch.nn.Linear(hidden_size, self.n_classes)\n", "\n", - " def forward(self, x: torch.Tensor) -> torch.Tensor: \n", + " def forward(self, x: torch.Tensor) -> torch.Tensor: \n", " x = self.patch_formation(x)\n", " x += self.pos_encoding(x)\n", " for trans_block in self.transformer_blocks:\n", @@ -406,44 +397,25 @@ }, { "cell_type": "code", - "execution_count": 21, - "id": "b57b43fe-0963-4576-95f3-55e7655858e4", + "execution_count": null, + "id": "b5e36d83-7aaa-4d7c-88a3-9cb59023ca13", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/zj/jmm9ywc51bb4p1pn12_23y340000gn/T/ipykernel_4329/535465168.py:22: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.\n", - " attention = torch.nn.functional.softmax((1/dim)*self.qK(X))*self.qQ(X)*self.qV(X)\n" - ] - } - ], + "outputs": [], "source": [ - "x = torch.rand(32, 3, 16, 16)\n", - "qVisTransformer = QVT(patch_size=4, in_dim=16, hidden_size=4, num_heads=1, n_classes=10, n_layers=4)\n", - "res = qVisTransformer(x)" + "from torchvision import datasets" ] }, { "cell_type": "code", - "execution_count": 22, - "id": "86242cc3-2d4d-48e2-83c2-1ea397976faa", + "execution_count": null, + "id": "7d76d0e7-dc24-40dc-ac59-d2332a466ae0", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([32, 10])" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "res.size()" + "transform=transforms.Compose([\n", + " transforms.ToTensor(), # first, convert image to PyTorch tensor\n", + " transforms.Normalize((0.1307,), (0.3081,)) # normalize inputs\n", + " ])" ] }, { @@ -452,7 +424,84 @@ "id": "79282b7f-cb02-4b20-a29a-51de390c2d17", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "#### Example with the MNIST Dataset:\n", + "\n", + "dataset1 = datasets.MNIST('../data', train=True, download=True,transform=transform)\n", + "dataset2 = datasets.MNIST('../data', train=False,transform=transform)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8772eb4c-075e-40a8-993b-2ec3faeb1b39", + "metadata": {}, + "outputs": [], + "source": [ + "train_loader = torch.utils.data.DataLoader(dataset1,batch_size=1)\n", + "test_loader = torch.utils.data.DataLoader(dataset2,batch_size=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc61ea1e-0cfa-4498-b5ec-eab29b102750", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "clf = QVT(in_channels=1, patch_size=7, in_dim=28, hidden_size=4, num_heads=1, n_classes=10, n_layers=1)\n", + "\n", + "opt = optim.SGD(clf.parameters(), lr=0.01, momentum=0.5)\n", + "\n", + "loss_history = []\n", + "acc_history = []\n", + "\n", + "def train(epoch):\n", + " clf.train() # set model in training mode (need this because of dropout)\n", + " \n", + " # dataset API gives us pythonic batching \n", + " for data, label in tqdm.tqdm(train_loader):\n", + " # forward pass, calculate loss and backprop!\n", + " opt.zero_grad()\n", + " preds = clf(data)\n", + " loss = torch.nn.functional.nll_loss(preds, label)\n", + " loss.backward()\n", + " loss_history.append(loss.item())\n", + " opt.step()\n", + "\n", + "def test(epoch):\n", + " clf.eval() # set model in inference mode (need this because of dropout)\n", + " test_loss = 0\n", + " correct = 0\n", + " \n", + " for data, target in tqdm.tqdm(test_loader):\n", + " \n", + " output = clf(data)\n", + " test_loss += torch.nn.functional.nll_loss(output, target).item()\n", + " pred = output.argmax() # get the index of the max log-probability\n", + " correct += pred.eq(target).cpu().sum()\n", + "\n", + " test_loss = test_loss\n", + " test_loss /= len(test_loader) # loss function already averages over batch size\n", + " accuracy = 100. * correct / len(test_loader.dataset)\n", + " acc_history.append(accuracy)\n", + " print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " accuracy))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6c0281a-c8e9-46c8-adbf-dfdce58ddc61", + "metadata": {}, + "outputs": [], + "source": [ + "for epoch in range(0, 3):\n", + " train(epoch)\n", + " test(epoch)" + ] } ], "metadata": {