{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "## Simple mnist from Chapter 2 of Chollet  \n",
        "\n",
        "With some stuff added by Rob."
      ],
      "metadata": {
        "id": "q7d2P0c4Zx5D"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## imports\n",
        "import pandas as pd\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "\n",
        "from tensorflow.keras.datasets import mnist\n",
        "from tensorflow import keras\n",
        "from tensorflow.keras import layers\n",
        "from tensorflow.keras import regularizers\n",
        "\n",
        "from sklearn.metrics import accuracy_score\n",
        "from sklearn.metrics import confusion_matrix"
      ],
      "metadata": {
        "id": "L8L4YFUfZ7Z3"
      },
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## look at data\n",
        "(train_images,train_labels), (test_images,test_labels) = mnist.load_data()\n",
        "\n",
        "## check basic dimensions\n",
        "print(train_images.shape)\n",
        "print(train_labels.shape)\n",
        "print(test_images.shape)\n",
        "print(test_labels.shape)\n",
        "print(train_labels)\n",
        "print(test_labels)\n",
        "\n",
        "ntr = len(train_labels)\n",
        "nte = len(test_labels)\n",
        "print(f'the number of train and test are: {ntr}, {nte}')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-5dhRziraECF",
        "outputId": "fbb850c9-4e82-442e-a3e3-fe9f36c28464"
      },
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n",
            "\u001b[1m11490434/11490434\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n",
            "(60000, 28, 28)\n",
            "(60000,)\n",
            "(10000, 28, 28)\n",
            "(10000,)\n",
            "[5 0 4 ... 5 6 8]\n",
            "[7 2 1 ... 4 5 6]\n",
            "the number of train and test are: 60000, 10000\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "## check the digit counts\n",
        "print(pd.Series(train_labels).value_counts()/ntr)\n",
        "print(pd.Series(test_labels).value_counts()/nte)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ZWR6P_tBaHmH",
        "outputId": "2cc9ac69-22d9-4c5c-ffca-a4b37655688d"
      },
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1    0.112367\n",
            "7    0.104417\n",
            "3    0.102183\n",
            "2    0.099300\n",
            "9    0.099150\n",
            "0    0.098717\n",
            "6    0.098633\n",
            "8    0.097517\n",
            "4    0.097367\n",
            "5    0.090350\n",
            "Name: count, dtype: float64\n",
            "1    0.1135\n",
            "2    0.1032\n",
            "7    0.1028\n",
            "3    0.1010\n",
            "9    0.1009\n",
            "4    0.0982\n",
            "0    0.0980\n",
            "8    0.0974\n",
            "6    0.0958\n",
            "5    0.0892\n",
            "Name: count, dtype: float64\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "## plot the 4th digit in the train data\n",
        "digit = train_images[4]\n",
        "plt.imshow(digit,cmap = plt.cm.binary)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 447
        },
        "id": "RZwawNnqaMPx",
        "outputId": "d2fb095b-c462-4ab7-c60c-5b3dc14b28a1"
      },
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<matplotlib.image.AxesImage at 0x7f376ec7a510>"
            ]
          },
          "metadata": {},
          "execution_count": 4
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAG2JJREFUeJzt3X9s1PUdx/HXgfREbK8rpb2eFCyooAJdhtI1KuJoKF1GQMgm6hYwBCIrRuycpk5EnVknZszoKv6zwdxEmIlA9A8cVtvOrbCBEsZ+dLTpBAItSNJeKVIY/eyPhtsOivA97vruHc9H8k3o3ffTe/P10qdf+u23PuecEwAA/WyQ9QAAgCsTAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACaush7gXD09PTp06JDS09Pl8/msxwEAeOScU2dnp0KhkAYNuvB5zoAL0KFDh5Sfn289BgDgMh04cEAjR4684PMDLkDp6emSegfPyMgwngYA4FU4HFZ+fn7k6/mFJCxA1dXVeumll9Ta2qrCwkK9+uqrmjJlykXXnf1nt4yMDAIEAEnsYt9GSchFCBs3blRFRYVWrlypTz75RIWFhSotLdWRI0cS8XIAgCSUkACtXr1aixcv1kMPPaRbbrlFr7/+uq655hr96le/SsTLAQCSUNwDdOrUKe3atUslJSX/e5FBg1RSUqKGhobz9u/u7lY4HI7aAACpL+4B+vzzz3XmzBnl5uZGPZ6bm6vW1tbz9q+qqlIgEIhsXAEHAFcG8x9EraysVEdHR2Q7cOCA9UgAgH4Q96vgsrOzNXjwYLW1tUU93tbWpmAweN7+fr9ffr8/3mMAAAa4uJ8BpaWlafLkyaqpqYk81tPTo5qaGhUXF8f75QAASSohPwdUUVGhBQsW6LbbbtOUKVP08ssvq6urSw899FAiXg4AkIQSEqD77rtPR48e1TPPPKPW1lZ99atf1datW8+7MAEAcOXyOeec9RD/LxwOKxAIqKOjgzshAEASutSv4+ZXwQEArkwECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMBE3AP07LPPyufzRW3jx4+P98sAAJLcVYn4pLfeeqs++OCD/73IVQl5GQBAEktIGa666ioFg8FEfGoAQIpIyPeA9u3bp1AopDFjxujBBx/U/v37L7hvd3e3wuFw1AYASH1xD1BRUZHWrVunrVu3as2aNWppadFdd92lzs7OPvevqqpSIBCIbPn5+fEeCQAwAPmccy6RL9De3q7Ro0dr9erVWrRo0XnPd3d3q7u7O/JxOBxWfn6+Ojo6lJGRkcjRAAAJEA6HFQgELvp1POFXB2RmZuqmm25SU1NTn8/7/X75/f5EjwEAGGAS/nNAx48fV3Nzs/Ly8hL9UgCAJBL3AD3++OOqq6vTv//9b/3pT3/Svffeq8GDB+v++++P90sBAJJY3P8J7uDBg7r//vt17NgxjRgxQnfeeae2b9+uESNGxPulAABJLO4B2rBhQ7w/JQAgBXEvOACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADARMJ/IR2QTHbs2OF5zW9+8xvPa+rr6z2v2bt3r+c1sfrZz37meU0oFPK85g9/+IPnNd/73vc8rykqKvK8BonHGRAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMcDdspKSNGzfGtO7RRx/1vObo0aOe1zjnPK+ZNm2a5zWff/655zWS9Pjjj8e0zqtYjkMsf6cNGzZ4XoPE4wwIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADDBzUjRr/7zn/94XvOXv/zF85rFixd7XiNJXV1dntfcfffdntesWLHC85o777zT85ru7m7PayTpO9/5juc177//fkyv5dVtt93WL6+DxOMMCABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwwc1I0a9++9vfel6zaNGiBEzStxkzZnhes3HjRs9rMjIyPK+JRSyzSf13Y9H8/HzPaxYsWJCASWCBMyAAgAkCBAAw4TlA9fX1mjVrlkKhkHw+nzZv3hz1vHNOzzzzjPLy8jR06FCVlJRo37598ZoXAJAiPAeoq6tLhYWFqq6u7vP5VatW6ZVXXtHrr7+uHTt2aNiwYSotLdXJkycve1gAQOrwfBFCWVmZysrK+nzOOaeXX35ZTz/9tGbPni1JeuONN5Sbm6vNmzdr/vz5lzctACBlxPV7QC0tLWptbVVJSUnksUAgoKKiIjU0NPS5pru7W+FwOGoDAKS+uAaotbVVkpSbmxv1eG5ubuS5c1VVVSkQCES2WC7LBAAkH/Or4CorK9XR0RHZDhw4YD0SAKAfxDVAwWBQktTW1hb1eFtbW+S5c/n9fmVkZERtAIDUF9cAFRQUKBgMqqamJvJYOBzWjh07VFxcHM+XAgAkOc9XwR0/flxNTU2Rj1taWrR7925lZWVp1KhRWr58uV544QXdeOONKigo0IoVKxQKhTRnzpx4zg0ASHKeA7Rz507dc889kY8rKiok9d6fad26dXriiSfU1dWlJUuWqL29XXfeeae2bt2qq6++On5TAwCSns8556yH+H/hcFiBQEAdHR18P2iAe/rppz2v+clPfuJ5jc/n87ymvLzc8xpJeuGFFzyvGcjv05tvvjmmdf/617/iPEnf3nnnHc9rzv6MIQauS/06bn4VHADgykSAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATnn8dA1LP888/H9O6WO5s7ff7Pa8pLS31vObFF1/0vEaShg4dGtM6r06ePOl5ze9//3vPaz777DPPayQplpvkr1ixwvMa7mx9ZeMMCABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwwc1IU0x7e7vnNa+99lpMr+Xz+TyvieXGops3b/a8pj81NTV5XvPggw96XrNz507Pa2L17W9/2/OaJ554IgGTIJVxBgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmOBmpCnm1KlTntccPXo0AZP07ZVXXvG85siRI57XrF271vMaSdqyZYvnNX/72988r+ns7PS8Jpabvw4aFNv/Y373u9/1vGbYsGExvRauXJwBAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmuBlpiklLS/O8JicnJ6bXiuUmoddff73nNbHchLM/XXfddZ7XZGRkeF5z6NAhz2uys7M9r5GkWbNmxbQO8IIzIACACQIEADDhOUD19fWaNWuWQqGQfD6fNm/eHPX8woUL5fP5oraZM2fGa14AQIrwHKCuri4VFhaqurr6gvvMnDlThw8fjmxvvfXWZQ0JAEg9ni9CKCsrU1lZ2Zfu4/f7FQwGYx4KAJD6EvI9oNraWuXk5GjcuHFaunSpjh07dsF9u7u7FQ6HozYAQOqLe4BmzpypN954QzU1NXrxxRdVV1ensrIynTlzps/9q6qqFAgEIlt+fn68RwIADEBx/zmg+fPnR/48ceJETZo0SWPHjlVtba2mT59+3v6VlZWqqKiIfBwOh4kQAFwBEn4Z9pgxY5Sdna2mpqY+n/f7/crIyIjaAACpL+EBOnjwoI4dO6a8vLxEvxQAIIl4/ie448ePR53NtLS0aPfu3crKylJWVpaee+45zZs3T8FgUM3NzXriiSd0ww03qLS0NK6DAwCSm+cA7dy5U/fcc0/k47Pfv1mwYIHWrFmjPXv26Ne//rXa29sVCoU0Y8YM/fjHP5bf74/f1ACApOc5QNOmTZNz7oLPv//++5c1EC5PZmam5zXn3s3iUn3rW9/yvObLLsm/kBtuuMHzmtmzZ3teI/XeycOrrKwsz2v+/2KdSxXLzUhjeR2gv3AvOACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJiI+6/kRvIpKiqKad3Ro0fjPElyqq+v97ymrq7O8xqfz+d5zZgxYzyvAfoLZ0AAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAluRgpcpi+++MLzmlhuLBrLmvnz53teA/QXzoAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABPcjBS4TKWlpdYjAEmJMyAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQ3IwUu0/vvv289ApCUOAMCAJggQAAAE54CVFVVpdtvv13p6enKycnRnDlz1NjYGLXPyZMnVV5eruHDh+vaa6/VvHnz1NbWFtehAQDJz1OA6urqVF5eru3bt2vbtm06ffq0ZsyYoa6ursg+jz32mN599129/fbbqqur06FDhzR37ty4Dw4ASG6eLkLYunVr1Mfr1q1TTk6Odu3apalTp6qjo0O//OUvtX79en3jG9+QJK1du1Y333yztm/frq9//evxmxwAkNQu63tAHR0dkqSsrCxJ0q5du3T69GmVlJRE9hk/frxGjRqlhoaGPj9Hd3e3wuFw1AYASH0xB6inp0fLly/XHXfcoQkTJkiSWltblZaWpszMzKh9c3Nz1dra2ufnqaqqUiAQiGz5+fmxjgQASCIxB6i8vFx79+7Vhg0bLmuAyspKdXR0RLYDBw5c1ucDACSHmH4QddmyZXrvvfdUX1+vkSNHRh4PBoM6deqU2tvbo86C2traFAwG+/xcfr9ffr8/ljEAAEnM0xmQc07Lli3Tpk2b9OGHH6qgoCDq+cmTJ2vIkCGqqamJPNbY2Kj9+/eruLg4PhMDAFKCpzOg8vJyrV+/Xlu2bFF6enrk+zqBQEBDhw5VIBDQokWLVFFRoaysLGVkZOiRRx5RcXExV8ABAKJ4CtCaNWskSdOmTYt6fO3atVq4cKEk6ec//7kGDRqkefPmqbu7W6WlpXrttdfiMiwAIHV4CpBz7qL7XH311aqurlZ1dXXMQwHJpLm52XoEIClxLzgAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYiOk3ogL4n7vuusvzmku5szyQ6jgDAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMcDNS4DJNnDjR85obb7zR85rm5uZ+WSNJI0aMiGkd4AVnQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACW5GChh46qmnPK9ZtGhRv7yOJP3iF7/wvOaWW26J6bVw5eIMCABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwwc1IAQNz5871vGbDhg2e12zbts3zGkl69tlnPa9Zu3at5zXDhg3zvAapgzMgAIAJAgQAMOEpQFVVVbr99tuVnp6unJwczZkzR42NjVH7TJs2TT6fL2p7+OGH4zo0ACD5eQpQXV2dysvLtX37dm3btk2nT5/WjBkz1NXVFbXf4sWLdfjw4ci2atWquA4NAEh+ni5C2Lp1a9TH69atU05Ojnbt2qWpU6dGHr/mmmsUDAbjMyEAICVd1veAOjo6JElZWVlRj7/55pvKzs7WhAkTVFlZqRMnTlzwc3R3dyscDkdtAIDUF/Nl2D09PVq+fLnuuOMOTZgwIfL4Aw88oNGjRysUCmnPnj168skn1djYqHfeeafPz1NVVaXnnnsu1jEAAEkq5gCVl5dr7969+vjjj6MeX7JkSeTPEydOVF5enqZPn67m5maNHTv2vM9TWVmpioqKyMfhcFj5+fmxjgUASBIxBWjZsmV67733VF9fr5EjR37pvkVFRZKkpqamPgPk9/vl9/tjGQMAkMQ8Bcg5p0ceeUSbNm1SbW2tCgoKLrpm9+7dkqS8vLyYBgQApCZPASovL9f69eu1ZcsWpaenq7W1VZIUCAQ0dOhQNTc3a/369frmN7+p4cOHa8+ePXrsscc0depUTZo0KSF/AQBAcvIUoDVr1kjq/WHT/7d27VotXLhQaWlp+uCDD/Tyyy+rq6tL+fn5mjdvnp5++um4DQwASA2e/wnuy+Tn56uuru6yBgIAXBl87mJV6WfhcFiBQEAdHR3KyMiwHgcYMGL5Gbkf/ehHMb3Wa6+95nnNX//6V89rbrnlFs9rMPBd6tdxbkYKADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJjgZqQAgLjiZqQAgAGNAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACAiausBzjX2VvThcNh40kAALE4+/X7YrcaHXAB6uzslCTl5+cbTwIAuBydnZ0KBAIXfH7A3Q27p6dHhw4dUnp6unw+X9Rz4XBY+fn5OnDgwBV9p2yOQy+OQy+OQy+OQ6+BcBycc+rs7FQoFNKgQRf+Ts+AOwMaNGiQRo4c+aX7ZGRkXNFvsLM4Dr04Dr04Dr04Dr2sj8OXnfmcxUUIAAATBAgAYCKpAuT3+7Vy5Ur5/X7rUUxxHHpxHHpxHHpxHHol03EYcBchAACuDEl1BgQASB0ECABgggABAEwQIACAiaQJUHV1ta6//npdffXVKioq0p///Gfrkfrds88+K5/PF7WNHz/eeqyEq6+v16xZsxQKheTz+bR58+ao551zeuaZZ5SXl6ehQ4eqpKRE+/btsxk2gS52HBYuXHje+2PmzJk2wyZIVVWVbr/9dqWnpysnJ0dz5sxRY2Nj1D4nT55UeXm5hg8frmuvvVbz5s1TW1ub0cSJcSnHYdq0aee9Hx5++GGjifuWFAHauHGjKioqtHLlSn3yyScqLCxUaWmpjhw5Yj1av7v11lt1+PDhyPbxxx9bj5RwXV1dKiwsVHV1dZ/Pr1q1Sq+88opef/117dixQ8OGDVNpaalOnjzZz5Mm1sWOgyTNnDkz6v3x1ltv9eOEiVdXV6fy8nJt375d27Zt0+nTpzVjxgx1dXVF9nnsscf07rvv6u2331ZdXZ0OHTqkuXPnGk4df5dyHCRp8eLFUe+HVatWGU18AS4JTJkyxZWXl0c+PnPmjAuFQq6qqspwqv63cuVKV1hYaD2GKUlu06ZNkY97enpcMBh0L730UuSx9vZ25/f73VtvvWUwYf849zg459yCBQvc7NmzTeaxcuTIESfJ1dXVOed6/9sPGTLEvf3225F9/vGPfzhJrqGhwWrMhDv3ODjn3N133+0effRRu6EuwYA/Azp16pR27dqlkpKSyGODBg1SSUmJGhoaDCezsW/fPoVCIY0ZM0YPPvig9u/fbz2SqZaWFrW2tka9PwKBgIqKiq7I90dtba1ycnI0btw4LV26VMeOHbMeKaE6OjokSVlZWZKkXbt26fTp01Hvh/Hjx2vUqFEp/X449zic9eabbyo7O1sTJkxQZWWlTpw4YTHeBQ24m5Ge6/PPP9eZM2eUm5sb9Xhubq7++c9/Gk1lo6ioSOvWrdO4ceN0+PBhPffcc7rrrru0d+9epaenW49norW1VZL6fH+cfe5KMXPmTM2dO1cFBQVqbm7WU089pbKyMjU0NGjw4MHW48VdT0+Pli9frjvuuEMTJkyQ1Pt+SEtLU2ZmZtS+qfx+6Os4SNIDDzyg0aNHKxQKac+ePXryySfV2Niod955x3DaaAM+QPifsrKyyJ8nTZqkoqIijR49Wr/73e+0aNEiw8kwEMyfPz/y54kTJ2rSpEkaO3asamtrNX36dMPJEqO8vFx79+69Ir4P+mUudByWLFkS+fPEiROVl5en6dOnq7m5WWPHju3vMfs04P8JLjs7W4MHDz7vKpa2tjYFg0GjqQaGzMxM3XTTTWpqarIexczZ9wDvj/ONGTNG2dnZKfn+WLZsmd577z199NFHUb++JRgM6tSpU2pvb4/aP1XfDxc6Dn0pKiqSpAH1fhjwAUpLS9PkyZNVU1MTeaynp0c1NTUqLi42nMze8ePH1dzcrLy8POtRzBQUFCgYDEa9P8LhsHbs2HHFvz8OHjyoY8eOpdT7wzmnZcuWadOmTfrwww9VUFAQ9fzkyZM1ZMiQqPdDY2Oj9u/fn1Lvh4sdh77s3r1bkgbW+8H6KohLsWHDBuf3+926devc3//+d7dkyRKXmZnpWltbrUfrVz/4wQ9cbW2ta2lpcX/84x9dSUmJy87OdkeOHLEeLaE6Ozvdp59+6j799FMnya1evdp9+umn7rPPPnPOOffTn/7UZWZmui1btrg9e/a42bNnu4KCAvfFF18YTx5fX3YcOjs73eOPP+4aGhpcS0uL++CDD9zXvvY1d+ONN7qTJ09ajx43S5cudYFAwNXW1rrDhw9HthMnTkT2efjhh92oUaPchx9+6Hbu3OmKi4tdcXGx4dTxd7Hj0NTU5J5//nm3c+dO19LS4rZs2eLGjBnjpk6dajx5tKQIkHPOvfrqq27UqFEuLS3NTZkyxW3fvt16pH533333uby8PJeWluauu+46d99997mmpibrsRLuo48+cpLO2xYsWOCc670Ue8WKFS43N9f5/X43ffp019jYaDt0AnzZcThx4oSbMWOGGzFihBsyZIgbPXq0W7x4ccr9T1pff39Jbu3atZF9vvjiC/f973/ffeUrX3HXXHONu/fee93hw4fthk6Aix2H/fv3u6lTp7qsrCzn9/vdDTfc4H74wx+6jo4O28HPwa9jAACYGPDfAwIApCYCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwMR/AQdKtRnTmOhjAAAAAElFTkSuQmCC\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "## check the pixels are in [0,255]\n",
        "print(train_images.min())\n",
        "print(train_images.max())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "GWi76BwdaQ6r",
        "outputId": "0d939930-59ba-4f19-87dc-127cdd5a89b3"
      },
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "0\n",
            "255\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## preparing the image data\n",
        "\n",
        "## change the 28 by 28 images to a 28^2 vector\n",
        "## change the type to double\n",
        "\n",
        "train_images = train_images.reshape((ntr,28*28))\n",
        "train_images = train_images.astype(\"float32\")/255\n",
        "test_images = test_images.reshape((nte,28*28))\n",
        "test_images = test_images.astype(\"float32\")/255"
      ],
      "metadata": {
        "id": "xIUy1tkIaTf3"
      },
      "execution_count": 6,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## model\n",
        "\n",
        "model = keras.Sequential([\n",
        "   layers.Dense(512,activation=\"relu\"),\n",
        "   #layers.Dense(512,activation=\"relu\",kernel_regularizer=regularizers.l1(0.1)),\n",
        "   layers.Dense(10,activation=\"softmax\")\n",
        "])\n"
      ],
      "metadata": {
        "id": "aFIAFKs4aWnI"
      },
      "execution_count": 7,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## compilaton step\n",
        "\n",
        "model.compile(optimizer = \"rmsprop\",\n",
        "   loss = \"sparse_categorical_crossentropy\",\n",
        "   metrics = [\"accuracy\"])"
      ],
      "metadata": {
        "id": "PUcBq5eoaaPV"
      },
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## fit\n",
        "\n",
        "nhist = model.fit(train_images,train_labels, epochs = 10, batch_size = 128, validation_data = (test_images,test_labels))\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "gTH3-y6fafJW",
        "outputId": "db79c29c-d8d8-499c-e7e3-be9166a0285b"
      },
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 15ms/step - accuracy: 0.8740 - loss: 0.4287 - val_accuracy: 0.9606 - val_loss: 0.1318\n",
            "Epoch 2/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 10ms/step - accuracy: 0.9657 - loss: 0.1146 - val_accuracy: 0.9740 - val_loss: 0.0848\n",
            "Epoch 3/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 13ms/step - accuracy: 0.9785 - loss: 0.0717 - val_accuracy: 0.9770 - val_loss: 0.0770\n",
            "Epoch 4/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 10ms/step - accuracy: 0.9844 - loss: 0.0504 - val_accuracy: 0.9779 - val_loss: 0.0716\n",
            "Epoch 5/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 13ms/step - accuracy: 0.9891 - loss: 0.0373 - val_accuracy: 0.9801 - val_loss: 0.0630\n",
            "Epoch 6/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 10ms/step - accuracy: 0.9927 - loss: 0.0266 - val_accuracy: 0.9788 - val_loss: 0.0711\n",
            "Epoch 7/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 13ms/step - accuracy: 0.9938 - loss: 0.0230 - val_accuracy: 0.9802 - val_loss: 0.0636\n",
            "Epoch 8/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 10ms/step - accuracy: 0.9961 - loss: 0.0155 - val_accuracy: 0.9827 - val_loss: 0.0629\n",
            "Epoch 9/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m5s\u001b[0m 11ms/step - accuracy: 0.9968 - loss: 0.0124 - val_accuracy: 0.9811 - val_loss: 0.0627\n",
            "Epoch 10/10\n",
            "\u001b[1m469/469\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 9ms/step - accuracy: 0.9980 - loss: 0.0095 - val_accuracy: 0.9814 - val_loss: 0.0633\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## predictions\n",
        "## just do first 10\n",
        "\n",
        "test_digits = test_images[0:10]\n",
        "predictions = model.predict(test_digits)\n",
        "\n",
        "# for each test image you get a probability vector\n",
        "print(type(predictions))\n",
        "print(predictions.shape)\n",
        "print(predictions.dtype)\n",
        "\n",
        "## should sum to 1\n",
        "print(predictions.sum(axis=1))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-cj17ETJai2c",
        "outputId": "877cf916-f28f-4bd0-b9a4-a21aae90697e"
      },
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 64ms/step\n",
            "<class 'numpy.ndarray'>\n",
            "(10, 10)\n",
            "float32\n",
            "[1.         0.99999994 1.         0.99999994 0.99999994 0.99999994\n",
            " 0.9999999  1.0000001  1.         1.        ]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "#  get predictions from biggest probability\n",
        "ypred = predictions.argmax(axis=1)\n",
        "print(ypred[:2])\n",
        "print(predictions[:2])"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "53kROxxka7hr",
        "outputId": "1948cb0d-17fb-4021-8237-2dc5a56bebc5"
      },
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[7 2]\n",
            "[[2.9927512e-11 1.2473622e-11 5.8623346e-09 2.9447915e-07 1.7770882e-14\n",
            "  2.4283412e-12 2.3309925e-15 9.9999970e-01 1.1810013e-11 5.8658493e-08]\n",
            " [3.7176550e-11 1.4711712e-07 9.9999970e-01 7.7161786e-08 6.4254966e-17\n",
            "  1.4121517e-09 2.5172477e-11 4.9320357e-16 4.0443670e-08 1.2140632e-16]]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "## Evaluating the model on new data\n",
        "\n",
        "test_loss , test_acc = model.evaluate(test_images, test_labels)\n",
        "print(f'test acc: {test_acc}')"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "E09x4Ykta-9X",
        "outputId": "56fb3c53-eb63-492c-c09f-137b3d0993e7"
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 5ms/step - accuracy: 0.9778 - loss: 0.0789\n",
            "test acc: 0.9814000129699707\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "### plot fitting by SGD\n",
        "trL = nhist.history['loss'] # loss on train\n",
        "teL = nhist.history['val_loss'] # loss on val\n",
        "\n",
        "epind = range(1,len(teL)+1)\n",
        "plt.plot(epind,trL,\"r--\")\n",
        "#plt.plot(epind,teL,\"b--\")\n",
        "plt.plot(epind,teL,color='black', linestyle='dashed')\n",
        "plt.xlabel(\"epoch number\"); plt.ylabel(\"cross entropy loss\")\n",
        "plt.legend(['train','test'])"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 466
        },
        "id": "D-Ld7-vybBjB",
        "outputId": "b02fe9dc-d398-4bb2-da74-dfc8207c894d"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<matplotlib.legend.Legend at 0x7f37697c0e90>"
            ]
          },
          "metadata": {},
          "execution_count": 13
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAGwCAYAAABB4NqyAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAX11JREFUeJzt3XlcVXX+x/HXZUdRXFAQQzGX3HFBcSubCZcy07I0s9TyV5NlpWal07iUlctYWqNpi6XOtNi02GJpSrnhghvuW+augLiAogLC+f1xhos30LjK5QD3/Xw8zgPuOd97zudCM7z9nu/5fm2GYRiIiIiIuBEPqwsQERERKWoKQCIiIuJ2FIBERETE7SgAiYiIiNtRABIRERG3owAkIiIibkcBSERERNyOl9UFFEfZ2dkcP36ccuXKYbPZrC5HRERECsAwDM6dO0doaCgeHtfu41EAysfx48cJCwuzugwRERG5DkeOHOGmm266ZhsFoHyUK1cOMH+A5cuXt7gaERERKYjU1FTCwsLsf8evRQEoHzm3vcqXL68AJCIiUsIUZPiKBkGLiIiI21EAEhEREbejACQiIiJuR2OAREREilB2djYZGRlWl1EieXt74+npWSjnUgASEREpIhkZGRw4cIDs7GyrSymxKlSoQEhIyA3P06cAJCIiUgQMw+DEiRN4enoSFhb2pxP1iSPDMLhw4QJJSUkAVKtW7YbOpwAkIiJSBC5fvsyFCxcIDQ2lTJkyVpdTIvn7+wOQlJRE1apVb+h2mOKniIhIEcjKygLAx8fH4kpKtpzwmJmZeUPnUQASEREpQlpj8sYU1s9PAUhERETcjgKQiIiIuB0FIBERESkS4eHhTJs2zeoyAD0FJiIiItdw++2306xZs0IJLuvXr6ds2bI3XlQhUA9QUTt9GnbutLoKERGRQmEYBpcvXy5Q2ypVqhSbKQAUgIrSd99B5crw6KNWVyIiIsVFWtrVt0uXCt724sWCtXXCwIEDWb58OW+//TY2mw2bzcacOXOw2Wz89NNPtGzZEl9fX1atWsX+/fvp0aMHwcHBBAQE0KpVK5YuXepwvj/eArPZbHz44Yfce++9lClThrp16/Ldd985VeP1UgAqSs2bm183boRz56ytRUREioeAgKtvvXo5tq1a9ept77zTsW14eP7tnPD222/Ttm1bHn/8cU6cOMGJEycICwsDYOTIkUycOJFdu3bRtGlTzp8/z1133UVMTAybN2+ma9eudO/encOHD1/zGq+88gq9e/dm69at3HXXXfTr14/Tp087Vef1UAAqSmFh5n+QWVmwerXV1YiIiFxTYGAgPj4+lClThpCQEEJCQuyzL7/66qt06tSJ2rVrU6lSJSIiIvjb3/5G48aNqVu3LuPHj6d27dp/2qMzcOBA+vbtS506dXjjjTc4f/48cXFxLv9sGgRd1Dp2hIMHYcUK6NLF6mpERMRq589f/dgfl3r43zpY+frj2mIHD153SQURGRnp8Pr8+fOMGzeOhQsXcuLECS5fvszFixf/tAeoadOm9u/Lli1L+fLl7et9uZICUFHr2BHmzoXly62uREREigNnnopyVdvr8MenuUaMGMGSJUuYMmUKderUwd/fn/vvv5+MjIxrnsfb29vhtc1mIzs7u9Dr/SMFoKJ2223m17g4uHABisloeBERkfz4+PjY1zG7ltjYWAYOHMi9994LmD1CB13cC3UjNAaoqN18M1SvDpmZsG6d1dWIiIhcU3h4OOvWrePgwYMkJydftXembt26fP3118THx7NlyxYeeuihIunJuV4KQEXNZoN//ANmz4ZGjayuRkRE5JpGjBiBp6cnDRs2pEqVKlcd0/PWW29RsWJF2rVrR/fu3enSpQstWrQo4moLzmYYhmF1EcVNamoqgYGBpKSkUL58eavLERGRUuDSpUscOHCAWrVq4efnZ3U5Jda1fo7O/P0uFj1AM2bMIDw8HD8/P6Kioq75+NsHH3zArbfeSsWKFalYsSLR0dF52g8cONA+YVPO1rVrV1d/DBERESkhLA9A8+fPZ/jw4YwdO5ZNmzYRERFBly5drvoI3LJly+jbty+//vora9asISwsjM6dO3Ps2DGHdl27drVP2nTixAk+++yzovg4BbdjB7zzjvlVREREipTlAeitt97i8ccf59FHH6Vhw4bMmjWLMmXK8NFHH+Xb/pNPPuGpp56iWbNm1K9fnw8//JDs7GxiYmIc2vn6+tonbQoJCaFixYpF8XEKbtw4eO45WLDA6kpERETcjqUBKCMjg40bNxIdHW3f5+HhQXR0NGvWrCnQOS5cuEBmZiaVKlVy2L9s2TKqVq3KLbfcwuDBgzl16tRVz5Genk5qaqrD5nIdO5pfV6xw/bVERETEgaUBKDk5mays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L5gzB3x9qfbhh9zzzjvcM2sWjB+PYRjYrlhVPiAggDp16nDgwAEuXrzItm3b2LZtm/34X//6V3sAeu+99/jll1+oW7euwxYUFORwThERKd4UgKT08vCA994DPz+YPt2++49BZdSoUYwaNYrMzEwOHjzIvn372LdvH3v37uX333+3z1kEsGzZMr744os8lwoMDKRu3bosXLiQqlWrAnDixAn8/PzUeyQiUgxpDFA+NAaolDEMiI2FDh1u+FQrVqxg/fr19pC0b98+jhwxRxl5eXlx8eJFvP63cv3DDz/MJ598QlBQUJ4eo7p16xIREYGnp+cN1yQiIiaNARK5ks3mGH6Sk+HLL+HJJ50+1W233cZtt93msO/ixYvs37+fY8eO2cMPwJkzZ/53uWSSk5MdFov19PTkwoUL9gA0e/ZskpKS7OGoTp06DhNGiohI4VIAEveSng6dOkF8PBw9as4efYNjd/z9/WncuDGNGzd22L9w4ULOnTvHb7/95tBjtG/fPrKyshwew//www9Zu3atw/urV69O3bp1qV+/Pu+++6791l12draeVBMRuUEKQOJefH2hXz8zAL3+Oly6BP/85w2HoKspV64czZs3NydovIbevXtTp04de0A6ffo0x44d49ixYxw8eNBh3NJf//pXDh48mO8ttSvHK4mIyNVpDFA+NAbIDUyfDs88Y37fpw9Mngx/mHnaSqdOnXLoLRo4cKD9WEhICImJifm+r0mTJmzZssUemP74xJu4VlpaGikpKYSGhtr3nT59mkqVKllYlYj70ESIN0gByE18+CE88YQ5SNrXF4YMgYkTzUfoi7HExMQ8t9T27t3Ljh076Ny5Mz/++KO9bbNmzQgJCaF9+/a0b9+eqKgojS0qJNnZ2ezbt4+1a9fat61bt/Lggw/yySefAJCVlUVgYCDly5cnMjKSli1bEhkZSWRkJMHBwRZ/ApHSRwHoBikAuZH16+HFF2HZMnNs0M8/W13RdTt//jynTp2iZs2aABw/fpzq1as7tPH09KR58+a0b9+eu+++m+joaCtKLdGys7Pp0aMHsbGx9oHuV+rQoQMrV64EYP/+/dSrV4/s7Ow87W666SaefPJJXn75ZZfXLOIu9BSYSEG1agW//AKLF8OVYeHkSfj2Wxg4sNj3COUICAhwWPQ1ODiYzZs3s2rVKmJjY1m1ahVHjx5l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Ta1atfD396d27dqMHz++YOtEyQ1bsWIF3bt3JzQ0FJvNxoIFCxyOG4bBmDFjqFatGv7+/kRHR7Nv374iq08BSAps+fLlPP3006xdu5YlS5aQmZlJ586dSUtLs7o0t7d+/Xree+89mjZtanUpbu3MmTO0b98eb29vfvrpJ3bu3Mmbb75JxYoVrS7NLU2aNImZM2cyffp0du3axaRJk5g8eTL/+te/rC7NLaSlpREREcGMGTPyPT558mTeeecdZs2axbp16yhbtixdunTh0qVLRVKfHoOX63by5EmqVq3K8uXLue2226wux22dP3+eFi1a8O677/Laa6/RrFkzpk2bZnVZbmnkyJHExsaycuVKq0sR4O677yY4OJjZs2fb9/Xq1Qt/f3/+85//WFiZ+7HZbHzzzTf07NkTMHt/QkNDef755xkxYgQAKSkpBAcHM2fOHB588EGX16QeILluKSkpAFSqVMniStzb008/Tbdu3YiOjra6FLf33XffERkZyQMPPEDVqlVp3rw5H3zwgdVlua127doRExPD3r17AdiyZQurVq3izjvvtLgyOXDgAAkJCQ7/vxUYGEhUVBRr1qwpkhosXw1eSqbs7GyGDh1K+/btady4sdXluK3PP/+cTZs2sX79eqtLEeD3339n5syZDB8+nL///e+sX7+eZ599Fh8fHwYMGGB1eW5n5MiRpKamUr9+fTw9PcnKyuL111+nX79+Vpfm9hISEgAIDg522B8cHGw/5moKQHJdnn76abZv386qVausLsVtHTlyhOeee44lS5bg5+dndTmC+Q+DyMhI3njjDQCaN2/O9u3bmTVrlgKQBb744gs++eQTPv30Uxo1akR8fDxDhw4lNDRUvw/RLTBx3pAhQ/jhhx/49ddfuemmm6wux21t3LiRpKQkWrRogZeXF15eXixfvpx33nkHLy8vsrKyrC7R7VSrVo2GDRs67GvQoAGHDx+2qCL39sILLzBy5EgefPBBmjRpwiOPPMKwYcOYMGGC1aW5vZCQEAASExMd9icmJtqPuZoCkBSYYRgMGTKEb775hl9++YVatWpZXZJbu+OOO9i2bRvx8fH2LTIykn79+hEfH4+np6fVJbqd9u3b55kaYu/evdSsWdOiitzbhQsX8PBw/DPn6elJdna2RRVJjlq1ahESEkJMTIx9X2pqKuvWraNt27ZFUoNugUmBPf3003z66ad8++23lCtXzn6fNjAwEH9/f4urcz/lypXLM/6qbNmyVK5cWeOyLDJs2DDatWvHG2+8Qe/evYmLi+P999/n/ffft7o0t9S9e3def/11atSoQaNGjdi8eTNvvfUWjz32mNWluYXz58/z22+/2V8fOHCA+Ph4KlWqRI0aNRg6dCivvfYadevWpVatWowePZrQ0FD7k2IuZ4gUEJDv9vHHH1tdmvxPx44djeeee87qMtza999/bzRu3Njw9fU16tevb7z//vtWl+S2UlNTjeeee86oUaOG4efnZ9x8883Gyy+/bKSnp1tdmlv49ddf8/2bMWDAAMMwDCM7O9sYPXq0ERwcbPj6+hp33HGHsWfPniKrT/MAiYiIiNvRGCARERFxOwpAIiIi4nYUgERERMTtKACJiIiI21EAEhEREbejACQiIiJuRwFIRERE3I4CkIiIiLgdBSARKXGWLVuGzWbj7NmzVpdSIAcPHsRmsxEfH291KSLyPwpAIiIi4nYUgERESqiMjAyrSxApsRSARMQp2dnZTJgwgVq1auHv709ERARffvml/XjO7amFCxfStGlT/Pz8aNOmDdu3b3c4z1dffUWjRo3w9fUlPDycN9980+F4eno6L730EmFhYfj6+lKnTh1mz57t0Gbjxo1ERkZSpkwZ2rVrx549e65ad85tqK+//pq//OUvlClThoiICNasWWNvM27cOJo1a+bwvmnTphEeHm5/PXDgQHr27Mkbb7xBcHAwFSpU4NVXX+Xy5cu88MILVKpUiZtuuomPP/44Tw27d++mXbt2+Pn50bhxY5YvX+5wfPv27dx5550EBAQQHBzMI488QnJysv347bffzpAhQxg6dChBQUF06dLlqp9XRK5NAUhEnDJhwgTmzZvHrFmz2LFjB8OGDePhhx/O88f8hRde4M0332T9+vVUqVKF7t27k5mZCZjBpXfv3jz44INs27aNcePGMXr0aObMmWN/f//+/fnss89455132LVrF++99x4BAQEO13j55Zd588032bBhA15eXjz22GN/Wv/LL7/MiBEjiI+Pp169evTt25fLly879TP45ZdfOH78OCtWrOCtt95i7Nix3H333VSsWJF169bx5JNP8re//Y2jR4/m+Zk8//zzbN68mbZt29K9e3dOnToFwNmzZ/nrX/9K8+bN2bBhA4sWLSIxMZHevXs7nGPu3Ln4+PgQGxvLrFmznKpbRK5QZOvOi0iJd+nSJaNMmTLG6tWrHfYPGjTI6Nu3r2EYhvHrr78agPH555/bj586dcrw9/c35s+fbxiGYTz00ENGp06dHM7xwgsvGA0bNjQMwzD27NljAMaSJUvyrSPnGkuXLrXvW7hwoQEYFy9ezPc9Bw4cMADjww8/tO/bsWOHARi7du0yDMMwxo4da0RERDi8b+rUqUbNmjXtrwcMGGDUrFnTyMrKsu+75ZZbjFtvvdX++vLly0bZsmWNzz77zOHaEydOtLfJzMw0brrpJmPSpEmGYRjG+PHjjc6dOztc+8iRIwZg7NmzxzAMw+jYsaPRvHnzfD+fiDhHPUAiUmC//fYbFy5coFOnTgQEBNi3efPmsX//foe2bdu2tX9fqVIlbrnlFnbt2gXArl27aN++vUP79u3bs2/fPrKysoiPj8fT05OOHTtes56mTZvav69WrRoASUlJhf6eP2rUqBEeHrn/9xkcHEyTJk3srz09PalcuXKe8175M/Hy8iIyMtL+M9myZQu//vqrw8+1fv36AA4/25YtWzpVq4jkz8vqAkSk5Dh//jwACxcupHr16g7HfH19C+06/v7+BWrn7e1t/95mswHmGKXrfY+HhweGYTi0z7ltd7Vz5Jwnv31/VsuVzp8/T/fu3Zk0aVKeYzlBDaBs2bIFPqeIXJ16gESkwBo2bIivry+HDx+mTp06DltYWJhD27Vr19q/P3PmDHv37qVBgwYANGjQgNjYWIf2sbGx1KtXD09PT5o0aUJ2dnaecUWuVqVKFRISEhxCUGHO3XPlz+Ty5cts3LjR/jNp0aIFO3bsIDw8PM/PVqFHpPApAIlIgZUrV44RI0YwbNgw5s6dy/79+9m0aRP/+te/mDt3rkPbV199lZiYGLZv387AgQMJCgqiZ8+eADz//PPExMQwfvx49u7dy9y5c5k+fTojRowAIDw8nAEDBvDYY4+xYMECDhw4wLJly/jiiy9c+vluv/12Tp48yeTJk9m/fz8zZszgp59+KrTzz5gxg2+++Ybdu3fz9NNPc+bMGfvA7aeffprTp0/Tt29f1q9fz/79+1m8eDGPPvooWVlZhVaDiJgUgETEKePHj2f06NFMmDCBBg0a0LVrVxYuXEitWrUc2k2cOJHnnnuOli1bkpCQwPfff4+Pjw9g9nZ88cUXfP755zRu3JgxY8bw6quvMnDgQPv7Z86cyf33389TTz1F/fr1efzxx0lLS3PpZ2vQoAHvvvsuM2bMICIigri4OHsoKwwTJ05k4sSJREREsGrVKr777juCgoIACA0NJTY2lqysLDp37kyTJk0YOnQoFSpUcBhvJCKFw2b88Ya3iMgNWLZsGX/5y184c+YMFSpUsLocEZF86Z8VIiIi4nYUgERERMTt6BaYiIiIuB31AImIiIjbUQASERERt6MAJCIiIm5HAUhERETcjgKQiIiIuB0FIBEREXE7CkAiIiLidhSARERExO38P/4iU8Z+k3U5AAAAAElFTkSuQmCC\n"
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "##################################################\n",
        "### predictions on all test data\n",
        "ppred = model.predict(test_images)\n",
        "ypred = ppred.argmax(axis=1)\n",
        "\n",
        "##crosstab\n",
        "ctab = pd.crosstab(pd.Series(ypred),pd.Series(test_labels))\n",
        "print(ctab)\n",
        "\n",
        "print(\"the accuracy is: \",accuracy_score(ypred,test_labels))\n",
        "print(confusion_matrix(ypred,test_labels))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ppZmg-QWbHED",
        "outputId": "f4a65347-d6b5-4037-b1b9-a2ec5492b9d0"
      },
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 5ms/step\n",
            "col_0    0     1     2    3    4    5    6     7    8    9\n",
            "row_0                                                     \n",
            "0      970     0     2    0    1    2    2     0    1    1\n",
            "1        0  1126     0    0    0    0    2     5    1    2\n",
            "2        1     3  1011    3    2    0    1     8    4    0\n",
            "3        0     1     1  994    1    9    1     3    6    3\n",
            "4        1     0     4    0  969    1    3     1    6   10\n",
            "5        0     1     0    2    0  868    6     0    2    1\n",
            "6        3     2     2    0    3    4  943     0    3    1\n",
            "7        1     1     8    2    1    1    0  1005    5    4\n",
            "8        3     1     4    2    0    4    0     2  942    1\n",
            "9        1     0     0    7    5    3    0     4    4  986\n",
            "the accuracy is:  0.9814\n",
            "[[ 970    0    2    0    1    2    2    0    1    1]\n",
            " [   0 1126    0    0    0    0    2    5    1    2]\n",
            " [   1    3 1011    3    2    0    1    8    4    0]\n",
            " [   0    1    1  994    1    9    1    3    6    3]\n",
            " [   1    0    4    0  969    1    3    1    6   10]\n",
            " [   0    1    0    2    0  868    6    0    2    1]\n",
            " [   3    2    2    0    3    4  943    0    3    1]\n",
            " [   1    1    8    2    1    1    0 1005    5    4]\n",
            " [   3    1    4    2    0    4    0    2  942    1]\n",
            " [   1    0    0    7    5    3    0    4    4  986]]\n"
          ]
        }
      ]
    }
  ]
}