{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "1gRj-x7h332N" }, "source": [ "# Training Neural Networks\n", "\n", "The network we built in the previous part isn't so smart, it doesn't know anything about our handwritten digits. Neural networks with non-linear activations work like universal function approximators. There is some function that maps your input to the output. For example, images of handwritten digits to class probabilities. The power of neural networks is that we can train them to approximate this function, and basically any function given enough data and compute time.\n", "\n", "\n", "\n", "At first the network is naive, it doesn't know the function mapping the inputs to the outputs. We train the network by showing it examples of real data, then adjusting the network parameters such that it approximates this function.\n", "\n", "To find these parameters, we need to know how poorly the network is predicting the real outputs. For this we calculate a **loss function** (also called the cost), a measure of our prediction error. For example, the mean squared loss is often used in regression and binary classification problems\n", "\n", "$$\n", "\\large \\ell = \\frac{1}{2n}\\sum_i^n{\\left(y_i - \\hat{y}_i\\right)^2}\n", "$$\n", "\n", "where $n$ is the number of training examples, $y_i$ are the true labels, and $\\hat{y}_i$ are the predicted labels.\n", "\n", "By minimizing this loss with respect to the network parameters, we can find configurations where the loss is at a minimum and the network is able to predict the correct labels with high accuracy. We find this minimum using a process called **gradient descent**. The gradient is the slope of the loss function and points in the direction of fastest change. To get to the minimum in the least amount of time, we then want to follow the gradient (downwards). You can think of this like descending a mountain by following the steepest slope to the base.\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "C-bEg-Zz4Q7z" }, "source": [ "## Backpropagation\n", "\n", "For single layer networks, gradient descent is straightforward to implement. However, it's more complicated for deeper, multilayer neural networks like the one we've built. Complicated enough that it took about 30 years before researchers figured out how to train multilayer networks.\n", "\n", "Training multilayer networks is done through **backpropagation** which is really just an application of the chain rule from calculus. It's easiest to understand if we convert a two layer network into a graph representation.\n", "\n", "\n", "\n", "In the forward pass through the network, our data and operations go from bottom to top here. We pass the input $x$ through a linear transformation $L_1$ with weights $W_1$ and biases $b_1$. The output then goes through the sigmoid operation $S$ and another linear transformation $L_2$. Finally we calculate the loss $\\ell$. We use the loss as a measure of how bad the network's predictions are. The goal then is to adjust the weights and biases to minimize the loss.\n", "\n", "To train the weights with gradient descent, we propagate the gradient of the loss backwards through the network. Each operation has some gradient between the inputs and outputs. As we send the gradients backwards, we multiply the incoming gradient with the gradient for the operation. Mathematically, this is really just calculating the gradient of the loss with respect to the weights using the chain rule.\n", "\n", "$$\n", "\\large \\frac{\\partial \\ell}{\\partial W_1} = \\frac{\\partial L_1}{\\partial W_1} \\frac{\\partial S}{\\partial L_1} \\frac{\\partial L_2}{\\partial S} \\frac{\\partial \\ell}{\\partial L_2}\n", "$$\n", "\n", "**Note:** I'm glossing over a few details here that require some knowledge of vector calculus, but they aren't necessary to understand what's going on.\n", "\n", "We update our weights using this gradient with some learning rate $\\alpha$. \n", "\n", "$$\n", "\\large W^\\prime_1 = W_1 - \\alpha \\frac{\\partial \\ell}{\\partial W_1}\n", "$$\n", "\n", "The learning rate $\\alpha$ is set such that the weight update steps are small enough that the iterative method settles in a minimum." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "worDfYepJH6j" }, "source": [ "## Import Resources" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "colab": {}, "colab_type": "code", "id": "jFdhxHwr57Yn" }, "outputs": [], "source": [ "%matplotlib inline\n", "%config InlineBackend.figure_format = 'retina'\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", "tfds.disable_progress_bar()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import logging\n", "logger = tf.get_logger()\n", "logger.setLevel(logging.ERROR)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 85 }, "colab_type": "code", "id": "yCtUH8paXqBQ", "outputId": "1a4c93cf-21a8-4574-d121-f238912d28e8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using:\n", "\t• TensorFlow version: 2.16.1\n", "\t• Running on GPU\n" ] } ], "source": [ "print('Using:')\n", "print('\\t\\u2022 TensorFlow version:', tf.__version__)\n", "print('\\t\\u2022 Running on GPU' if tf.test.is_gpu_available() else '\\t\\u2022 GPU device not found. Running on CPU')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "physical_devices = tf.config.list_physical_devices('GPU')\n", "for device in physical_devices:\n", " tf.config.experimental.set_memory_growth(device, True)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3zQV8MLaJOjN" }, "source": [ "## Load the Dataset" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 360 }, "colab_type": "code", "id": "Att74swb7Ol0", "outputId": "a98f6ee1-9881-4d8d-8766-b8b00a2cb4f8" }, "outputs": [], "source": [ "training_set, dataset_info = tfds.load('mnist', split='train', as_supervised = True, with_info = True)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IiSe5BPrJquE" }, "source": [ "## Create Pipeline" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "colab": {}, "colab_type": "code", "id": "9r4EMOdT9pM3" }, "outputs": [], "source": [ "def normalize(image, label):\n", " image = tf.cast(image, tf.float32)\n", " image /= 255\n", " return image, label\n", "\n", "num_training_examples = dataset_info.splits['train'].num_examples\n", "\n", "batch_size = 64\n", "\n", "training_batches = training_set.cache().shuffle(num_training_examples//4).batch(batch_size).map(normalize).prefetch(1)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "K9SC4gnUJucy" }, "source": [ "## Build the Model" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": {}, "colab_type": "code", "id": "Mo2DfMVvAdbd" }, "outputs": [], "source": [ "model = tf.keras.Sequential([\n", " tf.keras.layers.Flatten(input_shape=(28, 28, 1)),\n", " tf.keras.layers.Dense(128, activation='relu'),\n", " tf.keras.layers.Dense(64, activation='relu'),\n", " tf.keras.layers.Dense(10, activation='softmax')\n", "])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "5TCpaAlcKCDB" }, "source": [ "## Getting the Model Ready For Training\n", "\n", "Before we can train our model we need to set the parameters we are going to use to train it. We can configure our model for training using the `.compile` method. The main parameters we need to specify in the `.compile` method are:\n", "\n", "* **Optimizer:** The algorithm that we'll use to update the weights of our model during training. Throughout these lessons we will use the [`adam`](http://arxiv.org/abs/1412.6980) optimizer. Adam is an optimization of the stochastic gradient descent algorithm. For a full list of the optimizers available in `tf.keras` check out the [optimizers documentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/optimizers#classes).\n", "\n", "\n", "* **Loss Function:** The loss function we are going to use during training to measure the difference between the true labels of the images in your dataset and the predictions made by your model. In this lesson we will use the `sparse_categorical_crossentropy` loss function. We use the `sparse_categorical_crossentropy` loss function when our dataset has labels that are integers, and the `categorical_crossentropy` loss function when our dataset has one-hot encoded labels. For a full list of the loss functions available in `tf.keras` check out the [losses documentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/losses#classes).\n", "\n", "\n", "* **Metrics:** A list of metrics to be evaluated by the model during training. Throughout these lessons we will measure the `accuracy` of our model. The `accuracy` calculates how often our model's predictions match the true labels of the images in our dataset. For a full list of the metrics available in `tf.keras` check out the [metrics documentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/metrics#classes).\n", "\n", "These are the main parameters we are going to set throught these lesson. You can check out all the other configuration parameters in the [TensorFlow documentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/Model#compile)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "colab": {}, "colab_type": "code", "id": "jYv3pv5-InR1" }, "outputs": [], "source": [ "model.compile(optimizer='adam',\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy'])" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Y5CjYa8ES3OI" }, "source": [ "## Taking a Look at the Loss and Accuracy Before Training\n", "\n", "Before we train our model, let's take a look at how our model performs when it is just using random weights. Let's take a look at the `loss` and `accuracy` values when we pass a single batch of images to our un-trained model. To do this, we will use the `.evaluate(data, true_labels)` method. The `.evaluate(data, true_labels)` method compares the predicted output of our model on the given `data` with the given `true_labels` and returns the `loss` and `accuracy` values." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 105 }, "colab_type": "code", "id": "u_7aijzvJQZ7", "outputId": "f66f355e-d030-4c30-e50c-7bba125a20cf" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2/2 [==============================] - 9s 7ms/step - loss: 2.3233 - accuracy: 0.0938\n", "\n", "Loss before training: 2.323\n", "Accuracy before training: 9.375%\n" ] } ], "source": [ "for image_batch, label_batch in training_batches.take(1):\n", " loss, accuracy = model.evaluate(image_batch, label_batch)\n", "\n", "print(f'\\nLoss before training: {loss:,.3f}')\n", "print(f'Accuracy before training: {accuracy:.3%}')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zvsfbLEMZjZ5" }, "source": [ "## Training the Model\n", "\n", "Now let's train our model by using all the images in our training set. Some nomenclature, one pass through the entire dataset is called an *epoch*. To train our model for a given number of epochs we use the `.fit` method, as seen below:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 187 }, "colab_type": "code", "id": "Z-CgmnKBZDjq", "outputId": "38ab455c-767a-4705-c172-9d7cc926c239" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", "I0000 00:00:1713707293.846142 2594 service.cc:145] XLA service 0x75d9084ab520 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", "I0000 00:00:1713707293.846190 2594 service.cc:153] StreamExecutor device (0): NVIDIA GeForce RTX 3060, Compute Capability 8.6\n", "I0000 00:00:1713707293.846196 2594 service.cc:153] StreamExecutor device (1): NVIDIA GeForce RTX 2060 SUPER, Compute Capability 7.5\n", "I0000 00:00:1713707293.922612 2594 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "938/938 [==============================] - 6s 3ms/step - loss: 0.2724 - accuracy: 0.9203\n", "Epoch 2/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.1110 - accuracy: 0.9674\n", "Epoch 3/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.0778 - accuracy: 0.9757\n", "Epoch 4/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.0579 - accuracy: 0.9822\n", "Epoch 5/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.0457 - accuracy: 0.9854\n" ] } ], "source": [ "EPOCHS = 5\n", "\n", "history = model.fit(training_batches, epochs=EPOCHS)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IFgG_WfUjCic" }, "source": [ "The `.fit` method returns a `History` object which contains a record of training accuracy and loss values at successive epochs, as well as validation accuracy and loss values when applicable. We will discuss the history object in a later lesson. \n", "\n", "With our model trained, we can check out it's predictions." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 243 }, "colab_type": "code", "id": "ghr7z-SnctRw", "outputId": "8e946c9a-56b5-45f4-e79f-c6451ff8b7d5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2/2 [==============================] - 0s 3ms/step\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABJsAAAKPCAYAAADKYMuqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAB7CAAAewgFu0HU+AABaC0lEQVR4nO3dd3yV5f0//ncg7C1D2c6IezDqZihaF4ioFQe4tVqrdWtbpY6qtX7U2tYFiqiFOnDjREREkVHFLYIgKyAoCLJC4Pz+8Mf5EgkZcCcngefz8cjjcZ9zX3lf75M7QPLiuq+TlUqlUgEAAAAACaiS6QYAAAAA2HwImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAgA0644wzIisrK7KysmLQoEGZbody1qVLl/T1f/vttzPdTqGmT5+e7nHbbbdNrG5JXnv//v3TY/r371/omLfffjs9pkuXLon1BxWZsAkAADZDixcvjv/+979xzjnnxN577x0tW7aMGjVqRL169aJNmzZx2GGHxbXXXhvvv/9+plvdbKwbPBT2UatWrWjRokV069Ytrr/++pg2bVqmWwYoE8ImAADYjCxbtiz++te/xrbbbhsnn3xyDBw4MCZNmhRz5syJvLy8+Omnn2LmzJkxYsSIuO222+KAAw6InXfeOYYMGRKpVCrT7W/WVqxYEbm5uTFy5Mi46aabYscdd4wrrrgi8vLyMt0aFcC6wSRUdtmZbgAAAEjGjBkz4thjj42PP/64wPNt2rSJPffcM5o2bRqrV6+OuXPnxqRJk2LevHkRETF58uQ45ZRTYubMmXHVVVdlovXNTosWLaJXr14Fnlu6dGl88cUXMW7cuEilUrFmzZq48847Izc3Nx5//HEhA7DZEDYBAMBmYPr06bH//vvH3LlzI+LnVRJ9+vSJ6667Lnbbbbf1xqdSqZgwYULce++98cQTT8SaNWti2bJl5d32ZmunnXaKf/7zn4We++STT6JPnz7x2WefRUTEf/7znzjuuOPixBNPLM8WKUZSe1R16dLFqkG2OG6jAwCASi4vLy9OPPHEdNBUs2bNGDZsWDzxxBOFBk0RP4dRHTt2jMGDB8ekSZNi9913L8+Wt2h77LFHvPbaa9GgQYP0c3fddVcGOwJIlrAJAAAqub/97W8xYcKE9ONHH300jjvuuBJ//u677x5jx46N7t27l0F3FKZly5ZxxhlnpB+PGzcuFi9enLmGABIkbAIAgEps+fLl8Y9//CP9+Pjjj4+TTjqp1HXq1KkTBx544Eb3sWrVqnjttdfiqquuiq5du0aLFi2iZs2aUatWrWjVqlUceeSRcffdd8dPP/1U4ppffvllXHXVVbHffvtFkyZNonr16lGzZs1o1qxZtG/fPs4888x49NFHY+HChRus8dNPP8X9998fRx99dLRp0yZq164d1apViwYNGkS7du3i2GOPjb/+9a/x6aefbvRr31gHHHBA+nj16tUxY8aM9OO33347vVl0ly5d0s8PHz48+vTpEzvttFPUrVs3srKy4u67716vdiqViqeeeir69OkTO+ywQ9StWzfq1q0bO+ywQ5xyyinx9NNPb/StXTNnzow//elPsddee8VWW20VderUiXbt2sUf/vCHmDJlSolqlMX3yy+NGDEi/fpr1aoVTZs2jYMPPjj++c9/xsqVK4v9/C5duqSvwabcUreha/nLc+va0DsaTp8+PfLy8qJp06bp50rzjpKdO3dOf966f29A4lIAAEClNXjw4FREpD/efffdROv369cvXfuRRx4pdMyMGTNSjRs3LtDHhj4aN26cev3114ud94YbbkhVrVq1RDVPPfXUQmu89957qZYtW5aoRkSkVq1atSlfqtQNN9yQrtW5c+dix7/++usF5h8zZkz63MiRIwvUWrRoUapXr16F9n3XXXcVqDt58uTUPvvsU+zrbd++fWrq1KlF9ti5c+f0+JEjR6aef/75VIMGDTZYs1atWqkHHnigyJpJf79MmzYtPb5t27apvLy81HnnnVdk3V122SX11Vdfleq1F2bda37DDTcUOuaX13JD50ryMW3atFQqlUpdfvnl6efOOeecIl/HWpMnT05/To0aNVLff/99iT4PNoYNwgEAoBJ766230sdt2rTZpNVJG2vp0qXx/fffR0REo0aNYrfddou2bdtG3bp1Iy8vL6ZNmxZjx46NFStWxPfffx9HHXVUjBo1qsDKnnXdc8898Ze//CX9uEmTJrHffvtF8+bNIysrK3744Yf48ssv44svvojVq1cXWmPmzJlxxBFHxJIlSyIiolq1atGxY8fYcccdo3bt2rF06dKYPn16TJo0KWO3r/1yRda6ezitK5VKxWmnnRYvvfRSZGVlRYcOHWLXXXeNVCoVn376aYFVMV988UV07tw55s+fn35ujz32iL333juysrLiww8/jE8++SQiIiZOnBgHHHBAvPPOO5GTk1NsvxMmTIg//vGPkZeXF40bN44uXbpEo0aNYvr06TFq1KhYtWpVLF++PM4///yoWrVqnH322YXWSfr75ZeuvvrqePDBByMiYs8994y99947UqlUTJw4MT7//PP016lbt27x/vvvR+vWrUtUtyy0bNkyLrroooiI+Ne//pV+fu1zv1S/fv2IiDjvvPPizjvvjIiI//73v3H33XdHnTp1ipzr4YcfTh8ff/zxsdVWW21S71CkDIddAADAJthhhx3SqxVOPPHExOuXZGXT9OnTUxdffHHqgw8+SK1evbrQMT/++GOB1Rg5OTmFjl21alWqSZMm6XG33nprKi8vr9Ca33//ferhhx9O3X777eudu/TSS9M1Dj744NTs2bMLrbFq1arU22+/nTr11FNT+fn5G/gqlExpVzb9/ve/T4+vWrVq6scff0yfW3fFS3Z2dioiUnvssUfq448/Xq/OihUrUqlUKrVy5crUXnvtlf68Zs2apd544431xr/22msFvsb77rvvBr/G667uqV69eioiUldccUV6zrVmzpyZOvjgg9Nja9eunZoyZUqhNZP8fkmlCq5sqlatWnpF1Guvvbbe2BdeeCFVv3799Pgjjjii0Jq/fO1ltbJpXWvHlPTX9HX7e/jhh4scm5+fn2revHl6/IgRI0o0B2wsezYBAEAl9u2336aPN/TOc2Wtbdu28Y9//CM6deoUVaoU/itG/fr14+9//3tccMEFERExefLkeO2119Yb9+WXX8aCBQsiIuLAAw+Ma665JqpVq1Zoza222irOPPPMuOqqq9Y7N3r06PTxww8/HC1atCi0RnZ2dnTu3Dkef/zxqFq1atEvNEGzZ8+ORx99NP24Y8eO6VUrv5Sfnx/bbLNNvPXWW7HHHnusd75GjRoREfHEE0/EpEmTIuLnlVyvvvpqHHbYYeuNP/zww2P48OGRnf3zjS7/+9//YsiQIcX2nJeXFxdccEHccccd6TnXatWqVQwfPjzatWsXERHLli0rsDptXUl+v/zSqlWrokqVKvHCCy/E4Ycfvt75Y489Np555pn049dee63A6sDK5LzzzksfDxw4sMixw4cPj9zc3IiI2GGHHaJr165l2hsImwAAoJJavHhx5Ofnpx83bNgwc82U0Jlnnpk+fvPNN9c7v+4tbU2bNt3oeZKqUxY+/fTTOOKII+LHH39MP/eHP/yhyM+5/vrro0mTJkWOeeCBB9LHv/3tb2OfffbZ4NiOHTvGueeem3583333Fdd21KtXL2677bYNnq9bt2787W9/Sz9+6qmnCrzGjVHc90thTj311CJvuTvssMPi+OOPTz9+6KGHNr7BDOrdu3f6VrgxY8bEV199tcGx64ZRZ5111nobkkPS7NkEAACV1Nr9iNaqW7duhjr5f1atWhUffPBBTJo0KebOnRtLliwpEIit2/NHH3203uevu3/OyJEjY/LkySXaT6iwOl9//XVERNx///1x9dVXl7rGpvj666/jd7/7XYHnli1bFp9//nmMGzeuwDvBnXTSSXHiiScWWe83v/lNkeeXLFkSEyZMSD8+66yziu3xnHPOSYdM48ePj6VLlxa570+PHj02uK/UWkcddVQ0bdo05s+fHytWrIj3338/fv3rX29w/KZ+vxSmb9++xY7p169fDBs2LCJ+/j6rjGrUqBF9+/ZNvxvhwIEDC4R9a82bNy9efvnliIioWrVqnHHGGeXYJVsqYRMAAFRS9erVK/B4U94mflMtX748/vrXv8b999+fvg2uOIWNa926dey3334xduzY+PHHH6N9+/Zx+umnR69eveLAAw+M2rVrl6j2SSedlL496pprrok33ngjTj311OjevXu0atWq5C9sI82ZM6fAhs+FycrKiksuuSRuu+22IleabLfddsVu5vzxxx+nN0uvW7du7LnnnsX2uPfee0edOnVi6dKlsXr16pg0aVKRK4L233//YmtWrVo1OnbsGMOHD4+IiA8//LDQsCmp75dfysrKil/96lfFjlv3tcybNy9yc3OjefPmJeqjIjnvvPPSYdPgwYPjr3/9a/r2yLUeffTRdIB31FFHbfCWUkiS2+gAAKCSql+/foFfLBctWpSRPhYuXBgHHHBA3HzzzSUODiLWX5m11sCBA2PrrbeOiJ8DtPvuuy8OP/zwaNCgQXTs2DEuv/zyeP311zf4TnQRP6/aOe6449KPR4wYEWeddVa0bt062rZtG6eddloMHDiwVP1uqpo1a8Y222wTXbp0iT/96U8xZcqUuOuuu9bb/+iXSnIb4LrvPte6desS3SZVpUqVAivJivtatGnTptiavxy3bl9rJf39sq5GjRqtF8IWpmnTplGzZs0i+6wMdtlllzjooIMi4ufQ7KWXXlpvzLrvQnfOOeeUW29s2YRNAABQibVt2zZ9vPZt3cvbRRddlL7FqXr16nHOOefE888/H5MnT07fFpVKpSKVSsW0adPSn7dmzZpC6+26664xadKkuPjiiwvctpWfnx8TJkyI//u//4sjjjgi2rZtGwMGDCi0RtWqVWPYsGExYMCA2HXXXQucmzFjRjzxxBNxzjnnRIsWLeKcc86JH374YRO/CgV17tw5/ZrXfixfvjxyc3Nj5MiRcdNNN8X2229folq1atUqdsy6q9qKuhXul9YdW1yYU9JVZcXVTPr7ZWN6LEmflUVRG4W/++676b2cmjdvHkcffXS59saWS9gEAACV2NpVDRERH3zwQbnPP3v27Bg6dGhE/LxS5tVXX42HHnooevToETvttFPUrVu3wLu8lfSX+q233jr+8Y9/xLx58+Ltt9+Om266KY488sgC79g2e/bsOPfcc+P3v/99oTWysrLi7LPPjs8++yy++uqrePDBB6Nfv34FQp5Vq1bFwIEDo1OnTpV2dUtEwf26li5dWuLPW3dscSuCli1btsk1y+r7pbQ9FtdnZXLCCSdEo0aNIiLilVdeiTlz5qTPrRs+nXHGGeX6jots2YRNAABQiXXr1i19/O2338Z7771XrvO/9dZb6c2ujzzyyGLfUv3bb78tVf0aNWpE586d409/+lMMHz48FixYEK+88kqBkO3ee++N8ePHF1knJycnzj333Bg0aFBMnTo1vvrqq7jsssvSv3xPnTo1/vKXv5Sqt4pk3VvtZs2aVWAD8g1Zs2ZNzJw5M/24uHe7mzFjRol6KapmWX+/LFy4sER7ly1YsCBWrFixwT4rk1q1asVpp50WERGrV6+ORx99NCJ+DuqeeuqpiPh/wSuUF2ETAABUYieeeGKBX5T/7//+r1znX3cVxR577FHs+HfeeWeT5qtWrVr8+te/jjfffDN233339PMvvvhiqerk5OTEnXfeWSBgeuGFFzapt0zac88908HZkiVL4pNPPin2cyZNmpRe3VO1atXYa6+9ihw/duzYYmuuXr26QPC37777Fjhf1t8vqVSqRCv83n///fTx1ltvXek3zV73Vrq1ezQNHTo0fX07d+4cO+ywQ0Z6Y8skbAIAgEqsVq1aBW4je+aZZ+KZZ54pdZ2lS5du1KqoKlX+368Uxd3CtGzZshg8eHCp5yhMjRo14vDDD08/njdv3kbV6dGjxybXqAjq1asXHTp0SD8eNGhQsZ+z7i1WnTp1KnavpxdeeCEWL15c5JhXX301vvvuu4j4eUP0X76DXXl8vzz22GPFjlm3bnGrq8rLuhuWr1q1qlSfu/vuu6e/1lOmTIlRo0YVuL42Bqe8CZsAAKCSu+qqqwqsIDn99NNLtdLn008/jf322y9ef/31Us+97v5Hw4cPL/Id4i6//PJiA52FCxeWaCPoiIK3azVr1qzAuZK+y1lRNSqb888/P338r3/9Kz7++OMNjp04cWI88MAD6ccXXHBBsfUXL14c11133QbPL126NK666qr04xNOOKHABu8RyX+/FObxxx8vcnXTyJEjCwSyFSWIady4cfp49uzZpf78dVc3XX311emvQaNGjaJ3796b3iCUgrAJAAAquRo1asRTTz2VDkuWL18exx13XPTt2ze++OKLQj8nlUrF+PHjo1+/frHXXnvFp59+ulFzd+vWLf0OYFOmTIl+/frFokWLCoxZvHhxnHfeeXH//fcXu3rm+eefj5ycnPj73/8e06dPL3TMypUr45///Gc8/fTT6eeOPPLIAmPatGkT559/fowaNWqD4dWECRPi4osv3mCNyubUU09N3wqXl5cXRxxxRIwcOXK9cW+++WYceeSRkZ+fHxE/3+rWp0+fYutXr149/vWvf8U111wTeXl5Bc7Nnj07jj766PQ7ItaqVStuuOGG9Wok/f3yS9WqVYvVq1fHMcccE2+++eZ6519++eXo1atXet+o7t27x6GHHlqqOcrKureFrt1rqTROOumkdLi3bth26qmnFlg1BeUhO9MNAAAAm2777bePDz74II499tj49NNPY82aNfHYY4/FY489Fttuu23sueee0aRJk1i9enXMnTs3Pvroo/VWjWzMO3I1atQorrjiirjxxhsjIuKJJ56IV155JX71q19Fy5YtIzc3N95+++1YunRpZGdnx7///e/o169fkTWnTp0aV155ZVx55ZXRpk2b2HPPPdNB2ty5c2Ps2LHxww8/pMefeuqpccABBxSosXz58njwwQfjwQcfjHr16sXee+8dbdu2jTp16sSCBQviyy+/jM8++yw9vmnTptG/f/9Sv/6KpHr16jFkyJDo3LlzzJ8/P+bOnRvdunWLvfbaK/bee++IiPjoo49i0qRJ6c9p1qxZDBkyJKpVq1Zs/Ztvvjn++Mc/xu233x4DBw6MLl26RKNGjeLbb7+Nt99+u0AAdffdd8eOO+64Xo2y+H5ZV4sWLaJXr15x9913R/fu3dOvPZVKxcSJEwtc8+bNm8dDDz1U4tplrXfv3vHaa69FxM8rk1555ZXYbbfdokaNGukxf/zjH9PvPPdLtWvXjlNPPTX+/e9/F3i+oqzcYguTAgAANhtLlixJ3XjjjamGDRumIqJEH3vttVfq2WefLbRev3790uMeeeSRQsfk5+en+vbtW+QcDRs2TD377LOpadOmpZ9r27bterWeeuqpVFZWVon6rlKlSurCCy9M5eXlrVenbt26pXr9X3zxxSZ81X92ww03pGt27tx5k2qNHDlyo2t99dVXqX322afY173vvvumpkyZUmStzp07p8ePHDky9dxzz6Xq16+/wZo1a9ZM/fvf/y6yZpLfL6lUar0xeXl5qbPPPrvI+jvvvHOx1/yXr70w617zG264odAxJb2WeXl5qUMOOaTIvqdNm1Zkzx999FGB8R06dChyPJQVK5sAAGAzUrdu3fjzn/8cv//972P48OHxxhtvxMSJE+O7776LH374IapXrx5bbbVVtGvXLn71q1/Fcccdt947hpVW1apV49FHH40TTzwxHnzwwfjggw9i4cKF0ahRo2jTpk307NkzzjrrrGjRosUGb41b64QTTojc3Nx4/fXXY8yYMTFp0qT45ptv0rdaNWjQIHJycuKggw6Kvn37xq677lpone+//z7eeeedGDVqVIwfPz6+/vrrmDdvXqxYsSJq164drVq1ivbt20fv3r2jR48eBTauruxycnJiwoQJ8fTTT8czzzwT48aNS2/a3axZs/jVr34VJ5xwQvTu3TuysrJKVbtnz57x8ccfx/333x8vv/xyzJgxI/Ly8qJ169bx61//On73u9/FTjvtVGSNJL9fClOtWrUYMGBAnHjiiTFw4MAYP3585ObmRp06dWKXXXaJ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sAkAAACAxAibAAAAAEiMsAkAAACAxAibAAAAAEiMsAkAAACAxGRnugHYnHz99deJ1brrrrsSq3XfffclVitJ1atXT7Teqaeemlithg0bJlarV69eidU6+OCDE6sFAABQFqxsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAgFLIy8uLAQMGxBFHHBHNmzePGjVqRN26dWPnnXeOM888M957771MtwgAkFHZmW4AAKCy+Pbbb+Poo4+Ozz77rMDzeXl5MXny5Jg8eXIMGjQoLr744rjnnnsiKysrQ50CAGSOlU0AACWwatWqAkHTnnvuGYMGDYr3338/Xn/99bj++uujTp06ERFx7733xu23357JdgEAMsbKJgCAEnj++efTQdP+++8fo0ePjqpVq6bPd+/ePXr06BH7779/rFq1Km6//fa44oorIjvbj1sAwJbFyiYAgBJYdy+ma6+9tkDQtFb79u3jmGOOiYiIRYsWxRdffFFu/QEAVBTCJgCAEsjLy0sfb7/99hsct8MOOxT6OQAAWwphEwBACey8887p42+++WaD46ZOnRoREVlZWbHTTjuVeV8AABWNTQTY4o0bNy6xWr/+9a8Tq7VkyZLEah188MGJ1erWrVtitSqyhQsXJlbr+OOPT6zWrrvumlitJ598MrFaERFbb711ovWgounTp0/86U9/isWLF8ftt98eRx111Hq30n344Yfx8ssvR0TEKaecEvXr1y/VHLNmzSryfG5ubumaBgDIAGETAEAJNGnSJB577LHo06dPjBkzJjp27BiXXnpp5OTkxE8//RRjxoyJO++8M/Ly8mLfffeNO++8s9RztG7dugw6BwAoX8ImAIAS6tGjR0ycODHuvPPOGDhwYPTr16/A+a233jpuuummOPfcc6N27doZ6hIAILOETQAAJZSXlxeDBw+O559/PlKp1Hrn582bF48//nhst9120aNHj1LXnzlzZpHnc3Nzo1OnTqWuCwBQnoRNAAAlsHTp0jjyyCNj9OjRUbVq1bjqqqvizDPPjO233z5WrFgRH3zwQdx4443x7rvvxnHHHRd///vf47LLLivVHK1atSqj7gEAyo93owMAKIH+/fvH6NGjIyJi4MCBcfvtt0e7du2ievXqUb9+/ejevXuMHDkyunbtGqlUKq688sqYNGlShrsGACh/wiYAgGKkUql4+OGHIyIiJydnvb2a1srOzo6bbropIiLWrFkTgwYNKq8WAQAqDGETAEAx5s2bFz/88ENEROyzzz5Fjm3fvn36+MsvvyzTvgAAKiJhEwBAMbKz/982l/n5+UWOXbVqVaGfBwCwpRA2AQAUY6uttor69etHRMT7779fZOA0atSo9PF2221X5r0BAFQ0wiYAgGJUqVIljj766IiImDNnTtxyyy2Fjlu4cGFcffXV6cfHHHNMufQHAFCRWNsNAFAC119/fTz//POxbNmy6N+/f0ycODH69esX22+/faxYsSLGjh0bd999d8yYMSMiIg499NA4/PDDM9w1AED5EzYBAJRAu3bt4vnnn48+ffrEggUL4sUXX4wXX3yx0LHdunWLp556qpw7BACoGIRNAAAldNhhh8WXX34ZAwcOjFdeeSU+++yzWLRoUWRnZ8c222wTHTt2jFNOOSV69OgRWVlZmW4XACAjhE0AAKXQuHHjuOqqq+Kqq67KdCsAABWSDcIBAAAASIywCQAAAIDECJsAAAAASIywCQAAAIDE2CCcSmf58uWJ1jvvvPMSq7Vw4cLEag0ePDixWqeffnpitSi9P/zhD4nV6tq1a2K1jjrqqMRqRUS8+uqridVq2rRpYrUAAIDyZWUTAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQGGETAAAAAIkRNgEAAACQmOxMNwCltWzZskTrzZgxI7Fat9xyS2K1TjvttMRqkVnbbrttYrUuvfTSClkrIuLRRx9NrNYVV1yRWC0AAKB8WdkEAAAAQGKETQAAAAAkRtgEAAAAQGKETQAAJdClS5fIysoq1cfbb7+d6bYBAMqdsAkAoAxUqVIldtppp0y3AQBQ7rwbHQBACTzyyCOxdOnSIsd8/vnn8Zvf/CYiIg499NBo2bJlebQGAFChCJsAAEpgu+22K3bMY489lj7u27dvWbYDAFBhuY0OACABa9asiSeeeCIiIurWrRvHH398hjsCAMgMYRMAQAJGjBgRs2fPjoiIE044IWrXrp3hjgAAMkPYBACQgMGDB6eP3UIHAGzJ7NkEALCJfvrpp3j22WcjIqJt27bRpUuXjaoza9asIs/n5uZuVF0AgPIkbAIA2ETPPPNM+p3qTjvttMjKytqoOq1bt06yLQCAjHAbHQDAJnILHQDA/2NlEwDAJpg1a1a8/fbbERGx3377RU5OzkbXmjlzZpHnc3Nzo1OnThtdHwCgPAibAAA2weOPPx5r1qyJiIh+/fptUq1WrVol0RIAQEa5jQ4AYBM89thjERFRo0aN+M1vfpPhbgAAMk/YBACwkSZMmBCff/55REQcc8wx0ahRowx3BACQecImAICNtO7G4Jt6Cx0AwObCnk1UOo0bN0603sUXX5xYrcsuuyyxWhv7ttls3vbYY4/EamVnJ/tPwO23355YrSuuuCKxWlBWVq1aFUOHDo2IiKZNm8aRRx6Z4Y4AACoGK5sAADbCK6+8EvPnz4+IiFNOOSXxABcAoLISNgEAbIR1b6Hr27dvBjsBAKhYhE0AAKW0cOHCeOmllyIiYvfdd4999903wx0BAFQcwiYAgFL673//GytXrowIq5oAAH5J2AQAUEqPPfZYRERUrVo1Tj311Ax3AwBQsdjJEgCglMaMGZPpFgAAKiwrmwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABITHamG4BM+8tf/pLpFqDEunXrllitJk2aJFYrIuK7775LrNZbb72VWK0kv2YAAEDxrGwCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASk53pBgAAKqMZM2bEwIED4+WXX45vv/02lixZEk2bNo1tt902unbtGieddFLsvvvumW4TAKDcCZsAAErp3nvvjWuvvTaWLl1a4PlZs2bFrFmz4t13343FixfH3XffnZkGAQAySNgEAFAKN998c/z5z3+OiIicnJw499xzo2PHjtGgQYP4/vvv48MPP4xnn302qlSxWwEAsGUSNgEAlNCIESPSQVPfvn1jwIABUa1atQJjDj300LjiiisiLy8vEy0CAGScsAkAoATWrFkTv/3tbyMiYq+99oqBAwdGdvaGf5SqXr16ebUGAFChWN8NAFACr7/+enz99dcREXH11VcXGTQBAGzJ/JQEQCLWrFmTWK05c+YkVguS8tRTT0VERFZWVhxzzDHp53/44Yf4/vvvo3HjxrHVVltlqj0AgArDyiYAgBIYO3ZsRERsu+22Ua9evfjPf/4Te+yxRzRu3DhycnKicePGsfPOO8ff//73WLlyZYa7BQDIHCubAACKsWbNmvjyyy8jIqJJkyZxySWXxD/+8Y/1xk2ePDmuvPLKePbZZ+Pll1+Ohg0blmqeWbNmFXk+Nze3VPUAADJB2AQAUIwff/wxfavoJ598EuPHj4/mzZvHHXfcEUcddVTUrFkzxo8fH1dffXWMHTs23nvvvTjrrLNi2LBhpZqndevWZdE+AEC5chsdAEAxli5dmj5esWJF1K5dO0aOHBmnnnpqNGrUKGrVqhWHHHJIvPXWW7HXXntFRMSzzz4bH3zwQaZaBgDIGCubAACKUbNmzQKPzznnnNh5553XG1erVq245ZZb0huI//e//41f/epXJZ5n5syZRZ7Pzc2NTp06lbgeAEAmCJsAAIpRr169Ao8PP/zwDY499NBDIzs7O/Lz82P8+PGlmqdVq1Yb1R8AQEXiNjoAgGLUqFEjmjZtmn5c1N5KNWvWjCZNmkRExPz588u8NwCAikbYBABQArvttlv6ePXq1UWOXXs+O9sicgBgyyNsAgAogUMOOSR9/M0332xw3OLFi2PBggUREdGyZcsy7wsAoKIRNgEAlEDv3r3Tx88+++wGxz377LORSqUiIuLggw8u874AACoaYRMAQAnsueeeceSRR0ZExJAhQ2LEiBHrjZk7d2786U9/ioiI6tWrx5lnnlmuPQIAVATCJgCAErr77rujYcOGsWbNmjjmmGPi2muvjdGjR8eECRPi3//+d3Ts2DFmzZoVERE33XST2+gAgC2SXSsBAEooJycnXnzxxTjhhBNi3rx5cdttt8Vtt91WYExWVlb88Y9/jKuuuipDXQIAZJawCQCgFA466KD47LPP4t57743nnnsupk2bFnl5edG8efPo0qVLXHzxxbHPPvtkuk0AgIwRNgEAlFLjxo2jf//+0b9//0y3AgBQ4dizCQAAAIDECJsAAAAASIywCQAAAIDE2LMJgERkZWUlVqtmzZqJ1QIAAMqXlU0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBisjPdAAAlN3HixMRqLVq0KLFaERHVqlVLrNYJJ5yQWC0AAKB8WdkEAAAAQGKETQAAAAAkRtgEAAAAQGKETQAAAAAkRtgEAFBCWVlZJfro0qVLplsFAMgYYRMAAAAAicnOdAMAAJXNb3/727jwwgs3eL5OnTrl2A0AQMUibAIAKKVmzZrF7rvvnuk2AAAqJLfRAQAAAJAYYRMAAAAAiRE2AQAAAJAYezYBAJTSU089FU8++WRMnz49qlatGttss00ccMABccYZZ0TXrl03uu6sWbOKPJ+bm7vRtQEAyouwCQCglD7//PMCj6dMmRJTpkyJwYMHx3HHHReDBg2KBg0alLpu69atk2oRACBjhE0AACVUu3bt6NGjRxx66KHRrl27qFu3bsyfPz9GjRoV999/f3z//ffx3HPPRc+ePeONN96IatWqZbplAIByJ2wCACih2bNnR8OGDdd7vnv37nHxxRfHkUceGR9++GGMGjUq7rvvvvj9739fqvozZ84s8nxubm506tSpVDUBAMqbsAkAoIQKC5rW2nrrrePpp5+Odu3axapVq+Lee+8tddjUqlWrTewQACDzvBsdAEBCtt9+++jevXtE/LyP05w5czLcEQBA+RM2AQAkaNddd00fz549O4OdAABkhtvoACqRL774IrFaK1asSKxWRETPnj0TrQeVVVZWVqZbAADIKCubAAAS9Pnnn6ePW7RokcFOAAAyQ9gEAJCQadOmxRtvvBERETvssEO0bNkywx0BAJQ/YRMAQAm8+OKLkZ+fv8Hz8+bNi969e0deXl5ERFx44YXl1RoAQIVizyYAgBK4+OKLY9WqVdG7d+/Yf//9Y9ttt41atWrFggUL4u23344HHnggFixYEBERBx10UFx00UUZ7hgAIDOETQAAJTRnzpy499574957793gmN69e8eAAQOiRo0a5dgZAEDFIWwCACiBRx99NEaNGhXvv/9+fPPNN7FgwYJYvHhx1K1bN1q3bh0HHHBA9OvXL/bff/9MtwoAkFHCJgCAEujcuXN07tw5020AAFR4NggHAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHZmW4AMm3p0qWJ1XrkkUcSq7Vs2bLEag0ZMiSxWluKRo0aJVbr6KOPTqzWzTffnFitpF199dWZbgEAAKgArGwCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgCATXT11VdHVlZW+uPtt9/OdEsAABkjbAIA2AQfffRR/N///V+m2wAAqDCETQAAG2nNmjVx3nnnRX5+fjRr1izT7QAAVAjCJgCAjfSPf/wjxo8fH+3atYuzzz470+0AAFQI2ZluAErr448/TrTeEUcckVituXPnJlYrSb/61a8Sq7X11lsnVqsiW7JkSWK1rrjiisRqJalVq1aJ1svJyUm0HlR0M2bMiD//+c8REXH//ffHyJEjM9wRAEDFYGUTAMBGuOiii+Knn36Kfv36RefOnTPdDgBAhSFsAgAopSeffDJeeuml2GqrreLvf/97ptsBAKhQ3EYHAFAKixYtiksuuSQiIm6//fZo0qRJYrVnzZpV5Pnc3NzE5gIAKCvCJgCAUrjqqqti7ty5ceCBBya+KXjr1q0TrQcAkAluowMAKKHRo0fHgAEDIjs7O+6///7IysrKdEsAABWOlU0AACWQl5cX5513XqRSqfjDH/4Qu+++e+JzzJw5s8jzubm50alTp8TnBQBIkrAJAKAE/vrXv8aXX34Zbdq0iRtuuKFM5mjVqlWZ1AUAKE9uowMAKMaXX34Zt956a0RE3HvvvVGnTp0MdwQAUHFZ2QQAUIy77ror8vLyYvvtt49ly5bF0KFD1xvz6aefpo/feuutmDt3bkREHHvsscIpAGCLImwCACjGypUrIyLim2++iT59+hQ7/qabbkofT5s2TdgEAGxR3EYHAAAAQGKETQAAxRg0aFCkUqkiP9bdNHzkyJHp57fddtvMNQ4AkAHCJgAAAAASI2wCAAAAIDHCJgAAAAASI2wCAAAAIDHCJgCABPTv3z+9KXiXLl0y3Q4AQMYImwAAAABITHamG2DL8PrrrydW6/jjj0+sVkTE0qVLE6t1zjnnJFbrhBNOSKxW165dE6tVvXr1xGol7d13302s1rXXXptYrYpq7ty5idb75ptvEqvVuHHjxGoBAADly8omAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMdmZboAtw9ChQzPdwgbdcccdidW67LLLEqtVpcrmnwWPHTs20Xo9evRIrNbChQsTq1WtWrXEalWtWjWxWitWrEisVkTErbfemlitYcOGJVYLAAAoX5v/b7MAAAAAlBthEwAAAACJETYBAAAAkBhhEwAAAACJETYBAAAAkBhhEwAAAACJyc50AwAAlcHixYtj+PDhMX78+JgwYULMnj075s+fH8uXL4+GDRvGrrvuGkcddVScffbZ0bhx40y3CwCQMcImAIASGDduXPTp06fQc/Pnz49Ro0bFqFGj4o477ojHH388jjjiiHLuEACgYhA2AQCUUOvWraNr167Rvn37aN26dTRv3jzWrFkTs2bNiqeffjqGDRsWCxYsiB49esS4ceNir732ynTLAADlTtgEAFACXbt2jRkzZmzw/EknnRTPPfdc9OrVK/Ly8uIvf/lLDBs2rBw7BACoGGwQDgBQAlWrVi12zHHHHRc777xzRESMHj26rFsCAKiQhE0AAAmqV69eRESsWLEiw50AAGSGsAkAICFfffVVfPTRRxER0a5du8w2AwCQIfZsAgDYBMuWLYvZs2fHiy++GH/7298iPz8/IiIuvfTSUteaNWtWkedzc3M3pkUAgHIlbAIAKKVBgwbFmWeeucHz11xzTZxyyimlrtu6detNaQsAoEIQNgEAJGTvvfeOBx98MDp27JjpVgAAMkbYBABQSscdd1x06NAhIiKWL18eU6dOjSeffDKeffbZ6NOnT9x9991xzDHHlLruzJkzizyfm5sbnTp12qieAQDKi7AJAKCUGjZsGA0bNkw/7tixY5x88snx2GOPRb9+/aJnz54xcODAOOOMM0pVt1WrVsk2CgCQAVmpVCqV6SaomObMmZNYrbZt2yZW68QTT0ysVkTEf/7zn0TrVURz585NrNYDDzyQWK277747sVoREYsWLUqsVps2bRKr9eyzzyZWq3nz5onV2nXXXROrFRGxdOnSxGpNnz49sVotWrRIrBaUxG9+85t48skno06dOjFjxozYaqutEqs9a9as9L5OM2fOFE4BAJusLH6+qLLJFQAASOvZs2dE/BzAvvrqqxnuBgCg/AmbAAAS1LRp0/Txt99+m8FOAAAyQ9gEAJCg2bNnp4/r1q2bwU4AADJD2AQAkKCnnnoqfbzHHntksBMAgMwQNgEAlMCgQYNixYoVRY656667Yvjw4RERsd1228XBBx9cHq0BAFQo2ZluAACgMujfv39cfvnl0bt37zjooINihx12iLp168aSJUvik08+iSeeeCLGjBkTERHVq1ePBx98MKpWrZrhrgEAyp+wCQCghH744Yd46KGH4qGHHtrgmFatWsXDDz8chx12WDl2BgBQcQibAABK4LXXXouXX345xowZE1OmTIl58+bF999/H7Vq1YpmzZrF3nvvHcccc0ycdNJJUbt27Uy3CwCQMcImAIAS2HnnnWPnnXeOyy67LNOtAABUaDYIBwAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAx2ZlugIrrrbfeSqxWfn5+YrWuvvrqxGolbfny5YnV+sc//pFYrf/85z+J1fr4448Tq5WdnexfQd27d0+s1iOPPJJYrZYtWyZWK0lJfo9FRPTt2zexWkn+/XPaaaclVgsAACielU0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBikn3fcQAAysV+fx0R2fWbZLoNACAipt92dKZbqFCsbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAIASmjBhQtx4441x+OGHR6tWraJGjRpRt27dyMnJiTPPPDPefffdTLcIAJBx2ZluAACgMjjkkENi9OjR6z2fl5cXX3/9dXz99dcxaNCg6Nu3bzz00ENRvXr1DHQJAJB5wiYAgBKYM2dORES0aNEiTjzxxDj44IOjTZs2sXr16nj//ffjzjvvjNmzZ8fgwYNj1apV8Z///CfDHQMAZIawiUrnoosuSrRe3759E6t1//33J1brww8/TKxWlSrJ3TF78MEHJ1bruuuuS6xWRMSvf/3rROtt7rp3755ovW222SbRelDRtGvXLv76179G7969o2rVqgXO7bfffnH66afHgQceGJMnT44hQ4bEBRdcEIccckiGugUAyBx7NgEAlMBLL70UJ5100npB01pNmjSJO++8M/346aefLq/WAAAqFGETAEBCunbtmj6eOnVqBjsBAMgcYRMAQEJWrlyZPt7QCigAgM2dsAkAICGjRo1KH++yyy4Z7AQAIHNsEA4AkIA1a9bEbbfdln580kknlbrGrFmzijyfm5tb6poAAOVN2AQAkIC77rorxo0bFxERxx9/fLRv377UNVq3bp10WwAA5c5tdAAAm2jUqFFxzTXXREREs2bN4r777stwRwAAmWNlEwDAJvjss8+iV69ekZ+fHzVr1oynnnoqmjVrtlG1Zs6cWeT53Nzc6NSp00bVBgAoL8ImAICNNG3atDj88MNj4cKFUbVq1Rg6dGgccsghG12vVatWCXYHAJAZbqMDANgIc+bMicMOOyzmzJkTWVlZ8fDDD0fPnj0z3RYAQMYJmwAASmnBggXRvXv3+OabbyIi4t57742+fftmuCsAgIpB2AQAUAo//vhjHHHEEfH5559HRMRtt90WF110UYa7AgCoOIRNAAAltGzZsjj66KPjf//7X0RE/PGPf4yrr746w10BAFQswiYAgBLIy8uLXr16xZgxYyIi4pJLLombb745w10BAFQ83o0OAKAE+vTpE6+//npERHTr1i3OPvvs+PTTTzc4vnr16pGTk1Ne7QEAVBjCJgCAEhg2bFj6+K233oo999yzyPFt27aN6dOnl3FXAAAVj9voAAAAAEiMlU0AACWQSqUy3QIAQKUgbKJctGzZMrFaazdmraj1krL//vsnVuvCCy9MrNZpp52WWC0ya5tttkm03nbbbZdoPQAAoHJyGx0AAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJCY7Ew3AABA6Y297tBo1apVptsAAFiPlU0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJCY70w1QcfXq1SuxWh06dEis1g033JBYrYiIH374IbFaxx9/fGK1zjnnnMRqVatWLbFaAAAAUBQrmwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAAAAgMQImwAAAABIjLAJAKCEvvvuu3jppZfi+uuvjyOPPDKaNGkSWVlZkZWVFWeccUam2wMAqBCyM90AAEBlsfXWW2e6BQCACs/KJgCAjdCmTZs4/PDDM90GAECFY2UTAEAJXX/99dGxY8fo2LFjbL311jF9+vTYbrvtMt0WAECFImwCACihv/zlL5luAQCgwnMbHQAAAACJETYBAAAAkBi30QEAVBCzZs0q8nxubm45dQIAsPGETQAAFUTr1q0z3QIAwCZzGx0AAAAAibGyCQCggpg5c2aR53Nzc6NTp07l1A0AwMYRNrFBderUSaxWu3btEqv13//+N7FaQHJycnIy3QJUeq1atcp0CwAAm8xtdAAAAAAkRtgEAAAAQGKETQAAAAAkRtgEAAAAQGKETQAAAAAkRtgEAAAAQGKyM90AAEBl8e6778aUKVPSjxcsWJA+njJlSgwaNKjA+DPOOKOcOgMAqDiETQAAJTRgwIB49NFHCz03ZsyYGDNmTIHnhE0AwJbIbXQAAAAAJEbYBABQQoMGDYpUKlXiDwCALZGwCQAAAIDECJsAAAAASIywCQAAAIDECJsAAAAASIywCQAAAIDECJsAAAAASIywCQAAAIDECJsAAAAASEx2phsAYPMwaNCgTLcAAABUAFY2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQAAAJAYYRMAAAAAiRE2AQCU0rfffhuXX355tGvXLurUqRNbbbVVdOzYMe64445YtmxZptsDAMio7Ew3AABQmbz44otx2mmnxeLFi9PPLVu2LCZMmBATJkyIAQMGxMsvvxw77rhjBrsEAMgcK5sAAEroww8/jN/85jexePHiqFu3btxyyy3x3nvvxYgRI+Lcc8+NiIjJkyfH0UcfHUuWLMlwtwAAmWFlEwBACV1yySWxfPnyyM7Ojtdffz3233//9Llu3brFTjvtFFdddVVMnjw57rzzzujfv3/mmgUAyBArmwAASmDcuHExevToiIg4++yzCwRNa11++eWxyy67RETEPffcE6tWrSrXHgEAKgJhEwBACTz33HPp4zPPPLPQMVWqVIm+fftGRMSiRYti5MiR5dEaAECFImwCACiBd999NyIi6tSpE+3bt9/guM6dO6ePx4wZU+Z9AQBUNPZsAgAogS+++CIiInbcccfIzt7wj1Dt2rVb73NKatasWUWez83NLVU9AIBMEDYBABRjxYoVsWDBgoiIaNWqVZFjGzVqFHXq1ImlS5fGzJkzSzVP69atN7pHAICKwm10AADFWLJkSfq4bt26xY6vU6dORET89NNPZdYTAEBFZWUTAEAxVqxYkT6uXr16seNr1KgRERHLly8v1TzFrYTKzc2NTp06laomAEB5EzYBABSjZs2a6eO8vLxix69cuTIiImrVqlWqeYq7RQ8AoDJwGx0AQDHq1auXPi7JrXFLly6NiJLdcgcAsLkRNgEAFKNmzZrRuHHjiCj+HeMWLlyYDpts+A0AbImETQAAJbDrrrtGRMSUKVMiPz9/g+O+/PLL9PEuu+xS5n0BAFQ0wiYAgBI46KCDIuLnW+QmTpy4wXGjRo1KHx944IFl3hcAQEUjbAIAKIHjjjsuffzII48UOmbNmjUxePDgiIho2LBhdO3atTxaAwCoUIRNAAAl0KlTpzj44IMjImLgwIHx/vvvrzfmzjvvjC+++CIiIi655JKoVq1aufYIAFARZGe6AQCAyuKee+6JAw88MJYvXx6HH354XHfdddG1a9dYvnx5DB06NB588MGIiMjJyYnLL788w90CAGSGsAkAoIT22Wef+O9//xunnXZaLF68OK677rr1xuTk5MTLL78c9erVy0CHAACZ5zY6AIBSOPbYY+Pjjz+OP/zhD5GTkxO1a9eOhg0bRocOHeL222+PDz/8MHbcccdMtwkAkDFZqVQqlekmAAAo3qxZs6J169YRETFz5sxo1apVhjsCACq7svj5wsomAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABIjbAIAAAAgMcImAAAAABKTnekGAAAomfz8/PRxbm5uBjsBADYX6/5Mse7PGptC2AQAUEnMnz8/fdypU6cMdgIAbI7mz58f22677SbXcRsdAEAlMW/evEy3AABQLCubAAAqiXbt2qWP33vvvWjdunUGu9ky5ebmpleVjRs3Lpo3b57hjrZMrkPmuQYVg+uQeZvDNcjPz0+vnt5jjz0SqSlsAgCoJGrWrJk+bt26dbRq1SqD3dC8eXPXoAJwHTLPNagYXIfMq8zXIIlb59blNjoAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEiNsAgAAACAxwiYAAAAAEpOVSqVSmW4CAAAAgM2DlU0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAAAAJEbYBAAAAEBihE0AAOXo22+/jcsvvzzatWsXderUia222io6duwYd9xxRyxbtiyxeV555ZXo1atXtGrVKmrUqBGtWrWKXr16xSuvvJLYHJVZWV6HZcuWxbBhw+K3v/1tdOzYMRo1ahTVqlWLxo0bx/777x/9+/ePuXPnJvRKKq/y+rOwrmXLlsX2228fWVlZkZWVFdtuu22ZzFOZlOd1ePPNN+OMM86IHXfcMerUqRMNGjSInJycOOGEE+K+++6Ln376KdH5KovyuAbTp0+Pq6++Otq3bx8NGzaMatWqxVZbbRUHHHBA3HjjjfHdd98lMk9l891338VLL70U119/fRx55JHRpEmT9N8PZ5xxRpnMOWTIkDj88MNjm222iZo1a0bbtm3jtNNOi/fff79M5suYFAAA5eKFF15I1a9fPxURhX7k5OSkvv76602aY/Xq1amzzz57g3NEROqcc85JrV69OqFXVfmU5XWYNGlSqm7dukV+/SMiVb9+/dTQoUMTfmWVR3n8WSjM5ZdfXmCetm3bJj5HZVJe1+GHH35I9ezZs9g/Fx9++OGmv6hKpjyuweDBg1O1atUq8mu/1VZbpV5//fWEXlXlUdTXpF+/fonOtWzZstRRRx21wfmqVKmS6t+/f6JzZpKwCQCgHPzvf/9L/7Bft27d1C233JJ67733UiNGjEide+65BX6xWLx48UbPc80116Rr7bPPPqkhQ4akxo0blxoyZEhqn332SZ+79tprE3x1lUdZX4fRo0enaxx44IGpW2+9NfXGG2+k/ve//6Vee+211Pnnn5+qUqVKKiJSVatWTQ0fPrwMXmXFVl5/Fgqbt2rVqqmaNWum6tWrt8WHTeV1HRYtWpRq3759ul6vXr1STzzxRGrs2LGp8ePHp4YNG5a65JJLUq1atdriwqbyuAbvvvtu+u+cKlWqpM4888zUc889lxo3blzq6aefTh177LHpeWrVqpWaOnVqwq+yYls37GnTpk3q8MMPL7Ow6eSTT07X7tq1a/o6DBw4MLXDDjukzz3wwAOJzpspwiYAgHJw8MEHpyIilZ2dnXrvvffWO/+3v/0t/YPmDTfcsFFzfPXVV6ns7OxURKQ6dOiQWrZsWYHzS5cuTXXo0CHdR1msHKnoyvo6jBkzJnXSSSelPvvssw2Oee6551JZWVmpiEjtsMMOqTVr1pR6nsqsPP4s/FJ+fn468LjxxhtTbdu23eLDpvK6DqeffnoqIlI1atRIPf/88xsct2bNmtSqVas2ep7KqDyuwdFHH52u8a9//avQMZdddll6zEUXXbRR81RW119/ferFF19MzZ07N5VKpVLTpk0rk7BpxIgR6brHHntsKj8/v8D5+fPnp9q0aZOKiFTDhg1TP/zwQ2JzZ4qwCQCgjH3wwQfpHzLPP//8QsesXr06tcsuu6R/0MzLyyv1PL/97W/T87z//vuFjnn//ffTYy688MJSz1GZldd1KInevXune5k4cWKZzFERZeoa3HnnnamISO28886plStXbvFhU3ldh3VX+t1xxx2b2vZmpbyuQaNGjVIRkWrcuPEGxyxatCjdy7777lvqOTYnZRU2HXnkkelgcebMmYWOGTJkSHruv/3tb4nNnSk2CAcAKGPPPfdc+vjMM88sdEyVKlWib9++ERGxaNGiGDlyZKnmSKVS8fzzz0dERLt27WK//fYrdNx+++0XO++8c0REPP/885FKpUo1T2VWHtehpLp27Zo+njp1apnMURFl4hp8++23cf3110dExP333x/Vq1ffpHqbg/K6Dv/85z8jIqJBgwbxu9/9rvSNbsbK6xrk5eVFRMR22223wTENGjSIJk2aFBhPcpYsWRIjRoyIiIjDDjssWrVqVei4448/PurXrx8REc8++2y59VdWhE0AAGXs3XffjYiIOnXqRPv27Tc4rnPnzunjMWPGlGqOadOmxZw5c9arU9Q8s2fPjunTp5dqnsqsPK5DSa1cuTJ9XLVq1TKZoyLKxDW48MILY+nSpXH66adHly5dNqnW5qI8rkNeXl46AO/evXvUrFkzIiJWr14dM2fOjOnTp8eKFStK2/pmo7z+LKz9z4Vp06ZtcMzixYtjwYIFBcaTnPHjx6dDvKL+fa5evXr6P4rGjx8fq1atKpf+yoqwCQCgjH3xxRcREbHjjjtGdnb2Bse1a9duvc8pqc8//7zQOknPU5mVx3UoqVGjRqWPd9lllzKZoyIq72swdOjQGD58eDRq1CjuvPPOja6zuSmP6zBp0qR0mLTHHnvE4sWL49JLL40mTZpEmzZtYrvttosGDRpE9+7d4+233y79i6jkyuvPwgUXXBAREd9//33cf//9hY656aab1htPcjbm3+f8/Pz4+uuvy7SvsiZsAgAoQytWrEj/j/GGls6v1ahRo6hTp05ERMycObNU88yaNSt9XNw8rVu3Th+Xdp7KqryuQ0lMmjQpXn755Yj4+ZfwLSVsKu9rsHDhwrj00ksjIuK2226Lpk2bblSdzU15XYd1f8Fes2ZNdOjQIe65555YtGhR+vm8vLx48803o1u3bnH77beXqn5lVp5/Fs4666z0rXgXXXRRnHvuufHiiy/GhAkTYtiwYdGrV6/4+9//HhERf/zjH+Owww4r9RwUbUv991nYBABQhpYsWZI+rlu3brHj1/5S8dNPP5XZPGvn2Jh5Kqvyug7FWblyZZxzzjmxevXqiIi45ZZbEq1fkZX3Nbjyyitj3rx5sf/++8e55567UTU2R+V1HX744Yf08e233x5ff/11/PrXv45x48bFihUr4rvvvov77rsvGjRoEKlUKq655pr0bXebu/L8s1C1atV49NFH46mnnoq99torBgwYED169IiOHTtG796947nnnouuXbvGG2+8ETfffHOp61O8LfXfZ2ETAEAZWndPkpJsTFyjRo2IiFi+fHmZzbN2jo2Zp7Iqr+tQnN/97ncxYcKEiIjo169fHHvssYnWr8jK8xq888478fDDD0d2dnbcf//9kZWVVeoam6vyug5Lly4tMGf37t3jpZdeio4dO0aNGjWiadOmccEFF8RLL70UVar8/Gvptddeu0W8aUF5/330xRdfxODBg+OTTz4p9Pz7778fAwcOjNmzZ29UfYq2pf77LGwCAChDazfFjSjZu/ys3Ti6Vq1aZTbPuptTl3aeyqq8rkNRbr311hgwYEBERHTs2DH+9a9/JVa7Miiva7By5co477zzIpVKxSWXXBJ77rln6RrdzGXi76SIn1c3FbYZ/kEHHRTHH398RPwcimwoENmclOffR6NHj479998/XnzxxWjZsmU89thjMXfu3MjLy4uZM2fGv/71r6hdu3YMHTo0OnXqFJ999lmp56BoW+q/z8ImAIAyVK9evfRxSZbEr10NUJJbKzZ2nnVXHJR2nsqqvK7DhjzwwANx3XXXRcTPG8AOHz68wO0SW4Lyuga33HJLfPXVV9G6dev4y1/+UromtwCZ+DupadOmsc8++2xw7BFHHJE+Hj9+fKnmqYzK6xqsXLky+vTpEz/++GNss802MXbs2DjttNNi6623jmrVqkWrVq3iwgsvjHfeeSdq1qwZc+bMiX79+pXuxVCsLfXf5w1vew8AwCarWbNmNG7cOL7//vsCm4QWZuHChekfNNfdJLQk1t10tLh51t10tLTzVFbldR0KM2TIkLjwwgsjIqJt27bxxhtvRJMmTTa5bmVTXtdg7UbThx12WLz44ouFjllbe+nSpTF06NCIiGjWrFl069atVHNVRuV1HdYdX5pNkefPn1+qeSqj8roGr776avrWuIsvvji22WabQsfttttucdppp8WAAQNi4sSJMWnSpNhrr71KNRcb9st/nzt06LDBsZvTv8/CJgCAMrbrrrvG6NGjY8qUKZGfn7/Bt7n+8ssv08elfYeyXXfdtdA6Sc9TmZXHdfilF154Ifr27Rtr1qyJ5s2bx4gRI4r9xXtzVh7XYO1tKo888kg88sgjRY5dsGBB9OnTJyIiOnfuvEWETRHlcx1222239PHaDfE3ZN3zG+plc1Me1+CLL75IH++7775Fjm3fvn36Nt8vv/xS2JSgjfn3OTs7O3baaacy7ausuY0OAKCMHXTQQRHx8yqKiRMnbnDcqFGj0scHHnhgqebYbrvtokWLFuvVKcw777wTEREt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", "text/plain": [ "
" ] }, "metadata": { "image/png": { "height": 327, "width": 589 } }, "output_type": "display_data" } ], "source": [ "for image_batch, label_batch in training_batches.take(1):\n", " ps = model.predict(image_batch)\n", " first_image = image_batch.numpy().squeeze()[0]\n", " \n", " \n", "fig, (ax1, ax2) = plt.subplots(figsize=(6,9), ncols=2)\n", "ax1.imshow(first_image, cmap=plt.cm.binary)\n", "ax1.axis('off')\n", "ax2.barh(np.arange(10), ps[0])\n", "ax2.set_aspect(0.1)\n", "ax2.set_yticks(np.arange(10))\n", "ax2.set_yticklabels(np.arange(10))\n", "ax2.set_title('Class Probability')\n", "ax2.set_xlim(0, 1.1)\n", "plt.tight_layout()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "n4WcPdR9jKMB" }, "source": [ "WOW!! Now our network is brilliant. It can accurately predict the digits in our images. Let's take a look again at the loss and accuracy values for a single batch of images." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 105 }, "colab_type": "code", "id": "rFZKBfTgfPVy", "outputId": "b4d7816a-bbfa-4bb8-c453-82506029aeb8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2/2 [==============================] - 0s 5ms/step - loss: 0.1315 - accuracy: 0.9844\n", "\n", "Loss after training: 0.131\n", "Accuracy after training: 98.438%\n" ] } ], "source": [ "for image_batch, label_batch in training_batches.take(1):\n", " loss, accuracy = model.evaluate(image_batch, label_batch)\n", "\n", "print(f'\\nLoss after training: {loss:,.3f}')\n", "print(f'Accuracy after training: {accuracy:.3%}')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Wa5_vwtotNeg" }, "source": [ "> **Exercise:** Create a network with 784 input units, a hidden layer with 128 units, then a hidden layer with 64 units, then a hidden layer with 32 units and finally an output layer with 10 units. Use a ReLu activation function for all the hidden layers and a softmax activation function for the output layer. Then compile the model using an `adam` optimizer, a `sparse_categorical_crossentropy` loss function, and the `accuracy` metric. Finally, print the loss and accuracy of your un-trained model for a single batch of images." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 105 }, "colab_type": "code", "id": "txuSaeuirvgc", "outputId": "33af7e60-e292-4788-f168-940351b7e6b4" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2/2 [==============================] - 1s 4ms/step - loss: 2.2587 - accuracy: 0.0938\n", "\n", "Loss before training: 2.259\n", "Accuracy before training: 9.375%\n" ] } ], "source": [ "## Solution\n", "my_model = tf.keras.Sequential([\n", " tf.keras.layers.Flatten(input_shape=(28,28,1)),\n", " tf.keras.layers.Dense(128, activation='relu'),\n", " tf.keras.layers.Dense(64, activation='relu'),\n", " tf.keras.layers.Dense(32, activation='relu'),\n", " tf.keras.layers.Dense(10, activation='softmax')\n", "])\n", "\n", "\n", "my_model.compile(optimizer='adam',\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy'])\n", "\n", "\n", "for image_batch, label_batch in training_batches.take(1):\n", " loss, accuracy = my_model.evaluate(image_batch, label_batch)\n", "\n", "print(f'\\nLoss before training: {loss:,.3f}')\n", "print(f'Accuracy before training: {accuracy:.3%}')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bgdaQEVUumxo" }, "source": [ "> **Exercise:** Train the model you created above for 5 epochs and then print the loss and accuracy of your trained model for a single batch of images." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 275 }, "colab_type": "code", "id": "HzxZtgBDt3Ak", "outputId": "e487178a-e5dd-411b-e5dc-566983d4aa27" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "938/938 [==============================] - 3s 2ms/step - loss: 0.2824 - accuracy: 0.9155\n", "Epoch 2/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.1159 - accuracy: 0.9652\n", "Epoch 3/5\n", "938/938 [==============================] - 2s 3ms/step - loss: 0.0803 - accuracy: 0.9748\n", "Epoch 4/5\n", "938/938 [==============================] - 2s 2ms/step - loss: 0.0607 - accuracy: 0.9813\n", "Epoch 5/5\n", "938/938 [==============================] - 2s 3ms/step - loss: 0.0494 - accuracy: 0.9843\n", "2/2 [==============================] - 0s 4ms/step - loss: 0.0491 - accuracy: 0.9688\n", "\n", "Loss after training: 0.049\n", "Accuracy after training: 96.875%\n" ] } ], "source": [ "## Solution\n", "EPOCHS = 5\n", "\n", "history = my_model.fit(training_batches, epochs=EPOCHS)\n", "\n", "for image_batch, label_batch in training_batches.take(1):\n", " loss, accuracy = my_model.evaluate(image_batch, label_batch)\n", "\n", "print(f'\\nLoss after training: {loss:,.3f}')\n", "print(f'Accuracy after training: {accuracy:.3%}')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "CfBqrMikvVCY" }, "source": [ "> **Exercise:** Plot the prediction of the model you created and trained above on a single image from the training set. Also plot the probability predicted by your model for each digit." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 243 }, "colab_type": "code", "id": "NOwMUqYzvKtK", "outputId": "5f653945-0fe4-4699-e2cc-98e67e050dbb" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2/2 [==============================] - 0s 2ms/step\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABJsAAAKPCAYAAADKYMuqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAB7CAAAewgFu0HU+AABXv0lEQVR4nO3dd5RV5fk/7Htg6F2KggxYEXtBiB1Q0dhF1IgF7BpLNDG2FCUaE40xakxiA0XUL8aCDbAiIiIIGMUugiBtRFARpA1lv3/4cn6MTIU9c2bgutaatfY5+zn3c5/ZM8zMh2fvnZMkSRIAAAAAkIIa2W4AAAAAgI2HsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAACjWmWeeGTk5OZGTkxMDBw7MdjtUsm7dumWO/+uvv57tdoo0ffr0TI9bbbVVanXL8t779euXGdOvX78ix7z++uuZMd26dUutP6jKhE0AALARWrhwYfz3v/+Nc889N/bYY4/Ycssto06dOtGoUaNo165dHHrooXHttdfG2LFjs93qRmPt4KGoj3r16kWbNm3i4IMPjuuuuy6mTZuW7ZYBKoSwCQAANiJLliyJv/zlL7HVVlvFKaecEgMGDIhJkybFnDlzoqCgIH744YeYOXNmjBgxIm6++ebYb7/9YocddojBgwdHkiTZbn+jtmzZssjPz4+RI0fGjTfeGNttt1389re/jYKCgmy3RhWwdjAJ1V1uthsAAADSMWPGjDjmmGPi/fffL/R8u3btYrfddouWLVvGqlWr4quvvopJkybF3LlzIyJi8uTJceqpp8bMmTPjqquuykbrG502bdpEz549Cz23ePHi+OSTT2L8+PGRJEmsXr06brvttsjPz49HHnlEyABsNIRNAACwEZg+fXrsu+++8dVXX0XEj6skevfuHb/73e9i5513Xmd8kiQxceLEuOuuu+LRRx+N1atXx5IlSyq77Y3W9ttvH//617+K3PfBBx9E796946OPPoqIiP/7v/+L448/Pk466aTKbJFSpHWNqm7dulk1yCbHaXQAAFDNFRQUxEknnZQJmurWrRtDhgyJRx99tMigKeLHMKpz584xaNCgmDRpUuyyyy6V2fImbdddd42XXnopmjRpknnu9ttvz2JHAOkSNgEAQDX3t7/9LSZOnJh5/NBDD8Xxxx9f5tfvsssuMW7cuOjRo0cFdEdRttxyyzjzzDMzj8ePHx8LFy7MXkMAKRI2AQBANbZ06dL45z//mXl8wgknxMknn1zuOg0aNIj9999/vftYsWJFvPTSS3HVVVdF9+7do02bNlG3bt2oV69etG3bNo444oi444474ocffihzzU8//TSuuuqq2GeffaJFixZRu3btqFu3brRq1So6deoUZ511Vjz00EPx3XffFVvjhx9+iHvuuSeOOuqoaNeuXdSvXz9q1aoVTZo0iY4dO8YxxxwTf/nLX+LDDz9c7/e+vvbbb7/M9qpVq2LGjBmZx6+//nrmYtHdunXLPD98+PDo3bt3bL/99tGwYcPIycmJO+64Y53aSZLEE088Eb17945tt902GjZsGA0bNoxtt902Tj311HjyySfX+9SumTNnxh/+8IfYfffdY7PNNosGDRpEx44d49e//nVMmTKlTDUq4uvlp0aMGJF5//Xq1YuWLVvGgQceGP/6179i+fLlpb6+W7dumWOwIafUFXcsf7pvbcXd0XD69OlRUFAQLVu2zDxXnjtKdu3aNfO6tf/dgNQlAABAtTVo0KAkIjIfb775Zqr1+/btm6n94IMPFjlmxowZSfPmzQv1UdxH8+bNk5dffrnUea+//vqkZs2aZap52mmnFVnjrbfeSrbccssy1YiIZMWKFRvyqUquv/76TK2uXbuWOv7ll18uNP+YMWMy+0aOHFmo1oIFC5KePXsW2fftt99eqO7kyZOTPffcs9T326lTp2Tq1Kkl9ti1a9fM+JEjRybPPvts0qRJk2Jr1qtXL7n33ntLrJn218u0adMy49u3b58UFBQk559/fol1d9xxx+Szzz4r13svytrH/Prrry9yzE+PZXH7yvIxbdq0JEmS5Iorrsg8d+6555b4PtaYPHly5jV16tRJvvnmmzK9DtaHC4QDAEA19tprr2W227Vrt0Grk9bX4sWL45tvvomIiGbNmsXOO+8c7du3j4YNG0ZBQUFMmzYtxo0bF8uWLYtvvvkmjjzyyBg1alShlT1ru/POO+NPf/pT5nGLFi1in332idatW0dOTk58++238emnn8Ynn3wSq1atKrLGzJkz4/DDD49FixZFREStWrWic+fOsd1220X9+vVj8eLFMX369Jg0aVLWTl/76Yqsta/htLYkSeL000+PoUOHRk5OTuy9996x0047RZIk8eGHHxZaFfPJJ59E165dY968eZnndt1119hjjz0iJycn3n333fjggw8iIuKdd96J/fbbL954443o0KFDqf1OnDgxfv/730dBQUE0b948unXrFs2aNYvp06fHqFGjYsWKFbF06dK44IILombNmnHOOecUWSftr5efuvrqq+O+++6LiIjddtst9thjj0iSJN555534+OOPM5+ngw8+OMaOHRt5eXllqlsRttxyy7j44osjIuLf//535vk1z/1U48aNIyLi/PPPj9tuuy0iIv773//GHXfcEQ0aNChxrgceeCCzfcIJJ8Rmm222Qb1DibIcdgEAABtg2223zaxWOOmkk1KvX5aVTdOnT08uvfTS5O23305WrVpV5Jjvv/++0GqMDh06FDl2xYoVSYsWLTLj/vrXvyYFBQVF1vzmm2+SBx54ILnlllvW2Xf55Zdnahx44IHJ7Nmzi6yxYsWK5PXXX09OO+20ZOXKlcV8FsqmvCubfvWrX2XG16xZM/n+++8z+9Ze8ZKbm5tERLLrrrsm77///jp1li1bliRJkixfvjzZfffdM69r1apV8sorr6wz/qWXXir0Od5rr72K/Ryvvbqndu3aSUQkv/3tbzNzrjFz5szkwAMPzIytX79+MmXKlCJrpvn1kiSFVzbVqlUrsyLqpZdeWmfsc889lzRu3Dgz/vDDDy+y5k/fe0WtbFrbmjFl/TN97f4eeOCBEseuXLkyad26dWb8iBEjyjQHrC/XbAIAgGrsyy+/zGwXd+e5ita+ffv45z//GV26dIkaNYr+E6Nx48bx97//PS688MKIiJg8eXK89NJL64z79NNPY/78+RERsf/++8c111wTtWrVKrLmZpttFmeddVZcddVV6+wbPXp0ZvuBBx6INm3aFFkjNzc3unbtGo888kjUrFmz5DeaotmzZ8dDDz2Uedy5c+fMqpWfWrlyZWyxxRbx2muvxa677rrO/jp16kRExKOPPhqTJk2KiB9Xcr344otx6KGHrjP+sMMOi+HDh0du7o8nuvzvf/+LwYMHl9pzQUFBXHjhhXHrrbdm5lyjbdu2MXz48OjYsWNERCxZsqTQ6rS1pfn18lMrVqyIGjVqxHPPPReHHXbYOvuPOeaYeOqppzKPX3rppUKrA6uT888/P7M9YMCAEscOHz488vPzIyJi2223je7du1dobyBsAgCAamrhwoWxcuXKzOOmTZtmr5kyOuusszLbr7766jr71z6lrWXLlus9T1p1KsKHH34Yhx9+eHz//feZ537961+X+JrrrrsuWrRoUeKYe++9N7P9y1/+Mvbcc89ix3bu3DnOO++8zOO77767tLajUaNGcfPNNxe7v2HDhvG3v/0t8/iJJ54o9B7XR2lfL0U57bTTSjzl7tBDD40TTjgh8/j+++9f/wazqFevXplT4caMGROfffZZsWPXDqPOPvvsdS5IDmlzzSYAAKim1lyPaI2GDRtmqZP/Z8WKFfH222/HpEmT4quvvopFixYVCsTW7vm9995b5/VrXz9n5MiRMXny5DJdT6ioOp9//nlERNxzzz1x9dVXl7vGhvj888/jkksuKfTckiVL4uOPP47x48cXuhPcySefHCeddFKJ9X7xi1+UuH/RokUxceLEzOOzzz671B7PPffcTMg0YcKEWLx4cYnX/Tn22GOLva7UGkceeWS0bNky5s2bF8uWLYuxY8fGz3/+82LHb+jXS1H69OlT6pi+ffvGkCFDIuLHr7PqqE6dOtGnT5/M3QgHDBhQKOxbY+7cuTFs2LCIiKhZs2aceeaZldglmyphEwAAVFONGjUq9HhDbhO/oZYuXRp/+ctf4p577smcBleaosbl5eXFPvvsE+PGjYvvv/8+OnXqFGeccUb07Nkz9t9//6hfv36Zap988smZ06OuueaaeOWVV+K0006LHj16RNu2bcv+xtbTnDlzCl3wuSg5OTlx2WWXxc0331ziSpOtt9661Is5v//++5mLpTds2DB22223UnvcY489okGDBrF48eJYtWpVTJo0qcQVQfvuu2+pNWvWrBmdO3eO4cOHR0TEu+++W2TYlNbXy0/l5OTEz372s1LHrf1e5s6dG/n5+dG6desy9VGVnH/++ZmwadCgQfGXv/wlc3rkGg899FAmwDvyyCOLPaUU0uQ0OgAAqKYaN25c6A/LBQsWZKWP7777Lvbbb7/485//XObgIGLdlVlrDBgwIDbffPOI+DFAu/vuu+Owww6LJk2aROfOneOKK66Il19+udg70UX8uGrn+OOPzzweMWJEnH322ZGXlxft27eP008/PQYMGFCufjdU3bp1Y4sttohu3brFH/7wh5gyZUrcfvvt61z/6KfKchrg2nefy8vLK9NpUjVq1Ci0kqy0z0W7du1KrfnTcWv3tUbaXy9ra9as2TohbFFatmwZdevWLbHP6mDHHXeMAw44ICJ+DM2GDh26zpi170J37rnnVlpvbNqETQAAUI21b98+s73mtu6V7eKLL86c4lS7du0499xz49lnn43JkydnTotKkiSSJIlp06ZlXrd69eoi6+20004xadKkuPTSSwudtrVy5cqYOHFi/OMf/4jDDz882rdvH/379y+yRs2aNWPIkCHRv3//2GmnnQrtmzFjRjz66KNx7rnnRps2beLcc8+Nb7/9dgM/C4V17do1857XfCxdujTy8/Nj5MiRceONN8Y222xTplr16tUrdczaq9pKOhXup9YeW1qYU9ZVZaXVTPvrZX16LEuf1UVJFwp/8803M9dyat26dRx11FGV2hubLmETAABUY2tWNUREvP3225U+/+zZs+Oxxx6LiB9Xyrz44otx//33x7HHHhvbb799NGzYsNBd3sr6R/3mm28e//znP2Pu3Lnx+uuvx4033hhHHHFEoTu2zZ49O84777z41a9+VWSNnJycOOecc+Kjjz6Kzz77LO67777o27dvoZBnxYoVMWDAgOjSpUu1Xd0SUfh6XYsXLy7z69YeW9qKoCVLlmxwzYr6eilvj6X1WZ2ceOKJ0axZs4iIeOGFF2LOnDmZfWuHT2eeeWal3nGRTZuwCQAAqrGDDz44s/3ll1/GW2+9Vanzv/baa5mLXR9xxBGl3lL9yy+/LFf9OnXqRNeuXeMPf/hDDB8+PObPnx8vvPBCoZDtrrvuigkTJpRYp0OHDnHeeefFwIEDY+rUqfHZZ5/Fb37zm8wf31OnTo0//elP5eqtKln7VLtZs2YVugB5cVavXh0zZ87MPC7tbnczZswoUy8l1azor5fvvvuuTNcumz9/fixbtqzYPquTevXqxemnnx4REatWrYqHHnooIn4M6p544omI+H/BK1QWYRMAAFRjJ510UqE/lP/xj39U6vxrr6LYddddSx3/xhtvbNB8tWrVip///Ofx6quvxi677JJ5/vnnny9XnQ4dOsRtt91WKGB67rnnNqi3bNptt90ywdmiRYvigw8+KPU1kyZNyqzuqVmzZuy+++4ljh83blypNVetWlUo+Ntrr70K7a/or5ckScq0wm/s2LGZ7c0337zaXzR77VPp1lyj6bHHHssc365du8a2226bld7YNAmbAACgGqtXr16h08ieeuqpeOqpp8pdZ/Hixeu1KqpGjf/3J0VppzAtWbIkBg0aVO45ilKnTp047LDDMo/nzp27XnWOPfbYDa5RFTRq1Cj23nvvzOOBAweW+pq1T7Hq0qVLqdd6eu6552LhwoUljnnxxRfj66+/jogfL4j+0zvYVcbXy8MPP1zqmLXrlra6qrKsfcHyFStWlOu1u+yyS+ZzPWXKlBg1alSh4+vC4FQ2YRMAAFRzV111VaEVJGeccUa5Vvp8+OGHsc8++8TLL79c7rnXvv7R8OHDS7xD3BVXXFFqoPPdd9+V6ULQEYVP12rVqlWhfWW9y1lJNaqbCy64ILP973//O95///1ix77zzjtx7733Zh5feOGFpdZfuHBh/O53vyt2/+LFi+Oqq67KPD7xxBMLXeA9Iv2vl6I88sgjJa5uGjlyZKFAtqoEMc2bN89sz549u9yvX3t109VXX535HDRr1ix69eq14Q1COQibAACgmqtTp0488cQTmbBk6dKlcfzxx0efPn3ik08+KfI1SZLEhAkTom/fvrH77rvHhx9+uF5zH3zwwZk7gE2ZMiX69u0bCxYsKDRm4cKFcf7558c999xT6uqZZ599Njp06BB///vfY/r06UWOWb58efzrX/+KJ598MvPcEUccUWhMu3bt4oILLohRo0YVG15NnDgxLr300mJrVDennXZa5lS4goKCOPzww2PkyJHrjHv11VfjiCOOiJUrV0bEj6e69e7du9T6tWvXjn//+99xzTXXREFBQaF9s2fPjqOOOipzR8R69erF9ddfv06NtL9efqpWrVqxatWqOProo+PVV19dZ/+wYcOiZ8+emetG9ejRIw455JByzVFR1j4tdM21lsrj5JNPzoR7a4dtp512WqFVU1AZcrPdAAAAsOG22WabePvtt+OYY46JDz/8MFavXh0PP/xwPPzww7HVVlvFbrvtFi1atIhVq1bFV199Fe+99946q0bW545czZo1i9/+9rdxww03RETEo48+Gi+88EL87Gc/iy233DLy8/Pj9ddfj8WLF0dubm785z//ib59+5ZYc+rUqXHllVfGlVdeGe3atYvddtstE6R99dVXMW7cuPj2228z40877bTYb7/9CtVYunRp3HfffXHfffdFo0aNYo899oj27dtHgwYNYv78+fHpp5/GRx99lBnfsmXL6NevX7nff1VSu3btGDx4cHTt2jXmzZsXX331VRx88MGx++67xx577BEREe+9915MmjQp85pWrVrF4MGDo1atWqXW//Of/xy///3v45ZbbokBAwZEt27dolmzZvHll1/G66+/XiiAuuOOO2K77bZbp0ZFfL2srU2bNtGzZ8+44447okePHpn3niRJvPPOO4WOeevWreP+++8vc+2K1qtXr3jppZci4seVSS+88ELsvPPOUadOncyY3//+95k7z/1U/fr147TTTov//Oc/hZ6vKiu32MQkAADARmPRokXJDTfckDRt2jSJiDJ97L777snTTz9dZL2+fftmxj344INFjlm5cmXSp0+fEudo2rRp8vTTTyfTpk3LPNe+fft1aj3xxBNJTk5OmfquUaNGctFFFyUFBQXr1GnYsGG53v8nn3yyAZ/1H11//fWZml27dt2gWiNHjlzvWp999lmy5557lvq+99prr2TKlCkl1uratWtm/MiRI5Nnnnkmady4cbE169atm/znP/8psWaaXy9JkqwzpqCgIDnnnHNKrL/DDjuUesx/+t6LsvYxv/7664scU9ZjWVBQkBx00EEl9j1t2rQSe37vvfcKjd97771LHA8VxcomAADYiDRs2DD++Mc/xq9+9asYPnx4vPLKK/HOO+/E119/Hd9++23Url07Nttss+jYsWP87Gc/i+OPP36dO4aVV82aNeOhhx6Kk046Ke677754++2347vvvotmzZpFu3bt4rjjjouzzz472rRpU+ypcWuceOKJkZ+fHy+//HKMGTMmJk2aFF988UXmVKsmTZpEhw4d4oADDog+ffrETjvtVGSdb775Jt54440YNWpUTJgwIT7//POYO3duLFu2LOrXrx9t27aNTp06Ra9eveLYY48tdOHq6q5Dhw4xceLEePLJJ+Opp56K8ePHZy7a3apVq/jZz34WJ554YvTq1StycnLKVfu4446L999/P+65554YNmxYzJgxIwoKCiIvLy9+/vOfxyWXXBLbb799iTXS/HopSq1ataJ///5x0kknxYABA2LChAmRn58fDRo0iB133DF+8YtfxPnnn19oxVBVUKtWrXj11VdjwIAB8dRTT8WHH34Y33777TqnLJZk9913j2222Sa++OKLiLCqiezJSZL//2RVAAAAoNqaPn16bLPNNpEkSTRo0CDmzJkTjRs3znZbbII2nvgeAAAANmEPPPBA5uLnJ598sqCJrLGyCQAAAKq5ZcuWxdZbbx1fffVVRPx4R7ouXbpkuSs2VVY2AQAAQDX3hz/8IRM07bfffoImssoFwgEAAKCaefHFF+PFF1+MpUuXxvjx4+O9996LiIicnJz461//mt3m2OQJmwAAAKCaGTduXNx5553rPP/b3/42DjrooCx0BP+PsAkAAACqsfr168euu+4aF110UfTp0yfb7YALhAMAAACQHhcIBwAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUpOb7QYAACibZcuWxQcffBARES1btozcXL/KAQAbZuXKlTFv3ryIiNh1112jbt26G1zTbygAANXEBx98EF26dMl2GwDARmr8+PHRuXPnDa7jNDoAAAAAUmNlEwBANdGyZcvM9vjx46N169ZZ7AYA2Bjk5+dnVk6v/bvGhhA2AQBUE2tfo6l169bRtm3bLHYDAGxs0roepNPoAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAAACA1AibAAAAAEiNsAkAoByWLVsW//nPf+KQQw6Jli1bRu3ataNNmzZx5JFHxmOPPZbt9gAAsi432w0AAFQXn332WRx33HHx2WefFXo+Pz8/8vPz44UXXogHH3wwnnrqqWjYsGGWugQAyC4rmwAAyuDrr7+OHj16ZIKmk046KYYOHRr/+9//YujQoXHSSSdFRMTLL78cp5xySjZbBQDIKmETAEAZ3HDDDTFz5syIiLj++uvj8ccfj6OOOir23HPPOOqoo+Lxxx+P6667LiIihg0bFk8++WQ22wUAyJqcJEmSbDcBAFCVrVq1Kpo3bx7ff/99tG/fPqZOnRo1a9Ysctw222wTM2bMiE6dOsXEiRNT7WPWrFmRl5cXEREzZ86Mtm3bplofANj0VMTvF1Y2AQCU4vPPP4/vv/8+IiJ69OhRZNAUEVGzZs3o0aNHRES88847MW3atErrEQCgqhA2AQCU4ptvvslsb7755iWOXXv/6NGjK6wnAICqyt3oAABKsfad5dascCrO2vs//vjjcs0za9asEvfn5+eXqx4AQDYImwAASrHddttFrVq1YsWKFfHGG2+UOHbt/TNmzCjXPGuulwAAUJ05jQ4AoBQNGjSIgw8+OCIi3n///Rg8eHCR4wYPHhwffPBB5vGiRYsqpT8AgKrEyiYAgDLo169fjBgxIlauXBl9+/aNqVOnRp8+faJ169aRn58fgwYNihtuuCFq164dBQUFERGxdOnScs0xc+bMEvfn5+dHly5d1vs9AABUBmETAEAZ7LPPPnHvvffGBRdcECtWrIg//vGP8cc//rHQmHr16sWtt94al1xySURENGrUqFxzpHGrYQCAbHMaHQBAGZ199tnx9ttvR8+ePaNBgwaZ53Nzc+PYY4+N//3vf7H33ntnnm/WrFk22gQAyCormwAAymGvvfaKIUOGxMqVKyM/Pz8KCgpiyy23jLp160ZExCOPPJIZu/POO2erTQCArBE2AQCsh9zc3CLvHvfOO+9ktl1fCQDYFDmNDgAgJatWrYohQ4ZEREReXl7st99+We4IAKDyCZsAAFIyYMCAmDFjRkREXHDBBVGzZs0sdwQAUPmETQAAZTR79uxi97322mtx+eWXR0REhw4d4oorrqikrgAAqhbXbAIAKKNddtklunbtGkcddVTsvPPOUadOnZgxY0Y8/fTT8eijj8bq1atjs802i8cffzxzwXAAgE2NsAkAoIxWrFgRzz77bDz77LNF7t95553j0Ucfjd13372SOwMAqDqETQAAZdS/f/94+eWXY/z48ZGfnx8//PBDtGzZMnbbbbc46aST4vTTT49atWplu00AgKwSNgEAlNEpp5wSp5xySrbbAACo0lwgHAAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAAAASI2wCQAAAIDUCJsAAMqhoKAg+vfvH4cffni0bt066tSpEw0bNowddtghzjrrrHjrrbey3SIAQFblZrsBAIDq4ssvv4yjjjoqPvroo0LPFxQUxOTJk2Py5MkxcODAuPTSS+POO++MnJycLHUKAJA9VjYBAJTBihUrCgVNu+22WwwcODDGjh0bL7/8clx33XXRoEGDiIi466674pZbbslmuwAAWZOTJEmS7SYAAKq6J598Mk466aSIiNh3331j9OjRUbNmzUJj3nnnndh3331jxYoV0bRp05g3b17k5qa3kHzWrFmRl5cXEREzZ86Mtm3bplYbANg0VcTvF1Y2AQCUwdrXYrr22mvXCZoiIjp16hRHH310REQsWLAgPvnkk0rrDwCgqhA2AQCUQUFBQWZ7m222KXbctttuW+RrAAA2FcImAIAy2GGHHTLbX3zxRbHjpk6dGhEROTk5sf3221d4XwAAVY2wCQCgDHr37h2NGzeOiIhbbrklVq1atc6Yd999N4YNGxYREaeeempmfFnNmjWrxI/8/PwNfyMAABUsvStWAgBsxFq0aBEPP/xw9O7dO8aMGROdO3eOyy+/PDp06BA//PBDjBkzJm677bYoKCiIvfbaK2677bZyz7Hm4pwAANWZu9EBAJTDp59+GrfddlsMGDAgfvpr1Oabbx7XXnttnHfeeVG/fv1y187JySnzWHejAwDSUBF3o7OyCQCgjAoKCmLQoEHx7LPPrhM0RUTMnTs3Hnnkkdh6663j2GOPLXf9mTNnlrg/Pz8/unTpUu66AACVSdgEAFAGixcvjiOOOCJGjx4dNWvWjKuuuirOOuus2GabbWLZsmXx9ttvxw033BBvvvlmHH/88fH3v/89fvOb35RrDiuVAICNgQuEAwCUQb9+/WL06NERETFgwIC45ZZbomPHjlG7du1o3Lhx9OjRI0aOHBndu3ePJEniyiuvjEmTJmW5awCAyidsAgAoRZIk8cADD0RERIcOHaJv375FjsvNzY0bb7wxIiJWr14dAwcOrKwWAQCqDGETAEAp5s6dG99++21EROy5554lju3UqVNm+9NPP63QvgAAqiJhEwBAKXJz/99lLleuXFni2BUrVhT5OgCATYWwCQCgFJtttlk0btw4IiLGjh1bYuA0atSozPbWW29d4b0BAFQ1wiYAgFLUqFEjjjrqqIiImDNnTtx0001Fjvvuu+/i6quvzjw++uijK6U/AICqxNpuAIAyuO666+LZZ5+NJUuWRL9+/eKdd96Jvn37xjbbbBPLli2LcePGxR133BEzZsyIiIhDDjkkDjvssCx3DQBQ+YRNAABl0LFjx3j22Wejd+/eMX/+/Hj++efj+eefL3LswQcfHE888UQldwgAUDUImwAAyujQQw+NTz/9NAYMGBAvvPBCfPTRR7FgwYLIzc2NLbbYIjp37hynnnpqHHvssZGTk5PtdgEAsiInSZIk200AAFC6WbNmRV5eXkREzJw5M9q2bZvljgCA6q4ifr9wgXAAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1udluAACA8tvnLyMit3GLbLcBAJu86Tcfle0WqhwrmwAAAABIjbAJAAAAgNQImwAAAABIjbAJAAAAgNQImwAAAABIjbAJAAAAgNTkZrsBNg2LFi1KrdbYsWNTqxUR8dprr6VWa86cOanVysnJSa1WVTVo0KBst1CsXXbZJbVa//jHP1Kr1aNHj9RqAQAAVAQrmwAAAABIjbAJAAAAgNQImwAAAABIjbAJAKAMunXrFjk5OeX6eP3117PdNgBApRM2AQBUgBo1asT222+f7TYAACqdu9EBAJTBgw8+GIsXLy5xzMcffxy/+MUvIiLikEMOiS233LIyWgMAqFKETQAAZbD11luXOubhhx/ObPfp06ci2wEAqLKcRgcAkILVq1fHo48+GhERDRs2jBNOOCHLHQEAZIewCQAgBSNGjIjZs2dHRMSJJ54Y9evXz3JHAADZIWwCAEjBoEGDMttOoQMANmWu2QQAsIF++OGHePrppyMion379tGtW7f1qjNr1qwS9+fn569XXQCAyiRsAgDYQE899VTmTnWnn3565OTkrFedvLy8NNsCAMgKp9EBAGwgp9ABAPw/VjYBAGyAWbNmxeuvvx4REfvss0906NBhvWvNnDmzxP35+fnRpUuX9a4PAFAZhE0AABvgkUceidWrV0dERN++fTeoVtu2bdNoCQAgq5xGBwCwAR5++OGIiKhTp0784he/yHI3AADZJ2wCAFhPEydOjI8//jgiIo4++uho1qxZljsCAMg+YRMAwHpa+8LgG3oKHQDAxsI1myjWokWLUqt14oknplbrlVdeSa1W2pIkSa3W+t42uzpp3LhxqvXq1auXWq2PPvootVqPPvpoarV69OiRWi1gw6xYsSIee+yxiIho2bJlHHHEEVnuCACgarCyCQBgPbzwwgsxb968iIg49dRTIzfX/+EBAEQImwAA1svap9D16dMni50AAFQtwiYAgHL67rvvYujQoRERscsuu8Ree+2V5Y4AAKoOYRMAQDn997//jeXLl0eEVU0AAD8lbAIAKKeHH344IiJq1qwZp512Wpa7AQCoWlzJEgCgnMaMGZPtFgAAqiwrmwAAAABIjbAJAAAAgNQImwAAAABIjbAJAAAAgNQImwAAAABIjbAJAAAAgNTkZrsBAADKb9zvDom2bdtmuw0AgHVY2QQAAABAaoRNAAAAAKRG2AQAAABAaoRNAAAAAKRG2AQAAABAaoRNAAAAAKQmN9sNUHWdcMIJqdUaMWJEarXy8vJSqxURccopp6RWa4sttkit1iGHHJJaraqqYcOGqdYbNWpUarXOOeec1GoBAABsSqxsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUiNsAgAAACA1wiYAAAAAUpOb7QYAAKqjGTNmxIABA2LYsGHx5ZdfxqJFi6Jly5ax1VZbRffu3ePkk0+OXXbZJdttAgBUOmETAEA53XXXXXHttdfG4sWLCz0/a9asmDVrVrz55puxcOHCuOOOO7LTIABAFgmbAADK4c9//nP88Y9/jIiIDh06xHnnnRedO3eOJk2axDfffBPvvvtuPP3001GjhqsVAACbJmETAEAZjRgxIhM09enTJ/r37x+1atUqNOaQQw6J3/72t1FQUJCNFgEAsk7YBABQBqtXr45f/vKXERGx++67x4ABAyI3t/hfpWrXrl1ZrQEAVCnWdwMAlMHLL78cn3/+eUREXH311SUGTQAAmzK/JVGsV199NbVaN998c2q1LrrootRqRUQ0atQo1Xpkz/vvv5/tFoCN2BNPPBERETk5OXH00Udnnv/222/jm2++iebNm8dmm22WrfYAAKoMK5sAAMpg3LhxERGx1VZbRaNGjeL//u//Ytddd43mzZtHhw4donnz5rHDDjvE3//+91i+fHmWuwUAyB4rmwAASrF69er49NNPIyKiRYsWcdlll8U///nPdcZNnjw5rrzyynj66adj2LBh0bRp03LNM2vWrBL35+fnl6seAEA2CJsAAErx/fffx+rVqyMi4oMPPogJEyZE69at49Zbb40jjzwy6tatGxMmTIirr746xo0bF2+99VacffbZMWTIkHLNk5eXVxHtAwBUKqfRAQCUYvHixZntZcuWRf369WPkyJFx2mmnRbNmzaJevXpx0EEHxWuvvRa77757REQ8/fTT8fbbb2erZQCArLGyCQCgFHXr1i30+Nxzz40ddthhnXH16tWLm266KXMB8f/+97/xs5/9rMzzzJw5s8T9+fn50aVLlzLXAwDIBmETAEApfnrn0sMOO6zYsYccckjk5ubGypUrY8KECeWap23btuvVHwBAVeI0OgCAUtSpUydatmyZeVzStZXq1q0bLVq0iIiIefPmVXhvAABVjbAJAKAMdt5558z2qlWrShy7Zn9urkXkAMCmR9gEAFAGBx10UGb7iy++KHbcwoULY/78+RERseWWW1Z4XwAAVY2wCQCgDHr16pXZfvrpp4sd9/TTT0eSJBERceCBB1Z4XwAAVY2wCQCgDHbbbbc44ogjIiJi8ODBMWLEiHXGfPXVV/GHP/whIiJq164dZ511VqX2CABQFQibAADK6I477oimTZvG6tWr4+ijj45rr702Ro8eHRMnToz//Oc/0blz55g1a1ZERNx4441OowMANkmuWgkAUEYdOnSI559/Pk488cSYO3du3HzzzXHzzTcXGpOTkxO///3v46qrrspSlwAA2SVsAgAohwMOOCA++uijuOuuu+KZZ56JadOmRUFBQbRu3Tq6desWl156aey5557ZbhMAIGuETQAA5dS8efPo169f9OvXL9utAABUOa7ZBAAAAEBqhE0AAAAApEbYBAAAAEBqXLOJYo0ePTq1Wp06dUqtVr169VKrxcZlzJgxqdVKkqRK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AAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKnJzXYDAGkZOnRotlsAAADY5FnZBAAAAEBqhE0AAAAApEbYBAAAAEBqhE0AAAAApEbYBAAAAEBqhE0AAAAApCY32w0AAFQHCxcujOHDh8eECRNi4sSJMXv27Jg3b14sXbo0mjZtGjvttFMceeSRcc4550Tz5s2z3S4AQNYImwAAymD8+PHRu3fvIvfNmzcvRo0aFaNGjYpbb701HnnkkTj88MMruUMAgKpB2AQAUEZ5eXnRvXv36NSpU+Tl5UXr1q1j9erVMWvWrHjyySdjyJAhMX/+/Dj22GNj/Pjxsfvuu2e7ZQCASidsAgAog+7du8eMGTOK3X/yySfHM888Ez179oyCgoL405/+FEOGDKnEDgEAqgYXCAcAKIOaNWuWOub444+PHXbYISIiRo8eXdEtAQBUScImAIAUNWrUKCIili1bluVOAACyQ9gEAJCSzz77LN57772IiOjYsWN2mwEAyBLXbAIA2ABLliyJ2bNnx/PPPx9/+9vfYuXKlRERcfnll5e71qxZs0rcn5+fvz4tAgBUKmETAEA5DRw4MM4666xi919zzTVx6qmnlrtuXl7ehrQFAFAlCJsAAFKyxx57xH333RedO3fOdisAAFkjbAIAKKfjjz8+9t5774iIWLp0aUydOjUef/zxePrpp6N3795xxx13xNFHH13uujNnzixxf35+fnTp0mW9egYAqCzCJgCAcmratGk0bdo087hz585xyimnxMMPPxx9+/aN4447LgYMGBBnnnlmueq2bds23UYBALJA2ARQwQ4++OBstwBUkjPOOCOGDh0ajz/+eFxyySVx7LHHxmabbZbttgAAKlWNbDcAALAxOe644yIiYvHixfHiiy9muRsAgMonbAIASFHLli0z219++WUWOwEAyA5hEwBAimbPnp3ZbtiwYRY7AQDIDmETAECKnnjiicz2rrvumsVOAACyQ9gEAFAGAwcOjGXLlpU45vbbb4/hw4dHRMTWW28dBx54YGW0BgBQpbgbHQBAGfTr1y+uuOKK6NWrVxxwwAGx7bbbRsOGDWPRokXxwQcfxKOPPhpjxoyJiIjatWvHfffdFzVr1sxy1wAAlU/YBABQRt9++23cf//9cf/99xc7pm3btvHAAw/E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G/369YuvvvoqpXdSfVXW98LalixZEttss03k5ORETk5ObLXVVhUyT3VSmcfh1VdfjTPPPDO22267aNCgQTRp0iQ6dOgQJ554Ytx9993xww8/pDpfdVEZx2D69Olx9dVXR6dOnaJp06ZRq1at2GyzzWK//faLG264Ib7++utU5qluvv766xg6dGhcd911ccQRR0SLFi0y/z6ceeaZFTLn4MGD47DDDostttgi6tatG+3bt4/TTz89xo4dWyHzZU0CAECleO6555LGjRsnEVHkR4cOHZLPP/98g+ZYtWpVcs455xQ7R0Qk5557brJq1aqU3lX1U5HHYdKkSUnDhg1L/PxHRNK4cePkscceS/mdVR+V8b1QlCuuuKLQPO3bt099juqkso7Dt99+mxx33HGlfl+8++67G/6mqpnKOAaDBg1K6tWrV+LnfrPNNktefvnllN5V9VHS56Rv376pzrVkyZLkyCOPLHa+GjVqJP369Ut1zmwSNgEAVIL//e9/mV/2GzZsmNx0003JW2+9lYwYMSI577zzCv1hsXDhwvWe55prrsnU2nPPPZPBgwcn48ePTwYPHpzsueeemX3XXnttiu+u+qjo4zB69OhMjf333z/561//mrzyyivJ//73v+Sll15KLrjggqRGjRpJRCQ1a9ZMhg8fXgHvsmqrrO+FouatWbNmUrdu3aRRo0abfNhUWcdhwYIFSadOnTL1evbsmTz66KPJuHHjkgkTJiRDhgxJLrvssqRt27abXNhUGcfgzTffzPybU6NGjeSss85KnnnmmWT8+PHJk08+mRxzzDGZeerVq5dMnTo15XdZta0d9rRr1y457LDDKixsOuWUUzK1u3fvnjkOAwYMSLbddtvMvnvvvTfVebNF2AQAUAkOPPDAJCKS3Nzc5K233lpn/9/+9rfML5rXX3/9es3x2WefJbm5uUlEJHvvvXeyZMmSQvsXL16c7L333pk+KmLlSFVX0cdhzJgxycknn5x89NFHxY555plnkpycnCQikm233TZZvXp1ueepzirje+GnVq5cmQk8brjhhqR9+/abfNhUWcfhjDPOSCIiqVOnTvLss88WO2716tXJihUr1nue6qgyjsFRRx2VqfHvf/+7yDG/+c1vMmMuvvji9ZqnurruuuuS559/Pvnqq6+SJEmSadOmVUjYNGLEiEzdY445Jlm5cmWh/fPmzUvatWuXRETStGnT5Ntvv01t7mwRNgEAVLC3334780vmBRdcUOSYVatWJTvuuGPmF82CgoJyz/PLX/4yM8/YsWOLHDN27NjMmIsuuqjcc1RnlXUcyqJXr16ZXt55550KmaMqytYxuO2225KISHbYYYdk+fLlm3zYVFnHYe2VfrfeeuuGtr1Rqaxj0KxZsyQikubNmxc7ZsGCBZle9tprr3LPsTGpqLDpiCOOyASLM2fOLHLM4MGDM3P/7W9/S23ubHGBcACACvbMM89kts8666wix9SoUSP69OkTERELFiyIkSNHlmuOJEni2WefjYiIjh07xj777FPkuH322Sd22GGHiIh49tlnI0mScs1TnVXGcSir7t27Z7anTp1aIXNURdk4Bl9++WVcd911ERFxzz33RO3atTeo3sagso7Dv/71r4iIaNKkSVxyySXlb3QjVlnHoKCgICIitt5662LHNGnSJFq0aFFoPOlZtGhRjBgxIiIiDj300Gjbtm2R40444YRo3LhxREQ8/fTTldZfRRE2AQBUsDfffDMiIho0aBCdOnUqdlzXrl0z22PGjCnXHNOmTYs5c+asU6ekeWbPnh3Tp08v1zzVWWUch7Javnx5ZrtmzZoVMkdVlI1jcNFFF8XixYvjjDPOiG7dum1QrY1FZRyHgoKCTADeo0ePqFu3bkRErFq1KmbOnBnTp0+PZcuWlbf1jUZlfS+s+c+FadOmFTtm4cKFMX/+/ELjSc+ECRMyIV5JP59r166d+Y+iCRMmxIoVKyqlv4oibAIAqGCffPJJRERst912kZubW+y4jh07rvOasvr444+LrJP2PNVZZRyHsho1alRme8cdd6yQOaqiyj4Gjz32WAwfPjyaNWsWt91223rX2dhUxnGYNGlSJkzaddddY+HChXH55ZdHixYtol27drH11ltHkyZNokePHvH666+X/01Uc5X1vXDhhRdGRMQ333wT99xzT5FjbrzxxnXGk571+fm8cuXK+Pzzzyu0r4ombAIAqEDLli3L/I9xcUvn12jWrFk0aNAgIiJmzpxZrnlmzZqV2S5tnry8vMx2eeeprirrOJTFpEmTYtiwYRHx4x/hm0rYVNnH4LvvvovLL788IiJuvvnmaNmy5XrV2dhU1nFY+w/s1atXx9577x133nlnLFiwIPN8QUFBvPrqq3HwwQfHLbfcUq761Vllfi+cffbZmVPxLr744jjvvPPi+eefj4kTJ8aQIUOiZ8+e8fe//z0iIn7/+9/HoYceWu45KNmm+vNZ2AQAUIEWLVqU2W7YsGGp49f8UfHDDz9U2Dxr5lifeaqryjoOpVm+fHmce+65sWrVqoiIuOmmm1KtX5VV9jG48sorY+7cubHvvvvGeeedt141NkaVdRy+/fbbzPYtt9wSn3/+efz85z+P8ePHx7Jly+Lrr7+Ou+++O5o0aRJJksQ111yTOe1uY1eZ3ws1a9aMhx56KJ544onYfffdo3///nHsscdG586do1evXvHMM89E9+7d45VXXok///nP5a5P6TbVn8/CJgCACrT2NUnKcmHiOnXqRETE0qVLK2yeNXOszzzVVWUdh9JccsklMXHixIiI6Nu3bxxzzDGp1q/KKvMYvPHGG/HAAw9Ebm5u3HPPPZGTk1PuGhuryjoOixcvLjRnjx49YujQodG5c+eoU6dOtGzZMi688MIYOnRo1Kjx45+l11577SZx04LK/vfok08+iUGDBsUHH3xQ5P6xY8fGgAEDYvbs2etVn5Jtqj+fhU0AABVozUVxI8p2l581F46uV69ehc2z9sWpyztPdVVZx6Ekf/3rX6N///4REdG5c+f497//nVrt6qCyjsHy5cvj/PPPjyRJ4rLLLovddtutfI1u5LLxb1LEj6ubiroY/gEHHBAnnHBCRPwYihQXiGxMKvPfo9GjR8e+++4bzz//fGy55Zbx8MMPx1dffRUFBQUxc+bM+Pe//x3169ePxx57LLp06RIfffRRueegZJvqz2dhEwBABWrUqFFmuyxL4tesBijLqRXrO8/aKw7KO091VVnHoTj33ntv/O53v4uIHy8AO3z48EKnS2wKKusY3HTTTfHZZ59FXl5e/OlPfypfk5uAbPyb1LJly9hzzz2LHXv44YdntidMmFCueaqjyjoGy5cvj969e8f3338fW2yxRYwbNy5OP/302HzzzaNWrVrRtm3buOiii+KNN96IunXrxpw5c6Jv377lezOUalP9+Vz8Ze8BANhgdevWjebNm8c333xT6CKhRfnuu+8yv2iufZHQslj7oqOlzbP2RUfLO091VVnHoSiDBw+Oiy66KCIi2rdvH6+88kq0aNFig+tWN5V1DNZcaPrQQw+N559/vsgxa2ovXrw4HnvssYiIaNWqVRx88MHlmqs6qqzjsPb48lwUed68eeWapzqqrGPw4osvZk6Nu/TSS2OLLbYoctzOO+8cp59+evTv3z/eeeedmDRpUuy+++7lmovi/fTn8957713s2I3p57OwCQCggu20004xevTomDJlSqxcubLY21x/+umnme3y3qFsp512KrJO2vNUZ5VxHH7queeeiz59+sTq1aujdevWMWLEiFL/8N6YVcYxWHOayoMPPhgPPvhgiWPnz58fvXv3joiIrl27bhJhU0TlHIedd945s73mgvjFWXt/cb1sbCrjGHzyySeZ7b322qvEsZ06dcqc5vvpp58Km1K0Pj+fc3NzY/vtt6/Qviqa0+gAACrYAQccEBE/rqJ45513ih03atSozPb+++9frjm23nrraNOmzTp1ivLGG29ERMSWW24ZW221Vbnmqc4q4zisbcSIEXHyySfHypUro3nz5vHKK6/Etttuu971NgaVfQwoWmUch/bt20e7du0iImL69OklXvh76tSpme0tt9yyXPNUV5VxDNYOsFauXFni2BUrVhT5OjZc586dMxcGL+nnc0FBQYwbNy7zmlq1alVKfxVF2AQAUMGOP/74zHZxKy1Wr14dgwYNioiIpk2bRvfu3cs1R05OThx33HER8eP/jK75hfWnxo0bl/mf0+OOO26TuktXZRyHNd5666047rjjYvny5dGkSZN46aWXCq302FRVxjFIkqTUj/bt20fEj4HImudef/319XpP1VFlfS/06tUrIiIWLlwYI0aMKHbckCFDMttrQpiNXWUcg6233jqzPXr06BLHrh2CrP06NlyjRo3ikEMOiYiIV199tdhTJ4cMGRILFy6MiIiePXtWWn8VJgEAoMIdeOCBSUQkubm5yVtvvbXO/r/97W9JRCQRkVx//fXr7B85cmRmf9++fYuc47PPPktq1qyZRESy9957J0uWLCm0f8mSJcnee++d6WPy5MlpvLVqpTKOw7vvvps0bdo0iYikQYMGyZtvvpnyu6jeKuMYlKZ9+/ZJRCTt27dfr9dvDCrjOHz55ZdJ3bp1k4hIdt111+T7779fZ8zDDz+cqXPUUUdt6NuqVir6GHz33XdJ/fr1k4hIGjVqlLz//vtF9jF8+PCkRo0aSUQkW265ZbJq1aoNfWvV1rRp08r978uDDz5Y4nFKkiQZMWJEZsyxxx6brFy5stD+efPmJe3atUsiImnatGny7bffbuA7yT7r4wAAKsGdd94Z+++/fyxdujQOO+yw+N3vfhfdu3ePpUuXxmOPPRb33XdfRER06NAhrrjiivWao0OHDnHllVfGzTffHBMnToz9998/rr766th2221j6tSpccstt8S7774bERFXXnlltb8exPqo6OMwderUOPzww2PBggUREfHnP/85mjRpEh9++GGxr2nVqlW0atVqvd5PdVQZ3wuUrjKOQ7t27eKGG26Iq666Kj744IPo0qVLXH311bHbbrvFwoULY8iQIXH33XdHRETjxo3j9ttvT+39VQcVfQyaNm0a11xzTVx33XWxaNGi2G+//eLSSy+NHj16RLNmzWLu3Lnx7LPPxv333x+rV6+OiIibb745atTYdE6AevPNN2PKlCmZx/Pnz89sT5kyJQYOHFho/Jlnnrle8xx88MFxyimnxGOPPRbPPfdc9OjRIy6//PJo06ZNfPDBB3HTTTfFjBkzIuLHmxw0a9ZsveapUrKddgEAbCqee+65pHHjxpn/3fzpR4cOHZLPP/+8yNeWdTXHqlWrkrPPPrvYOSIiOeecczbp/7muyOOw9v9wl/WjuP8J35hVxvdCSaxs+lFlHYdrrrkmycnJKXaeVq1aFbmyZ1NQ0cdg9erVyeWXX17i5z8iklq1aiW33nprBb7Tqqlv377l+ve6KGVZ2ZQkP64uPvLII4utXaNGjY3q58GmE1kCAGTZMcccE++//378+te/jg4dOkT9+vWjadOmsffee2dWHW233XYbNEeNGjViwIABMWzYsDjuuOOiTZs2Ubt27WjTpk0cd9xxMXz48Ojfv/8m9T/XP1UZx4GSOQZVQ2Udh7/+9a8xZsyYOOOMM2KrrbaKOnXqRJMmTaJz585x4403xuTJk2PfffdN4R1VPxV9DHJycuL222+PCRMmxIUXXhi77LJLNGrUKGrWrBlNmjSJTp06xW9+85v48MMP47e//W2K74yfqlevXgwbNiweffTR6NGjR7Rq1Spq164deXl5ceqpp8abb74Z/fr1y3abqclJkhJuCwAAAAAA5bDp/pcWAAAAAKkTNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQGmETAAAAAKkRNgEAAACQmv8PGhyMOfv6c4UAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": { "image/png": { "height": 327, "width": 589 } }, "output_type": "display_data" } ], "source": [ "## Solution\n", "for image_batch, label_batch in training_batches.take(1):\n", " ps = my_model.predict(image_batch)\n", " first_image = image_batch.numpy().squeeze()[0]\n", " \n", " \n", "fig, (ax1, ax2) = plt.subplots(figsize=(6,9), ncols=2)\n", "ax1.imshow(first_image, cmap=plt.cm.binary)\n", "ax1.axis('off')\n", "ax2.barh(np.arange(10), ps[0])\n", "ax2.set_aspect(0.1)\n", "ax2.set_yticks(np.arange(10))\n", "ax2.set_yticklabels(np.arange(10))\n", "ax2.set_title('Class Probability')\n", "ax2.set_xlim(0, 1.1)\n", "plt.tight_layout()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dqREWxKKVwql" }, "source": [ "## Automatic Differentiation\n", "\n", "Let's now take a minute to see how TensorFlow calculates and keeps track of the gradients needed for backpropagation. TensorFlow provides a class that records automatic differentiation operations, called `tf.GradientTape`. Automatic differentiation, also known as algorithmic differentiation or simply “autodiff”, is a family of techniques used by computers for efficiently and accurately evaluating derivatives of numeric functions.\n", "\n", "`tf.GradientTape` works by keeping track of operations performed on tensors that are being \"watched\". By default `tf.GradientTape` will automatically \"watch\" any trainable variables, such as the weights in our model. Trainable variables are those that have `trainable=True`. When we create a model with `tf.keras`, all of the parameters are initialized with `trainable = True`. Any tensor can also be manually \"watched\" by invoking the watch method.\n", "\n", "\n", "Let's see a simple example. Let's take the following equation:\n", "\n", "$$\n", "y = x^2\n", "$$\n", "\n", "The derivative of `y` with respect to `x` is given by:\n", "\n", "$$\n", "\\frac{d y}{d x} = 2x\n", "$$\n", "\n", "Now, let's use `tf.GradientTape` to calculate the derivative of a tensor `y` with respect to a tensor `x`:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 204 }, "colab_type": "code", "id": "2-ktpx5dVU3O", "outputId": "d4a54fba-61eb-4419-e9d9-8162785ef09d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Gradient calculated by tf.GradientTape:\n", " tf.Tensor(\n", "[[1.1966898 0.12552415]\n", " [0.29263484 0.9696376 ]], shape=(2, 2), dtype=float32)\n", "\n", "True Gradient:\n", " tf.Tensor(\n", "[[1.1966898 0.12552415]\n", " [0.29263484 0.9696376 ]], shape=(2, 2), dtype=float32)\n", "\n", "Maximum Difference: 0.0\n" ] } ], "source": [ "# Set the random seed so things are reproducible\n", "tf.random.set_seed(7)\n", "\n", "# Create a random tensor\n", "x = tf.random.normal((2,2))\n", "\n", "# Calculate gradient\n", "with tf.GradientTape() as g:\n", " g.watch(x)\n", " y = x ** 2\n", " \n", "dy_dx = g.gradient(y, x)\n", "\n", "# Calculate the actual gradient of y = x^2\n", "true_grad = 2 * x\n", "\n", "# Print the gradient calculated by tf.GradientTape\n", "print('Gradient calculated by tf.GradientTape:\\n', dy_dx)\n", "\n", "# Print the actual gradient of y = x^2\n", "print('\\nTrue Gradient:\\n', true_grad)\n", "\n", "# Print the maximum difference between true and calculated gradient\n", "print('\\nMaximum Difference:', np.abs(true_grad - dy_dx).max())" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "QgLCJaooV5Un" }, "source": [ "The `tf.GradientTape` class keeps track of these operations and knows how to calculate the gradient for each one. In this way, it's able to calculate the gradients for a chain of operations, with respect to any one tensor.\n", "\n", "To know more about `tf.GradientTape` and trainable variables check the following links\n", "\n", "* [Gradient Tape](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/GradientTape)\n", "\n", "* [TensorFlow Variables](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/Variable)\n", "\n", "Next up you'll write the code for training a neural network on a more complex dataset." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "am0SvU9KWAD3" }, "outputs": [], "source": [] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "Part 3 - Training Neural Networks (Solution).ipynb", "provenance": [] }, "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.11.0rc1" } }, "nbformat": 4, "nbformat_minor": 1 }