{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "accelerator": "GPU", "colab": { "name": "kl_py_TF_Day_2_MNIST_Eager_ConvNet_Solution.ipynb", "provenance": [], "collapsed_sections": [], "include_colab_link": true }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "view-in-github", "colab_type": "text" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "aAOBNN50Tx5z" }, "source": [ "![TF](https://1.bp.blogspot.com/-eb-_3Aqu5bA/XnertoOpPgI/AAAAAAAAa6Y/8TPaJ8vjn2cN_so7xLeqPZDqX3pQjVARgCLcBGAsYHQ/s200/tf.jpg)\n", "\n", "# Exploring the New Eager Execution TensorFlow API" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "AfR0x2u-65MY", "outputId": "4d2de624-e8bd-45bf-ba50-068be7d28c2b", "colab": { "base_uri": "https://localhost:8080/", "height": 35 } }, "source": [ "import tensorflow as tf\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from mpl_toolkits.axes_grid1 import ImageGrid\n", "from tensorflow.examples.tutorials.mnist import input_data\n", "from keras.datasets import mnist\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.metrics import accuracy_score\n", "import keras\n", "plt.rcParams[\"axes.grid\"] = False" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Using TensorFlow backend.\n" ], "name": "stderr" } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vSfYB9xG1Mnb" }, "source": [ "# Deep Learning\n", "\n", "Deep Learning is a branch of machine learning focused on building algorithms that learn data representations (instead of task-specific solutions) \n", "\n", "Deep Learning is **state-of-the-art** in almost all **perception** problem: \n", "\n", "- Natural Language Processing (NLP)\n", "- Voice Recognition\n", "- Computer Vision\n", "\n", "![alt text](https://developer.nvidia.com/sites/default/files/Deep_Learning_Icons_R5_PNG.jpg.png)\n", "\n", "Deep Learning is a **family of methods**:\n", "- Feedforward Network\n", "- Convolutional Nets\n", "- Recurrent Nets\n", "- Auto-Encoders\n", "- Generative Adversarial Networks\n", "- etc..." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ii79jzp1aDmU" }, "source": [ "# TensorFlow Eager Execution\n", "\n", "Eager execution is a new **high-level TF API** that lets users execute tensors in real time (**Imperative**) fashion. \n", "\n", "- Brings TF to the level of some other Deep Learning frameworks like PyTorch and Chainer.\n", "- Run TF models just like any other python code (Numpy and python objects compliant)\n", "- Don't think about Computational Graphs - Just execute code normally \n", "- Allows for **real-time python** Debugging\n", "- To enable Eager Execution - just run: **tf.enable_eager_execution()**\n", "\n", "## Exercise\n", "\n", "1- Enable eager execution mode using *tf.enable_eager_execution()*." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "Fdqa3b6N723r", "colab": {} }, "source": [ "# Enable eager execution mode\n", "tfe = tf.contrib.eager\n", "\n", "## YOUR CODE GOES HERE\n", "tf.enable_eager_execution()" ], "execution_count": 0, "outputs": [] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "mivD5CTu65Mg", "outputId": "34784b3e-212e-49c5-d47c-b57957f39600", "colab": { "base_uri": "https://localhost:8080/", "height": 35 } }, "source": [ "if tf.executing_eagerly():\n", " print(\"Eager is Enabled!\")" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Eager is Enabled!\n" ], "name": "stdout" } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "UaY0efbWBjWj" }, "source": [ "# Computer Vision 101 with MNIST \n", "\n", "## Exploring the MNIST dataset\n", "\n", "Computer Vision is a branch of AI devoted to building algorithms that enable machines to perceive the world. \n", "\n", "MNIST is a computer vision dataset. \n", "\n", "It contains **greyscale images of handwritten digits** like these.\n", "\n", "The MNIST dataset is composed of **60000 thousand images**. *50000* for training and *10000* for testing." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "KQWMGeGGKiB1" }, "source": [ "![alt text](https://www.tensorflow.org/versions/r1.1/images/MNIST-Matrix.png)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Stm9ehUpby1U" }, "source": [ "## Numerical Stabilization\n", "\n", "Any time we are up to doing some calculus on a computer, we need to think about representation.\n", "- We all know, machines are **memory-limited**\n", "\n", "## Exercise\n", "\n", "Accessing numerical error.\n", "1. Create two variables a and b.\n", "2. Assign 1000000000 (one billion) to a and 0.000001 to be\n", "3. In the loop add b to a 1000000 (one million) times\n", "\n", "What happens? What should the result be?" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "UYvuPKzMdR8k", "outputId": "fc768dfd-a088-46a1-8eed-a01d245721cf", "colab": { "base_uri": "https://localhost:8080/", "height": 72 } }, "source": [ "a = 1000000000 # one billion\n", "b = 0.000001\n", "for i in range(1000000):\n", " a += b\n", "\n", "print(\"a:\", a)\n", "print(\"a - 1000000000:\", a - 1000000000)\n", "print(\"Error:\", 1 - (a - 1000000000))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "a: 1000000000.9536743\n", "a - 1000000000: 0.95367431640625\n", "Error: 0.04632568359375\n" ], "name": "stdout" } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "W3s4_BA-fX89" }, "source": [ "Try now to substitute the 1000000000 (one billion) to just one.\n", "\n", "What do you see? \n", "\n", "When calculating the grandients and the loss, we do NOT want their values to get too **BIG** or too **SMALL**.\n", "- **Facilitates the job of the optimizer** (find the best spot in the error function)\n", "- Makes convergence FASTER and reduces the probability of **DIVERGENCE**.\n", "\n", "**That is why normalization is important.**" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "LcaAcJGw65Mn" }, "source": [ "## Load MNIST data" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "ymF2hVMZ8Zd1", "colab": {} }, "source": [ "# Download the mnist data\n", "(X_train, y_train), (X_test, y_test) = mnist.load_data()" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "1Vn4TOoa8VJf" }, "source": [ "## Exercise\n", "\n", "Like we did before, divide the training data into **train** and **validation** sets.\n", "\n", "- You may use: [train_test_split()](http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html).\n", "- Choose a reasonable value for the split fraction." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "qS6KI6DT8RRu", "colab": {} }, "source": [ "## YOUR CODE GOES HERE\n", "X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.1, random_state=42)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vNcZQSOx65Ms" }, "source": [ "# Visualize the dataset Shapes" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "ltddY8_A65Mt", "outputId": "7e3d9f81-f83a-4b39-b37e-7430c73ce7de", "colab": { "base_uri": "https://localhost:8080/", "height": 126 } }, "source": [ "print(\"Train shape:\", X_train.shape)\n", "print(\"Train labels:\", y_train.shape)\n", "print(\"Validation shape:\", X_val.shape)\n", "print(\"Validation labels:\", y_val.shape)\n", "print(\"Test shape:\", X_test.shape)\n", "print(\"Test labels:\", y_test.shape)" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Train shape: (54000, 28, 28)\n", "Train labels: (54000,)\n", "Validation shape: (6000, 28, 28)\n", "Validation labels: (6000,)\n", "Test shape: (10000, 28, 28)\n", "Test labels: (10000,)\n" ], "name": "stdout" } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "6zQk8ZfnloDn" }, "source": [ "## Exercise\n", "\n", "Build the **normalizer()** function above. \n", "\n", "Our goal is to keep the input values (pixels) in a small range.\n", "\n", "1. Option 1: Dvide the image pixels by 255. What does it mean?\n", "2. Option 2: Subtract each pixel by 128 and divide by 128. " ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "o3JnPP0vB5gF", "colab": {} }, "source": [ "def normalizer(image, label):\n", " \"\"\"\n", " TODO: Finish the normalizer function\n", " \"\"\"\n", " return 2 * tf.to_float(image) / 255. - 1.0, label" ], "execution_count": 0, "outputs": [] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "UZQtKc7_65Mw", "outputId": "07a9c858-0276-4154-b7bb-be1ab15ecad6", "colab": { "base_uri": "https://localhost:8080/", "height": 413 } }, "source": [ "## Visualize the dataset distribution\n", "import pylab as P\n", "n, bins, patches = P.hist(y_train, bins=10, histtype=\"bar\", rwidth=0.8)\n", "print(\"Train:\", n)\n", "n, bins, patches = P.hist(y_test, bins=10, histtype=\"bar\", rwidth=0.8 )\n", "print(\"Test:\", n)\n", "P.xlabel('Classes')\n", "P.ylabel('Distribution')\n", "P.title('Train/Test distribution')\n", "P.show()" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Train: [5299. 6088. 5386. 5542. 5262. 4870. 5338. 5632. 5266. 5317.]\n", "Test: [ 980. 1135. 1032. 1010. 982. 892. 958. 1028. 974. 1009.]\n" ], "name": "stdout" }, { "output_type": "display_data", "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfgAAAFnCAYAAABKGFvpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3X1Y1HW+//HXcDNLIqggWLRWbuds\nZZLKerNCaN6gA3lazBuEtHZzaz2p2bUY4k1ax1MgRpkuR91ulCvXIrFajhlQhqUHpGNjpLvedp3T\nMVEYFEW5EcT5/dE2v2UxwpsR/PB8XFfXBZ+Z73feuLpPvt+Z+Y7F6XQ6BQAAjOLR1gMAAICrj8AD\nAGAgAg8AgIEIPAAABiLwAAAYiMADAGAgAg+40eLFi2Wz2WSz2XT33Xdr+PDhru/Pnj17Sfuy2Wyq\nqKj40fuVlZXpgQceuKqP/b133nmnVfdbuXKlFixYIEmaOnWq9u/ff9n7TUxM1KeffqpvvvlGoaGh\nrR/2b3bv3q2DBw9KkjIzM7Vy5cpL3gdwPbLwPnjg2hgxYoTS0tI0YMAAtz7Oe++9p/3792vevHlX\n9bEbGhoUERGhzz///Efvu3LlSh0/flzPP//8VdvvN998o7Fjx2rPnj2tnlmSFixYoPDwcN1///2X\ntB1wveMIHmhDU6dO1csvv6zo6GjZ7XZVVFRo2rRpstlsGjFihNauXeu67x133KHjx4+ruLhYcXFx\nSk9PV3R0tEaMGNEkjoWFhQoPD//Rxy4tLdXjjz+uMWPGaMyYMdq+fbsk6fz585o3b55sNptGjRql\nJ598UtXV1fr1r3+tqqoq2Ww2lZaWNtlXbW2tnnzySQ0fPlxTp05VWVmZ67ahQ4fqyy+/bPV+4+Pj\nXX8mX331leLj4/XBBx+49vfqq6/KZrNp5MiR+uSTTyRJL7/8shYtWuS6z/ffr1+/Xps3b1Zqaqoy\nMzOb3O/bb7/Vb37zG40ZM0Zjx45VTk6OpO9+kRg2bJjWrVunsWPHaujQocrLy2v1/6ZAe0HggTa2\nd+9effDBBwoLC9OqVav005/+VLm5ucrMzFR6erqOHTvWbJu//vWv6tu3rz788EMlJCRo1apVrtt2\n7drVqiP1pKQk3XPPPcrLy9Pq1as1Z84cnT59Wtu2bVN5ebk+/PBDffTRR7rttttUUlKiF154Qd7e\n3srNzVVISEiTfW3cuFGnTp3Sxx9/rFdeeUU7duxo9niXst/9+/dry5Ytuueee5rso6GhQV5eXsrN\nzdWiRYu0aNEinT9//gd/xilTpqh3795KTk7WI4880uS2hQsXKiIiQnl5eVq1apWee+4515/1iRMn\nZLVatXnzZiUlJWn58uU/+ucJtDcEHmhjw4YNk4fHd/8UFy5cqGeeeUaS1LNnTwUFBenbb79tto2v\nr69GjRolSbr77rtdR9QHDx7UTTfdJF9f3xYf88yZM9q1a5d+/etfS5J69eqlfv366bPPPlNAQIAO\nHDigrVu3qra2Vr///e9/9IzArl27NGbMGHl6eiogIEDDhg1rdp9L2e/QoUNlsViarTudTo0bN851\nn5qaGh09erTF2S7m3Llz2rlzp+Lj4yV992c9cOBAFRcXS/ruLMb48eMlSb17977oL1lAe0fggTbW\npUsX19d79uzRtGnTNHr0aNlsNjkcDl24cKHZNn5+fq6vPTw8XPcpLCzUkCFDfvQxz5w5I6fTqQkT\nJrheeLdv3z5VVVUpLCxM8+fP17p16xQREaE5c+bozJkzLe7v1KlT6ty580V/pu9dyn67du160XUP\nDw/XbRaLRZ07d9bp06d/9Of9R5WVlfLy8mryi5C/v79OnDghSfL29tZPfvITSZKnp6caGxsv+TGA\ntkbggXbk6aef1pgxY5SXl6fc3Fx169btkrZvbeC7d+8uDw8Pvf/++8rNzVVubq4+++wzPfTQQ5Kk\nmJgYrV+/Xp988onOnj3b5LUAF9OlS5cmr8w/efLkRe93qfv9RxcuXHD9UuB0OnXmzBl17dpVnp6e\nTX4RqqqqanE/AQEBOn/+fJOZT506pcDAwEuaB2jPCDzQjpw4cUJ9+vSRxWLRe++9p9raWtXU1LRq\n24aGBtdz8z/GarUqMjJSb7/9tiSppqZG8+bNU1lZmTZu3Kg1a9ZIkrp166ZevXrJYrHIy8tLjY2N\nF52nX79+2rp1qy5cuKATJ07os88+a3afy9nvP7JYLK4Xw3322Wfy9/fXzTffrKCgIB08eFAXLlzQ\nyZMnmzy+l5dXs+BbrVZFREQoKytLkvS///u/2r17d6t+OQKuFwQeaEdmz56tGTNm6F/+5V9UU1Oj\nuLg4PfPMM/q///u/H932yy+/VO/eveXt7d2qx1qyZIkKCwtls9n04IMP6rbbblOPHj00atQo7d69\n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\nwEAEHgAAA/0/5o/wXlH1828AAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "5C_DYDAE65Mz", "outputId": "b97fc78e-8e3a-486c-d339-98feccdc8a55", "colab": { "base_uri": "https://localhost:8080/", "height": 90 } }, "source": [ "print(\"Max value:\", np.max(X_train[0]))\n", "print(\"Min value:\", np.min(X_train[0]))\n", "print(\"Mean:\", np.mean(X_train[0]))\n", "print(\"Std:\", np.std(X_train[0]))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Max value: 255\n", "Min value: 0\n", "Mean: 11.565051020408163\n", "Std: 45.77647391710191\n" ], "name": "stdout" } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Hln7rscN65M2" }, "source": [ "## Visualize some MNIST images" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "w0HpFtdF65M2", "outputId": "3dbe0c91-67fd-426d-cac8-e81f96cd5adb", "colab": { "base_uri": "https://localhost:8080/", "height": 377 } }, "source": [ "fig = plt.figure(1, (6., 6.))\n", "grid = ImageGrid(fig, 111, # similar to subplot(111)\n", " nrows_ncols=(4, 4), # creates 2x2 grid of axes\n", " axes_pad=0.1, # pad between axes in inch.\n", " )\n", "\n", "for i in range(16):\n", " grid[i].imshow(X_train[i], cmap=\"gray\") # The AxesGrid object work as a list of axes.\n", "\n", "plt.show()" ], "execution_count": 0, "outputs": [ { "output_type": "display_data", "data": { "image/png": "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\nIrLM/wMPBZGMVPlHNgAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "GD40dOS165M6" }, "source": [ "## Building our Neural Net" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "TtwfoK4X65M7" }, "source": [ "\n", "![alt text](http://cs231n.github.io/assets/cnn/convnet.jpeg)\n", "\n", "The basic architecture follows a simple sequence of operations.\n", "1. Convolution\n", "2. Activation function\n", "3. Pooling\n", "4. Fully-Connected layers \n", "\n", "In the end, to build the classification layer, we usually use a fully-connected layer.\n", "\n", "Refer to these links for full documentations:\n", "\n", "- [Keras Conv2D](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D)\n", "- [Keras Activation](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Activation)\n", "- [Keras MaxPool2D](https://www.tensorflow.org/api_docs/python/tf/keras/layers/MaxPool2D)\n", "- [Keras Dense](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense)\n", "\n", "\n", "![LeNet-5](https://world4jason.gitbooks.io/research-log/content/deepLearning/CNN/img/lenet.png)\n", "\n", "\n", "## Convolutions and Non-linearity\n", "\n", "The convolution is a linear operation that uses **small local receptive fields** that pass over an image to create feature maps between the input and the next layer. \n", "\n", "Its main advantage is that we do not need to engineer the features (filter).\n", "- The network will learn them for us.\n", "\n", "Also, Convolution are very memory efficient.\n", "- They **share parameters** across space.\n", "\n", "![Convolution](http://deeplearning.net/software/theano/_images/numerical_padding_strides.gif)\n", "\n", "Non-linearity is what makes DNN cool.\n", "\n", "ReLU (rectified linear Unit) is one of the most simple functions one can think of.\n", "- Yet, they do just what we need. **Non-linearity** and **Differentiability**.\n", "\n", "![NonLinearity](https://tiny.colaflycdn.com/static/img/learn/relu.png)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "9LTfrgyDo7_o" }, "source": [ "## Exercise:\n", "\n", "Build your own DNN using eager execution.\n", "\n", "Hint: Use the [Keras layers](https://www.tensorflow.org/api_docs/python/tf/keras/layers) built into Tensorflow.\n", "\n", "Convolutional Net template:\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "G8Qn-lB4Np8b", "colab": {} }, "source": [ "# def ConvNet():\n", "# Conv()\n", "# Pooling()\n", "# Conv()\n", "# Pooling()\n", "# ...\n", "# Flatten()\n", "# Dense()\n", "# Dense()\n", "# ...\n", "# Classification layer - Dense()" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "CC9vwoYdN0wo" }, "source": [ "*tf.keras.layers.Conv2D(filters, kernel_size, strides, padding, activation=tf.nn.relu, use_bias)*\n", "- filters: Number of convolutional filters. Can be 16, 32, 48 .\n", "- kernel_size: The size of the filter. Usually 3, or 5.\n", "- strides: Number of pixels that the filter should skip. Usually 1 or 2 (if 2, the output will have a smaller size).\n", "- padding: One of 'same' or 'valid'. Valid padding means no padding.\n", "\n", "\n", "*tf.keras.layers.MaxPool2D(pool_size, strides=2, padding='same')*\n", "- Used to reduce the features spatial dimensions.\n", "\n", "- pool_size: Size of the pooling window. Usually, 2\n", "- strides: Go with 2.\n", "- padding: Go with 'same'. We want to reduce the feature vectors dimensions!\n", "\n", "*tf.keras.layers.Dense(units=128, activation=tf.nn.relu)*\n", "\n", "- units: Number of neuron units: 96, 128, 256, 512 ...\n", "\n", "Build a last Dense layer and set the *units* to have the **number of classes** of the dataset and **no Activation Function**." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "aJwsbTjl65M8", "colab": {} }, "source": [ "class MNISTModel(tf.keras.Model):\n", " \n", " def __init__(self):\n", " super(MNISTModel, self).__init__() # Call the super class constructor\n", " \n", " # Now define the layers of your model\n", " # The convolutions, ReLUs and classifications layers goes here\n", " # CODE GOES HERE\n", " self.conv1 = tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=(1, 1),\n", " padding='same', activation=tf.nn.relu, use_bias=True)\n", " self.pool1 = tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding=\"same\")\n", " self.flatten = tf.layers.Flatten()\n", " self.fc1 = tf.keras.layers.Dense(units=128, activation=tf.nn.relu)\n", " self.logits = tf.keras.layers.Dense(units=10)\n", "\n", " def call(self, inputs):\n", " # Use the layers defined in the constructor\n", " # Here, we define the model hierarchical computations\n", " # Start by passing the inputs to the first Conv layer and chain the results to the next layers\n", " # CODE GOES GERE\n", " conv1 = self.conv1(inputs)\n", " pool1 = self.pool1(conv1)\n", " flat = self.flatten(pool1)\n", " fc1 = self.fc1(flat)\n", " logits = self.logits(fc1)\n", " return logits" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zuCA-haQNTsu" }, "source": [ "# Loss\n", "\n", "The loss function (or objective) is responsible for measuring how **good/bad** our classifier is doing. \n", "\n", "There are many loss functions.\n", "\n", "For **multiclass problems**, we usually use the **cross-entropy** function.\n", "\n", "The cross-entropy loss (log-loss) is used to measure the performance of a classifier that outputs probabilities.\n", "\n", "![alt text](https://github.com/sthalles/tensorflow-tutorials/blob/master/images/cross_entropy.png?raw=true)\n", "\n", "- The cross-entropy **increases** when the predicted value deviates from the true values and **decreases** otherwise.\n", "\n", "One-hot encoding is a form of representing categorical data so that each category (class) contains the same power (magnitude) over one another.\n", "\n", "![One-hot encodding representation](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRRo9fhLj8UpmziNvD_eifQ3SkjybaaGmlfLd5Z2fsDn3XaASUoWw)\n", "\n", "### Exercise:\n", "\n", "Finish the **loss()** function bellow.\n", "\n", "1. Remember, our labels are vectors. *Example: [0, 3, 2, 5, 6, ..., 5]*. \n", "\n", "2. Each number represents the image corresponding class. However, in order to make the labels equally valued, we need to convert them to binary representations (**one-hot-encoding**).\n", "\n", "3. Use the [tf.one_hot()](https://www.tensorflow.org/api_docs/python/tf/one_hot) function to convert the labels to the proper format.\n", "\n", "4. For the cross-entropy loss you can choose to **write it your self** or use the built-in [tf.nn.softmax_cross_entropy_with_logits_v2()](https://www.tensorflow.org/api_docs/python/tf/nn/softmax_cross_entropy_with_logits_v2). \n", "\n", " - If you take the challenge of writing it, [tf.multiply()](https://www.tensorflow.org/api_docs/python/tf/multiply) and [tf.log()](https://www.tensorflow.org/api_docs/python/tf/log) will help. " ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "Mae8x2hL65NB", "colab": {} }, "source": [ "def loss(logits, labels):\n", " # YOUR CODE GOES HERE\n", " labels_one_hot = tf.one_hot(labels, 10)\n", " \n", " # cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=labels_one_hot, logits=logits)\n", " # print(cross_entropy.shape)\n", "\n", " cross_entropy = tf.multiply(labels_one_hot, tf.log(tf.nn.softmax(logits))) # element wise multiplication\n", " return - tf.reduce_mean(cross_entropy)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "N76qN4L_nkjz" }, "source": [ "## Exercise - Hyperparameters\n", "\n", "\n", "Tune the hyperparameters bellow.\n", "- Remember: The learning rate controls how fast your model learns. \n", "- A bigger learning rate might get you to a sub-optimal objective faster, but you might **overshoot the target.**" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "20uC6p7inXvK", "colab": {} }, "source": [ "## CODE GOES HERE\n", "epochs = 1\n", "batch_size = 32\n", "learning_rate = 0.001" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "dBp6U-eDJLhg" }, "source": [ "# Optimizers\n", "\n", "The Optimizer is the algorithm responsible for applying the gradients to the Model's weight variables. \n", "\n", "Imagine a curved surface (just an example), the goal is to find the minimal value of that surface. \n", "\n", "The Gradient points to the direction of **steepest ascent**. Thus, we follow the opposite direction of the gradient (**steepest descent**).\n", "\n", "These are some of the Optimizers available in Tensorflow\n", "\n", "- **AdadeltaOptimizer**: Optimizer that implements the Adadelta algorithm.\n", "\n", "- **AdagradOptimizer**: Optimizer that implements the Adagrad algorithm.\n", "\n", "- **AdamOptimizer**: Optimizer that implements the Adam algorithm.\n", "\n", "- **GradientDescentOptimizer**: Optimizer that implements the gradient descent algorithm.\n", "\n", "- **MomentumOptimizer**: Optimizer that implements the Momentum algorithm.\n", "\n", "[Tensorflow Build-in Optimizers](https://www.tensorflow.org/versions/r1.2/api_docs/python/tf/train)\n", "\n", "## Exercise:\n", "\n", "1. Pick one of these optimizers and use it to minimize the loss function for your model.\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "986czgX1GqWC" }, "source": [ "![alt text](https://cs231n.github.io/assets/nn3/opt1.gif)" ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "25d9ASXb65NE", "colab": {} }, "source": [ "# Choose one of the optimizers and set an initial learning rate\n", "# CODE GOES HERE\n", "optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "dgYl_Px-65NH", "colab": {} }, "source": [ "# Create the model\n", "model = MNISTModel()" ], "execution_count": 0, "outputs": [] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "0rCf3g0u8u00", "colab": {} }, "source": [ "dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train))\n", "dataset = dataset.map(normalizer)\n", "dataset = dataset.shuffle(1000) # shuffle before each epoch and bufferize some data\n", "dataset = dataset.repeat(epochs) # number of epochs\n", "dataset = dataset.batch(batch_size) # batch size\n", "\n", "val_dataset = tf.data.Dataset.from_tensor_slices((X_val, y_val))\n", "val_dataset = val_dataset.map(normalizer)\n", "val_dataset = val_dataset.repeat(1) # number of epochs\n", "val_dataset = val_dataset.batch(128) # batch size" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "U78KTudAy6En" }, "source": [ "## Exercise\n", "\n", "Finish the training loop. The main part is the **Gradient Tape**. It accumulates gradients for a batch.\n", "\n", "Inside the **GradientTape()** scope:\n", "1. Compute the logits, run a forward pass through the model.\n", "2. Use the logits to compute the loss value i.e. call the **loss()** function.\n", "3. Outside of the **GradientTape()** scope compute the **gradient of the loss with respect to the weights**." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "yKkQFfHl65NK", "outputId": "70d0063c-4541-495b-d198-94ffe11e8a81", "colab": { "base_uri": "https://localhost:8080/", "height": 635 } }, "source": [ "train_epoch_loss_avg = tfe.metrics.Mean()\n", "train_epoch_accuracy = tfe.metrics.Accuracy()\n", "\n", "for (step, (images, labels)) in enumerate(tfe.Iterator(dataset)):\n", " with tfe.GradientTape() as tape:\n", " # Call the model() here and pass it the input batches\n", " logits = model(tf.expand_dims(images, axis=3))\n", " \n", " # Call the loss() function - That will give you the loss signal for the given batch\n", " loss_value = loss(logits, labels)\n", " \n", " # Compute the gradient of the loss with respect to the models' weights\n", " grads = tape.gradient(loss_value, model.variables)\n", " \n", " optimizer.apply_gradients(zip(grads, model.variables),\n", " global_step=tf.train.get_or_create_global_step())\n", " \n", " train_epoch_loss_avg(loss_value)\n", " train_epoch_accuracy(tf.cast(tf.argmax(logits, axis=1), tf.uint8), labels)\n", " \n", " if step % 100 == 0:\n", " val_predictions = []\n", " for (val_step, (val_images, val_labels)) in enumerate(tfe.Iterator(val_dataset)):\n", " val_logits = model(tf.expand_dims(val_images, axis=3))\n", " val_pred = tf.argmax(val_logits, axis=1)\n", " val_predictions.extend(val_pred)\n", " \n", " print(\"Training loss: {: .3}\\tTrain Accuracy: {: .3}\\tValidation Accuracy: {: .3}\".format(train_epoch_loss_avg.result(), train_epoch_accuracy.result(), accuracy_score(val_predictions, y_val)))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Training loss: 0.178\tTrain Accuracy: 0.5\tValidation Accuracy: 0.525\n", "Training loss: 0.066\tTrain Accuracy: 0.807\tValidation Accuracy: 0.888\n", "Training loss: 0.0513\tTrain Accuracy: 0.848\tValidation Accuracy: 0.908\n", "Training loss: 0.0443\tTrain Accuracy: 0.869\tValidation Accuracy: 0.915\n", "Training loss: 0.0388\tTrain Accuracy: 0.887\tValidation Accuracy: 0.938\n", "Training loss: 0.0354\tTrain Accuracy: 0.896\tValidation Accuracy: 0.947\n", "Training loss: 0.0325\tTrain Accuracy: 0.904\tValidation Accuracy: 0.954\n", "Training loss: 0.0302\tTrain Accuracy: 0.911\tValidation Accuracy: 0.96\n", "Training loss: 0.0283\tTrain Accuracy: 0.917\tValidation Accuracy: 0.961\n", "Training loss: 0.0266\tTrain Accuracy: 0.921\tValidation Accuracy: 0.963\n", "Training loss: 0.025\tTrain Accuracy: 0.926\tValidation Accuracy: 0.969\n", "Training loss: 0.0237\tTrain Accuracy: 0.93\tValidation Accuracy: 0.969\n", "Training loss: 0.0228\tTrain Accuracy: 0.932\tValidation Accuracy: 0.972\n", "Training loss: 0.0221\tTrain Accuracy: 0.935\tValidation Accuracy: 0.962\n", "Training loss: 0.0213\tTrain Accuracy: 0.937\tValidation Accuracy: 0.975\n", "Training loss: 0.0207\tTrain Accuracy: 0.939\tValidation Accuracy: 0.973\n", "Training loss: 0.0199\tTrain Accuracy: 0.941\tValidation Accuracy: 0.975\n", "Training loss: 0.0193\tTrain Accuracy: 0.943\tValidation Accuracy: 0.971\n", "Training loss: 0.0188\tTrain Accuracy: 0.945\tValidation Accuracy: 0.969\n", "Training loss: 0.0182\tTrain Accuracy: 0.946\tValidation Accuracy: 0.974\n", "Training loss: 0.0178\tTrain Accuracy: 0.947\tValidation Accuracy: 0.974\n", "Training loss: 0.0174\tTrain Accuracy: 0.948\tValidation Accuracy: 0.976\n", "Training loss: 0.0171\tTrain Accuracy: 0.949\tValidation Accuracy: 0.98\n", "Training loss: 0.0168\tTrain Accuracy: 0.95\tValidation Accuracy: 0.979\n", "Training loss: 0.0165\tTrain Accuracy: 0.951\tValidation Accuracy: 0.975\n", "Training loss: 0.0161\tTrain Accuracy: 0.952\tValidation Accuracy: 0.976\n", "Training loss: 0.0158\tTrain Accuracy: 0.953\tValidation Accuracy: 0.979\n", "Training loss: 0.0154\tTrain Accuracy: 0.954\tValidation Accuracy: 0.982\n", "Training loss: 0.0152\tTrain Accuracy: 0.955\tValidation Accuracy: 0.982\n", "Training loss: 0.015\tTrain Accuracy: 0.955\tValidation Accuracy: 0.98\n", "Training loss: 0.0147\tTrain Accuracy: 0.956\tValidation Accuracy: 0.979\n", "Training loss: 0.0144\tTrain Accuracy: 0.957\tValidation Accuracy: 0.982\n", "Training loss: 0.0142\tTrain Accuracy: 0.958\tValidation Accuracy: 0.98\n", "Training loss: 0.0139\tTrain Accuracy: 0.958\tValidation Accuracy: 0.982\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "mi95YnV965NO", "colab": {} }, "source": [ "from sklearn.metrics import confusion_matrix\n", "import itertools\n", "\n", "def plot_confusion_matrix(cm, classes,\n", " normalize=False,\n", " title='Confusion matrix',\n", " cmap=plt.cm.Blues):\n", " \"\"\"\n", " This function prints and plots the confusion matrix.\n", " Normalization can be applied by setting `normalize=True`.\n", " \"\"\"\n", " if normalize:\n", " cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n", " print(\"Normalized confusion matrix\")\n", " else:\n", " print('Confusion matrix, without normalization')\n", "\n", " # print(cm)\n", "\n", " plt.imshow(cm, interpolation='nearest', cmap=cmap)\n", " plt.title(title)\n", " plt.colorbar()\n", " tick_marks = np.arange(len(classes))\n", " plt.xticks(tick_marks, classes, rotation=45)\n", " plt.yticks(tick_marks, classes)\n", "\n", " fmt = '.2f' if normalize else 'd'\n", " thresh = cm.max() / 2.\n", " for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n", " plt.text(j, i, format(cm[i, j], fmt),\n", " horizontalalignment=\"center\",\n", " color=\"white\" if cm[i, j] > thresh else \"black\")\n", "\n", " plt.tight_layout()\n", " plt.ylabel('True label')\n", " plt.xlabel('Predicted label')\n", " plt.show()\n", " \n", "def normalized_acc(conf_matrix):\n", " for i in range(conf_matrix.shape[0]):\n", " print(\"Acc class {0} --> {1: .3}\".format(i, conf_matrix[i,i]/sum(conf_matrix[i])))" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zxZiK6_00pt6" }, "source": [ "## Evaluation\n", "\n", "Run the trained model using the testing dataset." ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "pBS4S7kJ65NQ", "outputId": "e707dd2c-0a0c-46ac-d5fb-9fd794ad4916", "colab": { "base_uri": "https://localhost:8080/", "height": 35 } }, "source": [ "test_dataset = tf.data.Dataset.from_tensor_slices((X_test, y_test))\n", "test_dataset = test_dataset.map(normalizer)\n", "test_dataset = test_dataset.repeat(1) # number of epochs\n", "test_dataset = test_dataset.batch(128) # batch size\n", "\n", "test_predictions = []\n", "for (_, (test_images, test_labels)) in enumerate(tfe.Iterator(test_dataset)):\n", " test_logits = model(tf.expand_dims(test_images, axis=3))\n", " test_pred = tf.argmax(test_logits, axis=1)\n", " test_predictions.extend(test_pred)\n", "\n", "print(\"Test Overall Accuracy: {: .3}\".format(accuracy_score(test_predictions, y_test)))" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Test Overall Accuracy: 0.981\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "Y-tCNPPC65NR", "outputId": "d17ea147-506a-41f4-9f17-2f1cdf068c3d", "colab": { "base_uri": "https://localhost:8080/", "height": 434 } }, "source": [ "conf_matrix = confusion_matrix(test_predictions, y_test)\n", "_ = plot_confusion_matrix(conf_matrix, classes=[str(i) for i in range(10)])" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Confusion matrix, without normalization\n" ], "name": "stdout" }, { "output_type": "display_data", "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAcMAAAGOCAYAAADrQGhsAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3Xl4TOf7x/H3ZJPIgoQEQYg11tiq\niCYhxFq+FKGWWqsN0ZaW2qqb0lbVWm0pte9LxBZbFE3VvsSulixEQgSZhETy+8PPtLHFJDNnjsn9\nuq65LnNm5jyfnHPGPc9zNk1WVlYWQgghRD5mYeoAQgghhKlJMRRCCJHvSTEUQgiR70kxFEIIke9J\nMRRCCJHvSTEUQgiR70kxFCaRlZXFvHnzaNu2LYGBgQQEBDB+/Hju3r2bp/kOHz4cX19f9uzZo/dn\njx8/Tr9+/fLUvqFt2rSJe/fuPfO1yZMns3TpUoUTCWGeNHKeoTCF7777jr///psZM2bg5uaGVqvl\n66+/5tKlSyxevBiNRpOr+Xp5ebF161bKlClj4MSm0bJlS+bPn0/x4sVNHUUIsyY9Q6G427dvs3Dh\nQiZOnIibmxsABQsWZNy4cfTv35+srCzu37/PuHHjCAwMpFWrVkycOJGHDx8C0LRpU5YtW8Zbb72F\nj48PEydOBKBnz55kZmbSr18/du/eTdOmTTl48KCu3cfPMzIyGD16NIGBgTRv3pzBgwdz79499u/f\nT/PmzQFy1f6TevbsyS+//ELXrl15/fXXWbx4MbNmzaJly5a0bt2a6OhoAP755x+6detGq1ataN68\nOWFhYQB8+umnXLp0iZ49e3Lw4EFGjhzJN998Q7t27di8eTMjR45k1qxZHD9+HD8/P1JSUgCYPXs2\nISEhhl5tQpg1KYZCcceOHaN48eKUL18+2/QCBQrQtGlTLCws+P3337l+/TobN25k7dq1HDx4UFck\nAA4cOMDy5ctZvXo1ixYt4vr16yxcuBCAhQsX4uvr+9z29+7dS0xMDFu2bCE8PJwKFSpw5MiRbO/J\nTfvPcuDAARYvXsw333zDd999R/HixdmyZQsVKlRg9erVAHz77bf4+/uzefNmJkyYwOjRo0lPT+eb\nb77R/T316tUDIDIyklWrVtGqVStdGzVr1iQgIICff/6Z+Ph4lixZwpgxY3JcD0KIf0kxFIq7ffs2\nLi4uL3xPREQEXbp0wcrKCltbW9q1a8e+fft0r7dr1w5LS0vc3NxwcXHh2rVrL92+s7MzFy9eZNu2\nbaSmpvLBBx/QpEkTo7Tv7++PlZUVlSpVIjU1lcDAQAAqVarEjRs3AJg1a5ZuX2XdunW5f/8+CQkJ\nz5xfw4YNKVCgwFPTP/zwQ7Zs2cKnn37K+++/j6ur60svDyGEFENhAkWKFCE+Pv6F77l16xaFChXS\nPS9UqBA3b97UPXdwcND929LSUjeE+TJq1qzJmDFjWLhwIY0bN2bYsGHcuXPHKO3b29vr3vPf5xYW\nFmRmZgKwZ88e3n77bQIDA2ndujVZWVm6157030xPttOqVSsOHTpEu3btXvj3CyGeJsVQKM7b25ub\nN28SFRWVbXp6ejpTpkwhNTWVokWLcvv2bd1rt2/fpmjRonq189+CA5CcnKz7d8uWLVm4cCG7du0i\nNTWVuXPnZvusIdp/Genp6XzwwQe89957bN26ldDQ0FwdPBQfH8+GDRto06YNM2bMMHhOIcydFEOh\nOCcnJ/r378+IESO4cuUKAKmpqYwbN45Tp05hZ2eHn58fq1at4uHDh2i1WtavX//C/YDPUqxYMc6c\nOQM8OkXh/v37AKxevZqZM2cCULhwYTw9PZ/6rCHafxmpqalotVqqV68OPNpXaW1tjVarBcDKyuqp\nXuuzfP311/Tv359Ro0axefNmTp8+bfCsQpgzKYbCJIYMGUKXLl147733CAwMpGPHjri4uOh6NT17\n9qR48eK0adOGTp064efnl+2gkZfx/vvvM3/+fNq2bcvFixepUKECAM2aNSMqKooWLVrQqlUrLly4\nQJ8+fbJ91hDtv4zHPww6dOhAhw4dKFOmDAEBAQwaNAitVkvLli0JCgpi06ZNz51HREQEMTExBAUF\n4eDgwIcffsiYMWP0GjoWIr+T8wyFEELke9IzFEIIke9JMRRCCJHvSTEUQgiR70kxFEIIke9JMRRC\nCJHvWZk6wGN2nebm/CYFJC1X1y18hHjSw0zTHwBuaZG7u4oYmhwMn52dtTLrxa724DzPI/WIui4O\nIT1DIYQQ+Z5qeoZCCCFeERrz60dJMRRCCKGfXN58W82kGAohhNCP9AyFEELke2bYMzS/8i6EEELo\nSXqGQggh9GOGw6SvzF/U3bcCh37syLnZXZkb4ouNlQXzhvpydFon3eOfOd1Y+nFTShe1zzb96LRO\n3FzSm9b1Shs1Y9iGUBrU9ca7hhdNfX2IOnnSqO29yOZNG7Gz1nDl8mWTtK+WZbF2zWoa1PWmVvUq\nJsthygzp6el8+skwHApYEBsTA8CiBfMpWawwtWt46R6zZyl3zpept40rly/jVNAG7+peukf/Pr0V\nzfBYXFwcbVu1oErFcrxWpxZ79/xhkhx602jy/lCZV6JnWLV0ESa904CGw9cRczOF+R/48VGHmvSZ\nujvb+9aObsHCXeeJTkzBO2S1bnqZYg6EjWvJzuNxRssYGxvLgL692bl7H15Vq/LzT7MY/P677Ppj\nn9HafB6tVsvYUSNxdnZWvG1Qz7K4evUqIcGD2PvXQTw8PJgxbSrvDujL3si/802Grp06UKdevaem\nt2v/P36eM0+RDP+llm2jpLs7R0+a/gbIA/u9Q4vAloRtDmd3xC5mz5qJT5M3TB0rZ9IzNA2/GiXY\nfTKOmJspAMwIO0mH18tme0+L2qUoYGXJpoPRT33+6571+WbVUdIeGO9mp9bW1vy+aCleVasC0Kix\nD6dPRRmtvRf56ovxdOvREwdHR5O0r5ZlYW1tzfyFS/Dw8ADAv2kzzp87m68yjBg1hjHjPlesvZyo\nZdtQg5joaI4cPsR7wUMA8PXzZ9HS5SZOlX+9EsUwKyv75Z/upWVQvrhTtveM7VqHCSuPPPXZqqWL\n4O3pwrI/Lhg1o6urKy0CW+qeb926mfqvNTBqm89y8sQJdm7fRsjQDxVv+zG1LIsSJUrQLKA5ABkZ\nGSxcMJ+27drnqwwNXm/4zOnHjx2lZXN/vKtV5v13+5GcnKxIHrVsG3fv3KFLp//hXd2LN9u24sxp\n5XuJx48fw6NsOcaOHkmtalVo0cyPo0ee/j9MlcxwmPSVKIa7TsTRtKY7VUsXwdJCw7stvbC1sdS9\n/kb1Emg0sPfU9ac++2H7GswIi0LJSxju2rmDGVOn8O33U5RrlEfXaRwSPIjJP07H2tpa0bafx1TL\n4r9mTJuKh7sb+/bu4atvJuXbDI9VqFiJNu3eZOWaUP48cIQ7d+4y8mPlfzyZattwcHSkS1A3vps8\nhcPHo2jWLIAunTqQkZGhaI7k27eJOnmCxj5vcCzqDEHd36Zb106K58gVjUXeHypj1EQTJkyga9eu\nBAUFcfz48VzP50zMbT6aG8mCj/z5Y+KbnIm5ze2UB7rXu/qUZ8Xef576nI2VBe1e82D1n5dy3ba+\nQtevY0C/d1i9Lkw3FKSUub/+gpdXVRr7+Cja7vOYcln81+CQocRcT2RwyAf4v9GI1NTUfJnhsdcb\nNmLMuM9xdHSkYMGCDP9kJJs3bVQ0gym3DRcXF6ZMnYFH2bJYWFgQ8sFH3LgRz/lz5xTN4VSoEK5u\nbrR789FIQZ++/Um6dUvxHLkiPcOX9/fff3PlyhWWL1/O119/zddff52n+S2OuEC9D9fQ+JP1nLya\nRNTVW7rXWtUtxZbDT+8rfKN6Cc7G3ibxTlqe2n5ZO3dsZ/hHQwnbFE7dZxy0YGxhG9YTtmE9ZUsV\np2yp4sRER+PTsD67I3YpnsXUywLgzOnT7NyxHQCNRkPXoG7cvXOHc2eV22enhgxPiomOJiEhQfc8\nIyND0ZEEU28bSUlJXL6U/Qfyw4cPFR9NKVPGg3t375KZmQk82j4sLCywtLTM4ZPCGIxWDCMjIwkI\nCACgfPnyJCcnc+/evVzNy7O4I39934FCBW2wstTwScdaLNx1HoBiTrYUK2TH+bin93nU9HDmTMzt\n3P8RetBqtQzs34dlK9ZQxctLkTaftG7DJq7G3eByzHUux1ynVOnS7I08gK+fv6I51LAsABITE+jX\npxdxcY+OIv5z3z7S09Mp5+mZrzI8ac4vPzHkvYGkp6fz8OFDZs+aQWDL1oq0rYZt49DBA7QKbKb7\nQfDb3F8pXbqM4uukeo0alChRknm/zQFgzaqVFC5SBM/y5RXNkStmOExqtFMrEhMTqVatmu65s7Mz\nCQkJODg46D2vf67fJezAFf7+4X9kZWWxYu8/LI54dECMu4s9CXfSnrlP0N3FnvjbygxHbQhdT2JC\nAn16v51teviO3bi5uSmSQS3Usix8mrzBiJGjadMygMzMTArYFGDB4mU4OTnl/GEzyBAfH0/LAD/d\n81bN/bG0smLjlu18/tkY6tWqhoWFBQ0aNuLrid8ZPQ+oY9sIaN6Cge++RzNfHywsLCjp7s6S5asU\n75FpNBoWL1vJwP59mPzdJIoVc2XR0hVYWb0CZ7ypcJgzrzRZRro75tixY/H19dX1Drt168aECRMo\nV67cM98vN/cV4uXIzX3/JTf3zU6xm/u+MT7P80j9I+/zMCSj9VVdXV1JTEzUPb9x4wbFihUzVnNC\nCCFErhmtGDZu3JitW7cCEBUVhaura66GSIUQQqiM7DN8eXXq1KFatWoEBQWh0Wj47LPPjNWUEEII\nJalkmNyQjLqndvjw4cacvRBCCFNQYc8ur8zvLxJCCCH09AocwyuEEEJVzPDUCimGQggh9GOGw6RS\nDIUQQujHDHuG5lfehRBCCD1Jz1AIIYR+ZJhUCCFEvmeGw6RSDIUQQuhHeoZCCCHyPTPsGZpfeRdC\nCCH0JD1DIYQQ+pFhUuNRy30Ei9QfbOoIJB2YYeoIQsXUci9BNdCoZLgu391XUSXL3ZDMr7wLIYQw\nLoVu4XTu3DkCAgJYtGgRANeuXaNnz550796doUOH8uDBAwBCQ0Pp1KkTnTt3ZuXKlQCkp6czbNgw\nunXrRo8ePYiOjn5hW1IMhRBCqI5Wq+XLL7+kYcOGumnTpk2je/fuLFmyBA8PD1atWoVWq2XmzJnM\nnz+fhQsX8vvvv3P79m3CwsJwcnJi6dKlDBo0iMmTJ7+wPSmGQggh9KNAz9DGxoZff/0VV1dX3bT9\n+/fTrFkzAPz9/YmMjOTYsWPUqFEDR0dHbG1tqVOnDocPHyYyMpLmzZsD0KhRIw4fPvzC9lSzz1AI\nIcQrQoF9hlZWVlhZZS9Rqamp2NjYAODi4kJCQgKJiYk4Ozvr3uPs7PzUdAsLCzQaDQ8ePNB9/qn2\njPR3CCGEMFcqOJr0eQct6Tv9MdP/RUIIIcRLKFiwIGlpaQDEx8fj6uqKq6sriYmJuvfcuHFDNz0h\nIQF4dDBNVlbWc3uFIMVQCCGEvjSavD9yoVGjRmzduhWA8PBwmjRpQq1atThx4gR37twhJSWFw4cP\nU69ePRo3bsyWLVsA2LVrFw0aNHjhvGWYVAghhH4UGCY9efIkkyZNIjY2FisrK7Zu3cr333/PyJEj\nWb58OSVLlqRDhw5YW1szbNgw+vXrh0ajITg4GEdHR1q3bs2ff/5Jt27dsLGxYeLEiS/+k7JUcrZo\nWkbuPxuxayeffjKceyn3KFPGg5/nzKNUqVK5mtezTrq3srLgq5D2DO3ZjAqBY4i9cRuAYkUcmDfh\nHcqWdKF6+89173e0t2Xqp12oU7UMFhYWrNx6iC9/2gjAmY2f8/BhJukZD3Xv9+74Vbb28nLSfdiG\nUL4cP477D+7j7OzC9JmzqVa9eq7nl1uGXCeveg41ZADZNoyZIbf/jcbFxTGw3ztcuHAeJ0cnfpg6\nHZ8mb+Q6h521MifD23Wcm+d5pK5Rx4VWHnvlh0lTUlLo9XYQs36ew4lT52jdph0hwYMM2sbKKe9y\nT3s/27QiTgUJn/MBURfinnr/F4Pb8SD9IbU7fU2j7pMIalWPpg2q6F5v9e50vDt+pXsYSmxsLAP6\n9mb+wiUcPXGarkHdGfz+uwab/8tSYp28KjnUkAFk21BbhscG9nuHFoEtOXP+Et/98COzZ800SQ5h\nBsUwYtdOypbzpHadOgD07tOX7dvCuXv3rsHamPjrFr6avSnbtKysLLp89AthESeeev+6ncf4avZG\nsrKyuKe9z4lzsVQtX9xgeZ7H2tqa3xctxatqVQAaNfbh9Kkoo7f7JCXWyauSQw0ZQLYNtWUAiImO\n5sjhQ7wXPAQAXz9/Fi1drmiG3NJoNHl+qM0rXwzPnz+Hp2d53XMHBwdcXFy4eOGCwdrYf/zSU9Nu\n303l/JUbz3z/7gPniIl/NJTqaG9Lg1qeHDh5Rff6Nx924MCKUexd9DFtfGsYLKerqystAlvqnm/d\nupn6r714p7ExKLFOXpUcasgAsm2oLQPA8ePH8ChbjrGjR1KrWhVaNPPj6JEjimbILSmGKpSq1WJr\na5ttmq2dHSkpKSZK9C9rK0vmT3iHjbtP6Arqyq2HmL18D/W7TGDE5DX89lUvPEsXNXjbu3buYMbU\nKXz7/RSDzzsnalknasihhgxPyu/bhhoyACTfvk3UyRM09nmDY1FnCOr+Nt26diIjIw8HUChFY4CH\nyhi1GD55kVVjKFjQXnfeyWOpWi0ODg5Ga/Nl2NvZsGbaIBJu3WXI18t008dOC2XPofMA7DtykT8O\nXSDgdS+Dth26fh0D+r3D6nVhumExJallnaghhxoy/JdsG+rIAOBUqBCubm60e7M9AH369ifp1i3O\nnzunaA7xiNGK4bMusmoMlatU4eLFf4c3kpOTSUpKokLFikZt90UsLS1Y/sNATl+8xqDPF+uONLOx\ntsLLM/u+QytLi2xHlubVzh3bGf7RUMI2hVO3Xj2DzVcfalknasihhgyPybahngwAZcp4cO/uXTIz\nM4FHQ48WFhZYWloqmiM3ZJhUD8+6yKox+Pr5E331Cvv27gVg+tQptGrTFnt7e6O2+yLB3fy4l5LG\nJ5PXZJte0NaaiN+H0aBmOQCqVShJw1qe7Nx/1iDtarVaBvbvw7IVa6jiZdjepj7Usk7UkEMNGUC2\nDbVlAKheowYlSpRk3m9zAFizaiWFixTBs3z5HD5peuZYDI120v2zLrJqDHZ2dixYvIwPQ4JJ0aZQ\nvnwFfpk732Dzd3V2JHzOUN3zrb8OJePhQ76bt42P+zSnoK0NbkWdOLpmDHE3kmk9aDr9OjXG3s6G\no2vG6D63ZvsRvpi1kR4jfmPa6K7Y2lijTXtA3zG/cyXupkGybghdT2JCAn16v51teviO3bi5uRmk\njZdh7HXyKuVQQwaQbUNtGeBRQVm8bCUD+/dh8neTKFbMlUVLVyjy/2ZeqbGY5ZXRT7qfPn06RYoU\noUePHi98X15OujckudO9EEJfKrl2iWIn3TsFLcjzPO4s62WAJIaj/p8gQgghVMUce4ZSDIUQQujH\n/Gqh8Yrhsy6yOn36dAoXLmysJoUQQihAeoZ6qF69OgsXLjTW7IUQQgiDkWFSIYQQepGeoRBCiHxP\niqEQQoh8T4qhEEIIYX618NW/a4UQQgiRV9IzFEIIoRcZJhVCCJHvSTEUQgiR75ljMZR9hkIIIfI9\n6RkKIYTQj/l1DKUYCiGE0I85DpNKMXyCGu4lWOTNaaaOAEBSaIipIwiVysxUx/37LCzU8Z+yORaH\nFzHHv1f2GQohhMj3pGcohBBCL+bYM5RiKIQQQi9SDIUQQgjzq4Wyz1AIIYSQnqEQQgi9yDCpEEKI\nfM8ci6FZDJNG7NpJw/p1qFG1Em1aNicmJsYkOcI2hNKgrjfeNbxo6utD1MmTBpu3laUFE/v7kLop\nBHcXB930we29OTK7B8d+6cmsoc2wtvp3ldauUIyoub2ZNbTZU/Pr1rQKCasHEeRf2WAZ/ys9PZ0R\nHw/DzlpjsvUBxl0nL0st26cpc6SnpzPyk2HYF7Ag9j/tTpzwJbVreFGrWmV6vR1EcnKyInnWrllN\ng7re1KpexWTbBahn29CXRqPJ80NtXvlimJKSQq+3g5j18xxOnDpH6zbtCAkepHiO2NhYBvTtzfyF\nSzh64jRdg7oz+P13DTb/lePaci81Pdu01yoXJ7h9LfyGraDWwIUUti9A8Ju1APCp7s7sDwI4ePb6\nU/Ma3rkuHX0qcC7mtsHyPalzx/Y4ODjk/EYjMvY6eRlq2T5NnaNLpw5PbQ9r16xi9aqV/PHn3xw5\ncRqNRsOUyd8aPcvVq1cJCR7EijXrOXbyDB07debdAX2N3u6TTL1ORHavfDGM2LWTsuU8qV2nDgC9\n+/Rl+7Zw7t69q2gOa2trfl+0FK+qVQFo1NiH06eiDDb/iUv/5qvF+7NN69ikAqv+OE9yygMAfg+P\nomOTigAkJqcS8PFqzsU+XfB2H4+h8xdh3Et9YLB8Txo5aixjP/vcaPN/GcZeJy9DLdunqXOMHDWG\nMeOybw+Vq3jxy5x5ODo6YmFhQYPXG3L61CmjZ7G2tmb+wiV4eHgA4N+0GefPnTV6u08y9TrJE40B\nHirzyhfD8+fP4elZXvfcwcEBFxcXLl64oGgOV1dXWgS21D3funUz9V9rYLD57z/zdA+vgnsR/rn2\n77DSP9eSqVSqCABnom9x9znF7sDZeIPlep7XGzY0ehs5MfY6eRlq2T5NnaPB609vD1WrVqN2nbq6\n5+Fbt1DvtdeMnqVEiRI0C2gOQEZGBgsXzKdtu/ZGb/dJpl4neWGOw6Sv/AE0qVottra22abZ2tmR\nkpJiokSwa+cOZkydwubwnUZtp2ABK9LSH+qepz3IwN7W2qhtvqqUWidPUsv2qZYcz/PtxK+5cSOe\n94OVux7ujGlT+ebrL/AsX4EVq9cp1u5jal8nL6LGYpZXRu0Zfvvtt3Tt2pVOnToRHh5ulDYKFrQn\nLS0t27RUrdZk+6tC169jQL93WL0uTDc8ZywpaenYWlvqntsVsH5qv6JQdp08SS3bp1pyPMu4MZ+y\nft1aQjduxd7eXrF2B4cMJeZ6IoNDPsD/jUakpqYq1jaoe53kR0Yrhn/99Rfnz59n+fLlzJkzhwkT\nJhilncpVqnDx4r/DCsnJySQlJVGhYkWjtPciO3dsZ/hHQwnbFE7devWM3t65mCTKlyyke16hZGHO\nXL1l9HZfJUqvkyepZftUS44nff3leP6K/JMt23ZRtGhRRdo8c/o0O3dsBx71cLoGdePunTucO6vs\nfkO1rpOXYY7DpEYrhvXr12fq1KkAODk5kZqaysOHD3P4lP58/fyJvnqFfXv3AjB96hRatWmr6C9M\nAK1Wy8D+fVi2Yg1VvLwUaXP1nvN08a2Ma2E7LC00BLevxYrdyh8IoFamWCdPUsv2qZYc/3Xk8CGW\nLFrIyjWhODo6KtZuYmIC/fr0Ii4uDoA/9+0jPT2dcp6eimUAda6Tl2WOxdBo+wwtLS0pWLAgAKtW\nreKNN97A0tIyh0/pz87OjgWLl/FhSDAp2hTKl6/AL3PnG7ydnGwIXU9iQgJ9er+dbXr4jt24ubnl\nad6uhe0In9RJ93zrpI5kPMyk9ai1/LjmMNu/ewsNGnYcucovG08AMK7n63T0qYCLkx1WlhY0qlqC\n0Mh/GDf/T0K/bE8ZV0dKF3OkonthRgbVfzQ98p885XwsPj6eFs18dc8DA/ywsrJi09YduLu7G6SN\nl2HMdfKy1LJ9mjJHfHw8LQP8dM9bNvfHysqKRj4+JCffxs/ndd1rpct4ELpxi1Hz+DR5gxEjR9Om\nZQCZmZkUsCnAgsXLcHJyMmq7T1LLtpEr6qtleabJysoy6l06t2/fzs8//8xvv/32wl9/aRnGTPFq\nkZv7CrWTm/uqk61Ch0R6frQpz/P454fWBkhiOEZddHv27GH27NnMmTNH0WEQIYQQQh9GK4Z3797l\n22+/Zf78+RQuXNhYzQghhFCYGvf55ZXRiuGmTZtISkrigw8+0E2bNGkSJUuWNFaTQgghFGCGtdB4\nxbBr16507drVWLMXQghhIubYM3zlL8cmhBBC5NUrfzk2IYQQyjLDjqEUQyGEEPoxx2FSKYZCCCH0\nYoa1UPYZCiGEENIzFEIIoRclrvyTkpLCiBEjSE5OJj09neDgYIoVK8b48eMBqFy5Mp9//uiG0XPm\nzGHLli1oNBoGDx6Mr6/vC+b8bFIMhRBC6EWJYdK1a9dSrlw5hg0bRnx8PL1796ZYsWKMGjWKmjVr\nMmzYMHbv3o2npyebNm1i2bJl3Lt3j+7du+Pj46P3tbBlmFQIIYRelLhrRZEiRbh9+zYAd+7coXDh\nwsTGxlKzZk0A/P39iYyMZP/+/TRp0gQbGxucnZ1xd3fnwoULL5r1M0kxFEIIoTpt2rQhLi6O5s2b\n06NHDz755JNsdxZxcXEhISGBxMREnJ2dddOdnZ1JSEjQuz0ZJhVCCKEXJYZJ169fT8mSJZk7dy5n\nzpwhODg42w0fnnfDpdzeiEmKoRBCCL0ocZ7h4cOH8fHxAaBKlSrcv3+fjIx/7/UXHx+Pq6srrq6u\nXLp06anp+pJiqEJquY9gkf/9ZOoIACStfc/UEYDc/+I0NDWc8Cz3EczflNgGPTw8OHbsGIGBgcTG\nxmJvb4+7uzsHDx6kXr16hIeH07NnT8qWLcu8efMYMmQISUlJ3LhxgwoVKujdnhRDIYQQqtO1a1dG\njRpFjx49yMjIYPz48RQrVoxx48aRmZlJrVq1aNSoEQBdunShR48eaDQaxo8fj4WF/ofDGP1O9y9L\n7nSvPtIzzE4lXxVV9AyFOil1p3vv8TvyPI+j45sZIInhSM9QCCGEXszxB5kUQyGEEHoxw1oo5xkK\nIYQQ0jMUQgihFxkmFUIIke+ZYS2UYiiEEEI/5tgzNIt9hunp6Yz4eBh21hpiYmJMlmPtmtU0qOtN\nrepVaOrrQ9TJkybLsnnTRuysNVy5fNlobXT3r8ShmV0591sP5n7UFBsrC+xtrfh5qD/HfurGqV/f\nJsivou799Su58sf3HTn6UxAtGHyuAAAgAElEQVT7prxFYN0yRsv2WMSunTSsX4caVSvRpmVzk2wf\ncXFxtG3VgioVy/FanVrs3fOH4hlAPd+TsA2hNKjrjXcNL5N+T9SSA5T5vhqSRpP3h9qYRTHs3LE9\nDg4OJs1w9epVQoIHsWLNeo6dPEPHTp15d0Bfk2TRarWMHTUy28VrDa1qGWcm9W9E+8/CqNR3EZYW\nFnzUqTafdq2Hva0V3u8vpfnIdUx4pyEebo+uJ7j000C+XnoQ7/eWMWDKTuYPD8CpoI3RMqakpNDr\n7SBm/TyHE6fO0bpNO0KCBxmtvecZ2O8dWgS25Mz5S3z3w4/MnjVT8Qygju9JbGwsA/r2Zv7CJRw9\ncZquQd0Z/P67+TYHKPN9FTkzi2I4ctRYxn72uUkzWFtbM3/hEjw8PADwb9qM8+fOmiTLV1+Mp1uP\nnjj856K2huZXy53dx2OJSUwBYMb643Ro5EnT2qVYuP0sWVkQezOF0P2XaNegHEUcCuBe1IFdxx71\nSE5dvUXq/QzKuhkvY8SunZQt50ntOnUA6N2nL9u3hXP37l2jtfmkmOhojhw+xHvBQwDw9fNn0dLl\nirX/X2r5nvy+aCleVasC0KixD6dPReXbHKDM99XQlLiFk9LMohi+3rChqSNQokQJmgU0ByAjI4OF\nC+bTtl17xXOcPHGCndu3ETL0Q6O2k5WVheV/Lnl0Ly2d8iUKkZUFlv+5bmVKajrlSziRdO8+Ry4m\n0NX30bBpo6rFycjM5Ex0ktEynj9/Dk/P8rrnDg4OuLi4cDEX9zrLrePHj+FRthxjR4+kVrUqtGjm\nx9EjRxRr/7/U8D1xdXWlRWBL3fOtWzdT/7UG+TaHUt9XQ5NhUpGjGdOm4uHuxr69e/jqm0mKtp2V\nlcWQ4EFM/nE61tbWRm1r17FYmnqXomoZZywtNLzbpjq2NpbsPBrNu22qU8DaktLFHHizYTkK2Dw6\nTit4egQT+zUidkkfNn7Zjo9+3suDjEyjZUzVarG1tc02zdbOjpSUFKO1+aTk27eJOnmCxj5vcCzq\nDEHd36Zb107Zrr6fX+3auYMZU6fw7fdT8mUOJb+vhiY9Qz2kpqYydOhQevToQefOndm1a5exmlKV\nwSFDibmeyOCQD/B/oxGpqamKtT3311/w8qpK4/+/7YkxnYlO4qOf97Lgk+b8MbkTZ67e4nbKfb5Z\ndoi4mykcmN6Fae+/QfihqySn3MfWxpLlo1vy9sRw3LvPo+EHq5gR7EuZYsbbh1WwoD1paWnZpqVq\ntYruN3MqVAhXNzfavflolKBP3/4k3brF+XPnFMugRqHr1zGg3zusXhemG6rMbzmU/L6KnBmtGO7a\ntYvq1auzaNEifvzxRyZOnGisplThzOnT7NyxHXj0q6lrUDfu3rnDubPK7TcM27CesA3rKVuqOGVL\nFScmOhqfhvXZHWGcHyKLd56l3uDlNP5wFSev3CLq8i209zN4b3oENQct5X+fb8Le1pqTl2/pepAR\nx2OBR8X04rVk6lXS/75jL6tylSpcvPjvkGhycjJJSUlUqFjxBZ8yrDJlPLh39y6ZmY96wBqNBgsL\nCywtLRXLoDY7d2xn+EdDCdsUTt169fJtDqW/r4Ykw6R6aN26NQMGDADg2rVruLm5GaspVUhMTKBf\nn17ExcUB8Oe+faSnp1PO01OxDOs2bOJq3A0ux1zncsx1SpUuzd7IA/j6+Ru8Lc8STvw1tTOF7G2w\nsrTgk851WLjjLMM6eTOx76N9U1VKF6GpdynC9l/i6o27FLIvQN2KxQAoXcwBrzLOnDbiPkNfP3+i\nr15h3969AEyfOoVWbdpib29vtDafVL1GDUqUKMm83+YAsGbVSgoXKYJn+fI5fNI8abVaBvbvw7IV\na6ji5ZWvcyj5fTU0cxwmNfpJ90FBQVy/fp3Zs2cbZf7x8fG0aOarex4Y4IeVlRWbtu7A3d3dKG0+\ni0+TNxgxcjRtWgaQmZlJAZsCLFi8DCcnJ8UyKOmfa3cI23+Zv6d1ISsrixV/XGDxzrO4FrZjwcfN\nOfXr26Q+yKDfDztJTnkAQL8fdvDTEH8KWFuSmZXF6HmRnL5qvGJoZ2fHgsXL+DAkmBRtCuXLV+CX\nufON1t6zaDQaFi9bycD+fZj83SSKFXNl0dIVWFkpe70LtXxPNoSuJzEhgT693842PXzHbkV/MKsl\nx6tKhbUszxS5n+Hp06f55JNPCA0Nfe4vArmfofrI/Qyzk/sZCrVT6n6GPt/vyfM89g5vYoAkhmO0\nYdKTJ09y7do1ALy8vHj48CG3bt0yVnNCCCEUYo7DpEYrhgcPHuS3334DIDExEa1WS5EiRYzVnBBC\nCIVIMdRDUFAQt27donv37gwcOJBx48ZhYSGnNQohxKvOHI8mNdoIs62tLZMnTzbW7IUQQgiDkVs4\nCSGE0IsahznzSoqhEEIIvZhhLZRiKIQQQj/m2DOUI1qEEELke9IzFEIIoRcz7BhKMRRCCKEfCzOs\nhlIMhRBC6MUMa6HsMxRCCCGkZyiEEEIv5ng0qRRDIYQQerEwv1ooxVAIIYR+pGco8hW13EewaPf5\npo4AQOKSd0wdQQhhJFIMhRBC6MUMO4ZSDIUQQuhHg/lVQymGQggh9CIH0AghhMj3zPEAGjnpXggh\nRL4nPUMhhBB6McOOoRRDIYQQ+pELdQshhMj3zLAWmsc+w4hdO2lYvw41qlaiTcvmxMTE5Osc6enp\njPh4GHbWmnyxLLq9UZ4Dk9tzetZb/Dq4CTZWjzbrdvXLcHRqR05M78TiYX442lnrPjO6szenZ73F\niemdGNu1ttGygXq2i8c2b9qInbWGK5cvm6R9tSyPsA2hNKjrjXcNL5r6+hB18qTiGdauWU2Dut7U\nql7FZBnEI698MUxJSaHX20HM+nkOJ06do3WbdoQED8q3OQA6d2yPg4ODSdoGZZdF1dKFmdirPh0m\nbMPr/VVYWmj4sH11PIo5MKX/63ScsI0aQ1YTk6ilZZ1SAHTx8aRprZLU+WAtDYavp075olQqWcgo\n+dS0XQBotVrGjhqJs7OzSdpXy/KIjY1lQN/ezF+4hKMnTtM1qDuD339X0QxXr14lJHgQK9as59jJ\nM3Ts1Jl3B/RVNENuaTSaPD/URpOVlZX1rBdWrVr1wg++9dZbBg2SlpG7z20M28Ckb77mj31/AXDv\n3j1KujoTG38TR0dHAyZ8NXIA/BUZyesNG2JnreH8pWhKlSqlaPuGXhYvuhzbe628aFjFlV5TdgNQ\nt3xRpr/biPX7L+NayI5hv+1/6jNhY1swJ/ws6/Zf0StHbi7HpqbtAmDUyE9wKVqUX2bPInx7BB5l\nyyravlqWx40bNzh65DAtAlsCcOL4cZo3fYPribcVy3Dt2jVORZ2kWUBzAKJOnqSpb2Pibybnep62\nCu346jz/cJ7nsfKdOgZIYjjPXXSHDh164QcNXQxz6/z5c3h6ltc9d3BwwMXFhYsXLuBd27jDX2rM\nAfB6w4aKtvckJZdFVlYWlv85AzglLR3P4o7U8HAmOjGF0DEtKF3Unj+irjPy979JffCQGh7OlHF1\nIGJCGxxsrZm34xwzN54yaK7H1LRdnDxxgp3bt7En8m9+mT1L0bYfU8vycHV11RVCgK1bN1P/tQaK\ntQ9QokQJSpQoAUBGRgYLF8ynbbv2imbIrXx1AM0333yj+3dmZiY3b96kWLFiioTSR6pWi62tbbZp\ntnZ2pKSk5MscaqDksog4cY1xQXWoWrowZ2OTGdiyCrbWlhQqaEPFmoVo+8VWUu5nsOzjpnz8v5p8\nsfwIhextqOHhTPOxmynhXJAdX7Ym6moSESeuGTyfWraLrKwshgQPYvKP07G2ts75A0ailuXxX7t2\n7mDG1ClsDt9pkvZnTJvKN19/gWf5CqxYvc4kGcRL7DOMjIwkICCAnj17AjBhwgQiIiJeauZpaWkE\nBASwZs2aPIV8kYIF7UlLS8s2LVWrVXyfmVpyqIGSy+JMbDLD5+1n/lBfIia04UxMMskpD7iT+oCw\nA1dJuJOG9n4Gc8LP0LRWSQCStQ9YHHGB9IeZXE24x7r9l2lWs6TBs4F6tou5v/6Cl1dVGvv4KNru\nk9SyPB4LXb+OAf3eYfW6MLyqVjVJhsEhQ4m5nsjgkA/wf6MRqampJsmhD40BHmqTYzGcMmUKK1as\n0PUKBw0axKxZLzfE8tNPP1GokHEOTHiscpUqXLx4Qfc8OTmZpKQkKlSsaNR21ZpDDZReFkt2X+S1\n4etpMjKMqKtJRF1N4mpCCk4F/+0BPczM4mHmo93j0S94zdDUsl2EbVhP2Ib1lC1VnLKlihMTHY1P\nw/rsjtilaA61LA+AnTu2M/yjoYRtCqduvXqKt3/m9Gl27tgOPDogpWtQN+7eucO5s2cVz6IvczyA\nJsdiWLBgQYoWLap77uzs/FLDLBcvXuTChQv4+fnlKWBOfP38ib56hX179wIwfeoUWrVpi729vVHb\nVWsONVByWXi6OfLnt29SqKANVpYahv+vJot2X2BN5GU6NSxHSeeCWGg09GpaUTcMujryEu+1qoq1\npQXODgV48zUPowyRgnq2i3UbNnE17gaXY65zOeY6pUqXZm/kAXz9/BXNoZblodVqGdi/D8tWrKGK\nl5eibT+WmJhAvz69iIuLA+DPfftIT0+nnKenSfLow0KT94fa5Hjska2tLX///Tfw6Ffcxo0bKVCg\nQI4znjRpEmPHjmXdOuOOgdvZ2bFg8TI+DAkmRZtC+fIV+GXufKO2qeYc8fHxtGjmq3seGOCHlZUV\nm7buwN3dXZEMSi6Lf+LvsvHAVSK/e5OsLFi57x+W7L4IwISVR9n2RWvSH2by55l4Jq87AcC0DVGU\nc3XkxPROaB9k8POW00ScNE4xVMt2oRZqWR4bQteTmJBAn95vZ5sevmM3bm5uimTwafIGI0aOpk3L\nADIzMylgU4AFi5fh5OSkSPsiu+eeWvHYtWvXGD9+PPv378fGxoa6desyevToFx6uv27dOuLi4nj/\n/feZPn067u7udOzY8YVBcntqhTB/cqd7IV6OUqdW9Fh0LM/zWNSjlgGSGE6Oi65EiRL8/PPPes00\nIiKC6OhoIiIiuH79OjY2NhQvXpxGjRrlOqgQQgh1UGqXX2hoKHPmzMHKyoqQkBAqV67MJ598wsOH\nDylWrBjfffcdNjY2hIaG8vvvv2NhYUGXLl3o3Lmz3m3lWAwPHDjAxIkTuXjxIhqNhkqVKvHJJ59Q\nt27d537mxx9/1P37cc9QCqEQQpgHJQ6ASUpKYubMmaxevRqtVsv06dPZunUr3bt3p1WrVvzwww+s\nWrWKDh06MHPmTFatWoW1tTVvvfUWzZs3p3Dhwnq1l+MBNF988QXDhw9n//79REZGEhISwueff57r\nP1AIIYTISWRkJA0bNsTBwQFXV1e+/PJL9u/fT7NmzQDw9/cnMjKSY8eOUaNGDRwdHbG1taVOnToc\nPqz/FXJy7Bm6uLjQ8D9XNGncuDElS778OVlDhgzRO5QQQgj1UuJo0JiYGNLS0hg0aBB37txhyJAh\npKamYmNjAzyqTQkJCSQmJma71q6zszMJCQl6t/fcYhgdHQ1AjRo1+O2332jUqBEWFhZERkZS1UQn\npwohhDA9pc4TvH37NjNmzCAuLo5evXrx3+M9n3fsZw7HhD7Xc4th79690Wg0uhkvWrRI95pGoyEk\nJCRXDQohhHi1KVEKXVxcqF27NlZWVpQpUwZ7e3ssLS1JS0vD1taW+Ph4XF1dcXV1JTExUfe5Gzdu\n4O3trXd7zy2GO3c+/zp9uRmPFUIIIV6Wj48PI0eOZMCAASQnJ6PVavHx8WHr1q20b9+e8PBwmjRp\nQq1atRgzZgx37tzB0tKSw4cPM2rUKL3by3Gf4b1791i/fj1JSUnAoxvHrl69mr3/fwUJIYQQ+YsS\nd61wc3MjMDCQLl26ADBmzBhq1KjBiBEjWL58OSVLlqRDhw5YW1szbNgw+vXrh0ajITg4OFe3A8vx\npPv+/ftTsmRJ9u7dS2BgIPv27SMkJISAgIDc/YXPISfdi+eRk+6FeDlKnXQ/YMXJPM/j1y7VDZDE\ncHI8teL+/ft88cUXuLu7M2LECBYsWMDmzZuVyCaEEEKFzPFC3Tn+jkhPT0er1ZKZmUlSUhJFihTR\nHWkqhBAi/1FhLcuzHIth+/btWbFiBZ07d6Z169Y4OztTpkwZJbIJIYQQisixGHbr1k3374YNG3Lz\n5k05z1AIIfIxJQ6gUdpzi+HUqVOf+6Ft27YxdOhQowQSQgihbmZYC59fDC0tLZXMIYQQ4hWhxgNg\n8irHUyuUIqdWqI9KNg3VfPEqDDXujapf1oWpHUwdQTVkG81OqVMrgteezvM8Zv7PywBJDEehRSeE\nEMJc5HhO3itIiqEQQgi9qKUnbEgvVeCTkpI4ceIEAJmZmUYNJIQQQt0sNHl/qE2OxTAsLIyuXbvy\n6aefAvDll1+ycuVKowcTQgghlJJjMZw3bx7r16+nSJEiAIwYMYIVK1YYPZgQQgh1MseeYY77DB0d\nHbGzs9M9t7W1xdra2qihhBBCqJc57jPMsRgWKVKEtWvXcv/+faKioti0aRPOzs5KZBNCCKFCauzZ\n5VWOw6Sff/45J06cICUlhTFjxnD//n2++uorJbIJIYQQisixGDo5OTFu3Dg2btzI2rVrGTNmDIUL\nF1Yi20uL2LWThvXrUKNqJdq0bE5MTEy+zaGGDABxcXG0bdWCKhXL8VqdWuzd84dJcii5PLq8Xoad\nY5qya2wzlgxuRDlXe6a/U5eIsc10j0MTWvJL/9eyfc6tkC2nvm9D59eNewH8tWtW06CuN7WqV6Gp\nrw9RJ/N+T7rcMPU2euXyZZwK2uBd3Uv36N+nt6IZHlPLOtGXRpP3h9rkOEzq6+v7zPHhiIgIY+TR\nW0pKCr3eDmJ92BZq16nDzOnTCAkexJr1YfkuhxoyPDaw3zu0CGxJ2OZwdkfsYvasmfg0eUPRDEou\nj/JuDoz5XzVaTNjF9eQ0eviUZXKPOnT8YU+29y14/3VW/HU127TP36pBsjbd4Jn+6+rVq4QED2Lv\nXwfx8PBgxrSpvDugL3sj/zZqu09SyzZa0t2doyfzfhWVvFDLOskNc7xQd449wyVLlrB48WIWL17M\n/Pnzeffdd3nnnXcUiPZyInbtpGw5T2rXqQNA7z592b4tnLt37+a7HGrIABATHc2Rw4d4L3gIAL5+\n/ixaulzRDKDs8qhU3JFLN1K4npwGwL5zCVQu4ZTtPf5VXbGxsmT7yeu6aU2ruVGwgCWR5xMNnum/\nrK2tmb9wCR4eHo+yNG3G+XNnjdrms6hlG1UDtayT3LAwwENtcszk7u6ue5QtW5Zu3bqxZ8+enD6m\nmPPnz+HpWV733MHBARcXFy5euJDvcqghA8Dx48fwKFuOsaNHUqtaFVo08+PokSOKZgBll8fhy0l4\nFLOncglHAFp7l2TPmRvZ3jOsjRc/bjqje25rbcno/1VjzPLjBs/zpBIlStAsoDkAGRkZLFwwn7bt\n2hu93SepZRu9e+cOXTr9D+/qXrzZthVnTivfS1TLOhGP5DhMGhkZme359evXuXr16nPerbxUrRZb\nW9ts02zt7EhJScl3OdSQASD59m2iTp7g09FjmfjtZH6b+yvdunbixKlzWFkpdwVAJZdHfHIak0JP\nsfVTf+7dzyD1/kPe+vHfH42NKhYFDfx14aZu2oetK7PuQAxXb2oNnud5Zkybyjdff4Fn+QqsWK38\nhcfVsI06ODrSJagbH3w4nNJlyjB96hS6dOrA4eNRim6fj5l6neSGGY6S5twznDVrlu7x008/sW3b\nNj7//PMcZ7x//35ef/11evbsSc+ePfnyyy8NEvhJBQvak5aWlm1aqlaLg4ODUdpTcw41ZABwKlQI\nVzc32r356Fdun779Sbp1i/PnzimaQ8nlUa1UIYYEVqLRZ9uo/vEmvlkfxW+DXte93qF+KdYf/PdA\nkcolHPGr6sbs7ecNnuVFBocMJeZ6IoNDPsD/jUakpqYq2r4atlEXFxemTJ2BR9myWFhYEPLBR9y4\nEa/49vmYqddJblhoNHl+qE2OP4NGjhxJtWrVcjXz1157jWnTpuXqsy+rcpUqrFr57/6o5ORkkpKS\nqFCxolHbVWMONWQAKFPGg3t375KZmYmFhQUajQYLCwvF75Gp5PLwqVyMQ5duEZf06D+y0EOxTHun\nHs4ONty694Cm1dz4ece/Q4EBNYpTsrAd+78KBMDJ1pqWtUpQvJAt07ca/j/lM6dPExcXS9NmAWg0\nGroGdeOjoYM5d/Ystby9Dd7e86hhG01KSiL59m3Kliunm/bw4UPFLyailnWSGyqsZXmWY89w0qRJ\nSuTINV8/f6KvXmHf3r0ATJ86hVZt2mJvb5/vcqghA0D1GjUoUaIk836bA8CaVSspXKQInuXL5/BJ\nw1JyeVyMv0fdcs4Utn/0H2rT6m7EJ6dx694DXBxsKOpYgH9u3NO9f2b4eWqM2ESdT7dQ59MthB6O\n5bNVJ4xSCAESExPo16cXcXFxAPy5bx/p6emU8/Q0SnvPo4Zt9NDBA7QKbEZCQgIAv839ldKlyyi+\nLNSyTsQjOfYMS5YsSc+ePalVq1a2X05Dhw7NceYXLlxg0KBBJCcnM3jwYBo3bpy3tM9gZ2fHgsXL\n+DAkmBRtCuXLV+CXufMN3s6rkEMNGeDRpZoWL1vJwP59mPzdJIoVc2XR0hWK749RcnlsP3mdmmUK\nEzrMlyyyuJuWwaC5jw6RL1HEjpv3HmDK+9D6NHmDESNH06ZlAJmZmRSwKcCCxctwcnLK+cMGpIZt\nNKB5Cwa++x7NfH2wsLCgpLs7S5avUnzkQi3rJDfM8Qo0Od7pfsaMGc+cPnjw4BfOOD4+nkOHDtGq\nVSuio6Pp1asX4eHh2NjYPPP9cqd79ZG7iGcnd7pXH9lGs1PqTvdfbMv70b/jmlcwQBLDee6iCw0N\n5c0338yx6D2Pm5sbrVu3BqBMmTIULVqU+Ph4SpcunbukQgghVEEltd+gnrvPcNWqVXmacWhoKHPn\nzgUgISGBmzdv4ubmlqd5CiGEML18eQun3GratCnDhw9nx44dpKenM378+OcOkQohhBCm9NxieOTI\nEfz8/J6anpWVhUajyfHapA4ODsyePTuv+YQQQqiMBhV27fLoucWwatWq/PDDD0pmEUII8QpQ4zBn\nXj23GNrY2ODu7q5kFiGEEK8AcyyGzz2ApmbNmkrmEEIIIUzmuT3Djz/+WMkcQgghXhFqOa/SkJS/\nRLsQQohXmjkOk0oxFEIIoRcz7Biq8obDQgghhKKkZyiEEEIvarwfYV5JMRRCCKEX2WcohBAi3zPD\njqHsMxRCCCGkZyieyxzPJcoLtdxHsGTfJaaOQNxv3U0dAZBt1FQs8tO1SYUQQohnMcffIFIMhRBC\n6MUcD6CRfYZCCCHyPekZCiGE0IucZyiEECLfM8NaKMVQCCGEfsyxZyj7DIUQQuR7ZlEM09PTGfHx\nMOysNcTExOTrHBG7dtKwfh1qVK1Em5bNJYcKcoRtCKVBXW+8a3jR1NeHqJMnjdZW18bl+HNCa45P\nac9P7zbExsoCK0sN3/Wux18T2/D3t22Z/E59rCwf/bJ3KmjN7yFN+Pvbtuyb0JoOr5UxWrbH1LBO\nQL6veaHR5P2hNmZRDDt3bI+Dg4OpY5g8R0pKCr3eDmLWz3M4ceocrdu0IyR4kOQwYY7Y2FgG9O3N\n/IVLOHriNF2DujP4/XeN0paXeyG+6l6bzt9HUPPD9VhaaAhpU5XBrbwo5mhLo0830WT0JqqXKUIv\nvwoAfNbFm9ibKbz2SRidv9vFpF71KFHEzij5QB3r5DH5vuaehQEeaqPGTHobOWosYz/73NQxTJ4j\nYtdOypbzpHadOgD07tOX7dvCuXv3ruQwUQ5ra2t+X7QUr6pVAWjU2IfTp6KM0laTqm7sORVP7C0t\nALO3nqVdvdL8eeYGn684SmZWFvfTM9l/LoGKxZ0AaP9aGebtvABAXFIq+07H07K2u1HygTrWyWPy\nfc09jUaT54famEUxfL1hQ1NHAEyf4/z5c3h6ltc9d3BwwMXFhYsXLkgOE+VwdXWlRWBL3fOtWzdT\n/7UGRmkrC7D8z9nQKWnplHNz4O8LiVy6cQ8At0K2BNQswdajsRRxsMHZoQCXbvz7n++lG/eoVKKQ\nUfKBOtbJY/J9zT2NAR4vIy0tjYCAANasWcO1a9fo2bMn3bt3Z+jQoTx48ACA0NBQOnXqROfOnVm5\ncmWu/yazKIbikVStFltb22zTbO3sSElJkRwmzPHYrp07mDF1Ct9+P8Uo8/8j6jp+1Uvg5V4ISwsN\n/QIqYWttqXs9bFQAhye/SdihGCKirlPQxoqHmZlkPMzSvSftwUMKFrB81uwNQm3rxJRkWeTsp59+\nolChRz/Opk2bRvfu3VmyZAkeHh6sWrUKrVbLzJkzmT9/PgsXLuT333/n9u3buWrLqMUwNDSUN998\nk44dOxIREWHMpgRQsKA9aWlp2aalarWK7xeRHE8LXb+OAf3eYfW6MN2QqaGdjbvDiIUHmRPcmG2f\nBXI2Nplk7QPd620nbKfK4DVULunEZ128SbmfgaWFBdaW//43YFfAkpT7GUbJB+paJ6b2Ki8LC40m\nz4+cXLx4kQsXLuDn5wfA/v37adasGQD+/v5ERkZy7NgxatSogaOjI7a2ttSpU4fDhw/n7m/K1ade\nQlJSEjNnzmTJkiXMnj2bHTt2GKsp8f8qV6nCxYv/DrEkJyeTlJREhYoVJYcJc+zcsZ3hHw0lbFM4\ndevVM2pby/ZeovGoTTT9bAunYm5zKjqZVnXccXcpCMDdtAyW7LlE0xoluJ3ygIQ7aZRz+/c/3/Ju\njpyNTTZaPrWsEzV4lZeFEsOkkyZNYuTIkbrnqamp2NjYAODi4kJCQgKJiYk4Ozvr3uPs7ExCQkKu\n/iajFcPIyEgaNmyIg3pDJjMAACAASURBVIMDrq6ufPnll8ZqSvw/Xz9/oq9eYd/evQBMnzqFVm3a\nYm9vLzlMlEOr1TKwfx+WrVhDFS8vo7ZVztWB3V+2wqmgNVaWGj5qV42le/+hdZ1SjPxfDd3h7C28\nSxIV/Wgoad3+qwxqURmAyiWdaFTFlU2HY42WUQ3rRC1e5WVh7FMr1q1bh7e3N6VLl37m61lZWXpN\nfxlGuwJNTEwMaWlpDBo0iDt37jBkyBAaGmGHdXx8PC2a+eqeBwb4YWVlxaatO3B3N95RcWrMYWdn\nx4LFy/gwJJgUbQrly1fgl7nzFWlbcjzbhtD1JCYk0Kf329mmh+/YjZubm0HbunTjHpsPx7Dnq9Zk\nZWWx+q8rLNt7iS1HYvmuVz3+mtgWC42GM7G3+WjeAQC+WnmUGQMbcvC7dtxPf0jI3P0k3EnLoaXc\nU8M6Afm+ql1ERATR0dFERERw/fp1bGxsKFiwIGlpadja2hIfH4+rqyuurq4kJibqPnfjxg28vb1z\n1aYmKy+l9AV++eUXDh8+zIwZM4iLi6NXr17s2rXruYfUphlvN4UQZkVu7iuex1ahC2wuPZL30YNu\nL3kKz/Tp03F3d+fIkSPUq1eP9u3b89VXX1G5cmXatWtHu3btWL16NZaWlnTs2JFVq1bh6Oiodx6j\nLToXFxdq166NlZUVZcqUwd7enlu3buHi4mKsJoUQQijAFKchDBkyhBEjRrB8+XJKlixJhw4dsLa2\nZtiwYfTr1w+NRkNwcHCuCiEYsWcYHx/PyJEjmTt3LsnJyXTs2JEdO3ZgYfHsxSg9QyFejvQMxfMo\n1TNccTQuz/Po4l3SAEkMx2iLzs3NjcDAQLp06QLAmDFjnlsIhRBCCFMy6u+IoKAggoKCjNmEEEII\nhanvYmp5J/czFEIIoRc1Xls0r6QYCiGE0Is57vAyx79JCCGE0Iv0DIUQQuhFhkmFEELke+ZXCqUY\nCiGE0JMZdgxln6EQQgghPUMhhBB6sTDDgVIphkIIIfRijsOkUgyFEELoRWOGPUPZZyiEECLfk56h\nEEIIvcgwqVCEke6qpTdzPLHWHKjh9klFOsw0dQQAktYFmzoCoJ7vrFJnAMoBNEIIIfI9c/ydLPsM\nhRBC5HvSMxRCCKEXc+wZSjEUQgihF3M8tUKKoRBCCL1YmF8tlGIohBBCP+bYM5QDaIQQQuR7ZlEM\nI3btpGH9OtSoWok2LZsTExNjkhxhG0JpUNcb7xpeNPX1IerkSUXbv3L5Mk4FbfCu7qV79O/TW9EM\nj6WnpzPi42HYWWtMtj4A1q5ZTYO63tSqXsUk6wTUs30aO4eVpQUT+zUmNSwYdxd73fTBb9bkyE/d\nODa7O7OG+GNt9ei/HWsrC2YN8ef4z29z5KduvN+upu4zZ+b2JOrXHhz9qbvuYQybN23EzlrDlcuX\njTL/nMTFxdG2VQuqVCzHa3VqsXfPHybJoS+NJu8PtXnli2FKSgq93g5i1s9zOHHqHK3btCMkeJDi\nOWJjYxnQtzfz/6+9O4+Lqmz/OP6ZgcFBFlkCVFQQ3LdcMjXNDdweW8yVVEpwD3NpMcNMK33KpUjT\n1MLMfTe1XFNzTbTCBRcEcQNRBGQdQATm9wePU/xaDGXOjMP19jV/nDMz5/6OZ4Zr7nPuOfeK1ZyK\nusCAgIGMeW2k4jmqenpy6uwFwy186TLFMwD06/0i9vb2Jmn7vuvXrzM2ZBTrN2/l9Nloevfpx8jh\nwYpmMJf3pxI5Nkz5D9m590qse7quByEvPEnHtzbx5KjVONnbEPK/ojeuV1NcHCrw5KhVtH9jI2Ne\nbELzWm6G5/aYvJWmo1cbbmUtJyeHKaGTcHFxKfNt/1sjhg6ha7fuRMdeYfZnn7PoS/O4mMGDqMrg\nn7l57IvhgZ/2413Th2bNmwPwalAwe3/cQ1ZWlqI5NBoNy1auoX6DBgA807YdF86fUzSDOZkUOoUp\nUz8waQaNRsO3K1bj5eUFQKfOfsTGXFQ0g7m8P5XI8cnaX5i++kSJdb3b1WLj4VgydPkALPsxmt7t\nagHwUjtfluw6j14PWbn3+O5onOE+JUz/cBovDw7E3sFBsTb/KCE+npORvzE65HUAOnTsxMo160yS\npbTUqke/mZvHvhjGxsbg4+NrWLa3t8fV1ZW4S5cUzeHu7k7Xbt0Ny7t376Tl060UzQCQlZlJ/z4v\n0bRRfV54rgfRFy4ongGgdZs2Jmn3j6pUqYKffxcACgoKWLH8W557/kVFM5jL+1OJHMejk/60rpZn\nJS7fyjQsX76ZQZ1qTgDUrurE5VsZf7gvkzrVnA3LHwc/wy/zAzjyWV96Pu1dZjkBzkZFsX/vj4wd\nN6FMt1saZ86cxsu7JlMmT+LJhvXo6teRUydPmixPeffYF8PcnBy0Wm2JdVpbW3Q6nYkSwU/79zF/\nbhiz5oQp2q69gwP9A15m9qdhRJ45h5+fP/379KKgoEDRHOZm/ry5eHl6cPTIYaZ/PFPRts3l/Wmq\nHBUraMjL//39l5dfgJ1W87/7rLmbX/h7xvwC7LTFA9w3HIpl0fYoWo5ZyztLjvLNW13wqVKpTDLp\n9XpeDxnFp59/gUajKZNtPoyM9HTOnY2ibbv2nD4XTcDAQbw8oM9j8XmVw6SlsGHDBgIDAw23Zs2a\nGaWdihXtyMvLK7EuNyfHZOertm3dwvChQ9i05QfDIVOluLq6EjZ3Pl7e3qjVasaOf4Pbt5OIjYlR\nNIe5GTN2HAm3Uhgzdjyd2j9Dbm6uYm2by/vTVDl0effQ2vz+Cy7bCtaG84q6uwVUsLH6PWMFa3T/\nu2/KsggORyUCcPTcTQ5F3cC/WfUyybTk66+oX78Bbdu1K5PtPSzHSpVw9/Dg+ReKj1YEBQ8j7c6d\nx+LzKgNoSqFfv36sWLGCFStW8Prrr9OrVy+jtFO3Xj3i4n4/1JORkUFaWhq1atc2Snv/ZP++vbz1\nxjh+2LGHFk89pXj7aWlpXL1ypcS6wsJCk377NaXoCxfYv28vUDwDx4CAl8nKzCTmonLnDc3l/Wmq\nHDEJafj+oUdXq6oT0fF3/va+C/Fp2FirqV+j5KAWays19wqLyiTTD99v5Yfvt+JdrTLe1SqTEB9P\nuzYtOXjgpzLZ/r9Vo4YX2VlZFBUVvy6VSoVarcbKyuoBzzQ9VRnczI0ih0kXLFjAa6+9ZpRtd+jY\nifjr1zh65AgAX8wNo0fP57Czs3vAM8tWTk4OI4YFsXb9ZurVr69o2/f99usv9OjmR3JyMgDfLPma\n6tVrUNPHxyR5TC0lJZmhQa+QmFjcw/j56FHu3bun6P+Hubw/TZVj0+FL9G9fG3cnW6zUKkJeaML6\ng7GG+0Y/3wS1WkVl54r0a1882KZiBQ0H5vShVT0PABp6udCmfmX2n4ovk0xbvt/B9cTbXE24xdWE\nW1SrXp0jx36hQ8dOZbL9f6tR48ZUqVKVpd+EA7B54wacnJ3x8fV9wDOFMRj9CjRnzpyhSpUquLm5\nPfjBD8HW1pblq9YyYWwIuhwdvr61+GrJt0Zp6598v20rKcnJBL06qMT6PfsO4uHhoUgG/y5dGTFy\nNH4d2qFWq6nq6cnqdRsV/6aZlJREV78OhuVu/h2xtrZmx+59eHp6Kpaj3bPteWfSZHp296eoqIgK\nNhVYvmotjo6OimUwl/ensXO4O9my5+OXDMu7P36JgsIi/vPeVj7/7hR7Z/ZGpYJ9J+P5akfxbz3n\nbztDnWrOnFk0iILCIv675leirqQCMPiT3cwL6YhWY0XO3QKCP93LtSRlR+Aam0qlYtXaDYwYFsSn\ns2fi5ubOyjXrsbY2/wuDqc3xOOcjUumNPCvl+++/T8+ePWnV6p9HVuaZ/zljxZjLRKEyua/4OzK5\nb0nm8pm11SjzmY24lP7I22hdy6kMkpQdox8mPX78uNEGzwghhDABCzxpaNRimJSUhJ2dHTY2NsZs\nRgghhHgkRj04nZycbNJLHQkhhCh75vg7wUdl1GLYqFEjwsPDjdmEEEIIhVnicALzH7YkhBDCrFhg\nLXz8L8cmhBBCPCrpGQohhCgdC+waSjEUQghRKjKARgghRLlniQNo5JyhEEKIck96hkIIIUrFAjuG\nUgyFEEKUkgVWQymGQgghSkUG0AghhCj3ZACNEEIIYYGkZyjEv2Quc9aZwzyT5jKPoMcrK0wdAYBb\nywabOoKiTP8OLHtSDIUQQpSOBVZDKYZCCCFKxRIH0Mg5QyGEEOWe9AyFEEKUilKnrWfNmsVvv/1G\nQUEBI0eOpHHjxkycOJHCwkLc3NyYPXs2NjY2bNu2jWXLlqFWq+nfvz/9+vUrdVtSDIUQQpSKErUw\nIiKC2NhY1q1bR1paGi+99BJt2rRh4MCB9OjRg88++4yNGzfSq1cvFixYwMaNG9FoNPTt25cuXbrg\n5ORUqvbkMKkQQojSUZXB7QFatmzJ3LlzAXB0dCQ3N5fjx4/j5+cHQKdOnTh27BinT5+mcePGODg4\noNVqad68OZGRkaV+SVIMhRBCmB0rKysqVqwIwMaNG2nfvj25ubnY2NgA4OrqSnJyMikpKbi4uBie\n5+LiQnJycqnbk2IohBCiVFRl8O/f2rt3Lxs3buT9998vsf7vfvf7sL8HtohieO/ePd55+01sNSoS\nEhJMluPAT/tp07I5jRvUoWf3LopnuXb1Ko4VbWjaqL7hNizoVUUz3PfD99to1aIpTRvXp3OHdpw7\ne7bc5khMTOS5Hl2pV7smTzd/kiOHDymeAeC7zZto1aIpTzaqZ9J9omSOgGd9iJj1PGfn9Wbx6LbY\nWJf8k7d8XHt+eK+LYbmF7xPs+7AHv8x5gYMz/kOXplWNlu27TRtLfFabNqpPRRs1WVlZRmuzrKhU\nj377Nw4fPsyiRYv4+uuvcXBwoGLFiuTl5QGQlJSEu7s77u7upKSkGJ5z+/Zt3N3dS/2aLKIY9uv9\nIvb29ibNoNPpeGVQAF8uDifqfAz/6fk8Y0NGKZ6jqqcnp85eMNzCly5TPMONGzcYHvwq365Yzamo\nCwwIGMiY10aW2xwjhg6ha7fuRMdeYfZnn7PoywWKZ7h+/TpjQ0axfvNWTp+NpneffowcHmzROepX\nc+K/g1vQ55N9NBq7GSu1inHPNzTc37WpJ019XEs8Z8X49nyy+TQt39rGqIU/Ex7yLI62GqPke6lP\n3xKf1SlTP+DFXr1xcHAwSntlSYFThmRlZTFr1iwWL15sGAzzzDPPsHv3bgD27NnDs88+y5NPPklU\nVBSZmZnodDoiIyN56qmnSv2aLKIYTgqdwpSpH5g0w4Gf9uNd04dmzZsD8GpQMHt/3PNYfMsraxqN\nhmUr11C/QQMAnmnbjgvnz5XLHAnx8ZyM/I3RIa8D0KFjJ1auWadoBij+v/h2xWq8vLwA6NTZj9iY\nixado33Dyhw6d4sbd3IA+HLXBV5oWQMAWxsrPhrYnE82nTY83tnOBk9XOw6evQXAhYR0cvML8HI3\n/hftvLw8Ppg6hRkfzzR6W4+LHTt2kJaWxvjx4wkMDCQwMJBRo0axZcsWBg4cSHp6Or169UKr1fLm\nm28ydOhQgoKCCAkJeagvFBbx04rWbdqYOgKxsTH4+Pgalu3t7XF1dSXu0iWaNmumWI6szEz693mJ\nmIvR1PD2Ztbsz6hXv75i7QO4u7vTtVt3w/Lu3Ttp+XQrRTOYS44zZ07j5V2TKZMnsXP7djwqV2bW\nnDBF3xMAVapUoUqVKgAUFBSwYvm3PPf8i4pmUDqHXq/HSv17H0SXV4BP5eI/kpN6N2HdkStcT9YZ\n7k/T5XP6Sir92tZk1cE4Wtd1o6BQz8UbGUbJ90ffLl1C62fa4uPr++AHmwMFflsxYMAABgwY8Kf1\nS5cu/dO67t2707179z+tLw2L6Bmag9ycHLRabYl1WltbdDrd3zyj7Nk7ONA/4GVmfxpG5Jlz+Pn5\n079PLwoKChTL8P/9tH8f8+eGMWtOmMkymDJHRno6585G0bZde06fiyZg4CBeHtDHZPtk/ry5eHl6\ncPTIYaabsBeiRI6D527RsVEV6ldzwkqtYniXumg1VjSo7kTnJlWZt/3PRwnGhkcwY1ALrn7Vn63v\ndmHishPkFxQZJd99RUVFzPv8M8ZPeNOo7ZQlJQfQKMVoxVCn0zFmzBgCAwMJCAjg8OHDxmrKLFSs\naGc4sXtfbk6OoucyXV1dCZs7Hy9vb9RqNWPHv8Ht20nExsQoluGPtm3dwvChQ9i05QfDocrylsOx\nUiXcPTx4/oXi3k9Q8DDS7twx2T4ZM3YcCbdSGDN2PJ3aP0Nubq7F5rh4I4OJy37hm9efZf9HPYi+\nkU5mzj0+DXqaict+oaCw5KhDrcaKlRM68urcQ3iPWE/7yduZO6w11Z+wK/Nsf3Q84hj2dvY0aNjw\nwQ82E0oNoFGS0Yrhd999R82aNVmxYgVz585lxowZxmrKLNStV4+4uEuG5YyMDNLS0qhVu7ZiGdLS\n0rh65UqJdYWFhWg0xhkA8E/279vLW2+M44cde2jxECezLSVHjRpeZGdlUVRU3LtQqVSo1WqsrKwU\nzRF94QL79+01ZBgQ8DJZmZnEXFT2vKHSOdYcvkybd76nw+QdnI9P5+z1NBrVcGbZuPbEfNmXlRM6\n0KqOG0c/eY761SphpVZx8FzxOcOLNzKIu5VFC1/XB7TyaHZu/4Fu3XsYtQ3xYEYrhs7OzqSnpwOQ\nmZmJs7OzsZoyCx06diL++jWOHjkCwBdzw+jR8zns7Iz7rfKPfvv1F3p08zP84PSbJV9TvXoNavr4\nKJYBICcnhxHDgli7frPi5yvNLUejxo2pUqUqS78JB2Dzxg04OTsrfm4oJSWZoUGvkJiYCMDPR49y\n7949xd8bSubw8XDg8H97UqmiBmsrFW++2IjVh+KoPmwddV7bSJ3XNjI47CDHY5JpO+kHrqfoqFTR\nhub/G2FazbUi9atVIjrBuOcMz0SdoW49031OHoYSo0mVZrQBND179mTz5s106dKFzMxMFi9ebJR2\nkpKS6OrXwbDczb8j1tbW7Ni9D09PT6O0+VdsbW1ZvmotE8aGoMvR4etbi6+WfKtY+wD+XboyYuRo\n/Dq0Q61WU9XTk9XrNireC/l+21ZSkpMJenVQifV79h3Ew8OjXOVQqVSsWruBEcOC+HT2TNzc3Fm5\nZj3W1sqOXWv3bHvemTSZnt39KSoqooJNBZavWoujo6PF5riclMWO3+I58vFz6IFNP19lzeHLf/v4\n1Ky7jFx4hC9GtKGCtZoiPby/OpJoIw+gSUxIwKNyZaO2UebMsZo9IpXeSNN3b926lV9//ZWPPvqI\n6OhoQkND2bx5898+Ps90YzzMjsyobp5kv5gfmem+JFuNMu+N2KRHP8db28O2DJKUHaMdJo2MjKRd\nu3YA1KtXj9u3b1NYWGis5oQQQoiHZrRi6OXlxenTxT9ovXHjBnZ2doofrhNCCFH2LHE0qdFOXAwY\nMIDQ0FAGDx5MQUEB06ZNM1ZTQgghFGSGteyRGa0Y2tnZGeaiEkIIYUEssBpaxOXYhBBCKMccryDz\nqORybEIIIco96RkKIYQoFXMcAPOopBgKIYQoFQushVIMhRBClJIFVkM5ZyiEEKLck56hEEKIUrHE\n0aRSDIUQQpSKDKARQghR7llgLZRzhkIIIYT0DIUQQpSKJR4mNdp8hqUl8xmKv2Mmb1GZR1D8LZeA\nb0wdAYCcjcGKtJOQlv/I26jmbFMGScqO9AyFEEKUiiV+L5RzhkIIIco96RkKIYQoFQvsGEoxFEII\nUTqWeJhUiqEQQohSscQr0Mg5QyGEEOWe9AyFEEKUjuV1DC2jZ3jgp/20admcxg3q0LN7FxISEspt\nDnPIYE45EhMTea5HV+rVrsnTzZ/kyOFDJslx79493nn7TWw1qnK/T+7buWM7thoV165etfgMAzvU\n4tewl7i4sD/hr7fHxlrNN+M6cHJub8Pt8tcBrH6rc4nnVXG25eaywQzuWMuo+UpLVQY3c/PYF0Od\nTscrgwL4cnE4Uedj+E/P5xkbMqpc5jCHDOaUA2DE0CF07dad6NgrzP7scxZ9ucAkOfr1fhF7e3uT\ntA3mtU8AcnJymBI6CRcXF4vP0KC6E5+8+jQvTt9D3dHrsVKreKNXY4LnHqTZuM2G2+krqaz8KbbE\nc2cHtyZdd9eo+R6GSvXoN3Pz2BfDAz/tx7umD82aNwfg1aBg9v64h6ysrHKXwxwymFOOhPh4Tkb+\nxuiQ1wHo0LETK9esUzTDfZNCpzBl6gcmaRvMZ5/cN/3Dabw8OBB7BweTtK9khg6Nq3Lw7E1upOoA\nWLD9HL1aeZd4TNdm1bDRWLHjt3jDum7NqmFXwZpD524ZNZ8o9tgXw9jYGHx8fA3L9vb2uLq6Enfp\nUrnLYQ4ZzCnHmTOn8fKuyZTJk3iyYT26+nXk1MmTima4r3WbNiZp9z5z2ScAZ6Oi2L/3R8aOm6B4\n26bIoNfrsVL/3hXKzivAp7Jjice8178ZH284ZVi2tbFixistmRAeYfR8D0NVBv/MzWNfDHNzctBq\ntSXWaW1t0el05S6HOWQwpxwZ6emcOxtF23btOX0umoCBg3h5QB8KCsrfhXDNZZ/o9XpeDxnFp59/\ngUajUbRtU2U4EHWTzk2q0qC6E1ZqFSO710drY2W4v33DyqhUcOT87z3Ad/s1Y/3hy1y9bZqe+wNZ\n4ElDoxXDoqIipkyZQkBAAIGBgcTFxRmlnYoV7cjLyyuxLjcnR/HzM+aQwxwymFMOx0qVcPfw4PkX\nXgQgKHgYaXfuEBsTo2gOc2Au+2TJ119Rv34D2rZrp2i7pswQnZDOm0siWDahE4c+fp7ohHTSdb9f\n6HrAs76sP3LZsNyguhNdm3oSti1KkXwPwwJrofGK4b59+8jKymLt2rXMmDGDWbNmGaWduvXqERf3\n+6GejIwM0tLSqFW7tlHaM+cc5pDBnHLUqOFFdlYWRUVFQPGsE2q1Gisrqwc80/KYyz754fut/PD9\nVryrVca7WmUS4uNp16YlBw/8ZNEZVh28RMs3vqPtO9s4e+0O566nGe7r3rw6uyN/H9n7n6dq4PmE\nHTEL+3Pl6wD6PlOT2UGtmdj7SaPlE0YshlevXqVJkyYA1KhRg8TERAoLC8u8nQ4dOxF//RpHjxwB\n4Iu5YfTo+Rx2dnZl3pa55zCHDOaUo1HjxlSpUpWl34QDsHnjBpycnfHx9X3AMy2PueyTLd/v4Hri\nba4m3OJqwi2qVa/OkWO/0KFjJ4vN4FPZgYjZL1Kpog3WViom9n7SMGrUzVGLWyUtsTczDI+f890Z\nqgetpubwtdQcvpaNP1/h7aURzNp82ij5HoYljiY12o/u69Spw7Jly3j11Ve5du0a8fHxpKWl8cQT\nT5RpO7a2tixftZYJY0PQ5ejw9a3FV0u+LdM2Hpcc5pDBnHKoVCpWrd3AiGFBfDp7Jm5u7qxcsx5r\na2WvNZGUlERXvw6G5W7+HbG2tmbH7n14enoqksFc9kl5dPlWFj/8cp3jn/ZCr9ez/shlVh0s7qV7\nutqRkpmHmUzZ+a+Z4wCYR2XUyX3DwsI4fvw4devWJSoqisWLF+Pm5vaXj5XJfcXfkcl9hbkrb5P7\npuU8+lE+54rmdbrCqF+RJ0z4fdiyv78/rq6uxmxOCCGEeChGO2cYHR3Nu+++C8ChQ4do0KABavVj\n/0sOIYQQFsio5wz1ej19+/alQoUKzJkzx1hNCSGEUJAlnjEwWjFUq9V88sknxtq8EEIIE7HEATQy\nhZMQQohSscSeoZzEE0IIUe5Jz1AIIUSpWGDHUIqhEEKIUrLAaijFUAghRKlY4gAaOWcohBCi3JOe\noRBCiFKxxNGkUgyFEEKUigXWQimGQgghSkmhavjf//6X06dPo1KpCA0NNUwLaAxSDIUQQpidEydO\ncO3aNdatW0dcXByhoaGsW7fOaO3JABohhBCloiqDfw9y7Ngx/P39AfD19SUjI4Ps7GyjvSYphkII\nIUpFiZnuU1JScHZ2Niy7uLiQnJxstNdkNodJtWaTRJgfSzxdLyyJUpPqmgtT/L029iTf0jMUQghh\ndtzd3UlJSTEs3759Gzc3N6O1J8VQCCGE2Wnbti27d+8G4Ny5c7i7u2Nvb2+09uTgpBBCCLPTvHlz\nGjZsSEBAACqViqlTpxq1PZXe2AdihRBCCDMnh0mFEEKUe1IMhRBClHtSDIUQQpR7j3UxzMjIICsr\ny9QxKCwsNHUEoHjocXx8vEkzJCcnc/PmTZNmAIiLi+P69eumjkFkZCQHDhwwdQxu377NrVu3TJph\n//79fPLJJybNAJCamkpSUpKpY5CdnU1+fr6pY4j/eWxHkx48eJCvv/4ad3d3XFxceO+990yS48SJ\nE1y5coUuXbrg4uJikgwABw4cYOHChdja2vLEE08wZ84cxTMcPnyYBQsWYGdnh6enJx9++KHiGYqK\nisjOzmb48OH4+/vTt29f6tSpo3gOgIiICL788kveeustk7R/3969e/nqq6+oXbs2vXr1omXLlopn\nOHHiBEuWLAGKv6j4+voqngHgyJEjLFy4EHt7e9zd3fnoo49MkuPgwYN8++23eHt74+joyIQJE0yS\nQ/yB/jEUHx+vHzJkiD46Olqfk5OjDw4O1n/44Yf6O3fuKJ5lzJgx+vHjx+vXrVunT01NVbx9vV6v\nv3nzpj44OFh/9epVvV6v17/00kv6FStWKJohOjpaP2jQIP2FCxf0Op1O/8Ybb+jz8vIUzfBHU6ZM\n0U+cOFG/cuVK/blz5xRv/+eff9Z37dpVHxsbq9fr9XqdTqfPzs5WPIdOp9O//vrr+lOnThnW3b17\nV9EMERER+gEDBuhPnjypX7dunf7YsWOKtn/fhQsX9IMGDdJHR0fr9Xq9fuzYsfrMzEzFc1y9elU/\nePBgfXR0tD4/P1//yiuv6CdMmKD4fhElPZaHSW1tbbGyskKj0WBra8uiRYvIyspi3rx5imepUKEC\nlStXJi4ujj17OtBZgAAAChtJREFU9nDnzh3FM2g0Gu7evYtaXbw7hw8fTkFBgaIZbGxs8PHxoV69\neiQmJnLhwgU+++wzPvjgA0Vz3Ofj44NarebOnTucOnWK/fv3Ex0drUjber2e+Ph4nJyc0Gq15OXl\nMX78eCZOnEhoaCi5ubmK5ABQqVSkpaVRUFBAdnY2o0aNYvz48UyePFmR9vPz8zl58iTvvvsuTZs2\nxc3NjdWrV5vsc+Lj40PVqlVJS0sjKiqKefPmMX36dEVzaLVa7Ozs0Gq1aDQaZsyYwblz5/jyyy8V\nzSFKspo2bdo0U4coLa1WS1JSEmlpaXh4eODg4ECnTp1YunQpFy9e5Nlnn1UsS6NGjejRowf5+fmc\nP3+elJQUPD09sbW1Ra/Xo1JgSmiNRkO1atVo2LAhAJcuXSIiIoJu3boBUFBQYCiUxmJtbU2lSpWo\nXr0627Ztw8vLi1deeYVNmzYRERFhuPq8sd3/P9doNFhZWREcHMzq1asJDw+nadOm1K5d2+gZVCoV\nvr6+2NnZER4ezubNm+nTpw/Dhg1j165dJa7Gb2wajQatVsvhw4fZt28f/v7+DB06lE2bNnH8+HH8\n/PyM2r6VlRVNmjTB09OTwsJCPD09iY+Px8vLCycnJwoLC43+3vxjlqioKPbs2UN4eDj9+vUjMDCQ\n8PBwoqKi6Ny5syI5bGxsuH79OrGxsajVao4fP46Pjw8nTpwgMTGRp59+WpEcoqTHsmeoVqvp3r07\np0+f5sSJE9y+fRtra2vCwsLIyclRtFdUuXJlAPz8/GjWrBlXr14lIiKCVatWsXz5ckUyaDQa2rRp\nY1jWarVYWVkBsGXLFr755hujX+TWwcHBkGHIkCGMGTMGNzc3lixZQkpKimI9gftfPlxcXDh//jwH\nDx7k4sWLtG/fnqSkJGJiYhTJodVq6dq1K/7+/tSsWRN/f38cHByYO3cuqamppKWlKZIDoHXr1tjb\n25OamkrNmjVxdHQ07JfU1FSjt29jYwMUF6MKFSpQVFTE7NmzDeuKioqMngGgUqVKvPbaa4SEhODl\n5UWPHj1wcXFh1apVig7Gs7GxoV+/ftja2rJ8+XJiYmJ47bXXmDVrFnfv3lUkg/izx3YATY0aNRgy\nZAjLly8nLS2NFi1akJCQQGJiIoWFhVhbK/PS1Gq1oTfSrVs3XFxcWLBgAXfu3OHTTz9VJMP/5+rq\nSq1atTh16hRbtmzhvffeU6SHel9+fj537tzBysqK8+fPk5OTY/iDqBR3d3esrKyYO3cuoaGh+Pj4\nsH79ep544gnFMmi1Wnr16oWfnx9arZbc3FxOnDhBbm4uGo1GsRwuLi68/PLLLFmyhAMHDpCfn09m\nZia5ublUqFBBsRz3Pydjxozh7bff5p133mHmzJmK9QwB7O3tsbOzw8vLi19++YV27doRFRVFVlaW\n4QukEipXrkxwcLDh/+Tu3bscP36cmJgY8vPz0Wg0in5mhQVcji0+Pp59+/Zx9OhRbGxsGDdunElG\nD95/U//000/Mnj2b+fPn4+Pjo3gOgBs3btCzZ098fHyYM2eO4jmys7NZuXIlUVFR5OXlMWnSJEUO\nT/5/cXFxpKWl8dRTTwHFRVrponzf3r172blzJ7dv32bq1KnUqlVL8QypqalERkaya9cuVCoVw4YN\no169eopmKCoqQq1Wc/PmTcLDwwkJCTHJKOy4uDiWL19ORkYGmZmZhIaGmmSfQPHPb+bPn09hYSHv\nvfeeST4rwgKK4X1ZWVno9XocHR1NlqGwsJBDhw5Rs2ZNvL29TZajqKiIBQsW8MILL+Dl5WWSDNnZ\n2eh0OtRqtVGnXfk3lDp3+0+ys7NJS0tDo9EYDq2bSl5eHnq9HltbW5PmMOWXEwCdTkd6ejrW1tZ4\neHiYLAdgOFzt6upq0hzlmcUUQ3NhDn94oXjQjFKHioUQ4nEnxVAIIUS591iOJhVCCCHKkhRDIYQQ\n5Z4UQyGEEOWeFENhlhISEmjUqBGBgYEEBgYSEBDAm2++SWZm5kNvc8OGDUyaNAmACRMm/OPMBZGR\nkaWaAaSgoIC6dev+af0XX3xBWFjYPz63c+fOXLt27V+3NWnSJDZs2PCvHy+EeDAphsJsubi4sGLF\nClasWMHatWtxd3dn4cKFZbLtsLCwfxxOv3nzZpNPhyWEUI6MvRePjZYtW7Ju3TqguDfVo0cP4uPj\nmTdvHjt27GDlypXo9XpcXFyYPn06zs7OrFq1ijVr1lC5cmXc3d0N2+rcuTNLly6levXqTJ8+nbNn\nzwIQFBSEtbU1u3bt4syZM7z77rt4eXnxwQcfkJubS05ODm+88QbPPPMMly9f5u2338bW1pZWrVo9\nMP/q1avZunUrGo2GChUqEBYWZvhd7IYNG4iKiiI1NZUpU6bQqlUrEhMT/7JdIUTZk2IoHguFhYX8\n+OOPtGjRwrDO29ubt99+m5s3b7Jo0SI2btyIjY0Ny5YtY/HixYSEhDBv3jx27dqFs7Mzo0ePplKl\nSiW2u23bNlJSUli/fj2ZmZm89dZbLFy4kPr16zN69GjatGnDiBEjCA4OpnXr1iQnJzNgwAD27NnD\nggUL6NOnDwMHDmTPnj0PfA13795lyZIl2Nvb8/7777Nt2zYGDx4MgJOTE8uWLePYsWPMnDmTzZs3\nM23atL9sVwhR9qQYCrN1584dAgMDgeKr6jz11FMMGTLEcH+zZs0AOHnyJMnJyQwdOhQovrJJtWrV\nuHbtGp6enjg7OwPQqlWrP03jdObMGUOvztHRka+++upPOY4fP45Op2PBggVA8QwdqampxMTEMGLE\nCKD4YtgP4uTkxIgRI1Cr1dy4caPElXnatm1reE2XLl36x3aFEGVPiqEwW/fPGf6d+xe7trGxoUmT\nJixevLjE/VFRUSWuBvRXsyOoVKoHzppgY2PDF1988adraOr1esNFpgsLC/9xG7du3WLmzJls374d\nV1dXZs6c+acc/3+bf9euEKLsyQAa8dhr3LgxZ86cITk5GYCdO3eyd+9eatSoQUJCApmZmej1eo4d\nO/an5zZr1ozDhw8DxdcP7devH/n5+ahUKu7duwdAixYt2LlzJ1DcW50xYwYAvr6+nDp1CuAvt/1H\nqampODs74+rqSnp6OkeOHCE/P99wf0REBFA8ivX+hZr/rl0hRNmTnqF47Hl4eDB58mRGjhyJra0t\nWq2WmTNnUqlSJUaNGsWgQYPw9PTE09OTvLy8Es/t0aMHkZGRBAQEUFhYSFBQEDY2NrRt25apU6cS\nGhrK5MmTef/999m+fTv5+fmMHj0agJCQEN555x127dpFs2bN/vFasPXr18fLy4u+fftSo0YNxo4d\ny7Rp0+jQoQMA6enpjBw5ksTERKZOnQrwt+0KIcqeXJtUCCFEuSeHSYUQQpR7UgyFEEKUe1IMhRBC\nlHtSDIUQQpR7UgyFEEKUe1IMhRBClHtSDIUQQpR7UgyFEEKUe/8H/EFiss4vsD0AAAAASUVORK5C\nYII=\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "cell_type": "code", "metadata": { "colab_type": "code", "id": "E7eLhsYGQQCX", "outputId": "6f3f60df-477c-4fa3-b5a4-5a836af91705", "colab": { "base_uri": "https://localhost:8080/", "height": 199 } }, "source": [ "normalized_acc(conf_matrix)" ], "execution_count": 0, "outputs": [ { "output_type": "stream", "text": [ "Acc class 0 --> 0.959\n", "Acc class 1 --> 0.991\n", "Acc class 2 --> 0.981\n", "Acc class 3 --> 0.977\n", "Acc class 4 --> 0.99\n", "Acc class 5 --> 0.981\n", "Acc class 6 --> 0.995\n", "Acc class 7 --> 0.98\n", "Acc class 8 --> 0.97\n", "Acc class 9 --> 0.985\n" ], "name": "stdout" } ] } ] }