{ "cells": [ { "cell_type": "markdown", "id": "ee76baef-58a6-483e-8724-155765baa3ec", "metadata": {}, "source": [ "# Simple neural network trained on MNIST (Modified National Institute of Standards and Technology)" ] }, { "cell_type": "code", "execution_count": 1, "id": "ee25aae1-aa53-4f57-8a07-16ceabdcab64", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import tensorflow as tf\n", "from tensorflow.keras import layers, models\n", "\n", "import tensorflow_datasets as tfds\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "3b11f3a3-efd0-461b-b120-7b742e10bcb2", "metadata": {}, "outputs": [], "source": [ "(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()\n", "\n", "# Normalize the data\n", "x_train, x_test = x_train / 255.0, x_test / 255.0" ] }, { "cell_type": "code", "execution_count": 3, "id": "0c249fd6-4bac-450e-9a79-158936ef0e77", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "60000" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(x_train)" ] }, { "cell_type": "code", "execution_count": 4, "id": "a805ad45-0436-45d8-8220-61031b3519a9", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA8cAAAJPCAYAAABRm6ZbAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABVTElEQVR4nO3deXxN9/b/8XWQJjGGiKmXKDpQUTM3NUS5NSsV4nbSb1Unbn3VUNSQq6oDQVuK6kSr0w1RxdXeFr0d1ExrJjVXScSUEqTZvz/65Sfda+s5yTk5Oefzej4e/ug7K/usnOaTZNmxjsuyLEsAAAAAADBYEX83AAAAAACAvzEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEc58H+/fvF5XLJ5MmTvXbNVatWicvlklWrVnntmkBB4UwAuXEmgNw4E0BunInCyZjh+J133hGXyyXr16/3dys+Ub16dXG5XOqfG2+80d/toRAK9jOxcOFCSUhIkBo1akjx4sXl5ptvliFDhsipU6f83RoKqWA/E7t27ZLBgwdLbGyshIWFicvlkv379/u7LRRiwX4mRESOHDkivXv3loiICCldurTcdddd8tNPP/m7LRRSJpyJq/3tb38Tl8slAwcO9HcrBaaYvxuAd0ybNk0yMzNzZQcOHJDRo0fLnXfe6aeuAP955JFHpEqVKnLfffdJtWrV5Mcff5Tp06fLsmXLZOPGjRIeHu7vFoECtXr1annllVekTp06Urt2bdm8ebO/WwL8KjMzU9q0aSOnT5+WUaNGSUhIiEydOlVat24tmzdvlsjISH+3CPjNwoULZfXq1f5uo8AxHAeJ7t2727IJEyaIiMi9995bwN0A/pecnCxxcXG5skaNGknfvn1l/vz58vDDD/unMcBPunXrJqdOnZJSpUrJ5MmTGY5hvNdee0327Nkja9eulSZNmoiISMeOHaVu3bqSlJQkEydO9HOHgH9kZWXJkCFD5Omnn5axY8f6u50CZcyvVbvj4sWLMnbsWGnUqJGUKVNGSpQoIS1btpSVK1c6vs/UqVMlOjpawsPDpXXr1rJ161Zbzc6dOyU+Pl7KlSsnYWFh0rhxY1m8ePGf9nPu3DnZuXOnpKen5+njef/99+WGG26Q2NjYPL0/EMhn4o+DsYhIjx49RERkx44df/r+gCaQz0S5cuWkVKlSf1oHeCKQz0RycrI0adLkymAsInLLLbdI27Zt5eOPP/7T9wc0gXwmLnvppZckJydHhg4d6vb7BAuG46ucOXNG3njjDYmLi5MXX3xREhMTJS0tTdq3b6/+Dfu8efPklVdekQEDBsjIkSNl69atcscdd8ixY8eu1Gzbtk2aN28uO3bskBEjRkhSUpKUKFFCunfvLikpKdfsZ+3atVK7dm2ZPn26xx/Lpk2bZMeOHXLPPfd4/L7AZcF0JkREfvnlFxERKV++fJ7eHwi2MwHkV6CeiZycHPnhhx+kcePGtrc1bdpUUlNT5ezZs+49CcBVAvVMXHbw4EF54YUX5MUXXzTzn6BZhnj77bctEbHWrVvnWJOdnW1duHAhV3by5EmrYsWK1kMPPXQl27dvnyUiVnh4uHX48OEr+Zo1aywRsQYPHnwla9u2rRUTE2NlZWVdyXJycqzY2FjrxhtvvJKtXLnSEhFr5cqVtmzcuHEef7xDhgyxRMTavn27x+8LM5h2JizLsvr162cVLVrU2r17d57eH8HNpDMxadIkS0Ssffv2efR+MEswn4m0tDRLRKzx48fb3jZjxgxLRKydO3de8xowTzCficvi4+Ot2NjYK/8tItaAAQPcet9gwJ3jqxQtWlSuu+46Efn9bxQzMjIkOztbGjduLBs3brTVd+/eXa6//vor/920aVNp1qyZLFu2TEREMjIyZMWKFdK7d285e/aspKenS3p6upw4cULat28ve/bskSNHjjj2ExcXJ5ZlSWJiokcfR05Ojnz44YfSoEEDqV27tkfvC1wtWM6EyO//zODNN9+UIUOGsMEdeRZMZwLwhkA9E+fPnxcRkdDQUNvbwsLCctUAngjUMyEisnLlSlmwYIFMmzbNsw86iDAc/8HcuXOlXr16EhYWJpGRkRIVFSVLly6V06dP22q1H7BvuummKy+NsXfvXrEsS8aMGSNRUVG5/owbN05ERI4fP+71j+Grr76SI0eOsIgLXhEMZ+Lrr7+Wfv36Sfv27eW5557z+vVhlmA4E4A3BeKZuPzrohcuXLC9LSsrK1cN4KlAPBPZ2dny5JNPyv3335/r3+Gbhm3VV3nvvffkwQcflO7du8uwYcOkQoUKUrRoUXn++eclNTXV4+vl5OSIiMjQoUOlffv2ak2tWrXy1bNm/vz5UqRIEfn73//u9WvDLMFwJrZs2SLdunWTunXrSnJyshQrxpc95F0wnAnAmwL1TJQrV05CQ0Pl6NGjtrddzqpUqZLvx4F5AvVMzJs3T3bt2iWzZ8++MphfdvbsWdm/f79UqFBBihcvnu/HKsz4KfEqycnJUqNGDVm4cKG4XK4r+eW/lfmjPXv22LLdu3dL9erVRUSkRo0aIiISEhIi7dq1837DigsXLsiCBQskLi6OL+rIt0A/E6mpqdKhQwepUKGCLFu2TEqWLOnzx0RwC/QzAXhboJ6JIkWKSExMjKxfv972tjVr1kiNGjXY7o48CdQzcfDgQbl06ZLcfvvttrfNmzdP5s2bJykpKerLxwYTfq36KkWLFhUREcuyrmRr1qxxfAHsRYsW5fod/7Vr18qaNWukY8eOIiJSoUIFiYuLk9mzZ6t/M5mWlnbNfvKyen3ZsmVy6tQpfqUaXhHIZ+KXX36RO++8U4oUKSKfffaZREVF/en7AH8mkM8E4AuBfCbi4+Nl3bp1uQbkXbt2yYoVK6RXr15/+v6AJlDPRJ8+fSQlJcX2R0SkU6dOkpKSIs2aNbvmNYKBcXeO33rrLVm+fLktHzRokHTp0kUWLlwoPXr0kM6dO8u+fftk1qxZUqdOHcnMzLS9T61ataRFixby+OOPy4ULF2TatGkSGRkpw4cPv1IzY8YMadGihcTExEj//v2lRo0acuzYMVm9erUcPnxYtmzZ4tjr2rVrpU2bNjJu3Di3l63Mnz9fQkNDpWfPnm7VA8F6Jjp06CA//fSTDB8+XL755hv55ptvrrytYsWK8re//c2NZwcmCtYzcfr0aXn11VdFROTbb78VEZHp06dLRESEREREyMCBA915emCgYD0TTzzxhMyZM0c6d+4sQ4cOlZCQEJkyZYpUrFhRhgwZ4v4TBOME45m45ZZb5JZbblHfdsMNNwT9HeMr/LAh2y8ur153+nPo0CErJyfHmjhxohUdHW2FhoZaDRo0sJYsWWL17dvXio6OvnKty6vXJ02aZCUlJVlVq1a1QkNDrZYtW1pbtmyxPXZqaqr1wAMPWJUqVbJCQkKs66+/3urSpYuVnJx8pcYbq9dPnz5thYWFWXfffXdenyYYJNjPxLU+ttatW+fjmUOwCvYzcbkn7c/VvQOXBfuZsCzLOnTokBUfH2+VLl3aKlmypNWlSxdrz549eX3KEORMOBN/JIa9lJPLsq665w8AAAAAgIH4N8cAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMdwDAAAAAAwXjF3C10uly/7AK6pML4cN2cC/sSZAHLjTAC5cSaA3Nw5E9w5BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxivm7wYAFF5Dhw5V8/DwcDWvV6+eLYuPj/foMWfOnGnLVq9erda+++67Hl0bAAAAcMKdYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyGYwAAAACA8VyWZVluFbpcvu4FcOTmp2mBCqYz8dFHH6m5p5umfSU1NVXN27Vrp+YHDx70ZTuFAmfCbDfddJOa79y5U80HDRqk5q+++qrXevI3zkRgKFGihC2bNGmSWvvoo4+q+YYNG2xZr1691NoDBw540F1w4UwAublzJrhzDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMdwDAAAAAAwXjF/NwCgYGmbqb21lVrblPvZZ5+ptTVq1FDzrl272rKaNWuqtffee6+aP//8804tAkGhQYMGap6Tk6Pmhw8f9mU7gNsqV65sy/r376/WOn0+N2rUyJZ16dJFrZ0xY4YH3QH517BhQzVfuHChmlevXt2H3eTfnXfeact27Nih1h46dMjX7fgcd44BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxWMgFBKnGjRureY8ePdy+xrZt29S8W7duap6enm7LMjMz1drrrrtOzb///ntbdtttt6m1kZGRag4Eu/r166v5r7/+quYpKSk+7Aawi4qKUvO5c+cWcCdAwWrfvr2ah4aGFnAn3qEtSn3ooYfU2j59+vi6HZ/jzjEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgBt606Pj5ezfv376/mP//8sy3LyspSa+fPn6/mv/zyi5rv3btXzYHCoHLlymrucrlsmdNWaqeNi0ePHs17Y/9nyJAhal6nTh23r7F06dJ89wEUdnXr1rVlAwcOVGvfffddX7cD5PLkk0+qeffu3dW8adOmPumjVatWal6kiH4faMuWLWr+3//+12s9IbgVK6aPUZ06dSrgTnxrw4YNtuypp55Sa0uUKKHmTq+kUBhx5xgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYLyA21b90ksvqXn16tXzfe1HH31Uzc+ePavmTht+C7PDhw+rudPzun79el+2Ax/69NNP1bxWrVq2zOlzPCMjw6s9Xa1Pnz5qHhIS4rPHBALRLbfcYsucNoJ+9NFHvm4HyGXq1KlqnpOTU6B93H333R7lBw4cUPOEhARbpm3rBdq0aaPmf/3rX9Xc6Wftwq5s2bK2zOmVRYoXL67mbKsGAAAAACCAMBwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAG3kKt///5qXq9ePTXfsWOHLatdu7Za27BhQzWPi4tT8+bNm9uyQ4cOqbVVq1ZVc09kZ2ereVpamppXrlzZ7WsfPHhQzVnIFXyclpD4yrBhw9T8pptucvsaa9as8SgHgsnw4cNtmdM55ms2fGXZsmVqXqRIwd9nOXHihC3LzMxUa6Ojo9X8hhtuUPO1a9fasqJFi3rQHYJR3bp1bdkHH3yg1qampqr5xIkTvdpTQbnrrrv83UKB4s4xAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4Abet+ssvv/Qo1yxfvtyjxyxbtqya169f35Zt2LBBrW3SpIlHj6nJyspS8927d6u5tqm7XLlyaq3TZj3AE126dLFl48ePV2uvu+46NT9+/LgtGzlypFp77tw5D7oDCrfq1aureePGjW2Z09f9X3/91ZstwVCtW7e2ZTfffLNam5OT41HuiVmzZqn5559/bstOnz6t1t5xxx1q/swzz7jdx+OPP67mM2fOdPsaCGyjR4+2ZSVKlFBrO3TooOZOG9ULC6cZQft64I3zXVhx5xgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYLyA21btDydPnlTzlStXun0NT7Zpe6pnz55qrm3Z/vHHH9Xajz76yKs9wUzaVl2nrdROtM/Fr776Ks89AYFC2wjqJC0tzYedwBROG9I//PBDW1a+fHmvPOaBAwds2YIFC9Taf/7zn2ruySsVaI8nIvLII4+oeVRUlC176aWX1NqwsDA1nz59ui27dOmSU4soROLj49W8U6dOtmzv3r1q7fr1673aU0Fx2uCubaZetWqVWnvq1CkvduQf3DkGAAAAABiP4RgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABiPbdUBpEKFCmr+2muvqXmRIva/+xg/frxam5GRkffGYJxFixap+Z133un2NebNm6fmo0ePzktLQMCLiYlxu9Zpey7giWLF9B8DvbGZ2ulVBvr06WPL0tPT8/14Tpy2VT///PNqPmXKFFtWvHhxtdbpHC5evNiWpaamOrWIQqRXr15qrn0OOP38Xdg5bam/99571fy3336zZRMmTFBrg2ErO3eOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyGYwAAAACA8VjIFUAGDBig5lFRUWp+8uRJW7Zr1y6v9oTgVrlyZTWPjY1V89DQUFvmtGjFaZlDZmamm90Bgal58+Zq/j//8z9qvmnTJlv2n//8x6s9AXm1fv16NX/ooYfU3JfLtzyhLc0S0ZcSNWnSxNftoICVKVNGzZ2+PmtmzpzprXYK1COPPKLmTov4duzYYctWrlzp1Z4KE+4cAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx7bqQuj2229X8xEjRnh0ne7du9uyrVu35qUlGGrBggVqHhkZ6fY13nvvPTVPTU3NU09AoGvXrp2alytXTs2XL19uy7KysrzaE3C1IkXcv3fSrFkzH3biOy6XS821j92T50NEJDEx0Zbdf//9Hl0DvqW9uoaIyPXXX6/mH3zwgS/bKVA1a9b0qN602YE7xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA47GtuhDq1KmTmoeEhKj5l19+qearV6/2Wk8Ibt26dVPzhg0benSdVatW2bJx48blpSUgaN12221qblmWmicnJ/uyHRjsscceU/OcnJwC7qTgde3aVc0bNGhgy5yeD6dc21aNwuXs2bNqvnnzZjWvV6+eLXN6hYGMjIw89+VNFSpUUPP4+HiPrvPNN994o52AwZ1jAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPBZy+Vl4eLgt69Chg1p78eJFNXdaeHTp0qW8N4agFRkZactGjRql1jotgXOiLbLIzMz06BpAMKlUqZIta9mypVq7a9cuNU9JSfFqT8BlTkupAlFUVJSa16lTR82dvu95Ii0tTc35+avwO3/+vJqnpqaqec+ePW3Z0qVL1dopU6bkvbE/UbduXTWvUaOGLatevbpa67T80YkJC/quxp1jAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDx2FbtZ8OGDbNlDRo0UGuXL1+u5t99951Xe0JwGzJkiC1r0qSJR9dYtGiRmjttTgdM9eCDD9qyChUqqLX//ve/fdwNELyeeeYZNR8wYEC+r71//34179u3r5ofPHgw348J/3D6Ocblctmyzp07q7UffPCBV3u6Wnp6upprG6jLly/vlcd85513vHKdQMGdYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyGYwAAAACA8dhWXUCcNtqNGTPGlp05c0atHT9+vFd7gpmeeuqpfF9j4MCBap6ZmZnvawPBJDo62u3akydP+rATIHgsW7bMlt18880+e7zt27er+TfffOOzx4R/7Ny5U8179+5ty+rXr6/W1qpVy5st5ZKcnOx27dy5c9X83nvv9egxz58/71F9oOPOMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeGyr9rLIyEg1f+WVV9S8aNGitkzbwigi8v333+e9McCLypUrp+aXLl3yyeOdPn3ao8cLCQlR8zJlyrj9mBEREWrujW3fv/32m5o//fTTtuzcuXP5fjz4T5cuXdyu/fTTT33YCWDncrnUvEgR9++ddOzY0aPHfP31121ZlSpVPLqG1l9OTo5H1/BE165dfXZtBK7Nmzd7lBe0n376ySvXqVu3ri3bunWrV65dGHHnGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI+FXPmgLdNavny5WnvDDTeoeWpqqi0bM2ZM/hoDfOyHH34o0Mf717/+peZHjx5V84oVK6p5QkKC13ryhV9++cWWPffcc37oBJ5q0aKFmleqVKmAOwHcN3PmTDV/6aWX3L7GkiVL1NyTBVneWKblrYVcs2bN8sp1AH9zWrjnlDsJ5uVbGu4cAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx7bqfKhZs6Yta9SokUfXeOqpp2yZtsEa8JZly5bZsrvuussPnbivV69ePrt2dna2mnuy+XTx4sVqvn79eo96+frrrz2qR+HRo0cPNdde1WDTpk1q7X//+1+v9gT8mYULF6r5sGHDbFlUVJSv28mXtLQ0Nd+xY4eaP/LII2ru9CoIQKCxLMujHL/jzjEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHhsq3ZDdHS0mn/++eduX0Pb/CgismTJkjz1BOTV3XffbcuGDx+u1oaEhOT78W699VY1T0hIyPe133rrLTXfv3+/29dYsGCBmu/cuTMvLSHIFS9eXM07derk9jWSk5PV/LfffstTT0BeHThwQM379Oljy7p3767WDho0yJst5dlzzz2n5jNmzCjgToDCISwszKP68+fP+6iTwMKdYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyXZVmWW4Uul697KbScljyMHDnS7Ws0bdpUzdevX5+nnkzj5qdpgTL5TMD/OBP+4bSk7quvvlLz48eP27J77rlHrT137lzeGwNnwk86dOig5o888oiad+3a1ZYtXrxYrX399dfVXHtet2/frtYePHhQzU3AmTDbL7/8oubFiun7mJ999lk1f/nll73Wk7+5cya4cwwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7bqq/SokULNV+2bJmalyxZ0u1rs606f9i4COTGmQBy40wAuXEmzPbpp5+q+ZQpU9R85cqVvmynUGBbNQAAAAAAbmA4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxivm7wYKk5YtW6q5J1upU1NT1TwzMzNPPQEAAACAJ7p27ervFgISd44BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjW3U+bNmyxZa1bdtWrc3IyPB1OwAAAACAPOLOMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMJ7LsizLrUKXy9e9AI7c/DQtUJwJ+BNnAsiNMwHkxpkAcnPnTHDnGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPLe3VQMAAAAAEKy4cwwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcJwH+/fvF5fLJZMnT/baNVetWiUul0tWrVrltWsCBYUzAeTGmQBy40wAuXEmCidjhuN33nlHXC6XrF+/3t+t+MSuXbtk8ODBEhsbK2FhYeJyuWT//v3+bguFWLCfiT/629/+Ji6XSwYOHOjvVlBImXAmPvzwQ2nYsKGEhYVJVFSU9OvXT9LT0/3dFgqpYD8TiYmJ4nK5bH/CwsL83RoKqWA/EyJ8nyjm7wbgHatXr5ZXXnlF6tSpI7Vr15bNmzf7uyWg0Fi4cKGsXr3a320AfjVz5kx54oknpG3btjJlyhQ5fPiwvPzyy7J+/XpZs2YNAwGMNXPmTClZsuSV/y5atKgfuwH8h+8TDMdBo1u3bnLq1CkpVaqUTJ48meEY+D9ZWVkyZMgQefrpp2Xs2LH+bgfwi4sXL8qoUaOkVatW8p///EdcLpeIiMTGxkrXrl1lzpw58o9//MPPXQL+ER8fL+XLl/d3G4Bf8X3id8b8WrU7Ll68KGPHjpVGjRpJmTJlpESJEtKyZUtZuXKl4/tMnTpVoqOjJTw8XFq3bi1bt2611ezcuVPi4+OlXLlyEhYWJo0bN5bFixf/aT/nzp2TnTt3uvWrDOXKlZNSpUr9aR3giUA+E5e99NJLkpOTI0OHDnX7fQAngXomtm7dKqdOnZKEhIQrP/CIiHTp0kVKliwpH3744Z8+FqAJ1DNxNcuy5MyZM2JZltvvAzgJ1DPB94nfMRxf5cyZM/LGG29IXFycvPjii5KYmChpaWnSvn179U7svHnz5JVXXpEBAwbIyJEjZevWrXLHHXfIsWPHrtRs27ZNmjdvLjt27JARI0ZIUlKSlChRQrp37y4pKSnX7Gft2rVSu3ZtmT59urc/VMAtgX4mDh48KC+88IK8+OKLEh4e7tHHDmgC9UxcuHBBREQ9B+Hh4bJp0ybJyclx4xkAcgvUM3G1GjVqSJkyZaRUqVJy33335eoF8FSgngm+T/wfyxBvv/22JSLWunXrHGuys7OtCxcu5MpOnjxpVaxY0XrooYeuZPv27bNExAoPD7cOHz58JV+zZo0lItbgwYOvZG3btrViYmKsrKysK1lOTo4VGxtr3XjjjVeylStXWiJirVy50paNGzfOo4910qRJlohY+/bt8+j9YBYTzkR8fLwVGxt75b9FxBowYIBb7wvzBPOZSEtLs1wul9WvX79c+c6dOy0RsUTESk9Pv+Y1YJ5gPhOWZVnTpk2zBg4caM2fP99KTk62Bg0aZBUrVsy68cYbrdOnT//p+8M8wXwm+D7xO+4cX6Vo0aJy3XXXiYhITk6OZGRkSHZ2tjRu3Fg2btxoq+/evbtcf/31V/67adOm0qxZM1m2bJmIiGRkZMiKFSukd+/ecvbsWUlPT5f09HQ5ceKEtG/fXvbs2SNHjhxx7CcuLk4sy5LExETvfqCAmwL5TKxcuVIWLFgg06ZN8+yDBq4hUM9E+fLlpXfv3jJ37lxJSkqSn376Sb7++mtJSEiQkJAQERE5f/68p08HELBnQkRk0KBB8uqrr8o999wjPXv2lGnTpsncuXNlz5498tprr3n4TAC/C9QzwfeJ3zEc/8HcuXOlXr16EhYWJpGRkRIVFSVLly6V06dP22pvvPFGW3bTTTddeQmlvXv3imVZMmbMGImKisr1Z9y4cSIicvz4cZ9+PEB+BeKZyM7OlieffFLuv/9+adKkSb6vB1wtEM+EiMjs2bOlU6dOMnToUKlZs6a0atVKYmJipGvXriIiubb1Ap4I1DOhueeee6RSpUryxRdf+OwxEPwC9UzwfYJt1bm899578uCDD0r37t1l2LBhUqFCBSlatKg8//zzkpqa6vH1Lv9e/tChQ6V9+/ZqTa1atfLVM+BLgXom5s2bJ7t27ZLZs2fbXu/77Nmzsn//fqlQoYIUL148348FswTqmRARKVOmjHzyySdy8OBB2b9/v0RHR0t0dLTExsZKVFSUREREeOVxYJZAPhNOqlatKhkZGT59DASvQD4TfJ9gOM4lOTlZatSoIQsXLsy1pe3y38r80Z49e2zZ7t27pXr16iLy+4IHEZGQkBBp166d9xsGfCxQz8TBgwfl0qVLcvvtt9veNm/ePJk3b56kpKRI9+7dfdYDglOgnomrVatWTapVqyYiIqdOnZINGzZIz549C+SxEXyC4UxczbIs2b9/vzRo0KDAHxvBIRjOhMnfJ/i16qtcftF366pV/mvWrJHVq1er9YsWLcr1O/5r166VNWvWSMeOHUVEpEKFChIXFyezZ8+Wo0eP2t4/LS3tmv3k5eUIAG8K1DPRp08fSUlJsf0REenUqZOkpKRIs2bNrnkNQBOoZ8LJyJEjJTs7WwYPHpyn9wcC+Uxo15o5c6akpaVJhw4d/vT9AU0gnwmNad8njLtz/NZbb8ny5ctt+aBBg6RLly6ycOFC6dGjh3Tu3Fn27dsns2bNkjp16khmZqbtfWrVqiUtWrSQxx9/XC5cuCDTpk2TyMhIGT58+JWaGTNmSIsWLSQmJkb69+8vNWrUkGPHjsnq1avl8OHDsmXLFsde165dK23atJFx48b96T+iP336tLz66qsiIvLtt9+KiMj06dMlIiJCIiIiZODAge48PTBQMJ6JW265RW655Rb1bTfccAN3jHFNwXgmREReeOEF2bp1qzRr1kyKFSsmixYtks8//1wmTJjAv83HNQXrmYiOjpaEhASJiYmRsLAw+eabb+TDDz+U+vXry6OPPur+EwTjBOuZ4PuEmPdSTk5/Dh06ZOXk5FgTJ060oqOjrdDQUKtBgwbWkiVLrL59+1rR0dFXrnV59fqkSZOspKQkq2rVqlZoaKjVsmVLa8uWLbbHTk1NtR544AGrUqVKVkhIiHX99ddbXbp0sZKTk6/U5PflCC73pP25unfgsmA/ExrhpZxwDcF+JpYsWWI1bdrUKlWqlFW8eHGrefPm1scff5yfpwxBLtjPxMMPP2zVqVPHKlWqlBUSEmLVqlXLevrpp60zZ87k52lDEAv2M8H3CctyWdZV9/wBAAAAADAQ/+YYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxivmbqHL5fJlH8A1FcaX4+ZMwJ84E0BunAkgN84EkJs7Z4I7xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4xXzdwMAAACAL5QtW1bNq1Wrlu9rHzhwQM0HDx5sy7Zu3arW7t69W823bNmS98YA5Bl3jgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmNbdSHUtWtXNV+8eLGaDxw4UM1nzZply3777be8N4agVaFCBTX/+OOP1fy7775T89dff92W7d+/P899+VOZMmXUvFWrVrZs+fLlau2lS5e82hMAQKRz5862rFu3bmptXFycmteqVSvffThtmo6OjrZloaGhHl27aNGieeoJQP5w5xgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABjPZVmW5Vahy+XrXowUGRlpyzZv3qzW/uUvf/Ho2sWLF7dl58+f9+gahYWbn6YFKlDPRNmyZW2Z01IRp6VUKSkpap6QkJD3xvzE6WPcsGGDmkdFRdmyRo0aqbV79+7Ne2N/gjNRuJQuXVrNn3/+eVtWt25dtbZdu3ZqzmI393AmAkPNmjVt2YABA9Ta/v37q3l4eLgtC7bn2hsLuTgTQG7unAnuHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjFfM3w2YrlWrVrbM063UH3zwgZpnZWXlqScEh/Lly6v5Rx99ZMvKlSun1r722mtq/o9//CPvjRUyo0ePVvMbbrhBzR999FFb5sut1Chc7r33XjV/7rnn1Lxq1apuX9tp4/WJEyfcvgZQ2Gk/4wwaNMgPnbhv586dar5t27YC7gSmqFWrlpo7/WzXo0cPWxYXF6fW5uTkqPmsWbPU/Ntvv7VlwfxzD3eOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyGYwAAAACA8RiOAQAAAADGc1mWZblV6HL5upegFhoaqubaBrhGjRp5dO1OnTqp+b///W+PrlOYuflpWqAK+5m488471dyTz4tKlSqpeVpaWp568rdbb73Vlv34449qbUpKipo/+OCDtuzs2bP56isvOBO+5fSqAZs2bVLzyMhINffk/5O2SV5EZODAgbYsIyPD7euagjPhPdpGXKeN0trPMSIiy5cvV/PmzZvbsmXLlqm1v/76q5qXKFHCln3++edq7datW9V8zZo1aq6d8fPnz3vUX2HBmShc6tatq+ba1/i7775brXXaVu1L2dnZtmzXrl1q7TfffKPm2tePixcv5q+xPHDnTHDnGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGK+YvxswRUxMjJp7snxL+wfxIsG1eAueq1Chgpr37NnT7Wv069dPzYNp8ZaIyBdffOH2NZwWcvlj+RYK3tChQ9W8XLlyPnvMhIQENe/QoYMte+6559TaV199Vc39sfgEhZ+22EpEX2512223qbU9evTw6DG///57W9awYUO1dv/+/WperVo1W3b48GG1Nicnx/3mAA/Uq1dPzQcMGKDmTl/jS5cu7fZjHjlyRM2//vprW7Zv3z61dvjw4Wq+YcMGNW/atKktc/pe6LQkeMuWLbZs1qxZaq2/cecYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8tlUXEE82BzvRtkcCSUlJan7fffepubaN8F//+pdXe/K3li1bqnnFihVt2TvvvKPWvvfee95sCYVYdHS0Lfuf//kfj67xww8/qPmxY8dsWbt27Ty6dpkyZWyZ0zbt+fPnq/kvv/zi0WMiuFx33XVq/v7776u5tpl64sSJaq0nrwLgxGkrtZODBw/m+zEBT8yePduWOW1qL1++vEfX/vLLL23Zjz/+qNaOGjVKzbOystx+vNjYWDV//PHH1fytt96yZfXr11drte95IiIzZsywZQsWLFBr/f1KKdw5BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj23VBaRVq1Zu1168eFHNn3nmGW+1gyBiWZaa5+TkqPnPP/9sy5w+5wqL8PBwNXfa2vjEE0+oufZcPfTQQ3lvDEFB27pZqlQptfbrr79W89atW6t5WFiYLfv73/+u1jp9PtesWdOWVapUSa395JNP1Lxjx45qnpGRoeYIXCVLlrRlI0eOVGu7dOmi5unp6bZs8uTJau25c+c86A4oHLSvzSIiw4cPV/OHH37YlrlcLrXWadvyzJkz1XzSpEm27Ndff1VrvSEyMlLNixYtquaJiYm2bPny5Wqt9uoPgYY7xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA47Gt2stiY2M9yjVOG+o2b96cl5aAXDp37mzLPv/8c7X21KlTau60cdEbtK2/cXFxam3z5s09unZycnJeWkKQCw0NtWVOW+CnTp3q0bWzsrJs2dtvv63W9urVS81r1Kjh9uM5bQ4u7Bvp4T3du3e3ZSNGjFBrDx48qOYtW7a0ZadPn85XX0Bh4vRzxbBhw9Rc20x95MgRtbZnz55qvnbtWveaywNt03TVqlXV2nnz5qn5smXL1Lxs2bJu9+G0wfvdd9+1ZU4/Y/obd44BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxWMjlZU2aNMn3NXy57AjB5+WXX1bzNm3aqHmVKlVsWatWrdRap8UK3bp1c7M7z2mP6bQcyclPP/2k5qNGjcpTTwhuf//7392u1RbaiYgsWrQo3300btw439f4/vvv1TwzMzPf10Zg8GQB6KZNm9T88OHD3moHKJS0BVYiIr/99pvb18jOzlbzZs2aqXl8fLya33LLLW4/5vnz59W8du3abmUiIunp6WpesWJFt/twcuzYMTWfMGGCLbt06VK+H88XuHMMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADCey3JzDazT1lrk9u6776r5fffdp+anTp2yZTExMWqtydsjPd1WXBAK+5koW7asmtevX9+WdejQQa0dNmyYmh8/flzN586d615z16CdoS1btnh0jffee0/N+/btm6eeCiPOhPf07t3bln3wwQdq7Y8//qjmffr0UXPt63mPHj3U2l69eqn5mTNnbJnT+c7IyFBzp43027dvV/NAxJn4nfb1OTIyUq29cOGCmr/44ou27JNPPlFrN2/e7H5zKFCcCWfh4eFq/v7776t5u3btbFnx4sXV2iJF9HuPnvz/cNqa7bRl25dycnJsWUpKilr75JNPqvnRo0e92lNeufP/gDvHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAzHAAAAAADjsa06H1q0aGHLvvrqK7XWaXPdgQMHbFn16tXz1VcwYuOiOWrUqGHL9u7dq9Y6bUlt3769mqelpeW5r8KGM+E95cqVs2VOn3NlypRRc6eP3ZP/T1988YWaDxgwwJYtWbJErb3xxhvVfM6cOWr+2GOPudld4ceZ+J32PGjbZj3ldI1Zs2ap+ffff6/m1apVs2VO523btm1udidy6623qvnq1avV3IRXAOFMeE9ERIQtGzFihFp7++23q/mJEyfU/ODBg7YsNDRUrb3tttvUvGnTpmruDdoZHzVqlFqrvQpPYcK2agAAAAAA3MBwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMV83cDgSwyMtKWOS3ecvKf//zHW+0AQWHs2LG2zGmBwtNPP63mwbR4C76XkZFhy3r37q3WJicnq7nToi7Nq6++quZOn89ZWVm2bOHChWqt04IYpyV1NWvWtGWpqalqLQLD5MmTbdlTTz2V7+s6/XzzxBNPeJQXNKfvB6tWrVLzPn36+LAbBCpt0ZTT11tfmjdvnpp7spDr7Nmzau70deKdd96xZb/99pvbjxdouHMMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADCey3JaA/vHQpfL170EnHfffdeW3XfffWqttuVORORvf/ubLVu/fn2++gpGbn6aFijORP706tVLzT/66CNb5rRZsU2bNmq+cePGvDcWIDgT/tGuXTs1v+eee9Rc+9qvbWQXEcnMzHS7j/DwcDV///331bxbt25q/t5779myvn37ut1HYcKZ+F3RokVtWYMGDdRap8+XYsXsL2ZStWpVtdbTV+koLJw+XxITE23ZhAkTfNyNb3AmAtfw4cPV3OlzUTuzTu699141/+CDD9y+RqBy50wE5lc0AAAAAAC8iOEYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj23VbvjLX/6i5gcOHLBlTlsbt27dquYxMTF5b8wgbFwMPm+99ZaaP/jgg7bMaYOi08ZFE3AmoOnTp4+az58/X82PHDliy+rXr6/WZmRk5LmvgsCZ8K22bduqeUhIiJprW59FRJo0aeKtlnxi8eLFtqxHjx5+6CT/OBOB4eGHH7ZlU6ZMUWtLlizp9nW3bdum5o0bN1bzCxcuuH3tQMW2agAAAAAA3MBwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjFfM3w0EgtjYWDV32kytWbRokZe6AYJDx44d1fzXX3+1ZUlJSb5uBwgKH3/8sZp369ZNzRMSEmzZwIED1drx48fnvTEEvC+//NKjeqet59q26uzsbLX27bffVvM5c+bYsv/93/9Va++55x69QaCANW3aVM21n3E82UotIpKZmWnLHnvsMbXWhK3U+cGdYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDwWcrkhMjLS7dr09HQ1f/nll73VDhBQnBZCVKxYUc2PHz9uyzZu3OjVnoBglZOTo+YvvfSSmt911122bNy4cWrthx9+qOa7d+92szuY5PPPP1fz5557zpYVK6b/ONq/f381r1Wrli2Li4tzv7lrOHz4sFeuA/xR165d1bxUqVJuX0NbWiqiL1389ttv3b4u/j/uHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMe2aje0b9/e7dqDBw+q+enTp73VDhBQnLZVW5al5kuXLnX72k4bHsuWLavmTucTCHabN29W87Fjx9qySZMmqbUTJ05U8/vvv9+WnT9/3v3mEJR27Nih5h9//LEt6927t0fXbtOmjdu1v/32m5o7fa8ZMWKER70Af+T0s8nw4cPzfe358+er+apVq/J9bfyOO8cAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOOxrfoqISEhal6zZk23r5GVlaXmly5dylNPgGm0zaL33nuvWjt48GA137Ztm5r37ds3740BQWjevHm27NFHH1Vr7777bjUfP368Lfvhhx/y1xgCntPG8v/93/+1ZSVLllRrGzdurOYVKlSwZfv371dr3333XTVPTExUc8BdTp+327dvV3OnOUPj9DVUOz/wLu4cAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA47GQ6yo5OTlqvn79ejWvW7euLdu7d69XewJM8/DDD9uyfv36qbVvvvmmmj/77LNe7QkIVmlpabasXbt2aq3TwqOnn37aljkt0QOOHTtmy7p27arW3n///WrevHlzW/bPf/5TrT1+/LgH3QHuu+OOO9T8L3/5i5pbluX2tZ0Wjjot/oX3cOcYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8l+Xm6jSXy+XrXgqtKlWqqPmECRNs2YYNG9TaGTNmeLUn03iy4a+gmHwmPNGiRQs1Hz9+vJr/97//tWUzZ85Ua0+ePKnmFy9edLO7wMWZQEH7/PPP1fyvf/2rLWvWrJlau337dq/2dDXOBJAbZ8K3tmzZouYxMTEeXWfSpEm2THsVAOSfO2eCO8cAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOOxrRoBgY2LQG6cCRS00qVLq7m2sXXQoEFq7eLFi73a09U4E0BunAnfOnTokJr/5S9/UfPjx4+ref369W3Z0aNH89wXnLGtGgAAAAAANzAcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4xXzdwMAAKDwO3PmjJrfcMMNBdwJAPjflClTPMqfffZZNWczdeHCnWMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8l2VZlluFLpevewEcuflpWqA4E/AnzgSQG2cCyI0zAeTmzpngzjEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHhub6sGAAAAACBYcecYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+E4D/bv3y8ul0smT57stWuuWrVKXC6XrFq1ymvXBAoKZwLIjTMB5MaZAHLjTBROxgzH77zzjrhcLlm/fr2/W/GZI0eOSO/evSUiIkJKly4td911l/z000/+bguFlAlnQkTko48+kr/+9a9SokQJiYiIkNjYWFmxYoW/20IhZMKZ+PDDD6Vhw4YSFhYmUVFR0q9fP0lPT/d3WyikTDgT/OwETwT7mdi1a5cMHjxYYmNjJSwsTFwul+zfv9/fbRWoYv5uAN6RmZkpbdq0kdOnT8uoUaMkJCREpk6dKq1bt5bNmzdLZGSkv1sEClxiYqKMHz9e4uPj5cEHH5RLly7J1q1b5ciRI/5uDShwM2fOlCeeeELatm0rU6ZMkcOHD8vLL78s69evlzVr1khYWJi/WwQKFD87AbmtXr1aXnnlFalTp47Url1bNm/e7O+WChzDcZB47bXXZM+ePbJ27Vpp0qSJiIh07NhR6tatK0lJSTJx4kQ/dwgUrO+//17Gjx8vSUlJMnjwYH+3A/jVxYsXZdSoUdKqVSv5z3/+Iy6XS0REYmNjpWvXrjJnzhz5xz/+4ecugYLFz05Abt26dZNTp05JqVKlZPLkyUYOx8b8WrU7Ll68KGPHjpVGjRpJmTJlpESJEtKyZUtZuXKl4/tMnTpVoqOjJTw8XFq3bi1bt2611ezcuVPi4+OlXLlyEhYWJo0bN5bFixf/aT/nzp2TnTt3uvUrb8nJydKkSZMrX9xFRG655RZp27atfPzxx3/6/oAmkM/EtGnTpFKlSjJo0CCxLEsyMzP/9H2APxOoZ2Lr1q1y6tQpSUhIuDIYi4h06dJFSpYsKR9++OGfPhagCdQzIcLPTvCNQD4T5cqVk1KlSv1pXTBjOL7KmTNn5I033pC4uDh58cUXJTExUdLS0qR9+/bq35zMmzdPXnnlFRkwYICMHDlStm7dKnfccYccO3bsSs22bdukefPmsmPHDhkxYoQkJSVJiRIlpHv37pKSknLNftauXSu1a9eW6dOnX7MuJydHfvjhB2ncuLHtbU2bNpXU1FQ5e/ase08CcJVAPRMiIl9++aU0adJEXnnlFYmKipJSpUpJ5cqV3XpfwEmgnokLFy6IiEh4eLjtbeHh4bJp0ybJyclx4xkAcgvUM8HPTvCVQD0T+D+WId5++21LRKx169Y51mRnZ1sXLlzIlZ08edKqWLGi9dBDD13J9u3bZ4mIFR4ebh0+fPhKvmbNGktErMGDB1/J2rZta8XExFhZWVlXspycHCs2Nta68cYbr2QrV660RMRauXKlLRs3btw1P7a0tDRLRKzx48fb3jZjxgxLRKydO3de8xowTzCfiYyMDEtErMjISKtkyZLWpEmTrI8++sjq0KGDJSLWrFmzrvn+MFMwn4m0tDTL5XJZ/fr1y5Xv3LnTEhFLRKz09PRrXgPmCfYzwc9O8FQwn4k/mjRpkiUi1r59+zx6v0DHneOrFC1aVK677joR+f1vFDMyMiQ7O1saN24sGzdutNV3795drr/++iv/3bRpU2nWrJksW7ZMREQyMjJkxYoV0rt3bzl79qykp6dLenq6nDhxQtq3by979uy55mKguLg4sSxLEhMTr9n3+fPnRUQkNDTU9rbLC1Yu1wCeCNQzcflXqE+cOCFvvPGGDB06VHr37i1Lly6VOnXqyIQJEzx9KgARCdwzUb58eendu7fMnTtXkpKS5KeffpKvv/5aEhISJCQkRET4PoG8CdQzwc9O8JVAPRP4HcPxH8ydO1fq1asnYWFhEhkZKVFRUbJ06VI5ffq0rfbGG2+0ZTfddNOVled79+4Vy7JkzJgxEhUVlevPuHHjRETk+PHj+e758q/JXf61uatlZWXlqgE8FchnIiQkROLj46/kRYoUkYSEBDl8+LAcPHgw348DMwXimRARmT17tnTq1EmGDh0qNWvWlFatWklMTIx07dpVRERKlizplceBeQLxTPCzE3wpEM8Efse26qu899578uCDD0r37t1l2LBhUqFCBSlatKg8//zzkpqa6vH1Lv/7raFDh0r79u3Vmlq1auWrZ5Hf//F8aGioHD161Pa2y1mVKlXy/TgwTyCfibCwMImIiJCiRYvmeluFChVEROTkyZNSrVq1fD8WzBKoZ0JEpEyZMvLJJ5/IwYMHZf/+/RIdHS3R0dESGxsrUVFREhER4ZXHgVkC9UzwsxN8JVDPBH7HcHyV5ORkqVGjhixcuDDXNs/LfyvzR3v27LFlu3fvlurVq4uISI0aNUTk97tX7dq1837D/6dIkSISExOjviD5mjVrpEaNGsZvnkPeBPKZqF+/vqxbt04uXrx45debRER+/vlnERGJiory2eMjeAXqmbhatWrVrvzF0KlTp2TDhg3Ss2fPAnlsBJ9APRP87ARfCdQzgd/xa9VXuXyHybKsK9maNWtk9erVav2iRYty/Y7/2rVrZc2aNdKxY0cR+f0OVVxcnMyePVv9m8m0tLRr9uPJ6vX4+HhZt25dri/yu3btkhUrVkivXr3+9P0BTSCfiYSEBPntt99k7ty5V7KsrCyZP3++1KlThzsCyJNAPhOakSNHSnZ2Nq8FjjwL5DPBz07whUA+EzDwzvFbb70ly5cvt+WDBg2SLl26yMKFC6VHjx7SuXNn2bdvn8yaNUvq1KmjvkZqrVq1pEWLFvL444/LhQsXZNq0aRIZGSnDhw+/UjNjxgxp0aKFxMTESP/+/aVGjRpy7NgxWb16tRw+fFi2bNni2OvatWulTZs2Mm7cuD/9R/RPPPGEzJkzRzp37ixDhw6VkJAQmTJlilSsWFGGDBni/hME4wTrmXj00UfljTfekAEDBsju3bulWrVq8u6778qBAwfk008/df8JgnGC9Uy88MILsnXrVmnWrJkUK1ZMFi1aJJ9//rlMmDAh1+u8An8UrGeCn52QV8F6Jk6fPi2vvvqqiIh8++23IiIyffp0iYiIkIiICBk4cKA7T09g88OGbL+4vHrd6c+hQ4esnJwca+LEiVZ0dLQVGhpqNWjQwFqyZInVt29fKzo6+sq1Lq9enzRpkpWUlGRVrVrVCg0NtVq2bGlt2bLF9tipqanWAw88YFWqVMkKCQmxrr/+eqtLly5WcnLylRpvrF4/dOiQFR8fb5UuXdoqWbKk1aVLF2vPnj15fcoQ5Ew4E8eOHbP69u1rlStXzgoNDbWaNWtmLV++PK9PGYJcsJ+JJUuWWE2bNrVKlSplFS9e3GrevLn18ccf5+cpQ5AL9jNhWfzsBM8E+5m43JP25+reg5nLsq665w8AAAAAgIH4N8cAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMdwDAAAAAAwXjF3C10uly/7AK6pML4cN2cC/sSZAHLjTAC5cSaA3Nw5E9w5BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxivm7wYAFF6hoaFq/u2336p5gwYNbNmnn36q1nbv3j3PfQEAAADexp1jAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDx2FbthhYtWqj56tWrbdnNN9+s1nbp0kXNO3fubMuWLl3qQXci3333nZp/8803Hl0H5nLaSj116lQ1r1+/vppblmXLNmzYkOe+AAAATJOYmKjm48aNU/NVq1bZsjZt2nixI3Nw5xgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyXpa2X1QpdLl/3UmBKly6t5vPnz1fzO+64Q83Pnz9vy6677jq1tmTJkm525zmtDxGRc+fO2bLHH39crU1OTvZqT97m5qdpgQqmMzFs2DA1f/7559V8xYoVaj527Fhb9v333+e9MTjiTAC5cSYCQ9myZW2Z0ysgdOzYUc2171k5OTlqrdPPNwcOHFDzpKQkW3bs2DG1trDjTASulStXqnlcXJzb13DaVq1ttjaFO2eCO8cAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4xfzdgD+8+OKLat65c2ePrhMeHm7LduzYodampaWp+ZkzZ9x+PKclBk59a/29+eabau3u3bvV/IcffnCzOwSySpUqeVT/xRdfqDnLtwDALCEhIWo+ZMgQNR8wYIAtq1y5skePqS3fclq007NnT4+uXb58eVv20EMPeXQNIL88Wbzl6TVMXsjlDu4cAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACM57Kc1vv9sdBhU3Jhd+utt9oypy1tkZGRan748GE1f+CBB2zZ3r171dpTp06peWZmppprihTR/y5j7Nixaj569GhbVrRoUbV24cKFav7www/bspMnTzq16DNufpoWqEA9E5rXX39dze+//341v/3229V848aNXusJ18aZCAz169e3Zc8++6xa26lTJzXXvvZr23pFRJKTk9X8mWeeUfOjR4/asjZt2qi1X375pZqfP39ezQsaZ8I/Bg4cqObTpk3z2WP+97//tWWtWrXy2eMVKxaYL+7CmQhc3vh/x3Nt587zyp1jAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxgn5bdfPmzW3Zd999p9Y6PRVPPvmkms+YMSPvjRWAiRMn2rKhQ4eqtU6bGLt27WrLli5dmr/G8oCNi95TpUoVW3bo0CG11umstGzZ0qs9wXOcCf8ICQlR89atW6v522+/bcsqV67s0WNqz6un///fe+89Na9ataoti4uLU2v79u3r0bULGmfCt7RX/xARWbFihZo7vQKIJ0aMGKHmL7/8si0bP368Wjts2LB898G2au8JpjPhS2yr9g22VQMAAAAA4AaGYwAAAACA8RiOAQAAAADGYzgGAAAAABgvMDcMeCA0NNTt2rlz56p5YV+85WTUqFG2LCEhQa294YYb1Pzuu++2Zf5YyAXvGT16tL9b8DltEZ+IvnzIyZYtW9R89+7deeoJwaFhw4Zqvnz5crevcfToUTUfOHCgmp87d87ta0dHR6v5r7/+quavvvqqLbt48aJa69Q3go+2fOv5559Xa8uXL6/mTotvDhw4YMu6deum1u7YsUPNc3JybNnYsWPV2pSUFDVfvHixmmsfzw8//KDW1qtXT82B/PrnP/+p5uPGjXP7GomJiR7l+B13jgEAAAAAxmM4BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxgv6bdXPPvus27Vr1qzxYSeFw2effabmjz32mJo7bf1F4OrcubPbtW+++aYPO3HfzJkz1dzpYylbtqyah4eHu/2YZ86cUfOpU6faMk++ziAwaNt6RZw33Dr58ssvbdnIkSPV2o0bN3p0bU2VKlXU/JNPPlHziIgIWzZp0iS1VvtYEJy0rexOX2+LFNHvszhtPX/ttdds2bZt2zzoTnfp0iU1X7t2rZq/8847aj5kyBBbFhMTo9a+/vrrav7II4+oOeAuT7ZSw7u4cwwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMF7QbKuuUaOGmmubO0+fPq3W/vjjj17tqTBasWKFmjttq0bgKl68uJoXK2Y/9keOHFFrnbZ5ekJ7PBF9G6qISEpKii2rVKmSWuu0JTUtLU3Nv/jiC7f7qFatmpprW0jnzZun1h44cEDNUfiNGTNGzcuXL6/mS5cuVfOnnnrKlu3duzfvjf2JunXrqnmDBg3cvsby5cu91Q4CVMeOHW2ZZVlqbU5OjpqvWrVKzZOSkvLclzeNGDFCzbWP3elcNW7c2Ks9AfA/7hwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAzHAAAAAADjMRwDAAAAAIwXNNuq77vvPjXXtlgvWLBArf3uu++82hPgTw8//LCaV6xY0Za9/vrrXnlMbTu8tt1ZRGT06NFuX/fnn39W83fffVfNX3vtNTU/fPiw24+5ePFiNe/UqZMtq1y5slrLturAMGfOHFvWq1cvtfbXX39Vc6fNt77aTB0SEqLmI0eOVHOXy6XmX331lVsZglNkZKSaN23aNN/Xdvr6XNhpfb/44ot+6ASAP3DnGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGC9oFnL16dNHzU+fPm3LXn75ZV+3A/hdgwYN3K7ds2ePVx5TW7L16KOPqrWWZan5ihUrbNngwYPV2m3btnnQnWe89Zyg8GvcuLEtc/r8zMzMVPPt27d7taeracu3nn32WbW2ZcuWau708YwfPz7vjSHgNWrUSM2rV6/u9jW+/vprNV+6dGleWgooZcuWVXNtSePRo0d93Q4AL+DOMQAAAADAeAzHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeEGzrdrJzp07bdk333zjh06AglWlShWfXfumm25S84SEBLevMWfOHDUfNGiQLbt48aLb1/W1jRs3upUBnnLaEPzEE0/Ysqeeesqjazttyt28ebNH10FwcdpW7Ylx48ap+cmTJ/N97cKuatWqal63bl1bxrZqFLTExER/txCQuHMMAAAAADAewzEAAAAAwHgMxwAAAAAA4zEcAwAAAACMx3AMAAAAADBewG2rLlGihJqHhIQUcCdA4VaqVCk1d7lc+b72P/7xDzWPiIiwZe+//75a+/jjj+e7D19yev4uXbpkywrTNm14bvv27bYsJiZGrY2MjFTzTZs25buP8uXLq7m2ed6yLI+u/eWXX6r5qVOnPLoOgkvx4sXV3JPvE1999ZW32im0ihTR7yXl5OQUcCcAfI07xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgBt5Crd+/eal6zZk01T09P92U7Aadbt24e1WdnZ/uoE/ia08IeTxf5aCpXruz2tZ1qCwtt2ZGISL9+/dR84cKFvmwHfvDwww/bstKlS6u1nTp1UnOnBV7eoH3dfuCBB9Tanj17qvmsWbO82hOCQ5MmTdTcG98ngonT4i2eJyD4cOcYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYj+EYAAAAAGC8gNtWDfc1atTIlnXp0sWja4waNcpb7SCIPProo2p+++23u5WJiIwcOVLNX3/9dVt24sQJD7rzjNP26XPnzql5UlKSz3qBf5w/f96Wde3aVa2Ni4tT88aNG7v9eNu2bVPzf//732o+Y8YMWxYfH6/W7t69W81TU1Pd7A6AuzIzM9Xcl9+zAPgWd44BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjW3UQ0LZSi4g89dRTtiwiIkKt/fbbb9X8s88+y3NfKBhVqlRR88qVK/vsMZ02cTZs2NCWLV68WK199tln1bxDhw62zGnL+tmzZ9XcqX706NG2rEGDBmrthAkT1Pz7779Xc5hh1apVHuXe8Nhjj9kyy7LU2nXr1ql5WlqaV3sCgtUDDzzgdm1iYqKab9y40UvdwFRO31OcXjFB4/T56ZTjd9w5BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYL+C2Ve/fv1/NnbbWBpOiRYuq+dChQ9U8ISHBlh05csSja2RnZ7vZHfzl559/VvM9e/aoeXR0tC2744471NrZs2er+blz59T86NGjtqxJkyZqrdNG6R07dtgypy3rSUlJat6vXz811/p22krttE0b8JXq1au7XZuZmanm06ZN804zMMKIESPUfPny5basfPnyau1bb72l5g899FDeG/Mj7eN02vY+a9YsX7cDoIBx5xgAAAAAYDyGYwAAAACA8RiOAQAAAADGYzgGAAAAABgv4BZyrVy5Us2dFk2VLl3aljktlUhPT897Y3lUr149W/bEE0+otQ0bNlTzxo0bu/149913n5qvWbPG7WsgMDgtpVq6dKkt69Spk1r72WefqfmUKVPUXFvI5aRZs2ZqPnLkSLdrXS6Xmu/atUvNn3nmGVuWkpLi1CJQoMaMGeN27aeffqrmGzdu9FY7MMDmzZvVfNiwYbbsnXfeUWt79eql5tOnT1fzwvI5OmfOHDWvWLGiLfvXv/6l1mZlZXm1J5gpLi7OrQwFgzvHAAAAAADjMRwDAAAAAIzHcAwAAAAAMB7DMQAAAADAeAzHAAAAAADjBdy2ak/Vrl3bli1fvlyt9WTTrrc0b97clkVGRnp0Dact24sXL7Zl69at8+jaCFyHDx9W8w4dOtgypy3wf/3rX9XcaXOnxmmjtGVZbl/Dydtvv63mTz/9tJqfOHEi348J5Nett96q5j179nT7Gk6b5AFv+Pbbb23Z+++/r9bec889at66dWs1L+ht1W3atFHzHj16qPnx48dt2fjx473aE3C1cePG+bsFXIU7xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA4wXNtupnnnlGzUePHm3LGjZs6Ot28iUnJ0fNMzIy1HzKlClq/sILL3itJwQPbSu7tjVdRCQhIUHNa9Wqpeb9+/e3ZW+88YZa68m26jfffFPNd+7c6fY1gMLC6XtQqVKl1Fw7K1lZWV7tCbjaTz/9ZMvGjBmj1t5+++1q7rSBNyoqypaNGjXKg+5EbrrpJlvWpEkTtXbq1KlqHhERoeZJSUm2bPv27e43BziIi4vzKPeEtpV91apV+b6uibhzDAAAAAAwHsMxAAAAAMB4DMcAAAAAAOMxHAMAAAAAjOey3NyK43K5fN2LT1SpUsWWLV++XK2tW7eur9uxmTNnji3btGmTWjtr1ixft1NoebK8qaAE6plAcOBMBK7Bgwer+aRJk9R827Zttuy2227zak/BgDPhH5UrV1Zzp59ZWrdubcv27dvn0TXGjx9vyyIjI51aVC1ZskTNhwwZYstSU1M9unZhwZkoXJwWb61cudKW/fOf/1RrExMTvdiRedw5E9w5BgAAAAAYj+EYAAAAAGA8hmMAAAAAgPEYjgEAAAAAxmM4BgAAAAAYL+i3VSM4sHERyI0zEbicXpEgJiZGzUeMGGHLJk+e7NWeggFnonApU6aMmt988822bMyYMWptx44d1TwpKcntPhYsWKDmGzduVPPs7Gy3r13YcSaA3NhWDQAAAACAGxiOAQAAAADGYzgGAAAAABiP4RgAAAAAYDyGYwAAAACA8Yr5uwEAAEyyfft2NXfaVg0EotOnT6v52rVrbVnXrl193Q4AuIU7xwAAAAAA4zEcAwAAAACMx3AMAAAAADAewzEAAAAAwHgMxwAAAAAA47GtGgCAArR8+XI1r1mzppqvW7fOl+0AAID/w51jAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPJdlWZZbhS6Xr3sBHLn5aVqgOBPwJ84EkBtnAsiNMwHk5s6Z4M4xAAAAAMB4DMcAAAAAAOMxHAMAAAAAjMdwDAAAAAAwHsMxAAAAAMB4bm+rBgAAAAAgWHHnGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgPIZjAAAAAIDxGI4BAAAAAMZjOAYAAAAAGI/hGAAAAABgvP8H7tIdSQhvL08AAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, axes = plt.subplots(3, 5, figsize=(10, 6))\n", "axes = axes.ravel()\n", "\n", "for i in range(15):\n", " img= x_test[i]\n", " label = y_test[i]\n", " axes[i].imshow(img, cmap='gray')\n", " axes[i].set_title(f\"Label: {label}\")\n", " axes[i].axis('off')\n", "\n", "plt.tight_layout()\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "8b48fbc2-4e94-4e67-beff-446dd53aefd8", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/mitevzd/Downloads/.env3.9/lib/python3.9/site-packages/keras/src/layers/reshaping/flatten.py:37: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", " super().__init__(**kwargs)\n" ] } ], "source": [ "model = models.Sequential([\n", " layers.Flatten(input_shape=(28, 28)),\n", " layers.Dense(128, activation='relu'),\n", " layers.Dense(10, activation='softmax')\n", "])\n", "\n", "model.compile(optimizer='adam',\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy'])" ] }, { "cell_type": "code", "execution_count": 6, "id": "d39a3cba-3e79-4562-8659-0ca7ef2cb15c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Model: \"sequential\"\n",
       "
\n" ], "text/plain": [ "\u001b[1mModel: \"sequential\"\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ flatten (Flatten)               │ (None, 784)            │             0 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense (Dense)                   │ (None, 128)            │       100,480 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "
\n" ], "text/plain": [ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", "│ flatten (\u001b[38;5;33mFlatten\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m784\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m100,480\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m1,290\u001b[0m │\n", "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Total params: 101,770 (397.54 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m101,770\u001b[0m (397.54 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Trainable params: 101,770 (397.54 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m101,770\u001b[0m (397.54 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Non-trainable params: 0 (0.00 B)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "model.summary()" ] }, { "cell_type": "code", "execution_count": 7, "id": "375da91d-13e5-4d37-955d-00e4c3b4f7dc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 1ms/step - accuracy: 0.8803 - loss: 0.4266 - val_accuracy: 0.9583 - val_loss: 0.1400\n", "Epoch 2/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9618 - loss: 0.1275 - val_accuracy: 0.9681 - val_loss: 0.1051\n", "Epoch 3/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 1ms/step - accuracy: 0.9758 - loss: 0.0802 - val_accuracy: 0.9744 - val_loss: 0.0849\n", "Epoch 4/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 1ms/step - accuracy: 0.9831 - loss: 0.0578 - val_accuracy: 0.9749 - val_loss: 0.0844\n", "Epoch 5/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 1ms/step - accuracy: 0.9851 - loss: 0.0460 - val_accuracy: 0.9755 - val_loss: 0.0778\n", "Epoch 6/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9897 - loss: 0.0338 - val_accuracy: 0.9757 - val_loss: 0.0796\n", "Epoch 7/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9917 - loss: 0.0266 - val_accuracy: 0.9753 - val_loss: 0.0853\n", "Epoch 8/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9932 - loss: 0.0224 - val_accuracy: 0.9773 - val_loss: 0.0775\n", "Epoch 9/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9942 - loss: 0.0185 - val_accuracy: 0.9758 - val_loss: 0.0832\n", "Epoch 10/10\n", "\u001b[1m1875/1875\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 1ms/step - accuracy: 0.9961 - loss: 0.0135 - val_accuracy: 0.9763 - val_loss: 0.0926\n", "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 478us/step - accuracy: 0.9729 - loss: 0.1072\n", "Test accuracy: 0.9763\n" ] } ], "source": [ "# Train the model\n", "model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test))\n", "\n", "\n", "test_loss, test_acc = model.evaluate(x_test, y_test)\n", "print(f\"Test accuracy: {test_acc:.4f}\")" ] }, { "cell_type": "code", "execution_count": 8, "id": "7afd4e73-ae81-4a96-afaf-cfd6f20f4484", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 24ms/step\n" ] }, { "data": { "image/png": "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OcAtWbNmta7Zdi6+cOGCNce227gvXnvtNeuabZd/4I+6d+9ujD/77LPWnISEBK/v40vO8OHDjXFPJ794curUKWPcU7888cQTPt3LxJfPQbBg8P4DTw1Uu3ZtY9zTN5xr164Z41u3bvWusNuYOnWqMe7pSeCKFSuM8WLFillzzpw541VduDPZjh+S7MdreGI7Asz2jVCSLl686PV9AAAAADfwVnMAAAAAAFzE4A0AAAAAgIsYvAEAAAAAcBGDNwAAAAAALmLwBgAAAADARXfsrubvvvuuMb5//35rjm0H5ZkzZ3qds3z5cmuOP23YsMG6NmTIEGN806ZN1hzbETbr16/3rjBkCDly5DDG586da80JDw/3+j62Iyw8fa0CburQoYMx3rdvX6+vNW/ePOua7f9pX49bypYtmzFeuHBhr6914MABn2oAJM8nT9hOsvCFp5M0bH18+fJla86hQ4dSXROCT2RkpDGePXv2NK7EfVevXjXGf/rppzSuJDnb0Zd58+a15qSnU254xRsAAAAAABcxeAMAAAAA4CIGbwAAAAAAXMTgDQAAAACAixi8AQAAAABw0R27qzkAAL5q37691zmrV682xp9++mlrjq+7l9vYdnEuXry4Nef48ePG+FdffeWXmhD8fvnlF+vatWvXjPGoqChrztChQ43xf/7zn9ackydPGuPNmze35oSGhhrj27Zts+b8+OOP1jXALUeOHLGu2XYhz4i2b99ujMfGxqZtIT66Ywdv23b0jz76qDXHcRxjPHfu3Nacpk2bGuNptbX9unXrrGu2GsqVK2fNGT58uDHOcWJ3plKlShnjVapUSZP7d+rUybq2ZMmSNKkBAAAAuB3eag4AAAAAgIsYvAEAAAAAcBGDNwAAAAAALmLwBgAAAADARQzeAAAAAAC4KEPsat6wYUNj/J133rHmLF261BgfOHCgNWfv3r3G+IQJE6w5169ft64F2pw5c4zxcePGWXPuvvtuY9y2u7Xk+QgEpH/58+e3rtl2Dg8JCfFrDf379zfGPfWr7YSCwYMHW3N++uknr+pCxpYvXz7rWuPGjY3xTZs2WXMee+wxY9zfx6B46tl69ep5fb158+YZ48FyfAvc9/XXX1vX+vTpY4y/+eab1hzbCSp33XWXNef//u//jPExY8ZYc2y6dOnidQ7gprfeesu6dvr06TSsJLAuX75s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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Select some random images from the test set\n", "num_samples = 10\n", "indices = np.random.choice(len(x_test), num_samples, replace=False)\n", "sample_images = x_test[indices]\n", "sample_labels = y_test[indices]\n", "\n", "predictions = model.predict(sample_images)\n", "predicted_labels = np.argmax(predictions, axis=1)\n", "\n", "fig, axes = plt.subplots(2, 5, figsize=(10, 5))\n", "axes = axes.ravel()\n", "\n", "for i in range(num_samples):\n", " axes[i].imshow(sample_images[i].squeeze(), cmap='gray')\n", " axes[i].set_title(f\"Pred: {predicted_labels[i]}\\nTrue: {sample_labels[i]}\")\n", " axes[i].axis('off')\n", "\n", "plt.tight_layout()\n", "plt.show()\n" ] }, { "cell_type": "markdown", "id": "275c8c4c-02d5-4ebf-a8a6-23497ecdcc0c", "metadata": {}, "source": [ "# Finetuning " ] }, { "cell_type": "code", "execution_count": 9, "id": "20935a88-0b97-4975-9e67-8db6eba5b4d3", "metadata": {}, "outputs": [], "source": [ "IMG_SIZE = 224\n", "BATCH_SIZE = 32\n", "NUM_CLASSES = 102\n", "EPOCHS = 10" ] }, { "cell_type": "code", "execution_count": 10, "id": "317dfa46-5f23-4f38-a930-d1731138dcd5", "metadata": {}, "outputs": [], "source": [ "# Data preprocessing: resize and normalize images\n", "def preprocess_image(image, label):\n", " image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))\n", " image = tf.keras.applications.efficientnet_v2.preprocess_input(image)\n", " return image, label\n", "\n", "# Data augmentation for the training set\n", "def augment_image(image, label):\n", " image = tf.image.random_flip_left_right(image)\n", " image = tf.image.random_brightness(image, max_delta=0.2)\n", " return image, label\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "1d697558-87ad-404c-b509-699c38b6d688", "metadata": {}, "outputs": [], "source": [ "# Load Oxford Flowers 102 dataset from TFDS in supervised mode\n", "splits = tfds.Split.ALL\n", "(ds_train, ds_val, ds_test), ds_info = tfds.load(\n", " 'oxford_flowers102',\n", " split=['train', 'validation', 'test'],\n", " with_info=True,\n", " as_supervised=True\n", ")" ] }, { "cell_type": "code", "execution_count": 12, "id": "074d870f-dc7c-4441-97bc-93ff1fcdec38", "metadata": {}, "outputs": [], "source": [ "# Prepare the training dataset\n", "ds_train = ds_train.map(preprocess_image, num_parallel_calls=tf.data.AUTOTUNE)\n", "ds_train = ds_train.map(augment_image, num_parallel_calls=tf.data.AUTOTUNE)\n", "ds_train = ds_train.shuffle(1000).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n", "\n", "# Prepare the validation dataset\n", "ds_val = ds_val.map(preprocess_image, num_parallel_calls=tf.data.AUTOTUNE)\n", "ds_val = ds_val.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n", "\n", "# Prepare the test dataset\n", "ds_test = ds_test.map(preprocess_image, num_parallel_calls=tf.data.AUTOTUNE)\n", "ds_test = ds_test.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)" ] }, { "cell_type": "code", "execution_count": 13, "id": "d29196e0-3b34-4084-8660-163813a4d442", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Model: \"functional_1\"\n",
       "
\n" ], "text/plain": [ "\u001b[1mModel: \"functional_1\"\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ input_layer_2 (InputLayer)      │ (None, 224, 224, 3)    │             0 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ efficientnetv2-b0 (Functional)  │ (None, 7, 7, 1280)     │     5,919,312 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ global_average_pooling2d        │ (None, 1280)           │             0 │\n",
       "│ (GlobalAveragePooling2D)        │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout (Dropout)               │ (None, 1280)           │             0 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_2 (Dense)                 │ (None, 102)            │       130,662 │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "
\n" ], "text/plain": [ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", "│ input_layer_2 (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ efficientnetv2-b0 (\u001b[38;5;33mFunctional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m5,919,312\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ global_average_pooling2d │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "│ (\u001b[38;5;33mGlobalAveragePooling2D\u001b[0m) │ │ │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense_2 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m102\u001b[0m) │ \u001b[38;5;34m130,662\u001b[0m │\n", "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Total params: 6,049,974 (23.08 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m6,049,974\u001b[0m (23.08 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Trainable params: 130,662 (510.40 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m130,662\u001b[0m (510.40 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Non-trainable params: 5,919,312 (22.58 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m5,919,312\u001b[0m (22.58 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2025-03-06 22:54:21.304522: I tensorflow/core/kernels/data/tf_record_dataset_op.cc:376] The default buffer size is 262144, which is overridden by the user specified `buffer_size` of 8388608\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 628ms/step - accuracy: 0.0271 - loss: 4.6292 - val_accuracy: 0.3657 - val_loss: 3.6762\n", "Epoch 2/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m17s\u001b[0m 543ms/step - accuracy: 0.4629 - loss: 3.3349 - val_accuracy: 0.6245 - val_loss: 2.8383\n", "Epoch 3/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 569ms/step - accuracy: 0.7400 - loss: 2.3845 - val_accuracy: 0.7314 - val_loss: 2.2634\n", "Epoch 4/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 613ms/step - accuracy: 0.8393 - loss: 1.7807 - val_accuracy: 0.7755 - val_loss: 1.8674\n", "Epoch 5/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 568ms/step - accuracy: 0.9087 - loss: 1.3706 - val_accuracy: 0.7961 - val_loss: 1.5953\n", "Epoch 6/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 614ms/step - accuracy: 0.9178 - loss: 1.0359 - val_accuracy: 0.8186 - val_loss: 1.4040\n", "Epoch 7/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 607ms/step - accuracy: 0.9508 - loss: 0.8771 - val_accuracy: 0.8245 - val_loss: 1.2597\n", "Epoch 8/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 666ms/step - accuracy: 0.9717 - loss: 0.7116 - val_accuracy: 0.8412 - val_loss: 1.1464\n", "Epoch 9/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m19s\u001b[0m 604ms/step - accuracy: 0.9679 - loss: 0.6431 - val_accuracy: 0.8363 - val_loss: 1.0620\n", "Epoch 10/10\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m19s\u001b[0m 606ms/step - accuracy: 0.9748 - loss: 0.5632 - val_accuracy: 0.8500 - val_loss: 0.9909\n", "\u001b[1m193/193\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m59s\u001b[0m 308ms/step - accuracy: 0.8112 - loss: 1.1196\n", "Test accuracy: 0.82\n" ] } ], "source": [ "base_model = tf.keras.applications.EfficientNetV2B0(\n", " include_top=False,\n", " weights='imagenet',\n", " input_shape=(IMG_SIZE, IMG_SIZE, 3)\n", ")\n", "base_model.trainable = False\n", "\n", "inputs = tf.keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3))\n", "x = base_model(inputs, training=False)\n", "x = tf.keras.layers.GlobalAveragePooling2D()(x)\n", "x = tf.keras.layers.Dropout(0.2)(x)\n", "outputs = tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')(x)\n", "model = tf.keras.Model(inputs, outputs)\n", "\n", "# Compile the model\n", "model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy'])\n", "\n", "model.summary()\n", "\n", "history = model.fit(ds_train,\n", " validation_data=ds_val,\n", " epochs=10)\n", "\n", "# Evaluate on the test set\n", "test_loss, test_acc = model.evaluate(ds_test)\n", "print(f'Test accuracy: {test_acc:.2f}')\n" ] }, { "cell_type": "code", "execution_count": 19, "id": "1ad79201-c261-48d2-a86b-21dbdd43fa35", "metadata": {}, "outputs": [], "source": [ "base_model = tf.keras.applications.EfficientNetV2B0(\n", " include_top=False,\n", " weights='imagenet',\n", " input_shape=(IMG_SIZE, IMG_SIZE, 3)\n", ")\n", "for layer in base_model.layers:\n", " if (layer.name.startswith('stem') or \n", " layer.name.startswith('block1') or \n", " layer.name.startswith('block2') or \n", " layer.name.startswith('block3')):\n", " layer.trainable = False\n", " else:\n", " layer.trainable = True\n", "inputs = tf.keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3))\n", "x = base_model(inputs, training=False)\n", "x = tf.keras.layers.GlobalAveragePooling2D()(x)\n", "x = tf.keras.layers.Dropout(0.2)(x)\n", "outputs = tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')(x)\n", "model = tf.keras.Model(inputs, outputs)\n", "\n", "# Compile the model\n", "model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy'])\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "ba57efcb-ed45-4c27-b3ea-b83646a64e34", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
Model: \"functional_3\"\n",
       "
\n" ], "text/plain": [ "\u001b[1mModel: \"functional_3\"\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ input_layer_6 (InputLayer)      │ (None, 224, 224, 3)    │             0 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ efficientnetv2-b0 (Functional)  │ (None, 7, 7, 1280)     │     5,919,312 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ global_average_pooling2d_2      │ (None, 1280)           │             0 │\n",
       "│ (GlobalAveragePooling2D)        │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_2 (Dropout)             │ (None, 1280)           │             0 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_4 (Dense)                 │ (None, 102)            │       130,662 │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "
\n" ], "text/plain": [ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", "│ input_layer_6 (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ efficientnetv2-b0 (\u001b[38;5;33mFunctional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m5,919,312\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ global_average_pooling2d_2 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "│ (\u001b[38;5;33mGlobalAveragePooling2D\u001b[0m) │ │ │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dropout_2 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense_4 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m102\u001b[0m) │ \u001b[38;5;34m130,662\u001b[0m │\n", "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Total params: 6,049,974 (23.08 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m6,049,974\u001b[0m (23.08 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Trainable params: 5,795,062 (22.11 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m5,795,062\u001b[0m (22.11 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Non-trainable params: 254,912 (995.75 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m254,912\u001b[0m (995.75 KB)\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "model.summary()" ] }, { "cell_type": "code", "execution_count": 21, "id": "d9a659d6-289e-4a06-bf2a-91f1acb5d473", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m57s\u001b[0m 1s/step - accuracy: 0.1591 - loss: 4.1740 - val_accuracy: 0.7255 - val_loss: 1.5996\n", "Epoch 2/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m33s\u001b[0m 1s/step - accuracy: 0.8709 - loss: 1.0392 - val_accuracy: 0.8637 - val_loss: 0.6301\n", "Epoch 3/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m33s\u001b[0m 1s/step - accuracy: 0.9680 - loss: 0.2431 - val_accuracy: 0.8980 - val_loss: 0.4345\n", "Epoch 4/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m33s\u001b[0m 1s/step - accuracy: 0.9912 - loss: 0.0787 - val_accuracy: 0.8990 - val_loss: 0.3686\n", "Epoch 5/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m32s\u001b[0m 1s/step - accuracy: 0.9879 - loss: 0.0492 - val_accuracy: 0.9196 - val_loss: 0.3177\n", "Epoch 6/6\n", "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m33s\u001b[0m 1s/step - accuracy: 0.9987 - loss: 0.0243 - val_accuracy: 0.9088 - val_loss: 0.3439\n" ] } ], "source": [ "history = model.fit(ds_train,\n", " validation_data=ds_val,\n", " epochs=6)" ] }, { "cell_type": "code", "execution_count": 22, "id": "39c06741-e347-4b1c-858a-7d5259c921df", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m193/193\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m48s\u001b[0m 250ms/step - accuracy: 0.8819 - loss: 0.4619\n", "Test accuracy: 0.88\n" ] } ], "source": [ "# Evaluate on the test set\n", "test_loss, test_acc = model.evaluate(ds_test)\n", "print(f'Test accuracy: {test_acc:.2f}')" ] }, { "cell_type": "code", "execution_count": null, "id": "66f7e274-62b6-4c25-bd4a-e49ed7e08990", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.20" } }, "nbformat": 4, "nbformat_minor": 5 }