{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Training hybrid models using the Pennylane backend\n", "\n", "In this example, we will first train a pure quantum model using PennyLane and PyTorch to classify whether a sentence is about cooking or computing. We will then train a hybrid model that takes in pairs of sentences and determines whether they are talking about the same or different topics." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "BATCH_SIZE = 10\n", "EPOCHS = 30\n", "LEARNING_RATE = 0.1\n", "SEED = 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import torch\n", "import random\n", "import numpy as np\n", "\n", "torch.manual_seed(SEED)\n", "random.seed(SEED)\n", "np.random.seed(SEED)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Read in the data and create diagrams" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def read_data(filename):\n", " labels, sentences = [], []\n", " with open(filename) as f:\n", " for line in f:\n", " t = float(line[0])\n", " labels.append([t, 1-t])\n", " sentences.append(line[1:].strip())\n", " return labels, sentences\n", "\n", "\n", "train_labels, train_data = read_data('datasets/mc_train_data.txt')\n", "dev_labels, dev_data = read_data('datasets/mc_dev_data.txt')\n", "test_labels, test_data = read_data('datasets/mc_test_data.txt')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "import os\n", "\n", "TESTING = int(os.environ.get('TEST_NOTEBOOKS', '0'))\n", "\n", "if TESTING:\n", " train_labels, train_data = train_labels[:3], train_data[:3]\n", " dev_labels, dev_data = dev_labels[:3], dev_data[:3]\n", " test_labels, test_data = test_labels[:3], test_data[:3]\n", " EPOCHS = 1" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Tagging sentences.\n", "Parsing tagged sentences.\n", "Turning parse trees to diagrams.\n", "Tagging sentences.\n", "Parsing tagged sentences.\n", "Turning parse trees to diagrams.\n", "Tagging sentences.\n", "Parsing tagged sentences.\n", "Turning parse trees to diagrams.\n" ] } ], "source": [ "from lambeq import BobcatParser\n", "\n", "reader = BobcatParser(verbose='text')\n", "\n", "raw_train_diagrams = reader.sentences2diagrams(train_data)\n", "raw_dev_diagrams = reader.sentences2diagrams(dev_data)\n", "raw_test_diagrams = reader.sentences2diagrams(test_data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Remove cups" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from lambeq import RemoveCupsRewriter\n", "\n", "remove_cups = RemoveCupsRewriter()\n", "\n", "train_diagrams = [remove_cups(diagram) for diagram in raw_train_diagrams]\n", "dev_diagrams = [remove_cups(diagram) for diagram in raw_dev_diagrams]\n", "test_diagrams = [remove_cups(diagram) for diagram in raw_test_diagrams]\n", "\n", "train_diagrams[0].draw()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create circuits" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0MAAAMzCAYAAABk4skuAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC4AElEQVR4nOzde1zO9/8/8MfVSV1FoVQOCRmXUyqiyJIsp4zFDCGzjY01I7PNRuNjMxPmy7CPtozmsI0ktsmhJoeiNEyOQ5tdbFGmouPr94df18clhw7X1bur9+N+u3XT9T683s/3W8/r/X6+D6+3QgghQEREREREJDNGUgdAREREREQkBRZDREREREQkSyyGiIiIiIhIllgMERERERGRLLEYIiIiIiIiWWIxREREREREssRiiIiIiIiIZInFEBERERERyRKLISIiIiIikiUWQ0REREREJEsshoiIiIiISJZYDBERERERkSyxGCIiIiIiIlliMURERERERLLEYoiIiIiIiGSJxRAREREREckSiyEiIiIiIpIlFkNERERERCRLLIaIiIiIiEiWWAwREREREZEssRgiIiIiIiJZYjFERERERESyxGKIiIiIiIhkicUQERERERHJEoshIiIiIiKSJRZDREREREQkSyyGiIiIiIhIllgMERERERGRLLEYIiIiIiIiWWIxREREREREssRiiIiIiIiIZInFEBERERERyRKLISIiIiIikiUWQ0REREREJEsshoiIiIiISJZYDBERERERkSyxGCIiIiIiIlliMURERERERLLEYoiIiIiIiGSJxRAREREREckSiyEiIiIiIpIlFkNERERERCRLLIaIiIiIiEiWWAwREREREZEssRgiIiIiIiJZYjFERERERESyxGKIiIiIiIhkicUQERERERHJEoshIiIiIiKSJRZDREREREQkSyyGiIiIiIhIllgMERERERGRLLEYIiIiIiIiWWIxREREREREssRiiIiIiIiIZInFEBERERERyRKLISIiIiIikiUWQ0REREREJEsshoiIiIiISJZYDBERERERkSyxGCIiIiIiIlliMURERERERLLEYoiIiIiIiGSJxRAREREREckSiyEiIiIiIpIlFkNERERERCRLLIaIiIiIiEiWWAwREREREZEssRgiIiIiIiJZYjFERERERESyxGKIiIiIiIhkicUQ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jfHtt99qukt+3C1zZcOHDh2K6Ojocg+5kzzxO792mTBhAn755RecOXMGrq6uMDMzQ7169RAcHIzevXtj6tSplW4zMDBQ523qW2ZmJt5//33NKz2ISFoG1ZucLpS9p0FKAwcOfOyL1vLy8sr1xFPm/fff13qB36OUvWvpUX788ccK3S4wfPjwGrnXnKgiLCws8P3332PTpk1YsWIFjh07Vm4aDw8PvPXWW3jppZdYCJGW2vCdL5XMzEx06NDhkePKunR+XPfbZ86c0boFUFe6dOmC77//HsXFxbhx4wbq1atX7Y569NHm40RHR2veUfWwli1b4rfffntqG2WdXxBR7SC7Yqg2WLduneYh34dZWFg8dlyjRo2e2nZ6evpjx5X1vkNkaIyNjREcHIzg4GCkp6dj8uTJuHnzJt555x14enqyswSqEF9fX52/hqBMSEgIQkJC9NJ2VTVt2vSJ+4SnzatPJiYmOt8n6aPNhw0dOvSx7y97uLtuIjIMLIYkoM8va55torqua9eucHFxgaWlJd8jRPQEJiYm3CfoWP369VG/fn2pwyAiHZLVM0NERERERERlWAwREREREZEssRgiIiIiIiJZYjFERERERESyxGKIiIiIiIhkicUQERERERHJEoshIiIiIiKSJYN+z1BGRobUIdQp3J5kKOrXr4979+5JHQZRhfH7Vbe4PYlIVwyyGLK1tYVSqURwcLDUodQ5SqUStra2UodB9ER37txBdna21GEQPRX3V/rD/RUR6YJBFkNOTk7IyMhAVlaW1KE81dKlS3Ho0CH88MMPUodSIba2tnBycpI6DCKiOsGQ9leTJ0+Gra0tFi5cKHUoFcL9FRHpgkEWQ8D9HYwhfAna29vD3Nwc7u7uUodCREQSMJT9Vf369dGoUSPur4hIVtiBAhERERERyRKLISIiIiIikiUWQ0REREREJEsshoiIiIiISJZYDBERERERkSyxGKpDrly5AoVCgfT09MdOk5CQAIVCgZycnBqLi8iQMa+IdI95RUS1BYshmfH29oZarYa1tTUAICoqCjY2NtIGRWTgmFdEuse8IqKaYLDvGaKqMTMzg4ODg9RhENUpzCsi3WNeEVFN4JWhWiQvLw/jx4+HlZUVHB0dERERAV9fX0yfPh0AoFAoEBMTozWPjY0NoqKitIadPXsW3t7eMDc3R6dOnZCYmKgZ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oYMuXLigNWvWKCQk5K70+/PPP6tLly7av3+/oqKicjy8IuAM7Ha7OnfuLA8PD23YsEGPPPLIXen3+++/V8eOHfXjjz/qk08+UcuWLe9Kv4AzCA8Pl7+/v6Kjo80uBbil/fv3q0GDBtq3b58SExO1bt06bd261eyy8iw2NlZhYWG5vpQ8r/76vtavX/+2yx86dEjh4eE6evSoU19dwWVytxEQECC73a6aNWsqLCzsrhwkDh06pKCgIKWmpio2NpYghCInKChISUlJKl26tIKDg7MuJShICQkJCgwM1KVLl5SYmEgQAoAi4LnnnlPTpk114cIFs0vJs5CQkGz3JhV2DodDH3zwgVMHIYkwlCM+Pj6KiYlRjx49FBkZqVdeeSXfRun4uy1btig4OFilS5dWUlKSgoKCCqQfwGyVKlVSXFycmjdvrvbt2+udd94psG/DoqOjFRYWppo1a8put2ddKw4AcG7FihXT+PHjVapUKbNLyTM3N7dsI6NGR0dnG477rz85uaJi0KBB/7j+zeaFhoZKkt54440c1duiRQu1bt06dxtbiBQzuwBnUaJECS1btkwBAQF66aWXdOTIEUVFReXb0+kNw9C7776r4cOHq3379oqOji4SOzZwK6VKldJnn32msWPH6oUXXlBKSormzZt3wzChuZWZmanJkyfrtddeU9++fbVo0SKVKFEiX9oGAKAgderU6R+/FM/JcXLKlCkaNWrUTeeVLl36hnmHDh1SRERE1vOZrIIwdAdsNpvGjBmj6tWrKzIyUs2bN9fatWvl7++fp3avXr2qF198UQsXLtTIkSM1ffr0bKOUAEWZq6urZs6cqZo1a2rw4MH69ttv9fHHH6tMmTJ5avfSpUvq27evPvnkE02bNk1jxozhAcUAAKdRqlSpPH0xXr58+WzDi99s/l9dHz25bNmyue7TGXGZXC506dJFcXFx+t///V8FBgYqOTk51239+uuvat++vZYsWaIlS5Zo5syZBCFY0jPPPKNt27Zp7969Cg4OzvaE8DvlcDjUvHlzbdy4UatXr9bYsWMJQgAA4AaEoVyqV6+ekpKS5Ovrq9DQUK1bt+6O20hNTVVwcLD27t2rbdu26ZlnnimASgHnERYWJrvdrszMTAUFBenLL7+84zaSk5MVGBiokydPateuXerSpUsBVAoAAIoCwlAeVKhQQV9++aXa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JRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFgSYQgAAACAJRGGAAAAAFjS/wMjmnamoMZj7gAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from lambeq import AtomicType, IQPAnsatz\n", "\n", "ansatz = IQPAnsatz({AtomicType.NOUN: 1, AtomicType.SENTENCE: 1},\n", " n_layers=1, n_single_qubit_params=3)\n", "\n", "train_circuits = [ansatz(diagram) for diagram in train_diagrams]\n", "dev_circuits = [ansatz(diagram) for diagram in dev_diagrams]\n", "test_circuits = [ansatz(diagram) for diagram in test_diagrams]\n", "\n", "train_circuits[0].draw(figsize=(8, 8))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create (pure quantum) model and initialise parameters" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from lambeq import PennyLaneModel\n", "\n", "all_circuits = train_circuits + dev_circuits + test_circuits\n", "\n", "model = PennyLaneModel.from_diagrams(all_circuits)\n", "model.initialise_weights()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Prepare train dataset" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "from lambeq import Dataset\n", "\n", "train_dataset = Dataset(train_circuits,\n", " train_labels,\n", " batch_size=BATCH_SIZE)\n", "\n", "val_dataset = Dataset(dev_circuits, dev_labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Training" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Using `PytorchTrainer`" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def acc(y_hat, y):\n", " return (torch.argmax(y_hat, dim=1) == \n", " torch.argmax(y, dim=1)).sum().item()/len(y)\n", "\n", "def loss(y_hat, y):\n", " return torch.nn.functional.mse_loss(y_hat, y)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Epoch 1: train/loss: 0.1542 valid/loss: 0.2271 train/time: 0.88s valid/time: 0.23s train/acc: 0.5571 valid/acc: 0.5333\n", "Epoch 2: train/loss: 0.1318 valid/loss: 0.2877 train/time: 0.59s valid/time: 0.17s train/acc: 0.8571 valid/acc: 0.6000\n", "Epoch 3: train/loss: 0.0677 valid/loss: 0.1879 train/time: 0.53s valid/time: 0.16s train/acc: 0.8429 valid/acc: 0.7333\n", "Epoch 4: train/loss: 0.1274 valid/loss: 0.1289 train/time: 0.62s valid/time: 0.17s train/acc: 0.9000 valid/acc: 0.8333\n", "Epoch 5: train/loss: 0.0604 valid/loss: 0.1909 train/time: 0.48s valid/time: 0.16s train/acc: 0.8571 valid/acc: 0.6667\n", "Epoch 6: train/loss: 0.0572 valid/loss: 0.1599 train/time: 0.48s valid/time: 0.16s train/acc: 0.8857 valid/acc: 0.7333\n", "Epoch 7: train/loss: 0.0147 valid/loss: 0.1156 train/time: 0.58s valid/time: 0.47s train/acc: 0.9286 valid/acc: 0.8000\n", "Epoch 8: train/loss: 0.0057 valid/loss: 0.0661 train/time: 0.76s valid/time: 0.21s train/acc: 0.8857 valid/acc: 0.9333\n", "Epoch 9: train/loss: 0.0988 valid/loss: 0.1100 train/time: 0.47s valid/time: 0.16s train/acc: 0.9429 valid/acc: 0.8667\n", "Epoch 10: train/loss: 0.0067 valid/loss: 0.0928 train/time: 0.65s valid/time: 0.17s train/acc: 0.9714 valid/acc: 0.8667\n", "Epoch 11: train/loss: 0.0854 valid/loss: 0.0410 train/time: 0.47s valid/time: 0.16s train/acc: 0.9714 valid/acc: 0.9667\n", "Epoch 12: train/loss: 0.0434 valid/loss: 0.0416 train/time: 0.54s valid/time: 0.17s train/acc: 0.9714 valid/acc: 0.9333\n", "Epoch 13: train/loss: 0.0368 valid/loss: 0.0262 train/time: 0.56s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 14: train/loss: 0.0007 valid/loss: 0.0239 train/time: 0.48s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 15: train/loss: 0.0002 valid/loss: 0.0109 train/time: 0.47s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 16: train/loss: 0.0002 valid/loss: 0.0057 train/time: 0.56s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 17: train/loss: 0.0014 valid/loss: 0.0078 train/time: 0.46s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 18: train/loss: 0.0048 valid/loss: 0.0071 train/time: 0.46s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 19: train/loss: 0.0021 valid/loss: 0.0060 train/time: 0.57s valid/time: 0.25s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 20: train/loss: 0.0007 valid/loss: 0.0051 train/time: 0.46s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 21: train/loss: 0.0002 valid/loss: 0.0046 train/time: 0.49s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 22: train/loss: 0.0001 valid/loss: 0.0054 train/time: 0.58s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 23: train/loss: 0.0001 valid/loss: 0.0057 train/time: 0.49s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 24: train/loss: 0.0000 valid/loss: 0.0058 train/time: 0.46s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 25: train/loss: 0.0000 valid/loss: 0.0058 train/time: 0.57s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 26: train/loss: 0.0000 valid/loss: 0.0058 train/time: 0.46s valid/time: 0.17s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 27: train/loss: 0.0000 valid/loss: 0.0059 train/time: 0.45s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 28: train/loss: 0.0000 valid/loss: 0.0059 train/time: 0.47s valid/time: 0.31s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 29: train/loss: 0.0000 valid/loss: 0.0059 train/time: 0.46s valid/time: 0.17s train/acc: 1.0000 valid/acc: 1.0000\n", "Epoch 30: train/loss: 0.0000 valid/loss: 0.0059 train/time: 0.45s valid/time: 0.16s train/acc: 1.0000 valid/acc: 1.0000\n", "\n", "Training completed!\n", "train/time: 15.95s train/time_per_epoch: 0.53s train/time_per_step: 0.08s valid/time: 5.52s valid/time_per_eval: 0.18s\n" ] } ], "source": [ "from lambeq import PytorchTrainer\n", "\n", "trainer = PytorchTrainer(\n", " model=model,\n", " loss_function=loss,\n", " optimizer=torch.optim.Adam,\n", " learning_rate=LEARNING_RATE,\n", " epochs=EPOCHS,\n", " evaluate_functions={\"acc\": acc},\n", " evaluate_on_train=True,\n", " use_tensorboard=False,\n", " verbose='text',\n", " seed=SEED\n", " )\n", "\n", "trainer.fit(train_dataset, val_dataset)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Determine test accuracy" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def accuracy(circs, labels):\n", " probs = model(circs)\n", " return (torch.argmax(probs, dim=1) == \n", " torch.argmax(torch.tensor(labels), dim=1)).sum().item()/len(circs)\n", "\n", "accuracy(test_circuits, test_labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Using standard PyTorch\n", "\n", "As we have a small dataset, we can use early stopping to prevent overfitting to the training data." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def accuracy(circs, labels):\n", " probs = model(circs)\n", " return (torch.argmax(probs, dim=1) == \n", " torch.argmax(torch.tensor(labels), dim=1)).sum().item()/len(circs)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch: 0\n", "Train loss: 1.8844525068998337\n", "Dev acc: 0.8\n", "Epoch: 5\n", "Train loss: 0.19278147350996733\n", "Dev acc: 0.9666666666666667\n", "Epoch: 10\n", "Train loss: 0.014470159949269146\n", "Dev acc: 0.9333333333333333\n", "Epoch: 15\n", "Train loss: 0.000635529821011005\n", "Dev acc: 0.9666666666666667\n", "Early stopping\n" ] } ], "source": [ "import pickle\n", "\n", "model = PennyLaneModel.from_diagrams(all_circuits)\n", "model.initialise_weights()\n", "optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)\n", "\n", "best = {'acc': 0, 'epoch': 0}\n", "\n", "for i in range(EPOCHS):\n", " epoch_loss = 0\n", " for circuits, labels in train_dataset:\n", " optimizer.zero_grad()\n", " probs = model(circuits)\n", " d_type = model.weights[0].dtype\n", " probs = probs.to(d_type)\n", " loss = torch.nn.functional.mse_loss(probs, \n", " torch.tensor(labels))\n", " epoch_loss += loss.item()\n", " loss.backward()\n", " optimizer.step()\n", " \n", " if i % 5 == 0:\n", " dev_acc = accuracy(dev_circuits, dev_labels)\n", " \n", " print(\"Epoch: {}\".format(i))\n", " print(\"Train loss: {}\".format(epoch_loss))\n", " print(\"Dev acc: {}\".format(dev_acc))\n", " \n", " if dev_acc > best['acc']:\n", " best['acc'] = dev_acc\n", " best['epoch'] = i\n", " model.save(\"model.lt\")\n", " elif i - best['epoch'] >= 10:\n", " print(\"Early stopping\")\n", " break\n", " \n", "if best[\"acc\"] > accuracy(dev_circuits, dev_labels): \n", " model.load(\"model.lt\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Determine the test accuracy" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9666666666666667" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "accuracy(test_circuits, test_labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating a hybrid model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This model will take in pairs of diagrams and attempt to determine whether they are talking about the same or different topics. It does this by first running the circuits to get a probability ouput on the open wire, and then passes this output to a simple neural network. We expect the circuits to learn to output [0, 1] or [1, 0] depending on the topic they are referring to (cooking or computing), and the neural network to learn to XOR these outputs to determine whether the topics are the same (in which case it should ouput 0) or different (in which case it should output 1). PennyLane allows us to train both the circuits and the NN simultaneously using PyTorch autograd." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "BATCH_SIZE = 50\n", "EPOCHS = 100\n", "LEARNING_RATE = 0.1\n", "SEED = 2" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "torch.manual_seed(SEED)\n", "random.seed(SEED)\n", "np.random.seed(SEED)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As the probability outputs from our circuits are guaranteed to be positive, we transform these outputs `x` by `2 * (x - 0.5)`, giving inputs to the neural network in the range [-1, 1]. This helps us to avoid \"dying ReLUs\", which could otherwise occur if all the input weights to a given neuron were negative, leading to the gradient of all these weights being 0. (A couple of alternative approaches could also involve initialising all the neural network weights to be positive, or using `LeakyReLU` as the activation function)." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "from torch import nn\n", "\n", "class XORSentenceModel(PennyLaneModel):\n", " def __init__(self, **kwargs):\n", " PennyLaneModel.__init__(self, **kwargs)\n", " \n", " self.xor_net = nn.Sequential(\n", " nn.Linear(4, 10),\n", " nn.ReLU(),\n", " nn.Linear(10, 1),\n", " nn.Sigmoid()\n", " )\n", " \n", " def forward(self, diagram_pairs):\n", " a, b = zip(*diagram_pairs)\n", " evaluated_pairs = torch.cat((self.get_diagram_output(a),\n", " self.get_diagram_output(b)),\n", " dim=1)\n", " evaluated_pairs = 2 * (evaluated_pairs - 0.5)\n", " out = self.xor_net(evaluated_pairs)\n", " return out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Make paired dataset" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "from itertools import combinations\n", "\n", "def make_pair_data(diagrams, labels):\n", " pair_diags = list(combinations(diagrams, 2))\n", " pair_labels = [int(x[0] == y[0]) for x, y in combinations(labels, 2)]\n", " \n", " return pair_diags, pair_labels\n", "\n", "train_pair_circuits, train_pair_labels = make_pair_data(train_circuits, \n", " train_labels)\n", "dev_pair_circuits, dev_pair_labels = make_pair_data(dev_circuits, dev_labels)\n", "test_pair_circuits, test_pair_labels = make_pair_data(test_circuits, \n", " test_labels)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are lots of pairs (2415 train pairs), so we'll sample a subset to make this example train more quickly." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "TRAIN_SAMPLES, DEV_SAMPLES, TEST_SAMPLES = 300, 200, 200" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "if TESTING:\n", " TRAIN_SAMPLES, DEV_SAMPLES, TEST_SAMPLES = 2, 2, 2" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "train_pair_circuits, train_pair_labels = (\n", " zip(*random.sample(list(zip(train_pair_circuits, train_pair_labels)),\n", " TRAIN_SAMPLES)))\n", "dev_pair_circuits, dev_pair_labels = (\n", " zip(*random.sample(list(zip(dev_pair_circuits, dev_pair_labels)), DEV_SAMPLES)))\n", "test_pair_circuits, test_pair_labels = (\n", " zip(*random.sample(list(zip(test_pair_circuits, test_pair_labels)), TEST_SAMPLES)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Initialise the model" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "all_pair_circuits = (train_pair_circuits +\n", " dev_pair_circuits +\n", " test_pair_circuits)\n", "a, b = zip(*all_pair_circuits)\n", "\n", "model = XORSentenceModel.from_diagrams(a + b)\n", "model.initialise_weights()\n", "\n", "train_pair_dataset = Dataset(train_pair_circuits,\n", " train_pair_labels,\n", " batch_size=BATCH_SIZE)\n", "\n", "optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Train the model and log accuracies" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Only log every five epochs as evaluating is expensive." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "def accuracy(circs, labels):\n", " predicted = model(circs)\n", " return (torch.round(torch.flatten(predicted)) == \n", " torch.Tensor(labels)).sum().item()/len(circs)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch: 0\n", "Train loss: 4.250532507896423\n", "Dev acc: 0.53\n", "Epoch: 5\n", "Train loss: 1.186747632920742\n", "Dev acc: 0.825\n", "Epoch: 10\n", "Train loss: 0.35468656790908426\n", "Dev acc: 0.545\n", "Epoch: 15\n", "Train loss: 0.41043267399072647\n", "Dev acc: 0.875\n", "Epoch: 20\n", "Train loss: 0.0038383470964618027\n", "Dev acc: 0.88\n", "Epoch: 25\n", "Train loss: 0.0011570464266696945\n", "Dev acc: 0.88\n", "Epoch: 30\n", "Train loss: 0.0007703642331762239\n", "Dev acc: 0.88\n", "Early stopping\n" ] } ], "source": [ "best = {'acc': 0, 'epoch': 0}\n", "\n", "for i in range(EPOCHS):\n", " epoch_loss = 0\n", " for circuits, labels in train_pair_dataset:\n", " optimizer.zero_grad()\n", " predicted = model(circuits)\n", " loss = torch.nn.functional.binary_cross_entropy(\n", " torch.flatten(predicted), torch.Tensor(labels))\n", " epoch_loss += loss.item()\n", " loss.backward()\n", " optimizer.step()\n", "\n", " if i % 5 == 0:\n", " dev_acc = accuracy(dev_pair_circuits, dev_pair_labels)\n", "\n", " print(\"Epoch: {}\".format(i))\n", " print(\"Train loss: {}\".format(epoch_loss))\n", " print(\"Dev acc: {}\".format(dev_acc))\n", "\n", " if dev_acc > best['acc']:\n", " best['acc'] = dev_acc\n", " best['epoch'] = i\n", " model.save(\"xor_model.lt\")\n", " elif i - best['epoch'] >= 10:\n", " print(\"Early stopping\")\n", " break\n", " \n", "if best[\"acc\"] > accuracy(dev_pair_circuits, dev_pair_labels): \n", " model.load(\"xor_model.lt\")\n", " model = model.double()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.89" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "accuracy(test_pair_circuits, test_pair_labels)" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 4 }