Skip to content
Snippets Groups Projects
GINN_P3.ipynb 119 KiB
Newer Older
  • Learn to ignore specific revisions
  • Friedrich Heitzer's avatar
    Friedrich Heitzer committed
     "nbformat": 4,
     "nbformat_minor": 0,
     "metadata": {
      "colab": {
       "provenance": [],
       "gpuType": "T4",
       "toc_visible": true
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
      "kernelspec": {
       "name": "python3",
       "language": "python",
       "display_name": "Python 3 (ipykernel)"
      },
      "language_info": {
       "name": "python"
      },
      "accelerator": "GPU"
     },
     "cells": [
      {
       "cell_type": "markdown",
       "source": [
        "# 0.  Imports und Helper"
       ],
       "metadata": {
        "id": "194EMZeTSLIk"
       }
      },
      {
       "cell_type": "code",
       "source": [
        "!pip install torchinfo"
       ],
       "metadata": {
        "id": "6IoTrfAlzktH",
        "colab": {
         "base_uri": "https://localhost:8080/"
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
        "outputId": "f9bdc25e-4895-436b-91ab-00d3a38af883",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:19:19.732145Z",
         "start_time": "2023-11-20T22:19:18.131897Z"
        }
       },
       "execution_count": 1,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "Collecting torchinfo\r\n",
          "  Downloading torchinfo-1.8.0-py3-none-any.whl.metadata (21 kB)\r\n",
          "Downloading torchinfo-1.8.0-py3-none-any.whl (23 kB)\r\n",
          "Installing collected packages: torchinfo\r\n",
          "Successfully installed torchinfo-1.8.0\r\n"
         ]
        }
       ]
      },
      {
       "cell_type": "code",
       "execution_count": 4,
       "metadata": {
        "id": "dPt0DPgfLjEQ",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:29:17.347227Z",
         "start_time": "2023-11-20T22:29:15.452701Z"
        }
       },
       "outputs": [],
       "source": [
        "# Imports\n",
        "import copy\n",
        "\n",
        "import ipywidgets as widgets\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "import time\n",
        "import torch\n",
        "import torchvision\n",
        "#import torchvision.datasets as datasets\n",
        "import torch.nn.functional as F\n",
        "import torch.nn as nn\n",
        "import torch.optim as optim\n",
        "import tqdm\n",
        "\n",
        "import random\n",
        "import keras.datasets.imdb\n",
        "\n",
        "from torch.autograd import Variable\n",
        "from tqdm.auto import tqdm as tqdmauto"
       ]
      },
      {
       "cell_type": "code",
       "source": [
        "def set_seed(seed=None, seed_torch=True):\n",
        "  \"\"\"\n",
        "  Handles variability by controlling sources of randomness\n",
        "  through set seed values\n",
        "\n",
        "  Args:\n",
        "    seed: Integer\n",
        "      Set the seed value to given integer.\n",
        "      If no seed, set seed value to random integer in the range 2^32\n",
        "    seed_torch: Bool\n",
        "      Seeds the random number generator for all devices to\n",
        "      offer some guarantees on reproducibility\n",
        "\n",
        "  Returns:\n",
        "    Nothing\n",
        "  \"\"\"\n",
        "  if seed is None:\n",
        "    seed = np.random.choice(2 ** 32)\n",
        "  random.seed(seed)\n",
        "  np.random.seed(seed)\n",
        "  if seed_torch:\n",
        "    torch.manual_seed(seed)\n",
        "    torch.cuda.manual_seed_all(seed)\n",
        "    torch.cuda.manual_seed(seed)\n",
        "    torch.backends.cudnn.benchmark = False\n",
        "    torch.backends.cudnn.deterministic = True\n",
        "  print(f'Random seed {seed} has been set.')\n",
        "SEED = 2021\n",
        "set_seed(seed=SEED)\n",
        "DEVICE = \"mps\"\n",
        "\n",
        "def zero_grad(params):\n",
        "  \"\"\"\n",
        "  Clear gradients as they accumulate on successive backward calls\n",
        "\n",
        "  Args:\n",
        "    params: an iterator over tensors\n",
        "      i.e., updating the Weights and biases\n",
        "\n",
        "  Returns:\n",
        "    Nothing\n",
        "  \"\"\"\n",
        "  for par in params:\n",
        "    if not(par.grad is None):\n",
        "      par.grad.data.zero_()\n",
        "\n",
        "\n",
        "def print_params(model):\n",
        "  \"\"\"\n",
        "  Lists the name and current value of the model's\n",
        "  named parameters\n",
        "\n",
        "  Args:\n",
        "    model: an nn.Module inherited model\n",
        "      Represents the ML/DL model\n",
        "\n",
        "  Returns:\n",
        "    Nothing\n",
        "  \"\"\"\n",
        "  for name, param in model.named_parameters():\n",
        "    if param.requires_grad:\n",
        "      print(name, param.data)\n",
        "\n",
        "def sample_minibatch(input_data, target_data, num_points=100):\n",
        "  \"\"\"\n",
        "  Sample a minibatch of size num_point from the provided input-target data\n",
        "\n",
        "  Args:\n",
        "    input_data: Tensor\n",
        "      Multi-dimensional tensor containing the input data\n",
        "    target_data: Tensor\n",
        "      1D tensor containing the class labels\n",
        "    num_points: Integer\n",
        "      Number of elements to be included in minibatch with default=100\n",
        "\n",
        "  Returns:\n",
        "    batch_inputs: Tensor\n",
        "      Minibatch inputs\n",
        "    batch_targets: Tensor\n",
        "      Minibatch targets\n",
        "  \"\"\"\n",
        "  # Sample a collection of IID indices from the existing data\n",
        "  batch_indices = np.random.choice(len(input_data), num_points)\n",
        "  # Use batch_indices to extract entries from the input and target data tensors\n",
        "  batch_inputs = input_data[batch_indices, :]\n",
        "  batch_targets = target_data[batch_indices]\n",
        "\n",
        "  return batch_inputs, batch_targets\n",
        "\n",
        "\n",
        "def gradient_update(loss, params, lr=1e-3):\n",
        "  \"\"\"\n",
        "  Perform a gradient descent update on a given loss over a collection of parameters\n",
        "\n",
        "  Args:\n",
        "    loss: Tensor\n",
        "      A scalar tensor containing the loss through which the gradient will be computed\n",
        "    params: List of iterables\n",
        "      Collection of parameters with respect to which we compute gradients\n",
        "    lr: Float\n",
        "      Scalar specifying the learning rate or step-size for the update\n",
        "\n",
        "  Returns:\n",
        "    Nothing\n",
        "  \"\"\"\n",
        "  # Clear up gradients as Pytorch automatically accumulates gradients from\n",
        "  # successive backward calls\n",
        "  zero_grad(params)\n",
        "\n",
        "  # Compute gradients on given objective\n",
        "  loss.backward()\n",
        "\n",
        "  with torch.no_grad():\n",
        "    for par in params:\n",
        "      # Here we work with the 'data' attribute of the parameter rather than the\n",
        "      # parameter itself.\n",
        "      # Hence - use the learning rate and the parameter's .grad.data attribute to perform an update\n",
        "      par.data -= lr * par.grad.data"
       ],
       "metadata": {
        "id": "U6niQp1RNHxp",
        "colab": {
         "base_uri": "https://localhost:8080/"
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
        "outputId": "f07ba931-b6c5-4157-df21-91a429ff70a1",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:30:27.238079Z",
         "start_time": "2023-11-20T22:30:27.232238Z"
        }
       },
       "execution_count": 7,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "Random seed 2021 has been set.\n"
         ]
        }
       ]
      },
      {
       "cell_type": "code",
       "source": [
        "(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=10000, maxlen=250,)\n",
        "def vectorize_sequences(sequences, dimension=10000):\n",
        "    # all zero matrix of shape (len(sequences), dimension)\n",
        "    result = np.zeros((len(sequences), dimension))\n",
        "    for i,sequence in enumerate(sequences):\n",
        "        result[i, sequence] = 1\n",
        "    return result\n",
        "\n",
        "\n",
        "x_train = vectorize_sequences(x_train)\n",
        "x_test = vectorize_sequences(x_test)\n",
        "#x_train = np.expand_dims(x_train, -1)\n",
        "#x_test = np.expand_dims(x_test, -1)\n",
        "\n",
        "x_train = Variable(torch.from_numpy(x_train)).float().to(DEVICE)\n",
        "y_train = Variable(torch.from_numpy(y_train)).long().to(DEVICE)\n",
        "x_test  = Variable(torch.from_numpy(x_test)).float().to(DEVICE)\n",
        "y_test  = Variable(torch.from_numpy(y_test)).long().to(DEVICE)\n",
        "\n",
        "print(\"x_train shape:\", x_train.shape)\n",
        "print(\"y_train shape:\", y_train.shape)\n",
        "print(x_train.shape[0], \"train samples\")\n",
        "print(x_test.shape[0], \"test samples\")"
       ],
       "metadata": {
        "id": "tNDNF10dyqUm",
        "colab": {
         "base_uri": "https://localhost:8080/"
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
        "outputId": "f654597c-411a-45ac-f694-aba79e025aa8",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:30:31.684372Z",
         "start_time": "2023-11-20T22:30:29.176089Z"
        }
       },
       "execution_count": 8,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "x_train shape: torch.Size([17121, 10000])\n",
          "y_train shape: torch.Size([17121])\n",
          "17121 train samples\n",
          "17588 test samples\n"
         ]
        }
       ]
      },
      {
       "cell_type": "markdown",
       "source": [
        "# 1.  Softmax Implementieren\n",
        "Implementieren Sie die Softmax Funktion mit Numpy und stellen Sie zunächst sicher, dass diese die selben Ergebnisse liefert wie die Pytorch-Funktion im Beispiel. Vergleichen Sie dann Ihre Implementierungen mit anderen Gruppen und diskutieren Sie auch über Performance und numerische Stabilität. Erstellen Sie ein kleines Benchmark, um Performance und numerische Stabilität zu testen."
       ],
       "metadata": {
        "id": "tKJZz5YsSSyT"
       }
      },
      {
       "cell_type": "markdown",
       "source": [],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "source": [
        "# If values get too large this function becomes numerically unstable\n",
        "def softmax(x):\n",
        "    return np.exp(x)/np.exp(x).sum()\n",
        "\n",
        "def softmax_stable(x):\n",
        "    return np.exp(x - np.max(x)) / np.exp(x - np.max(x)).sum()"
       ],
       "metadata": {
        "id": "_80I03V8ogds",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:37:21.783849Z",
         "start_time": "2023-11-20T22:37:21.779265Z"
        }
       },
       "execution_count": 9,
       "outputs": []
      },
      {
       "cell_type": "code",
       "source": [
        "array_small = np.array([2, 11, 7])\n",
        "array_large = np.array([555, 999, 111])\n",
        "\n",
        "print(softmax(array_small).round(3))\n",
        "print(softmax(array_large))\n",
        "print(softmax_stable(array_large).round(2))"
       ],
       "metadata": {
        "id": "x0VacAxQu5JS",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:38:06.327953Z",
         "start_time": "2023-11-20T22:38:06.325348Z"
        }
       },
       "execution_count": 15,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "[0.    0.982 0.018]\n",
          "[ 0. nan  0.]\n",
          "[0. 1. 0.]\n"
         ]
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stderr",
         "output_type": "stream",
         "text": [
          "/var/folders/_v/gtvs0k6x72bf23jbq0yd1wh40000gn/T/ipykernel_78955/2076069751.py:3: RuntimeWarning: overflow encountered in exp\n",
          "  return np.exp(x)/np.exp(x).sum()\n",
          "/var/folders/_v/gtvs0k6x72bf23jbq0yd1wh40000gn/T/ipykernel_78955/2076069751.py:3: RuntimeWarning: invalid value encountered in divide\n",
          "  return np.exp(x)/np.exp(x).sum()\n"
         ]
        }
       ]
      },
      {
       "cell_type": "markdown",
       "source": [
        "# 2.  Regularisierung Implementieren\n",
        "\n",
        "Unten finden Sie einen Pytorch-SGD Schritt mit eingebauter L2-Regularisierung und ohne. Interpretieren Sie die unterschiedlichen Ausgaben. Modifizieren Sie den ersten Codabschnitt mit einer eigenen L2-Regularisierung so, dass identische Ergebnisse erzeugt werden. Sie können dazu die noch nicht verwendete und noch falsch definierte Variable \"regtermwrong\" umdefinieren und zu einem späteren Zeitpunkt im Code darauf zurückgreifen. ACHTUNG: weight_decay*2=lambda."
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "source": [
        "#Datendefinition\n",
        "np.random.seed(123)\n",
        "np.set_printoptions(8, suppress=True)\n",
        "\n",
        "x_numpy = np.random.random((3, 4)).astype(np.double)\n",
        "w_numpy = np.random.random((4, 5)).astype(np.double)\n",
        "w_numpy[0,0] =9.9\n",
        "x_torch = torch.tensor(x_numpy, requires_grad=True)\n"
       ],
       "metadata": {
        "id": "S5XEpjWFTTzi",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:39:36.082809Z",
         "start_time": "2023-11-20T22:39:36.080252Z"
        }
       },
       "execution_count": 16,
       "outputs": []
      },
      {
       "cell_type": "code",
       "source": [
        "# mit Regularisierung\n",
        "w_torch = torch.tensor(w_numpy, requires_grad=True)\n",
        "print('Original weights', w_torch)\n",
        "\n",
        "lr = 0.1\n",
        "sgd = torch.optim.SGD([w_torch], lr=lr, weight_decay=0)\n",
        "#regtermwrong = max(p.max() for p in w_torch)\n",
        "regterm = sum(sum(p) for p in w_torch)\n",
        "y_torch = torch.matmul(x_torch, w_torch)\n",
        "loss = y_torch.sum() + 4 * regterm\n",
        "\n",
        "\n",
        "sgd.zero_grad()\n",
        "loss.backward()\n",
        "sgd.step()\n",
        "\n",
        "w_grad = w_torch.grad.data.numpy()\n",
        "print('0 weight decay', w_torch)\n"
       ],
       "metadata": {
        "id": "WiQW-Y4VkH7v",
        "ExecuteTime": {
         "end_time": "2023-11-20T22:39:38.992708Z",
         "start_time": "2023-11-20T22:39:38.699008Z"
        }
       },
       "execution_count": 17,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "Original weights tensor([[9.9000, 0.0597, 0.3980, 0.7380, 0.1825],\n",
          "        [0.1755, 0.5316, 0.5318, 0.6344, 0.8494],\n",
          "        [0.7245, 0.6110, 0.7224, 0.3230, 0.3618],\n",
          "        [0.2283, 0.2937, 0.6310, 0.0921, 0.4337]], dtype=torch.float64,\n",
          "       requires_grad=True)\n"
         ]
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "ename": "TypeError",
         "evalue": "cannot inherit non-frozen dataclass from a frozen one",
         "output_type": "error",
         "traceback": [
          "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
          "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
          "Cell \u001B[0;32mIn[17], line 6\u001B[0m\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mOriginal weights\u001B[39m\u001B[38;5;124m'\u001B[39m, w_torch)\n\u001B[1;32m      5\u001B[0m lr \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0.1\u001B[39m\n\u001B[0;32m----> 6\u001B[0m sgd \u001B[38;5;241m=\u001B[39m \u001B[43mtorch\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43moptim\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mSGD\u001B[49m\u001B[43m(\u001B[49m\u001B[43m[\u001B[49m\u001B[43mw_torch\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlr\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlr\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mweight_decay\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m      7\u001B[0m regtermwrong \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mmax\u001B[39m(p\u001B[38;5;241m.\u001B[39mmax() \u001B[38;5;28;01mfor\u001B[39;00m p \u001B[38;5;129;01min\u001B[39;00m w_torch)\n\u001B[1;32m      8\u001B[0m y_torch \u001B[38;5;241m=\u001B[39m torch\u001B[38;5;241m.\u001B[39mmatmul(x_torch, w_torch)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/sgd.py:26\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, lr, momentum, dampening, weight_decay, nesterov, maximize, foreach, differentiable)\u001B[0m\n\u001B[1;32m     21\u001B[0m defaults \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mdict\u001B[39m(lr\u001B[38;5;241m=\u001B[39mlr, momentum\u001B[38;5;241m=\u001B[39mmomentum, dampening\u001B[38;5;241m=\u001B[39mdampening,\n\u001B[1;32m     22\u001B[0m                 weight_decay\u001B[38;5;241m=\u001B[39mweight_decay, nesterov\u001B[38;5;241m=\u001B[39mnesterov,\n\u001B[1;32m     23\u001B[0m                 maximize\u001B[38;5;241m=\u001B[39mmaximize, foreach\u001B[38;5;241m=\u001B[39mforeach,\n\u001B[1;32m     24\u001B[0m                 differentiable\u001B[38;5;241m=\u001B[39mdifferentiable)\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m nesterov \u001B[38;5;129;01mand\u001B[39;00m (momentum \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mor\u001B[39;00m dampening \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m):\n\u001B[0;32m---> 26\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNesterov momentum requires a momentum and zero dampening\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(params, defaults)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/optimizer.py:266\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, defaults)\u001B[0m\n\u001B[1;32m    262\u001B[0m \u001B[38;5;129m@staticmethod\u001B[39m\n\u001B[1;32m    263\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mprofile_hook_step\u001B[39m(func):\n\u001B[1;32m    265\u001B[0m     \u001B[38;5;129m@functools\u001B[39m\u001B[38;5;241m.\u001B[39mwraps(func)\n\u001B[0;32m--> 266\u001B[0m     \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrapper\u001B[39m(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[1;32m    267\u001B[0m         \u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m_ \u001B[38;5;241m=\u001B[39m args\n\u001B[1;32m    268\u001B[0m         profile_name \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mOptimizer.step#\u001B[39m\u001B[38;5;132;01m{}\u001B[39;00m\u001B[38;5;124m.step\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;241m.\u001B[39mformat(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__class__\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_compile.py:22\u001B[0m, in \u001B[0;36minner\u001B[0;34m(*args, **kwargs)\u001B[0m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m allowed_functions, convert_frame, eval_frame, resume_execution\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m list_backends, register_backend\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconvert_frame\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m replay\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/convert_frame.py:29\u001B[0m\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mguards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CheckFunctionManager, GuardedCode\n\u001B[1;32m     28\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mhooks\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Hooks\n\u001B[0;32m---> 29\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01moutput_graph\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m OutputGraph\n\u001B[1;32m     30\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mreplay_record\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ExecutionRecord\n\u001B[1;32m     31\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_convert\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m InstructionTranslator\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/output_graph.py:23\u001B[0m\n\u001B[1;32m     14\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m_guards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m (\n\u001B[1;32m     15\u001B[0m     Checkpointable,\n\u001B[1;32m     16\u001B[0m     Guard,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m     19\u001B[0m     TracingContext,\n\u001B[1;32m     20\u001B[0m )\n\u001B[1;32m     21\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mfx\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexperimental\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_shapes\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ShapeEnv\n\u001B[0;32m---> 23\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m config, logging \u001B[38;5;28;01mas\u001B[39;00m torchdynamo_logging, variables\n\u001B[1;32m     24\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CompiledFn, CompilerFn\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbytecode_transformation\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m create_instruction, Instruction, unique_id\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbase\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m VariableTracker\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbuiltin\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m BuiltinVariable\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconstant\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ConstantVariable, EnumVariable\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/base.py:6\u001B[0m\n\u001B[1;32m      4\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m variables\n\u001B[1;32m      5\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexc\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m unimplemented\n\u001B[0;32m----> 6\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msource\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m AttrSource, Source\n\u001B[1;32m      7\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m dict_values, identity, istype, odict_values\n\u001B[1;32m     10\u001B[0m \u001B[38;5;28;01mclass\u001B[39;00m \u001B[38;5;21;01mMutableLocal\u001B[39;00m:\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/source.py:49\u001B[0m\n\u001B[1;32m     39\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mis_input_source\u001B[39m(source):\n\u001B[1;32m     40\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m source\u001B[38;5;241m.\u001B[39mguard_source() \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m     41\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL,\n\u001B[1;32m     42\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL,\n\u001B[1;32m     43\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL_NN_MODULE,\n\u001B[1;32m     44\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL_NN_MODULE,\n\u001B[1;32m     45\u001B[0m     ]\n\u001B[1;32m     48\u001B[0m \u001B[38;5;129;43m@dataclasses\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdataclass\u001B[49m\n\u001B[0;32m---> 49\u001B[0m \u001B[38;5;28;43;01mclass\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43;01mLocalSource\u001B[39;49;00m\u001B[43m(\u001B[49m\u001B[43mSource\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n\u001B[1;32m     50\u001B[0m \u001B[43m    \u001B[49m\u001B[43mlocal_name\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mstr\u001B[39;49m\n\u001B[1;32m     52\u001B[0m \u001B[43m    \u001B[49m\u001B[38;5;28;43;01mdef\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43mreconstruct\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcodegen\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1184\u001B[0m, in \u001B[0;36mdataclass\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m   1181\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m wrap\n\u001B[1;32m   1183\u001B[0m \u001B[38;5;66;03m# We're called as @dataclass without parens.\u001B[39;00m\n\u001B[0;32m-> 1184\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mwrap\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1175\u001B[0m, in \u001B[0;36mdataclass.<locals>.wrap\u001B[0;34m(cls)\u001B[0m\n\u001B[1;32m   1174\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrap\u001B[39m(\u001B[38;5;28mcls\u001B[39m):\n\u001B[0;32m-> 1175\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_process_class\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43minit\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mrepr\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43meq\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43morder\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43munsafe_hash\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m   1176\u001B[0m \u001B[43m                          \u001B[49m\u001B[43mfrozen\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmatch_args\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mkw_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mslots\u001B[49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:985\u001B[0m, in \u001B[0;36m_process_class\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m    982\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m has_dataclass_bases:\n\u001B[1;32m    983\u001B[0m     \u001B[38;5;66;03m# Raise an exception if any of our bases are frozen, but we're not.\u001B[39;00m\n\u001B[1;32m    984\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m frozen:\n\u001B[0;32m--> 985\u001B[0m         \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcannot inherit non-frozen dataclass from a \u001B[39m\u001B[38;5;124m'\u001B[39m\n\u001B[1;32m    986\u001B[0m                         \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfrozen one\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[1;32m    988\u001B[0m     \u001B[38;5;66;03m# Raise an exception if we're frozen, but none of our bases are.\u001B[39;00m\n\u001B[1;32m    989\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m frozen:\n",
          "\u001B[0;31mTypeError\u001B[0m: cannot inherit non-frozen dataclass from a frozen one"
         ]
        }
       ]
      },
      {
       "cell_type": "code",
       "execution_count": 18,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "name": "stdout",
         "output_type": "stream",
         "text": [
          "Reset Original weights tensor([[9.9000, 0.0597, 0.3980, 0.7380, 0.1825],\n",
          "        [0.1755, 0.5316, 0.5318, 0.6344, 0.8494],\n",
          "        [0.7245, 0.6110, 0.7224, 0.3230, 0.3618],\n",
          "        [0.2283, 0.2937, 0.6310, 0.0921, 0.4337]], dtype=torch.float64,\n",
          "       requires_grad=True)\n"
         ]
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "ename": "TypeError",
         "evalue": "cannot inherit non-frozen dataclass from a frozen one",
         "output_type": "error",
         "traceback": [
          "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
          "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
          "Cell \u001B[0;32mIn[18], line 8\u001B[0m\n\u001B[1;32m      4\u001B[0m w_torch \u001B[38;5;241m=\u001B[39m torch\u001B[38;5;241m.\u001B[39mtensor(w_numpy, requires_grad\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[1;32m      6\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mReset Original weights\u001B[39m\u001B[38;5;124m'\u001B[39m, w_torch)\n\u001B[0;32m----> 8\u001B[0m sgd \u001B[38;5;241m=\u001B[39m \u001B[43mtorch\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43moptim\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mSGD\u001B[49m\u001B[43m(\u001B[49m\u001B[43m[\u001B[49m\u001B[43mw_torch\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlr\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlr\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mweight_decay\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m2\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m     10\u001B[0m y_torch \u001B[38;5;241m=\u001B[39m torch\u001B[38;5;241m.\u001B[39mmatmul(x_torch, w_torch)\n\u001B[1;32m     11\u001B[0m loss \u001B[38;5;241m=\u001B[39m y_torch\u001B[38;5;241m.\u001B[39msum()\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/sgd.py:26\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, lr, momentum, dampening, weight_decay, nesterov, maximize, foreach, differentiable)\u001B[0m\n\u001B[1;32m     21\u001B[0m defaults \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mdict\u001B[39m(lr\u001B[38;5;241m=\u001B[39mlr, momentum\u001B[38;5;241m=\u001B[39mmomentum, dampening\u001B[38;5;241m=\u001B[39mdampening,\n\u001B[1;32m     22\u001B[0m                 weight_decay\u001B[38;5;241m=\u001B[39mweight_decay, nesterov\u001B[38;5;241m=\u001B[39mnesterov,\n\u001B[1;32m     23\u001B[0m                 maximize\u001B[38;5;241m=\u001B[39mmaximize, foreach\u001B[38;5;241m=\u001B[39mforeach,\n\u001B[1;32m     24\u001B[0m                 differentiable\u001B[38;5;241m=\u001B[39mdifferentiable)\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m nesterov \u001B[38;5;129;01mand\u001B[39;00m (momentum \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mor\u001B[39;00m dampening \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m):\n\u001B[0;32m---> 26\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNesterov momentum requires a momentum and zero dampening\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(params, defaults)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/optimizer.py:266\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, defaults)\u001B[0m\n\u001B[1;32m    262\u001B[0m \u001B[38;5;129m@staticmethod\u001B[39m\n\u001B[1;32m    263\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mprofile_hook_step\u001B[39m(func):\n\u001B[1;32m    265\u001B[0m     \u001B[38;5;129m@functools\u001B[39m\u001B[38;5;241m.\u001B[39mwraps(func)\n\u001B[0;32m--> 266\u001B[0m     \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrapper\u001B[39m(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[1;32m    267\u001B[0m         \u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m_ \u001B[38;5;241m=\u001B[39m args\n\u001B[1;32m    268\u001B[0m         profile_name \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mOptimizer.step#\u001B[39m\u001B[38;5;132;01m{}\u001B[39;00m\u001B[38;5;124m.step\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;241m.\u001B[39mformat(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__class__\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_compile.py:22\u001B[0m, in \u001B[0;36minner\u001B[0;34m(*args, **kwargs)\u001B[0m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m allowed_functions, convert_frame, eval_frame, resume_execution\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m list_backends, register_backend\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconvert_frame\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m replay\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/convert_frame.py:29\u001B[0m\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mguards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CheckFunctionManager, GuardedCode\n\u001B[1;32m     28\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mhooks\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Hooks\n\u001B[0;32m---> 29\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01moutput_graph\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m OutputGraph\n\u001B[1;32m     30\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mreplay_record\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ExecutionRecord\n\u001B[1;32m     31\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_convert\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m InstructionTranslator\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/output_graph.py:23\u001B[0m\n\u001B[1;32m     14\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m_guards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m (\n\u001B[1;32m     15\u001B[0m     Checkpointable,\n\u001B[1;32m     16\u001B[0m     Guard,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m     19\u001B[0m     TracingContext,\n\u001B[1;32m     20\u001B[0m )\n\u001B[1;32m     21\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mfx\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexperimental\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_shapes\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ShapeEnv\n\u001B[0;32m---> 23\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m config, logging \u001B[38;5;28;01mas\u001B[39;00m torchdynamo_logging, variables\n\u001B[1;32m     24\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CompiledFn, CompilerFn\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbytecode_transformation\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m create_instruction, Instruction, unique_id\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbase\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m VariableTracker\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbuiltin\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m BuiltinVariable\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconstant\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ConstantVariable, EnumVariable\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/base.py:6\u001B[0m\n\u001B[1;32m      4\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m variables\n\u001B[1;32m      5\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexc\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m unimplemented\n\u001B[0;32m----> 6\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msource\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m AttrSource, Source\n\u001B[1;32m      7\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m dict_values, identity, istype, odict_values\n\u001B[1;32m     10\u001B[0m \u001B[38;5;28;01mclass\u001B[39;00m \u001B[38;5;21;01mMutableLocal\u001B[39;00m:\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/source.py:49\u001B[0m\n\u001B[1;32m     39\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mis_input_source\u001B[39m(source):\n\u001B[1;32m     40\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m source\u001B[38;5;241m.\u001B[39mguard_source() \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m     41\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL,\n\u001B[1;32m     42\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL,\n\u001B[1;32m     43\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL_NN_MODULE,\n\u001B[1;32m     44\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL_NN_MODULE,\n\u001B[1;32m     45\u001B[0m     ]\n\u001B[1;32m     48\u001B[0m \u001B[38;5;129;43m@dataclasses\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdataclass\u001B[49m\n\u001B[0;32m---> 49\u001B[0m \u001B[38;5;28;43;01mclass\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43;01mLocalSource\u001B[39;49;00m\u001B[43m(\u001B[49m\u001B[43mSource\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n\u001B[1;32m     50\u001B[0m \u001B[43m    \u001B[49m\u001B[43mlocal_name\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mstr\u001B[39;49m\n\u001B[1;32m     52\u001B[0m \u001B[43m    \u001B[49m\u001B[38;5;28;43;01mdef\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43mreconstruct\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcodegen\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1184\u001B[0m, in \u001B[0;36mdataclass\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m   1181\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m wrap\n\u001B[1;32m   1183\u001B[0m \u001B[38;5;66;03m# We're called as @dataclass without parens.\u001B[39;00m\n\u001B[0;32m-> 1184\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mwrap\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1175\u001B[0m, in \u001B[0;36mdataclass.<locals>.wrap\u001B[0;34m(cls)\u001B[0m\n\u001B[1;32m   1174\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrap\u001B[39m(\u001B[38;5;28mcls\u001B[39m):\n\u001B[0;32m-> 1175\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_process_class\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43minit\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mrepr\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43meq\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43morder\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43munsafe_hash\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m   1176\u001B[0m \u001B[43m                          \u001B[49m\u001B[43mfrozen\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmatch_args\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mkw_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mslots\u001B[49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:985\u001B[0m, in \u001B[0;36m_process_class\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m    982\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m has_dataclass_bases:\n\u001B[1;32m    983\u001B[0m     \u001B[38;5;66;03m# Raise an exception if any of our bases are frozen, but we're not.\u001B[39;00m\n\u001B[1;32m    984\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m frozen:\n\u001B[0;32m--> 985\u001B[0m         \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcannot inherit non-frozen dataclass from a \u001B[39m\u001B[38;5;124m'\u001B[39m\n\u001B[1;32m    986\u001B[0m                         \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfrozen one\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[1;32m    988\u001B[0m     \u001B[38;5;66;03m# Raise an exception if we're frozen, but none of our bases are.\u001B[39;00m\n\u001B[1;32m    989\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m frozen:\n",
          "\u001B[0;31mTypeError\u001B[0m: cannot inherit non-frozen dataclass from a frozen one"
         ]
        }
       ],
       "source": [
        "#mit Regularisierung\n",
        "\n",
        "w_torch = torch.tensor(w_numpy, requires_grad=True)\n",
        "\n",
        "print('Reset Original weights', w_torch)\n",
        "\n",
        "sgd = torch.optim.SGD([w_torch], lr=lr, weight_decay=2)\n",
        "\n",
        "y_torch = torch.matmul(x_torch, w_torch)\n",
        "loss = y_torch.sum()\n",
        "\n",
        "sgd.zero_grad()\n",
        "loss.backward()\n",
        "sgd.step()\n",
        "\n",
        "w_grad = w_torch.grad.data.numpy()\n",
        "print('1 weight decay', w_torch)"
       ],
       "metadata": {
        "collapsed": false,
        "ExecuteTime": {
         "end_time": "2023-11-20T22:39:58.623547Z",
         "start_time": "2023-11-20T22:39:58.475069Z"
        }
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "# 3.&nbsp; Einfaches MLP in Pytorch\n",
        "Machen Sie sich ein wenig mit dem `IMDB` Datensatz und den für Sie erstellten Datenstrukturen in x/y_train/test vertraut."
       ],
       "metadata": {
        "id": "mLeOKvUxMunF"
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "## 3.1 Modell erstellen und  Angaben zur Modellgröße verstehen\n",
        "Definieren Sie ein Pytorch Multilayer Perzeptron mit der Größe des IMDB-Dictionaries für one-hot-encodierte Wörte als Eingabe (Sigmoid Aktivierung), 50 Neuronen im Hidden Layer und 2 Ausgabeneuronen. Layer 1 und 2 Ihres Netzes verwendet die Sigmoid-Aktivierungsfunktion, Layer 3 die Softmax-Aktivierungsfunktion.\n",
        "\n",
        "Generieren Sie Modell-Summary mit torchinfo und erklären Sie, was die ausgegebenen Werte bedeuten und wie diese zustande kommen."
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "execution_count": 24,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "data": {
          "text/plain": "=================================================================\nLayer (type:depth-idx)                   Param #\n=================================================================\nModel                                    --\n├─Linear: 1-1                            500,050\n├─Linear: 1-2                            102\n├─Sigmoid: 1-3                           --\n├─Softmax: 1-4                           --\n=================================================================\nTotal params: 500,152\nTrainable params: 500,152\nNon-trainable params: 0\n================================================================="
         },
         "execution_count": 24,
         "metadata": {},
         "output_type": "execute_result"
        }
       ],
       "source": [
        "from torchinfo import summary\n",
        "\n",
        "class Model(nn.Module):\n",
        "\n",
        "  def __init__(self,\n",
        "               n_input: int = 10000,\n",
        "               n_hidden: int = 50,\n",
        "               n_out: int = 2):\n",
        "      super(Model, self).__init__()\n",
        "      self.hidden = nn.Linear(n_input, n_hidden)\n",
        "      self.out = nn.Linear(n_hidden, n_out)\n",
        "      self.sigmoid = nn.Sigmoid()\n",
        "      self.softmax = nn.Softmax()\n",
        "\n",
        "\n",
        "  def forward(self, x):\n",
        "      x = self.hidden(x)\n",
        "      x = self.sigmoid(x)\n",
        "      x = self.out(x)\n",
        "      x = self.softmax(x)\n",
        "      return x\n",
        "\n",
        "model = Model()\n",
        "summary(m)"
       ],
       "metadata": {
        "collapsed": false,
        "ExecuteTime": {
         "end_time": "2023-11-20T23:09:52.169718Z",
         "start_time": "2023-11-20T23:09:52.161860Z"
        }
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "## 3.2 Modell trainieren und Performancekurven interpretieren\n",
        "Nutzen Sie den untenstehenedn Code um Ihr Modell zu trainieren. Interpretieren und diskutieren Sie die entstehenden Performancekurven. Falls Sie einen unerwarteten Anstieg Ihres Losses beobachten, recherchieren Sie wie Sie diese mit dem Einbau einer einzelnen Verbesserung innerhalb des gegebenen SGD Lernverfahrens beheben können. ACHTUNG: Wenn Sie Ihr Modell nicht oben neu initialisieren, optimieren Sie weiter auf den schon veränderten Parametern."
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "execution_count": 25,
       "outputs": [
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
         "ename": "TypeError",
         "evalue": "cannot inherit non-frozen dataclass from a frozen one",
         "output_type": "error",
         "traceback": [
          "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
          "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
          "Cell \u001B[0;32mIn[25], line 3\u001B[0m\n\u001B[1;32m      1\u001B[0m EPOCHS  \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m291\u001B[39m \u001B[38;5;66;03m#@param {type:\"slider\", min:2, max:1000, step:1}\u001B[39;00m\n\u001B[1;32m      2\u001B[0m RATE \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0.902\u001B[39m \u001B[38;5;66;03m#@param {type:\"slider\", min:0.001, max:2, step:0.001}\u001B[39;00m\n\u001B[0;32m----> 3\u001B[0m optimizer \u001B[38;5;241m=\u001B[39m \u001B[43mtorch\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43moptim\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mSGD\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmodel\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparameters\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mlr\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mRATE\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mweight_decay\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m      4\u001B[0m loss_fn   \u001B[38;5;241m=\u001B[39m nn\u001B[38;5;241m.\u001B[39mCrossEntropyLoss()\n\u001B[1;32m      5\u001B[0m loss_list     \u001B[38;5;241m=\u001B[39m np\u001B[38;5;241m.\u001B[39mzeros((EPOCHS,))\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/sgd.py:26\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, lr, momentum, dampening, weight_decay, nesterov, maximize, foreach, differentiable)\u001B[0m\n\u001B[1;32m     21\u001B[0m defaults \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mdict\u001B[39m(lr\u001B[38;5;241m=\u001B[39mlr, momentum\u001B[38;5;241m=\u001B[39mmomentum, dampening\u001B[38;5;241m=\u001B[39mdampening,\n\u001B[1;32m     22\u001B[0m                 weight_decay\u001B[38;5;241m=\u001B[39mweight_decay, nesterov\u001B[38;5;241m=\u001B[39mnesterov,\n\u001B[1;32m     23\u001B[0m                 maximize\u001B[38;5;241m=\u001B[39mmaximize, foreach\u001B[38;5;241m=\u001B[39mforeach,\n\u001B[1;32m     24\u001B[0m                 differentiable\u001B[38;5;241m=\u001B[39mdifferentiable)\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m nesterov \u001B[38;5;129;01mand\u001B[39;00m (momentum \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mor\u001B[39;00m dampening \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m):\n\u001B[0;32m---> 26\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNesterov momentum requires a momentum and zero dampening\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(params, defaults)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/optim/optimizer.py:266\u001B[0m, in \u001B[0;36m__init__\u001B[0;34m(self, params, defaults)\u001B[0m\n\u001B[1;32m    262\u001B[0m \u001B[38;5;129m@staticmethod\u001B[39m\n\u001B[1;32m    263\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mprofile_hook_step\u001B[39m(func):\n\u001B[1;32m    265\u001B[0m     \u001B[38;5;129m@functools\u001B[39m\u001B[38;5;241m.\u001B[39mwraps(func)\n\u001B[0;32m--> 266\u001B[0m     \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrapper\u001B[39m(\u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[1;32m    267\u001B[0m         \u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m_ \u001B[38;5;241m=\u001B[39m args\n\u001B[1;32m    268\u001B[0m         profile_name \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mOptimizer.step#\u001B[39m\u001B[38;5;132;01m{}\u001B[39;00m\u001B[38;5;124m.step\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;241m.\u001B[39mformat(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__class__\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m)\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_compile.py:22\u001B[0m, in \u001B[0;36minner\u001B[0;34m(*args, **kwargs)\u001B[0m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m allowed_functions, convert_frame, eval_frame, resume_execution\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m list_backends, register_backend\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconvert_frame\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m replay\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/convert_frame.py:29\u001B[0m\n\u001B[1;32m     27\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mguards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CheckFunctionManager, GuardedCode\n\u001B[1;32m     28\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mhooks\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Hooks\n\u001B[0;32m---> 29\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01moutput_graph\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m OutputGraph\n\u001B[1;32m     30\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mreplay_record\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ExecutionRecord\n\u001B[1;32m     31\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_convert\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m InstructionTranslator\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/output_graph.py:23\u001B[0m\n\u001B[1;32m     14\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m_guards\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m (\n\u001B[1;32m     15\u001B[0m     Checkpointable,\n\u001B[1;32m     16\u001B[0m     Guard,\n\u001B[0;32m   (...)\u001B[0m\n\u001B[1;32m     19\u001B[0m     TracingContext,\n\u001B[1;32m     20\u001B[0m )\n\u001B[1;32m     21\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mtorch\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mfx\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexperimental\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msymbolic_shapes\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ShapeEnv\n\u001B[0;32m---> 23\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m config, logging \u001B[38;5;28;01mas\u001B[39;00m torchdynamo_logging, variables\n\u001B[1;32m     24\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbackends\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mregistry\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m CompiledFn, CompilerFn\n\u001B[1;32m     25\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbytecode_transformation\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m create_instruction, Instruction, unique_id\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/__init__.py:1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbase\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m VariableTracker\n\u001B[1;32m      2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mbuiltin\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m BuiltinVariable\n\u001B[1;32m      3\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mconstant\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m ConstantVariable, EnumVariable\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/variables/base.py:6\u001B[0m\n\u001B[1;32m      4\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m variables\n\u001B[1;32m      5\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mexc\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m unimplemented\n\u001B[0;32m----> 6\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01msource\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m AttrSource, Source\n\u001B[1;32m      7\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m dict_values, identity, istype, odict_values\n\u001B[1;32m     10\u001B[0m \u001B[38;5;28;01mclass\u001B[39;00m \u001B[38;5;21;01mMutableLocal\u001B[39;00m:\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/site-packages/torch/_dynamo/source.py:49\u001B[0m\n\u001B[1;32m     39\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mis_input_source\u001B[39m(source):\n\u001B[1;32m     40\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m source\u001B[38;5;241m.\u001B[39mguard_source() \u001B[38;5;129;01min\u001B[39;00m [\n\u001B[1;32m     41\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL,\n\u001B[1;32m     42\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL,\n\u001B[1;32m     43\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mLOCAL_NN_MODULE,\n\u001B[1;32m     44\u001B[0m         GuardSource\u001B[38;5;241m.\u001B[39mGLOBAL_NN_MODULE,\n\u001B[1;32m     45\u001B[0m     ]\n\u001B[1;32m     48\u001B[0m \u001B[38;5;129;43m@dataclasses\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdataclass\u001B[49m\n\u001B[0;32m---> 49\u001B[0m \u001B[38;5;28;43;01mclass\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43;01mLocalSource\u001B[39;49;00m\u001B[43m(\u001B[49m\u001B[43mSource\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n\u001B[1;32m     50\u001B[0m \u001B[43m    \u001B[49m\u001B[43mlocal_name\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mstr\u001B[39;49m\n\u001B[1;32m     52\u001B[0m \u001B[43m    \u001B[49m\u001B[38;5;28;43;01mdef\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43mreconstruct\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcodegen\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1184\u001B[0m, in \u001B[0;36mdataclass\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m   1181\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m wrap\n\u001B[1;32m   1183\u001B[0m \u001B[38;5;66;03m# We're called as @dataclass without parens.\u001B[39;00m\n\u001B[0;32m-> 1184\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mwrap\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:1175\u001B[0m, in \u001B[0;36mdataclass.<locals>.wrap\u001B[0;34m(cls)\u001B[0m\n\u001B[1;32m   1174\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrap\u001B[39m(\u001B[38;5;28mcls\u001B[39m):\n\u001B[0;32m-> 1175\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43m_process_class\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43minit\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mrepr\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43meq\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43morder\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43munsafe_hash\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m   1176\u001B[0m \u001B[43m                          \u001B[49m\u001B[43mfrozen\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmatch_args\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mkw_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mslots\u001B[49m\u001B[43m)\u001B[49m\n",
          "File \u001B[0;32m~/miniconda3/envs/ginn/lib/python3.10/dataclasses.py:985\u001B[0m, in \u001B[0;36m_process_class\u001B[0;34m(cls, init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, slots)\u001B[0m\n\u001B[1;32m    982\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m has_dataclass_bases:\n\u001B[1;32m    983\u001B[0m     \u001B[38;5;66;03m# Raise an exception if any of our bases are frozen, but we're not.\u001B[39;00m\n\u001B[1;32m    984\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m frozen:\n\u001B[0;32m--> 985\u001B[0m         \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTypeError\u001B[39;00m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mcannot inherit non-frozen dataclass from a \u001B[39m\u001B[38;5;124m'\u001B[39m\n\u001B[1;32m    986\u001B[0m                         \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfrozen one\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[1;32m    988\u001B[0m     \u001B[38;5;66;03m# Raise an exception if we're frozen, but none of our bases are.\u001B[39;00m\n\u001B[1;32m    989\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m any_frozen_base \u001B[38;5;129;01mand\u001B[39;00m frozen:\n",
          "\u001B[0;31mTypeError\u001B[0m: cannot inherit non-frozen dataclass from a frozen one"
         ]
    
    Friedrich Heitzer's avatar
    Friedrich Heitzer committed
       ],
       "source": [
        "EPOCHS  = 291 #@param {type:\"slider\", min:2, max:1000, step:1}\n",
        "RATE = 0.902 #@param {type:\"slider\", min:0.001, max:2, step:0.001}\n",
        "optimizer = torch.optim.SGD(model.parameters(), lr=RATE, weight_decay=0)\n",
        "loss_fn   = nn.CrossEntropyLoss()\n",
        "loss_list     = np.zeros((EPOCHS,))\n",
        "accuracy_list = np.zeros((EPOCHS,))\n",
        "accuracy_list_test = np.zeros((EPOCHS,))\n",
        "\n",
        "\n",
        "for epoch in tqdm.trange(EPOCHS):\n",
        "    y_pred = model(x_train)\n",
        "    #loss = loss_fn(y_pred, y_train)\n",
        "    loss_list[epoch] = loss.item()\n",
        "    loss = loss_fn(y_pred, y_train)# + 0.01 *l2_reg(model)\n",
        "\n",
        "    # Zero gradients\n",
        "    optimizer.zero_grad()\n",
        "\n",
        "    loss.backward()\n",
        "    #torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)#, args.clip)\n",
        "    optimizer.step()\n",
        "\n",
        "    with torch.no_grad():\n",
        "        y_pred = model(x_train)\n",
        "        correct = (torch.argmax(y_pred, dim=1) == y_train).type(torch.FloatTensor)\n",
        "        accuracy_list[epoch] = correct.mean()\n",
        "        y_pred = model(x_test)\n",
        "        correct = (torch.argmax(y_pred, dim=1) == y_test).type(torch.FloatTensor)\n",
        "        accuracy_list_test[epoch] = correct.mean()\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(12, 6), sharex=True)\n",
        "\n",
        "ax1.plot(accuracy_list)\n",
        "ax1.set_ylabel(\"train accuracy\")\n",
        "ax2.plot(loss_list)\n",
        "ax2.set_ylabel(\"train loss\")\n",
        "ax3.plot(accuracy_list_test)\n",
        "ax3.set_ylabel(\"test acc\")\n",
        "ax3.set_xlabel(\"epochs\");"
       ],
       "metadata": {
        "collapsed": false,
        "ExecuteTime": {
         "end_time": "2023-11-20T23:10:04.077035Z",
         "start_time": "2023-11-20T23:10:03.912932Z"
        }
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "## 3.3.&nbsp;Momentum Implementieren\n",
        "Vervollständigen Sie Methode momentum_update. Überlegen Sie sich, wie Sie die Korrektheit mit einem Durchlauf inkl. Momentum Update auf Ihrem oben definierten Modell prüfen können"
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "execution_count": null,
       "outputs": [],
       "source": [
        "def momentum_update(loss, params, grad_vel, lr=1e-3, beta=0.8):\n",
        "  # Clear up gradients as Pytorch automatically accumulates gradients from\n",
        "  # successive backward calls\n",
        "  zero_grad(params)\n",
        "  # Compute gradients on given objective\n",
        "  loss.backward()\n",
        "\n",
        "  with torch.no_grad():\n",
        "    for (par, vel) in zip(params, grad_vel):\n",
        "      w_u = lr * par.grad + beta * grad_vel\n",
        "      grad_vel = w_u\n",
        "      par -= w_u"
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "## 3.4 Experimente zum Lernverhalten mit Momentum und Batch Size\n",
        "Im folgenden können Sie für ein festgelegtes Zeitbudget schauen, wie sich der Loss Ihres neuronalen Netzes innerhalb dieser Zeit entwickelt.\n",
        "Experimentieren Sie zunächst mit den Voreinstellungen mit und ohne Momentum, probieren Sie dann eigene Einstellungen aus. Diskutieren Sie das visualisierte Lernverhalten insbesondere bzgl. unterschiedlicher Batch Sizes."
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "code",
       "execution_count": null,
       "outputs": [],
       "source": [
        "@widgets.interact_manual\n",
        "def minibatch_experiment(batch_sizes='1, 20, 500, 17000',\n",
        "                         lrs='0.9, 0.9, 0.9, 0.9',\n",
        "                         time_budget=widgets.Dropdown(options=[\"0.05\", \"0.5\",  \"2.0\", \"5.0\", \"7.5\"],\n",
        "                                                      value=\"5.0\"),\n",
        "                         use_momentum = widgets.ToggleButton(value=True)):\n",
        "\n",
        "  \"\"\"\n",
        "  Demonstration of minibatch experiment\n",
        "\n",
        "  Args:\n",
        "    batch_sizes: String\n",
        "      Size of minibatches\n",
        "    lrs: String\n",
        "      Different learning rates\n",
        "    time_budget: widget dropdown instance\n",
        "      Different time budgets with default=2.5s\n",
        "\n",
        "  Returns:\n",
        "    Nothing\n",
        "  \"\"\"\n",
        "  batch_sizes = [int(s) for s in batch_sizes.split(',')]\n",
        "  lrs = [float(s) for s in lrs.split(',')]\n",
        "\n",
        "  LOSS_HIST = {_:[] for _ in batch_sizes}\n",
        "\n",
        "  #X, y = train_set.data, train_set.targets\n",
        "  base_model = Model(x_train.shape[1]).to(DEVICE)\n",
        "  #base_model = MLP(in_dim=784, out_dim=10, hidden_dims=[100, 100])\n",
        "\n",
        "  for id, batch_size in enumerate(tqdm.auto.tqdm(batch_sizes)):\n",
        "    start_time = time.time()\n",
        "    # Create a new copy of the model for each batch size\n",
        "    model = copy.deepcopy(base_model)\n",
        "    params = list(model.parameters())\n",
        "    lr = lrs[id]\n",
        "    # Fixed budget per choice of batch size\n",
        "    #initial_vel = [torch.randn_like(p) for p in model.parameters()]\n",
        "    aux_tensors = [torch.zeros_like(_) for _ in params]\n",
        "    while (time.time() - start_time) < float(time_budget):\n",
        "      data, labels = sample_minibatch(x_train, y_train, batch_size)\n",
        "      loss = loss_fn(model(data), labels)\n",
        "      if use_momentum:\n",
        "        momentum_update(loss, params, grad_vel=aux_tensors, lr=lr, beta=0.5)\n",
        "      else:\n",
        "        gradient_update(loss, params, lr=lr)\n",
        "      LOSS_HIST[batch_size].append([time.time() - start_time,\n",
        "                                    loss.item()])\n",
        "\n",
        "  fig, axs = plt.subplots(1, len(batch_sizes), figsize=(10, 3))\n",
        "  for ax, batch_size in zip(axs, batch_sizes):\n",
        "    plot_data = np.array(LOSS_HIST[batch_size])\n",
        "    ax.plot(plot_data[:, 0], plot_data[:, 1], label=batch_size,\n",
        "            alpha=0.8)\n",
        "    #ax.set_title('Batch size: ' + str(batch_size) + ' #: ' + str(batch_size*len(LOSS_HIST[batch_size])))\n",
        "    ax.set_title(' #: ' + str(batch_size*len(LOSS_HIST[batch_size])))\n",
        "    ax.set_xlabel('Seconds')\n",
        "    ax.set_ylabel('Loss')\n",
        "  plt.show()\n",
        "  #return(LOSS_HIST)\n"
       ],
       "metadata": {
        "collapsed": false
       }
      },
      {
       "cell_type": "markdown",
       "source": [
        "![image.png](data:image/png;base64,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)"
       ],
       "metadata": {
        "collapsed": false
       }
      }
     ]
    }