{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Decoding with Key-Value Cache\n",
    "\n",
    "Lecture 9 | CMU ANLP Fall 2025 | Instructor: Sean Welleck\n",
    "\n",
    "This notebook shows key-value (KV) caching for transformer language models."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Motivation\n",
    "\n",
    "During autoregressive generation, transformers generate tokens one at a time:\n",
    "- Token 1: Compute attention for token 1\n",
    "- Token 2: Compute attention for tokens 1-2\n",
    "- Token 3: Compute attention for tokens 1-3\n",
    "- ...\n",
    "\n",
    "**Problem**: Without caching, we recompute the keys and values for all previous tokens at each step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from time import time\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Transformer Block with Optional KV Cache"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class BlockWithCache(nn.Module):\n",
    "    \"\"\"Transformer block with optional key-value caching.\"\"\"\n",
    "    \n",
    "    def __init__(self, d_model, nhead, dim_ff=64, max_len=128):\n",
    "        super().__init__()\n",
    "        assert d_model % nhead == 0\n",
    "        \n",
    "        self.d_model = d_model\n",
    "        self.nhead = nhead\n",
    "        self.d_k = d_model // nhead\n",
    "        \n",
    "        # Attention projections\n",
    "        self.q_proj = nn.Linear(d_model, d_model)\n",
    "        self.k_proj = nn.Linear(d_model, d_model)\n",
    "        self.v_proj = nn.Linear(d_model, d_model)\n",
    "        self.o_proj = nn.Linear(d_model, d_model)\n",
    "        \n",
    "        # Feed-forward\n",
    "        self.ff1 = nn.Linear(d_model, dim_ff)\n",
    "        self.ff2 = nn.Linear(dim_ff, d_model)\n",
    "        self.ln1 = nn.LayerNorm(d_model)\n",
    "        self.ln2 = nn.LayerNorm(d_model)\n",
    "        self.act = nn.ReLU()\n",
    "        \n",
    "        # Cache for keys and values\n",
    "        self.cache_k = None\n",
    "        self.cache_v = None\n",
    "        \n",
    "    def forward(self, x, use_cache=False):\n",
    "        B, T, D = x.size()\n",
    "        \n",
    "        # Pre-normalization\n",
    "        x_norm = self.ln1(x)\n",
    "        \n",
    "        # Compute Q, K, V\n",
    "        Q = self.q_proj(x_norm)\n",
    "        \n",
    "        if use_cache and self.cache_k is not None:\n",
    "            # Only compute K, V for the new token(s)\n",
    "            K_new = self.k_proj(x_norm)\n",
    "            V_new = self.v_proj(x_norm)\n",
    "            \n",
    "            # Append to cache\n",
    "            K = torch.cat([self.cache_k, K_new], dim=1)\n",
    "            V = torch.cat([self.cache_v, V_new], dim=1)\n",
    "            \n",
    "            # Update cache\n",
    "            self.cache_k = K\n",
    "            self.cache_v = V\n",
    "            \n",
    "        else:\n",
    "            # Compute K, V for all tokens\n",
    "            K = self.k_proj(x_norm)\n",
    "            V = self.v_proj(x_norm)\n",
    "            \n",
    "            if use_cache:\n",
    "                # Initialize cache\n",
    "                self.cache_k = K\n",
    "                self.cache_v = V\n",
    "            \n",
    "        # Reshape for multi-head attention\n",
    "        T_k = K.size(1)  # Total sequence length including cache\n",
    "        Q = Q.view(B, T, self.nhead, self.d_k).transpose(1, 2)\n",
    "        K = K.view(B, T_k, self.nhead, self.d_k).transpose(1, 2)\n",
    "        V = V.view(B, T_k, self.nhead, self.d_k).transpose(1, 2)\n",
    "        \n",
    "        # Scaled dot-product attention\n",
    "        scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.d_k ** 0.5)\n",
    "        \n",
    "        # Apply causal mask\n",
    "        if T == 1 and use_cache:\n",
    "            # During generation with cache, we only process single token\n",
    "            pass  # No mask needed for single token with cache\n",
    "        else:\n",
    "            # During initial forward pass or without cache\n",
    "            mask = torch.triu(torch.ones(T, T_k, device=x.device), diagonal=1 + (T_k - T)).bool()\n",
    "            scores = scores.masked_fill(mask.unsqueeze(0).unsqueeze(0), float('-inf'))\n",
    "        \n",
    "        # Apply softmax and compute weighted values\n",
    "        attn_weights = torch.softmax(scores, dim=-1)\n",
    "        context = torch.matmul(attn_weights, V)\n",
    "        \n",
    "        # Reshape and project output\n",
    "        context = context.transpose(1, 2).contiguous().view(B, T, D)\n",
    "        output = self.o_proj(context)\n",
    "        \n",
    "        # Residual connection\n",
    "        x = x + output\n",
    "        \n",
    "        # Feed-forward with residual\n",
    "        x_norm = self.ln2(x)\n",
    "        ff_out = self.ff2(self.act(self.ff1(x_norm)))\n",
    "        x = x + ff_out\n",
    "        \n",
    "        return x\n",
    "    \n",
    "    def clear_cache(self):\n",
    "        \"\"\"Clear the key-value cache.\"\"\"\n",
    "        self.cache_k = None\n",
    "        self.cache_v = None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Transformer Language Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TransformerLM(nn.Module):\n",
    "    \"\"\"Transformer Language Model with optional caching.\"\"\"\n",
    "    \n",
    "    def __init__(self, vocab_size, d_model, nhead, num_layers, dim_ff, max_len=128):\n",
    "        super().__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, d_model)\n",
    "        self.pos_encoder = nn.Embedding(max_len, d_model)\n",
    "        self.blocks = nn.ModuleList([\n",
    "            BlockWithCache(d_model, nhead, dim_ff, max_len) for _ in range(num_layers)\n",
    "        ])\n",
    "        self.ln_f = nn.LayerNorm(d_model)\n",
    "        self.fc = nn.Linear(d_model, vocab_size)\n",
    "        self.d_model = d_model\n",
    "        self.max_len = max_len\n",
    "\n",
    "    def forward(self, x, use_cache=False, past_length=0):\n",
    "        B, T = x.size()\n",
    "        \n",
    "        # Position encoding accounts for cached positions\n",
    "        pos = torch.arange(past_length, past_length + T, device=x.device)\n",
    "        pos = pos.unsqueeze(0).expand(B, -1)\n",
    "        \n",
    "        x = self.embedding(x) + self.pos_encoder(pos)\n",
    "        \n",
    "        for block in self.blocks:\n",
    "            x = block(x, use_cache=use_cache)\n",
    "        \n",
    "        x = self.ln_f(x)\n",
    "        logits = self.fc(x)\n",
    "        \n",
    "        return logits\n",
    "    \n",
    "    def clear_cache(self):\n",
    "        \"\"\"Clear cache in all blocks.\"\"\"\n",
    "        for block in self.blocks:\n",
    "            block.clear_cache()\n",
    "    \n",
    "    @torch.no_grad()\n",
    "    def generate(self, context, max_length=20, temperature=1.0, use_cache=True):\n",
    "        \"\"\"Generate text with optional caching.\"\"\"\n",
    "        self.eval()\n",
    "        self.clear_cache()\n",
    "        \n",
    "        # Start with context\n",
    "        if len(context) == 0:\n",
    "            context = [0]  # Start token\n",
    "        \n",
    "        generated = context.copy()\n",
    "        \n",
    "        for i in range(max_length):\n",
    "            if use_cache and i > 0:\n",
    "                # With cache: only process the new token\n",
    "                x = torch.tensor([[generated[-1]]], dtype=torch.long)\n",
    "                past_length = len(generated) - 1\n",
    "            else:\n",
    "                # Without cache or first iteration: process all tokens\n",
    "                x = torch.tensor([generated], dtype=torch.long)\n",
    "                past_length = 0\n",
    "            \n",
    "            # Get predictions\n",
    "            logits = self(x, use_cache=use_cache, past_length=past_length)\n",
    "            logits = logits[0, -1] / temperature\n",
    "            \n",
    "            # Sample next token\n",
    "            probs = torch.softmax(logits, dim=-1)\n",
    "            next_token = torch.multinomial(probs, 1).item()\n",
    "            \n",
    "            generated.append(next_token)\n",
    "        \n",
    "        return generated"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model parameters: 581348\n"
     ]
    }
   ],
   "source": [
    "# Create model with random weights (no training needed for demonstration)\n",
    "vocab_size = 100\n",
    "model = TransformerLM(\n",
    "    vocab_size=vocab_size,\n",
    "    d_model=64,\n",
    "    nhead=4,\n",
    "    num_layers=16,\n",
    "    dim_ff=128,\n",
    "    max_len=512\n",
    ")\n",
    "\n",
    "print(f\"Model parameters: {sum(p.numel() for p in model.parameters())}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Performance Comparison"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequence length: 512\n",
      "\n",
      "Without Cache:\n",
      "  Time: 5.6287s\n",
      "\n",
      "With Cache:\n",
      "  Time: 0.8062s\n",
      "\n",
      "Speedup: 6.98x\n"
     ]
    }
   ],
   "source": [
    "def compare_generation(model, context=[], max_length=20):\n",
    "    \"\"\"Compare generation with and without cache.\"\"\"\n",
    "    \n",
    "    # Generate WITHOUT cache\n",
    "    model.clear_cache()\n",
    "    start_time = time()\n",
    "    generated_no_cache = model.generate(context, max_length=max_length, use_cache=False)\n",
    "    time_no_cache = time() - start_time\n",
    "    \n",
    "    # Generate WITH cache\n",
    "    model.clear_cache()\n",
    "    start_time = time()\n",
    "    generated_with_cache = model.generate(context, max_length=max_length, use_cache=True)\n",
    "    time_with_cache = time() - start_time\n",
    "    \n",
    "    print(f\"Sequence length: {max_length}\")\n",
    "    print(f\"\\nWithout Cache:\")\n",
    "    print(f\"  Time: {time_no_cache:.4f}s\")\n",
    "    print(f\"\\nWith Cache:\")\n",
    "    print(f\"  Time: {time_with_cache:.4f}s\")\n",
    "    print(f\"\\nSpeedup: {time_no_cache/time_with_cache:.2f}x\")\n",
    "\n",
    "# Test with different lengths\n",
    "compare_generation(model, context=[], max_length=512)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generation Time Scaling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqoAAAHbCAYAAAADE7iTAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAiqlJREFUeJzt3QWYlFUbBuBnu7vIpbs7REAFAQsBUUJaEBULMbCxUPztAFRaEUEEVARpEMmlW7phi202Z/7rPeuMM7M9G1PPfTkuX+w3Z+bMzL5z4j1OWq1WCyIiIiIiK+Ns6QIQEREREeWHgSoRERERWSUGqkRERERklRioEhEREZFVYqBKRERERFaJgSoRERERWSUGqkRERERklRioEhEREZFVYqBKRERERFaJgSoR6Z07dw5OTk4YOXIkbFH37t1V+ansvPnmm+o53bRpk6WLQhXM1j8PyD4wUCW7tn//fowfPx6NGzeGv78/3N3dUalSJfTs2RMfffQRYmJi4Ghq1qypbtZO/kCW5GZv0tLS8Nlnn+G2225DWFgY3NzcEBwcjC5duuD99993yNduedO9lpo0aYKcnJw8x69du6aOyxei8rZ+/XoMGTJEvVe9vLzg4+ODRo0a4dFHH8XOnTvL/f6JrIWrpQtAVB40Gg1eeOEFFYy6uLiga9euuPPOO9WHfXR0NLZv345JkybhjTfewIkTJ1C1alVLF9kqyPNw7NgxBAQEWLooqm5Mffrpp0hMTMz3mJg/f74K8GzdgQMH0LdvX5w/fx41atTAfffdh4iICCQlJWHHjh2YPHkypk6diitXrqjXNJWto0ePYu7cuRgzZkyF3/fNmzcxevRoLFq0CN7e3ujRowfq16+vjv3zzz/44Ycf8M0336jX+rBhwyq8fEQVjYEq2aVXXnlFBamtW7fGTz/9hLp16+Y5Z+/evXjxxRfVHwbKJa12DRs2hLV0OZuS4EEC1fyOicjISNi6S5cuqS9VsbGx6jX89NNPqy9bhvbt24cJEyYgKyvLYuW0V+Hh4erLjrzGhg4dCk9Pzwq9fwmOJUiVXp8FCxaoLyiGEhIS1JcU+UnkCNj1T3ZHWh0+/PBD1V26evXqfINUIUHs2rVr8+0GP3jwIAYNGoTKlSur4QLSqvXkk08iLi6uwDFcp06dQr9+/RAUFKRauaQlRFrG8iOtus8++6wqm4eHB0JDQzFgwAAcPny4wK56+cMkwUn16tXh6uqqgjaxZ88etb9p06aqJVS6CZs1a6a6hw0DGV1ZpZVObobd5rrAr7AxafI78kdUWl3lOalWrZravnDhQoFjReX+5dpSfnmc0jL09ddfoyLHqMrzJPvk52+//YYOHTqolip5HK+99ppqfRfz5s1DixYt1PMnAa+8hvKj1Woxe/Zs3HLLLWo4iVyrbdu2al9ZfcmS18fLL7+MiRMn5glSRatWrbB582Z1/zpy/9IKK8+1BFcyTKBXr17YuHFjgfe1ZcsW3H///SoYkvqR11b//v2xdevWfM9fuHAhWrZsqZ4jeW9IEF3QFz259r333qte23LtevXq4dVXXy1Wi7ec4+fnhzp16hR4TvPmzVU5pJVZpKenq8Be6lDeB/IelOfiwQcfLPB9mB95/z733HPqC4MMvSgu+WLxzDPPoFatWurxSsAr953fe7ogUlc//vijep8sX748T5AqAgMD8cEHH2DcuHH6fcX9DDAkrzF5nA0aNFDny+tF3hv/+9//8j2/vD7fiIqkJbIzL7/8slZe2q+++qpZv79ixQqth4eH1svLSzto0CDt888/r7377rvVNevVq6eNj4/Xn3v27Fm1v1u3btqQkBBt165dtRMnTtT27dtX7Q8KCtJeu3bN6PqnTp3SVqtWTR2/8847tc8995x22LBhWm9vb62Pj492x44dRufXqFFDW6lSJW2rVq3U/T/++OPap556SvvHH3+o448++qi2SpUq+rI+8cQT2iZNmqjr9+/fX3+dGzduaN944w1tQECAusm/dbeNGzcaPZ4RI0YYleHEiRPasLAwdezee+/VvvTSS9p77rlHbct+OW5Ing85NmDAAG316tW148aN0z722GPqOZL933zzjVl1I89FYR9buvs1NGfOHLXvvvvu03p6eqrn6dlnn9XWr19f7X/llVe006ZN0/r7+6t6kOe2atWq6ti8efOMrqXRaLSDBw/WvxbkuX/yySe1DRs2VPukLk3J/uJ+1Kampmrd3d3Vay8hIUFbEvLYOnTooB0zZoyqH3ksfn5+WmdnZ+3y5cvznP/pp59qnZyc1Otu6NCh2smTJ2uHDx+urV27tvbpp5/WnyevD11dyutzyJAh6vlr1KiR2i/bpr7++mt1bXn9yzUnTZqk7d69uzq/c+fO2oyMjCIfj7wG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wupPfppOjJOZjZIJgHVcsSZMmKAms23cuFFNzNGRepBhOAkJCYXWY371rDtGFUNaaurWrYs2bdqobA4y0fGzzz5jHdoI6RaWz8PWrVurniW5yRcNmZAq/5ZWNdaj7QkMDET9+vVx6tQph3gvOjvah6584K5fv96oa1K2pXuLrFutWrXUm8qw/mSMjYw91dWf/JQ3rHxA62zYsEHVs3wLpfIn8+AkSJVuYnnupd4MyXvQzc3NqB4lfZWMuTKsR+l2NvzSIa1CkiZJup7JMuR9lJGRwTq0EXfccYeqA2kV191k/L6McdT9m/Voe1JSUnD69GmVptEh3otaB7No0SI1S3zu3Llqhvi4ceO0gYGBRrPhyLKzU/ft26du8vL8+OOP1b/Pnz+vjr///vuqvlasWKE9ePCgtm/fvtpatWppb968qb9G7969ta1atdLu3LlTu3XrVjXbdfDgwRZ8VI7lscce0wYEBGg3bdqkvXr1qv6WlpamP2f8+PHayMhI7YYNG7RRUVHaTp06qZtOdna2tmnTpto777xTu3//fu3q1au1YWFh2smTJ1voUTmel156SWVqOHv2rHqvybZkz1izZo06zjq0TYaz/gXr0fo999xz6vNU3ot///23tkePHtrQ0FCVUcUR6tDhAlXxxRdfqEp1d3dX6ap27Nhh6SLRvzZu3KgCVNPbiBEj9CmqXnvtNW1ERIT6wnHHHXdoT5w4YXSNuLg4FZj6+vqq9BujRo1SATBVjPzqT25z5szRnyNfLB5//HGV7sjb21vbr18/FcwaOnfunLZPnz5aLy8v9aEsH9ZZWVkWeESOafTo0doaNWqoz0n5oybvNV2QKliH9hGosh6t30MPPaStXLmyei9WrVpVbZ86dcph6tBJ/mfpVl0iIiIiIoceo0pEREREtoOBKhERERFZJQaqRERERGSVGKgSERERkVVioEpEREREVomBKhERERFZJQaqRERERGSVGKgSERERkVVioEpERFZr5MiR8PX1tXQxiMhCGKgSkdU4dOgQHnjgAdSoUQOenp6oWrUqevbsiS+++MLSRbNpmzZtgpOTE37++WdYo7S0NLz55puqnEREhhioEpFV2LZtG9q2bYsDBw5g7Nix+PLLL/HII4/A2dkZn332maWLR+UcqE6ZMoWBKhHl4Zp3FxFRxXv33XcREBCA3bt3IzAw0OhY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qjzXoaGhJXpsElj37dtXlU+eKxlTKuWUANYweJUctzJGV+paWsnl+Zdz5EZEDs7SaQeIiMSqVatUKqeGDRtqfX19te7u7tq6detqn3zySe3169fznL906VJtly5dVEolucnvPfHEE9oTJ04Ynff111+r1FEeHh7atm3bards2aJSUxmmpxKnT5/W9ujRQ50XERGhffnll7Vr1641Sk+ls2/fPm3//v1ViiY5X1ItPfjgg9r169fnSU8lqZcMFZQKa/bs2SrlklwvKChIlU/u35CUQ1JjSUoqT09PbZ06dbQjR47URkVFFSs9VUG3v/76S50naaQmT56snnd5/kNDQ7WdO3fW/u9//9OnCdOlp/rwww/z3E9+KaYWLVqk6kYeV9OmTbW//vqrdsCAAWqfoW3btql0U3K/hteR9FRSv6Z0zy8R2Tcn+Z+lg2UiooqkW5WKa8tbhozFlRZhSbtFRFQYjlElIqJyIeNpTYdPyJcDST1muIQtEVFBOEaViIjKhYzdlSwCDz/8sBpvK+NjZXKbpNgyTeBPRJQfBqpERFQuJO2XTMqSCWiSmcDHxwd333033n//fYSEhFi6eERkAzhGlYiIiIisEseoEhEREZFVYqBKRERERFaJgSoRERERWSUGqkRERERklRioEhEREZFVYqBKRERERFaJgSoRERERWSUGqkREREQEa/R//B61DmhZvGwAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Speedup factors:\n",
      "  Length 16: 1.61x\n",
      "  Length 32: 1.57x\n",
      "  Length 64: 1.73x\n",
      "  Length 96: 2.08x\n",
      "  Length 128: 2.38x\n",
      "  Length 256: 3.73x\n",
      "  Length 512: 7.39x\n"
     ]
    }
   ],
   "source": [
    "def benchmark_generation_time(model):\n",
    "    \"\"\"Benchmark generation time at different sequence lengths.\"\"\"\n",
    "    lengths = [16, 32, 64, 96, 128, 256, 512]\n",
    "    times_no_cache = []\n",
    "    times_with_cache = []\n",
    "    \n",
    "    for length in lengths:\n",
    "        # Without cache\n",
    "        model.clear_cache()\n",
    "        start = time()\n",
    "        _ = model.generate([], max_length=length, use_cache=False)\n",
    "        times_no_cache.append(time() - start)\n",
    "        \n",
    "        # With cache\n",
    "        model.clear_cache()\n",
    "        start = time()\n",
    "        _ = model.generate([], max_length=length, use_cache=True)\n",
    "        times_with_cache.append(time() - start)\n",
    "    \n",
    "    return lengths, times_no_cache, times_with_cache\n",
    "\n",
    "lengths, t_no_cache, t_cache = benchmark_generation_time(model)\n",
    "\n",
    "# Plot the results\n",
    "plt.figure(figsize=(8, 5))\n",
    "plt.plot(lengths, t_no_cache, 'o-', label='Without Cache', linewidth=2, markersize=8)\n",
    "plt.plot(lengths, t_cache, 's-', label='With Cache', linewidth=2, markersize=8)\n",
    "plt.xlabel('Sequence Length', fontsize=12)\n",
    "plt.ylabel('Generation Time (seconds)', fontsize=12)\n",
    "plt.title('Generation Time: Cache vs No Cache', fontsize=14)\n",
    "plt.legend(fontsize=11)\n",
    "plt.grid(True, alpha=0.3)\n",
    "plt.show()\n",
    "\n",
    "# Print speedup factors\n",
    "print(\"\\nSpeedup factors:\")\n",
    "for l, t1, t2 in zip(lengths, t_no_cache, t_cache):\n",
    "    speedup = t1/t2\n",
    "    print(f\"  Length {l}: {speedup:.2f}x\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
