{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Data Driven Modeling\n", "### (Theme of this semester: CODING AS LITERACY)\n", "
\n", "### PhD seminar series at Chair for Computer Aided Architectural Design (CAAD), ETH Zurich\n", "\n", "[Vahid Moosavi](https://vahidmoosavi.com)\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "# First Session: Introduction \n", "
\n", "
\n", "\n", " 28th February 2017" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# What do I mean by \"Modeling\"?\n", "\n", "\n", "## Formally speaking...\n", "### \n", "![](Images/RosenModel.png)\n", "\n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Why Data Driven Modeling and what is Coding as Literacy? \n", "\n", "
\n", "\n", "![](Images/Theory_Data_Modeling1.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# They are not opposing each other\n", "\n", "
\n", "![](Images/DDMTDM.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# This literacy will turn the classical notion of expertise as \n", "\n", "“Having the Answers to the Known Questions” \n", "\n", "# to\n", "“Learning to Ask Good Questions” \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \n", "
\n", "# But now how to learn this if it is like a new language?\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## This is how I framed it few months ago...\n", "![](Images/DataDrivenModelingElements.png)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# With different approaches?\n", "## Resource Based --> Forward but slow and might take a BSc.\n", "## Market Oriented --> Backward, following the fashion: itmight work, but mostly we get simply puzzled\n", "## Connecting the dots in a guided path --- Wiki-based approach\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "![](Images/DataDrivenModelingKW.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# But now I prefer this more as my own image of the field...\n", "### Green color indicates we previously discussed the topic to an extent.\n", "\n", "![](Images/KW2016_1.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# This semester I would like to offer two scenarios:\n", "# 1- Discussions on algorithms and their implementations\n", "\n", "* **Theories**\n", " * Convolutional Neural Networks\n", " * Recurrent Neural Networks\n", " * Ensemble Models\n", " * Resampling and Data Completion \n", " * Dimensionality Reduction and Topological Data Analysis\n", " * How to compare objects? On similarity measures\n", " * Intro to Reinforcement Learning\n", " * Support Vector Machines\n", "\n", "\n", "# 2- Workshop style sessions around applications\n", "\n", "\n", "\n", "\n", "* **Applications**\n", " * Image Modeling: Big Data and Urban Design \n", " * Time Series Analysis and Forecasting\n", " * Text Modeling and sentiment analysis\n", " * Real Estate Market \n", " * Traffic Modeling \n", " * Urban Air pollution modeling\n", " * Water flow Emulations\n", " * Analyzing Food Recipes \n", "\n", "\n", "* **Data Wrangling with Pandas** \n", "* **Data Collection and use of APIs**\n", "* **Web Application Development**\n", "\n", "\n", "* **Frameworks to be used**\n", " * Scikit-learn: Classical Machine Learning\n", " * Gensim: Text Modeling\n", " * Tensorflow: Deep Learning\n", " * Flask: Web Application Framework\n", " * BS4: HTML Parsing\n", " * Leaflet: Geo Mapping\n", " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "# Back to the original idea of coding as litercy\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Does it make sense to use data driven modeling if we have a valid descriptive theory or an explicit logic of a phenomenon?\n", "## This seems silly!\n", "## But, as we can see in the following example, we can solve logical games without explicit implementation of the logic of the game.\n", "
\n", "![](Images/DDMTDM.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A very funny intro to TensorFlow and Machine Learning for the logical game of fizzbuzz!\n", "http://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow/" ] }, { "cell_type": "code", "execution_count": 107, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np\n", "import tensorflow as tf" ] }, { "cell_type": "code", "execution_count": 108, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def binary_encode(i, num_digits):\n", " return np.array([i >> d & 1 for d in range(num_digits)][::-1])" ] }, { "cell_type": "code", "execution_count": 109, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([0, 0, 0, 0, 0, 0, 1, 0, 0, 1])" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "binary_encode(9,10)" ] }, { "cell_type": "code", "execution_count": 110, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def fizz_buzz_encode(i):\n", " if i % 15 == 0: return np.array([0, 0, 0, 1])\n", " elif i % 5 == 0: return np.array([0, 0, 1, 0])\n", " elif i % 3 == 0: return np.array([0, 1, 0, 0])\n", " else: return np.array([1, 0, 0, 0])\n", " " ] }, { "cell_type": "code", "execution_count": 142, "metadata": { "collapsed": true }, "outputs": [], "source": [ "NUM_DIGITS = 11\n", "test_number = 200\n", "trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(test_number+1, 2 ** NUM_DIGITS)])\n", "trY = np.array([fizz_buzz_encode(i) for i in range(test_number+1, 2 ** NUM_DIGITS)])" ] }, { "cell_type": "code", "execution_count": 143, "metadata": { "collapsed": false }, "outputs": [], "source": [ "NUM_HIDDEN = 400" ] }, { "cell_type": "code", "execution_count": 144, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X = tf.placeholder(\"float\", [None, NUM_DIGITS])\n", "Y = tf.placeholder(\"float\", [None, 4])" ] }, { "cell_type": "code", "execution_count": 145, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def init_weights(shape):\n", " return tf.Variable(tf.random_normal(shape, stddev=0.01))\n", "\n", "w_h = init_weights([NUM_DIGITS, NUM_HIDDEN])\n", "w_o = init_weights([NUM_HIDDEN, 4])" ] }, { "cell_type": "code", "execution_count": 146, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(11, 400)\n", "(400, 4)\n" ] } ], "source": [ "print w_h.get_shape()\n", "print w_o.get_shape()" ] }, { "cell_type": "code", "execution_count": 147, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def model(X, w_h, w_o):\n", " h = tf.nn.relu(tf.matmul(X, w_h))\n", " return tf.matmul(h, w_o)" ] }, { "cell_type": "code", "execution_count": 151, "metadata": { "collapsed": true }, "outputs": [], "source": [ "py_x = model(X, w_h, w_o)\n", "cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(py_x, Y))\n", "train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost)" ] }, { "cell_type": "code", "execution_count": 152, "metadata": { "collapsed": true }, "outputs": [], "source": [ "predict_op = tf.argmax(py_x, 1)" ] }, { "cell_type": "code", "execution_count": 153, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def fizz_buzz(i, prediction):\n", " return [str(i), \"fizz\", \"buzz\", \"fizzbuzz\"][prediction]" ] }, { "cell_type": "code", "execution_count": 157, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0, 0.53329723876556578)\n", "(500, 0.57011369788846777)\n", "(1000, 0.92528424472116944)\n", "(1500, 0.9821331889550623)\n", "(2000, 0.99133730373578777)\n", "(2500, 0.99891716296697342)\n", "(3000, 1.0)\n", "(3500, 1.0)\n", "(4000, 1.0)\n", "(4500, 1.0)\n", "(5000, 1.0)\n", "(5500, 1.0)\n", "(6000, 1.0)\n", "(6500, 1.0)\n", "(7000, 1.0)\n", "(7500, 1.0)\n", "(8000, 1.0)\n", "(8500, 1.0)\n", "(9000, 1.0)\n", "(9500, 1.0)\n" ] } ], "source": [ "BATCH_SIZE = 128\n", "\n", "# Launch the graph in a session\n", "with tf.Session() as sess:\n", " tf.global_variables_initializer().run()\n", "\n", " for epoch in range(10000):\n", " # Shuffle the data before each training iteration.\n", " p = np.random.permutation(range(len(trX)))\n", " trX, trY = trX[p], trY[p]\n", "\n", " # Train in batches of 128 inputs.\n", " for start in range(0, len(trX), BATCH_SIZE):\n", " end = start + BATCH_SIZE\n", " sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end]})\n", "\n", " # And print the current accuracy on the training data.\n", " if epoch%500 ==0:\n", " print(epoch, np.mean(np.argmax(trY, axis=1) ==\n", " sess.run(predict_op, feed_dict={X: trX, Y: trY})))\n", "\n", " # And now for some fizz buzz\n", " numbers = np.arange(1, test_number)\n", " teX = np.transpose(binary_encode(numbers, NUM_DIGITS))\n", " pred_label = sess.run(predict_op, feed_dict={X: teX})\n", " output = np.vectorize(fizz_buzz)(numbers, pred_label)\n", " \n" ] }, { "cell_type": "code", "execution_count": 158, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0,\n", " 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0,\n", " 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1,\n", " 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0,\n", " 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2,\n", " 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1,\n", " 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0,\n", " 1, 0, 0, 3, 0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0,\n", " 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, 3, 0, 0, 1, 0])" ] }, "execution_count": 158, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def setlabel(i):\n", " if i % 15 == 0: return 3\n", " elif i % 5 == 0: return 2\n", " elif i % 3 == 0: return 1\n", " else: return 0\n", "numbers = np.arange(1, test_number)\n", "correct_label = np.vectorize(setlabel)(numbers)\n", "correct_label" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 170, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from sklearn.metrics import confusion_matrix\n", "\n", "%matplotlib inline\n", "import itertools\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", " 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", " 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", " thresh = cm.max() / 2.\n", " for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n", " plt.text(j, i, cm[i, j],\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", " font = {'size' : 8}\n", " plt.rc('font', **font)\n", "\n" ] }, { "cell_type": "code", "execution_count": 171, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Confusion matrix, without normalization\n", "[[106 1 0 0]\n", " [ 0 53 0 0]\n", " [ 0 0 26 0]\n", " [ 0 1 0 12]]\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAcMAAAGICAYAAAA9GYtxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XecFPX9x/HX+xAFlKYUG4i9i4C9i8YeNfaGLbYYo7HG\nmJ8aNcUUe1RiNIq9xBKVGDWKGjsKgkbFBmIFDwUUFBE+vz9mDveOK7t7Zed2308e++B2ZnbmM7Oz\n+9lvme8oIjAzM6tkVaUOwMzMrNScDM3MrOI5GZqZWcVzMjQzs4rnZGhmZhXPydDMzCqek6GZmVU8\nJ0MzM6t4ToZmZlbxnAzLjKRLJE2RNFPS2s1c10GS3mip2LJI0hbpsVIJtt0v3faAJpabL2lo20RV\nPiQdJumDnOdXS7qmFbeX1/tp2eRk2EYkrSvpNkkfpx+Y9yTdImlQC25jE+AnwMCI6BYR/2vO+iLi\n1ohYs2WiazuStk4TSJPnd0Q8nR6rNh+XMCI+SLc9CRb+8m5LkkZJOr8U225lC97XiPhJRBzTEiuV\ndK6k/9baUJ3309oXJ8M2IGkb4AXgE2CTiOgGrA88CuzTgptaBZgaEZ+24DrbI5F8CTZa2pO0SNuE\nk7eauCuGpI6ljqEZKuq9KnsR4UcrP4A3gRvyWO5w4FVgOjAeODRn3grAfOBQ4BVgJvAssEY6/9fA\n18B3wJfAq+n0icCRdbYzHxia/t0PGAlMy9nu5um8w4APcl63GPAH4L10+SeAjXLmHwZ8AByTbvcL\n4E5giUb2+XrgduAqoBqYCpwELA/8O93P10h+RNS8ZmvgmXT5acBjJKXhmv2ZDcxLj8NM4MycY/Fr\n4CFgBnBGuq75JD8MBTwM/CNnW1sAX+Vuv4n38G7gNznPnwA+y3m+P/B2nfd0pXQ7ue/fTODAnPfr\nBODpdN64mvconV8FnA5MSI/5i8BOdd+XOnGeCzyV/n11ut1varbdwL41eg4WeI4cn74fM9Ppo4DL\n03NhBjA5PVbrpNuYCTwPrJqzrn2Al4DP0/Pmn8CAOtuaXOdcuzH9e4+c4zwz/Xs+6Wcuje/VNJaP\ngRuBJdN5BwFzgLk569g89/1sic+0H237KHkA5f4gKa3NB7ZrYrm90w/eNiRfytulH7Td0/k1H5xH\ngD7AosBdwKicddT68KfTmkqGNwN/BTqmz1cFVqhvfcAVJF/EKwKLAKekH+Blc5afC1yUxtcXeAs4\nt5H9vp4kCfwo3e/dSRLZY8Ba6bRLgTdzXrMpsAnQAVgcGA5MAhZJ52+drkP1HIuPSb+cgU45y1al\n05ZMlzs1Pc4fAj8t4P0+Fhid/t0lfQ/fBYak0/4GXJnzns6r+fKs7/3Leb/Gpse9CrgEmJQz/1SS\n5DEwnb8/yZf1oEbOiwXJMH0+Cji/iX3L5xzM9xwZnh6fTjnb/xzYIn1+IsmPkAdIfuAsAvwDeChn\nWzsA6+a8b/8Enm3o80BOMqxn385K3/dl0uc/AlZJ/+4HPAfc0tDxa+D9bPZn2o+2e5Q8gHJ/AJul\nH5DVm1ju38BFdaZdCvwr/bvmg5NbItgF+CrneTHJ8O/pl8ha9cS0YH3ph3kWsFudZV4BzshZfjZp\nYkmn/REY2ch+Xw88Wmfa5zXrTJ8PTo9h1wbW0TPdp7XT57USXJ1j8Zs60xZaFhjC9yWwmwt8vweQ\nlLKWBHYFHidJXmel8ycBe9R5T/NJhgfnPF8rjbl3+vxN4IQ6r7kPuKqR86I5ybDec7CAc+RbYLE6\ny4wC/pbzvFu6rf1ypu0FTGskvkHpcVm8vv2mgWQIHAVMIafUWc8ye1K7hN9QMsx9P5v9mfaj7R5u\nM2x9U0m+JJZvYrl+JCWIXO8A/XOeB0m7Y41ZQOd8Ooo04tR0O/dI+lTSdZL61LNcL6AzSfVXYzFW\nR8T8OjF2bSKGT+o8nwV8Wuc5NetJOyPdL+lDSdPTmILk13VTJjW1QES8TFJdtQ5wXh7rzH3tpDSe\nHdLHIyRtwztJWg1YliRBFqru+y6+P679aPp9aSmNnYP5niNTI2JOPeuuu15Y+DxYcC6lHaX+k3ZK\nm05SJQv5nQc169gD+BOwa0S8nTN9L0nPpD2zpwM3AUsW2Ou4VJ9pK4IPeCuLiHdIqgqHNbHoB8DK\ndaatQlL91RxfklQlAiBp2TrxfRERp0bEGiS/rFckqeasq5qkTalujCu3QIyFuovkS2WtiOhBErP4\nvsPM/IZe2MQ8ACQdD6ydbucGSR0KjO8/JInwByRtkE+QHNt9gRcj4sucZaOQ2Bp4XX3nTu77Uusc\nSC1b53kh225IvudIs7eVdrx5APgXSXVmD5JSPjTRcSpnHVsCI0hKny/lTF+OpK37MmD5dN01n9+m\nzrGm3peW+ExbK3AybBvHAvtK+rOk/gCSukoaJumCdJlrgSPTX7tV6XVlR5C059Uo5lq4l4ADJXWX\n1A34PTkfWEn7S1op/cU7i+87BtQSSR3O34HzJa0oqaOkk0k+7LcUEVehcve9O2mnB0lLklRD5n4J\n1ZQm1ih4I9LGJB1A9iHp/NAZuDhnfs1lG42Vuh4haXNaKiLGRsRskk4tp6XzGtqvT4Fe6T41GWrO\n39cCp0kamJ47+wE7k7RPQtLe2FXSvkpsQ5KYc30KrFbgdmtp43NkUZI23+kRMTv9kfebfF8saV2S\nquTjI+LROrOXINnPaRExV9KqwC/rLPMp0F/SYnVXnfN3a32mrRU4GbaBiHgS2BhYDnhR0kyS9qgd\nSToFEBH/IKmyvIqkR+BlwIkR8c/cVRWx+f8jSRwfAKOBe+rMH0hSbTcTeDvd9ukNrOtUki/zUSRt\nLD8Cto+Ij4qIqzH17WfutCOA/UhKPM8CD9ZaMKnuuhwYJelzSWc0st4FJPUiKQ3+MiKej4hvSJLi\nIWmCgaRN8G2gsX1+nKRzSO6X7MMk7WB1k2FuTI+TtN++lcZ9QCNx5067GLiS5Fz6nOT9+1FEjAWI\niIkkvVEvInl/jyZJWrkuAlZPt/t5I/vW1DlY7DnS1D7WnhExi6St7+z08zSSpDSXr71IflQNT6/7\n/TL9/8CImECS/G6SNIOkrfGmOq+/g6T37sfpMdusbsyt+Jm2VqDkx5yZ5UPSTcB9EXF3qWMxs5bj\nZGhmZhXP1aRmZlbxnAzNzKziORmamVnFy9pAxZkmaSmSHqCTSK6nMjPLik4kvZ0fjohpbbHB9BKj\nXkW+vDoi6r3mUtJlJEMzrgCsHxHj0+mrkFwb2otkvNcjIuL1dN4kkqEdvyHppfv7iLgr32CcDAuz\nI21zTZ2ZWbEOBm5t7Y1I6k/VIu8z/7tiVzFb0poNJMS7SK73fbrO9L8CwyPiJkl7AzcAG6Xzaobv\ne7WYYJwMCzMJYJH+P6CqU88Sh/K9uR89Tcfltih1GLU8fuMZTS/Uxn5x2sn84c+XlDqMWqra/p7C\nTTrjtJP5Y8aOUxZl7ThNePMNjjjsEMhjyMEW0ov539Gx//aoUz7jRHwvvvmcuZP/04WkhLdQMoyI\npwFyh7+T1Jtk3OAfpMvcLekvklaKiPeoPQpVwZwMC/MNQFWnnlR16V3qWBZQh0UzFQ/AoEGDSx3C\nQrp375G5uKqqspcMu3fvzqDB2TpOWZTh49SmTTjqvBRVXfIeDhaA+cX9COwHfFJn7OPJJGO91oyH\ne2OaQF8kGTyjOt+VOxmamVnxpOTRgHmfT2DeF2/Vmhbz6hunvbit5/y9ZUR8mI4l/FuStsVd812R\nk6GZmRVPVcmjAR2WWpMOS61Za9r82VP59o2CmzU/AJaRVJVTOuxHWs0aER+m/8+TdCnJcHl586UV\nZmbWPDWlw3wfRYiIz4AxpHcQkbQP8EFEvCepi6TuOYsfRDJAfd5cMiwDHXquWuoQ2oV99z+g6YWM\nffc/sNQhtAs+TqkmSoYNvqax2dJwkirOvsDDkr6MiNWA40huq3YWMINk0H7S5e5O7wMpkjbEQwsJ\nycmwDHTomc+dd2w/f3nlZf8DfJzy4eOUKqa018TyEXFcA9PfAjarZ/pEoFm9mVxNamZmFc8lQzMz\nK55URDVp9i4pcjI0M7PitUI1aSk4GZqZWTMU0YEmgy10ToZmZlY8lwzNzKziuc3QzMwqnkuGZmZW\n8VrhovtSyF5EZmZmbcwlQzMza4Yi2gyLv+1gq3EyNDOz4lUpeRT6moxxMjQzs+KVSZuhk6GZmRVP\nFNGbtFUiaRYnQzMzawaPQGNmZpWuTK4zzF56NjMza2MuGZqZWfE8HJuZmVW8MqkmdTI0M7Pi+dIK\nMzOzIkqGGby2Invp2dh80MrcdemxvPvwb5j18uXsuvW6Cy1z9k925b1Hfsu0Zy/mwatPYKV+vRZa\nZqct1ubJEacy7dmL+eiJP3D7n49qi/Az5Zmn/8u+e+3BKisuzxKdOjDygftLHVJmDb/qStZYdUV6\ndu3MVptvwkujR5c6pEzycaqjps2woIeToeWhS+dFGT/hQ37++zuJWHj+qYdvz3H7b8UJv7mNLYf9\nidlfz+GBK39Kx0U6LFhmz+3W59oLDuWG+55jg/1+x7aHX8wd/36pDfciG2bNmsV6AwdyyaV/QRn8\nAGbFXXfewZlnnMrZ55zH86PHst56A9l91x2prq4udWiZ4uNUj5o2w0IfGeNkmEGPPvsGF1w9kgee\nGF/vOfPTg7blwr/9m3899Rqvv/sJPz77Jpbp3Z3dt10PgKoq8afT9ubMi+/h+nufZeKH1bw1aQr3\n/ueVNt6T0tthx504+9zz+eEeexL1/bIwAK647BJ+fPSxHDzsUFZfYw2uuGo4nbt0YcQNfy91aJni\n41SPgkuFxVyk3/qyF5E1aoVll6LvUl0Z9eKEBdO+nPUNo197n43XWxGAwWv2Z5ne3QF49tZf8N4j\nv+XeK37CGistXZKYLdvmzp3L2DEvs+3Q7RZMk8TQodvzwvPPlTCybPFxKm9Ohu3M0r26EQFTp31Z\na/rUaTPp26sbAAOWWwoJfnXszvz+mof40c+uZvrM2Txy7Ul0X6JzKcK2DKuurmbevHn06dO31vQ+\nffsy5dNPSxRV9vg4NcBthtklaaKk9UodR1uStKB9sSq9PcqF1z7MA0+MZ9yEDznm3JuJgL1+MKiE\nUVp7EhFuZ82Dj1Mx7YXZO15lmQxbgqQOTS/V9j6tnokEfZbqWmt67yW7MnXaTAA++Sz5f8LE73+t\nzv1uHpM+rKbfMj3bLlhrF3r16kWHDh2YOnVKremfTZ1Kn759G3hV5fFxaoDbDIsjab6kX0p6QdK7\nkg7PmVerRCdptKSt0r9HSfqzpCclTZJ0vqSdJf1X0nuSTq6zqUMkvSTpLUmn5axzFUkPptt/RdLx\ndWL7taQXgd+12kFohvc/nsaUaV+y7UarL5jWdfFObLjOCjw/biIAY9+YzJxvv2PVFb7/gC6ySBX9\nl12KyZ983uYxW7Z17NiRQYOHMOrxxxZMiwhGjXqMTTbdrISRZYuPUwPKpDdpqS66/zoiNpa0OjBa\n0o0RMT+P1/WPiK0l9QAmAT0iYktJywITJF0XETPTZftExAaSlgLGSHoGeAG4DTg4It6S1Bl4XtIL\nEfFy+rq5EbFRi+5tgbp0WpSV+/deUJGw4nJLse5qy/HFjFl8OGU6f7llFL84aife/eAz3v/4c849\nflc+mjqdB54YD8BXs+dw7T+e5uzjduGjKdOZ/MnnnHL49kQE9zw6tnQ7VgKzZs3i3XffWdCTdOLE\n9xg/fhxL9lyS5fv1K3F02XHiz0/h6CMPY/DgIWyw4UZccdklfD17NsMOPbzUoWWKj1M9PDZps9wK\nEBETJM0FlgY+zuN1/0hfN13Se8CD6fOPJX0GDADGp8tel86bJukeYDtgOrA2cLu+r+RfAlgLqEmG\n1zcVxNyPnkYdFq01rUPPVenQc7U8dqFpg9fuz8PXnEgERMCFp+wFwM0PvMBx593CxSP+Q+dOi/KX\n/zuQ7kt05pmx77LHCVcx97t5C9Zx5iX3Mve7eVx7wTA6d+rI6FffZ+djL2fmV9+0SIztxZiXX2Ln\nHYYiCUn88hdJJcHBww5l+DUV3B2+jn323Y9p1dWcf945TJ0yhfUGrs/9Ix+md+/epQ4tU7JynO64\n/TbuuuO2WtNmzJjRpjEsUCZjk6qtr72SNA/oWVOCS5PYkIiYLOltYL+IGJvOexX4aUQ8JWkUcElE\n3J/OGw2cGhFPpc/fBvaPiDGSJgKHRsR/03mXANXAvcAjEbF8PrHVM38w8PKiq+1HVRd/STRm2gtX\nlDqEdqGms5NZc40dM4bNNh4CyffpmNbe3oLvw23PpqrHCgW9dv709/l21AXQRrHmoxStmI19+t8B\nNgaQtBGweiPLNuXwdD1LAj8C/gNMAGbUaadcOa12bSo2MzOrQ2hBzUvejwx+1ZaimrRuUTT3+f8B\nIyQdCzwHvJbn6+o+D+AzSS8B3YDLI+IFAEm7AZdJ+jnJ/n8GHERSheohSszMClCT4Ap9Tda0eTKM\niA51nvfJ+ftlYJ0GXje0zvON6jxfLefvlRrZ/kRg93xiMzOzJhRz2WATy0vaCbgA6AjMBo6LiPGS\negM3AisD35A0o/230JDr41s4mZlZ8VRESa+RxdNmq5uBLSLiTUlbALcA6wJ/AJ6LiJ0lbQDcK2lA\nRMxreI35cTI0M7OitUI16cpAdUS8CRART0vqJ2kQsG86n4h4SdJHwNbA48XEnit7wwCYmVm70Qod\naN4GlpK0CYCk3YGuwIrAIhExNWfZ94H+LbEfLhmamVmrmfv+c8yd/Hztid9+3eDyETFT0j7AhZIW\nJ+lM+TrJNeF1Ozm2WE8cJ0MzMytaU9Wkiw7YjEUH1B6ubt7nk5j1yDkNviYingS2Sde/KPAJ8DQw\nT1KfnNLhCsDk5sRfw9WkZmZWPBX5aGyVUu7NV88BHouI94C7gJ+ky2wILAs82RK74ZKhmZkVrZWu\nM7wg7UXagaSa9Kh0+pnATZLeAuaQjDPd7J6k4GRoZmbN0cKXVgBExNENTJ8K7FjYxvLjZGhmZkWr\n6U1a6GuyxsnQzMyK5uHYzMzMWmE4tlJwb1IzM6t4LhmamVnRXE1qZmYVz8nQzMyMbCa3QjkZmplZ\n8cqkA42ToZmZFc3VpGZmVvHKJRn60gozM6t4LhmamVnRyqVk6GRoZmZFczI0MzODTPYOLZSToZmZ\nFa8VbuFUCk6GZmZWNFeTmplZxXMyNDMzK5MRaHydoZmZVTyXDM3MrGiiiGrSDBYNnQzNzKxobjM0\nMzPzpRVmZlbpXDKsYE/c9AsGDR5c6jAy7dT7Xy91CO3CRbuvVeoQzJqnTHqTOhmamVnRyqUDjS+t\nMDOziueSoZmZFc1thmZmVvGk5FHoa7LGydDMzIpXRMkwi9nQydDMzIrmkqGZmVU8UXgbYAZzoZOh\nmZkVzyVDMzOreKoSVVUFlgwbWV7SksBjQKSTFgdWBPoA9wH9genpvBERcVmBIdfLydDMzDIjIj4H\nBtU8l3QqsFVETJcUwEkR8UBLb9fJ0MzMitYG1aRHAmfmvrywreXHI9CYmVnRaoZjK+iRZz6TtBnQ\nExiZM/lCSeMk3SZpxZbaD5cMzcysaE2VDKe/NooZ/xtVa9q8ObPyXf2RwI0RMT99fkhEfJRsVz8F\nHgTWLjDkejkZmplZ0Zoajq3nukPpue7QWtO+/uRt3rn2+KbWuziwH7BBzbSaRJj+faWkP0vqGRFf\nFBn+Ak6GZmZWvNYbgeYA4JWIeCt5iToAS0XE1PT53sCnLZEIwcnQzMyaoRU70BwBXJPzfDFgpKRF\nSS67+AzYvbAtN8zJ0MzMMicitqjzfDawYWttz8nQzMyK5uHYzMys4nk4NjMzq3i+ua+ZmVU8lwzN\nzMx8c18zM6t0SQeawl+TNU6GZmZWtHJpM/RA3WZmVvFcMjQzs6K5A42ZmVW8cqkmdTI0M7PiFVEy\nzGIPGrcZtnPDr7qSNVZdkZ5dO7PV5pvw0ujRpQ6pZEbfeRVX7bNOrcdtJ/1wwfwn/noeN/90J645\ncAjXH7ElD134M774aGIJI84Wn0v58XGqrWY4tsJu7ps9Lhm2Y3fdeQdnnnEqV159DRtsuBFXXHYJ\nu++6I+Nff4tevXqVOrySWLLfquzx6+sIAoCqqg4L5vVZeW1W32o3lui1DHO+msGLd1zJgxccwyFX\nP5LJapu25HMpPz5OCyuXNkOXDNuxKy67hB8ffSwHDzuU1ddYgyuuGk7nLl0YccPfSx1ayVR16EDn\n7kvSpftSdOm+FJ269lgwb63t92GZNYfQtfey9FpxTTY+8ES+mvYpX079qJE1VgafS/nxcVpYwaXC\nYi7SbwNOhu3U3LlzGTvmZbYdut2CaZIYOnR7Xnj+uRJGVlozPnmfEUdvy83H78Sjl/2CL6s/qXe5\nud/M5o3H76Fbn+VZotfSbRxltvhcyo+PU3lzNWk7VV1dzbx58+jTp2+t6X369uWttyaUKKrS6rvq\negw94bf0WG5FZn/xGaPvuJL7zj6MAy65j46dugDw2r9v57mbLmLunK/pudxK/PCcv1HVobI/Bj6X\n8uPjVL9y6U1aliVDSbtLel3SWElzJS1e6pjaSkRk8kRrC/0HbcHKm+7AUv1Xpd/Azdj1V8OZ89VM\n3nn24QXLrLb1D9nvorv50QUj6LHMCjx80SnMm/ttCaPOrko+lwpR8cdJ37cb5vvIYg+askyGwHHA\neRExKCI6RsSsUgfU0nr16kWHDh2YOnVKremfTZ1Kn759G3hVZVls8a70WHYFZnwyecG0RTsvTvel\n+7PMmkPY4bSL+eKj93jvxcdKGGXp+VzKj49T/UQRbYYZzIZllwwlXQZsCfxO0jOS5kvqJmlgWlIc\nk/4/Q9LZknauM/1rScNKvR9N6dixI4MGD2HU499/kUcEo0Y9xiabblbCyLJj7tezmPHpByzes4Fe\nfhEQVHzJ0OdSfnyc6ldoqbCY3qdtoewaSyLiJEnrARdHxAOS5qXTxwGDACRtA1wDXBsRnwAPpdMP\nBk4B7ilF7IU68eencPSRhzF48JAF3by/nj2bYYceXurQSuLZEX9mwAbb0LX3snz1+RRG33ElVR0W\nYdUtd2XmlA9555mH6Lf+5nTq1pOvqj9l7L3XsshinVhh8FalDr3kfC7lx8dpYeXSZlh2yTCH6vyf\nPJHWBq4HdkkTYc30bYFzgS2bqlY947ST6d69e61p++5/IPsfcGBLxJ23ffbdj2nV1Zx/3jlMnTKF\n9Qauz/0jH6Z3795tGkdWfDXtUx699Ay++Wo6nbv1ZJk1BrP372+lU9cezPtuLh+/MYbxI29mzqyZ\ndO6+FMuutQF7/fYWOnfrWerQS87nUn6ycpzuuP027rrjtlrTZsyY0aYx1CiX6wwVEaWOocVJGgVc\nEhH3S5oP9IiImZKWBZ4EjoqIJ3OWXwe4nyRBvtnIegcDLz/7wssMGjy4lfeifTv1/tdLHUK7cNHu\na5U6BCsTY8eMYbONhwAMiYgxrb29mu/Djc64gW79Vi/otTM/mMCLfzwc2ijWfJRdm2FDJC0BPAic\nUycRLgfcCxzRWCI0M7PyVa7VpFHP33sBqwOnSzojnT4cWBroBVyipCI7SBLmg20Yr5lZu1Qu1aRl\nmQwjYmjO3zWDU96YPupzfqsHZWZWhmoG6i70NVlTlsnQzMzahgRVLhmamVkl86UVZmZW8dxmaGZm\nFU8UPryah2MzMzPLIJcMzcysaO5AY2ZmFa/mrhWFviZr8kqGkkZT+0L2WiJioxaLyMzM2o1K60Bz\nZqtGYWZm7VKVRFWB2a2p5SUtClwE7Ah8DYyLiEMlrQKMIBk1bDpweES8UUzcdeWVDCNiwQ28JHUA\n+kXEpJYIwMzM2rFi7k/Y9PJ/AOZHxGoAkvqk0/8KDI+ImyTtTZIYW6RmsqDepJK2BD4Ankqfbyhp\nREsEYmZm7U9STVro3e4bW5+6AEcCv6qZFhFTJfUGhgC3pNPuBvpJWqkl9qPQSyv+CGwNTEuDGQ1s\n0BKBmJlZ+5OMTVrgo/FVrgx8DvxK0mhJT0oaCvQDPomI+TnLTgb6t8R+FNqbdJGIeLtOz6FvWyIQ\nMzMrP5Of/zcfvPBwrWlzZ3/Z2Es6AisAr0XELyWtDzwK7MrCebTFuuIUmgznSFqctGeppLWAb1oq\nGDMza1+a6kAzYNOdGbDpzrWmfTHpDR799cENveR9YB5wK0BEvCJpIkmCXFpSVU7psB9J6bDZCq0m\n/S3wCLCspBuAx4GzWyIQMzNrn1TgozERMQ14DNgJQNKKwADgaWAMMCydvg/wQUS81xL7UFDJMCIe\nkvQ2sDPJPv0uIt5qiUDMzKz9aaW7VvwEuE7SH0hKicdExCeSjgNukHQWMAM4ooiQ61XMCDQfATUX\n4X/QUoGYmVn7U1XEcGxNLR8RE4Gh9Ux/C9issK3lp6BkKGkb4HZgKknJsJekAyLiyVaIzczMMq5S\n72d4ObB3RDwDIGlTkosg12vpwMzMrH3IYG4rWKEdaKImEaZPnqORMUvNzMzag0KT4WOSDql5Iukg\n4D8tG5KZmbUXhY8+U3i1alvI964Vn5GUAAX8XNLf0lmLAdXAqa0TnpmZZVlrdKAphXzbDDdp1SjM\nzKxdqhmbtNDXZE2+d614t7UDMTOz9imDua1ghV5a0Qs4FxgIdKqZ7pv7mplVpta4n2EpFNqB5jrg\nU2Bp4Pckd694pKWDMjOz9qEV7lpREoUmwxUi4rfANxFxL7AHsF3Lh2VmZtZ2Cr5rRfr/t5KWBL4A\nerVsSGZm1l5U6gg076VJ8FbgeWA6MLbFozIzs3ahpuqz0NdkTaF3rTgw/fNiSWOAHsCDLR6VmZm1\nCyqiA005lAwXiIgnWjAOMzNrhyqqZJgzAk29IqJPi0VkZmbthiiizTCD/Uk9Ao21iot2X6vUIbQL\nr0yaXuoQ2o31B/QodQhWD1H4ZQnZS4UegcbMzJqhXIZjKzShm5mZlZ2iO9CYmZlV2l0rzMzMFqIi\nkmG7ryaV1E3SpZL+mT5fU9J+rROamZllXbnc3LfQNsPhJKPOrJw+fx84q0UjMjOzdqOK76tK836U\nOuh6FBrl/HdSAAAgAElEQVTTGhHxa2AuQETMJpu9ZM3MrA0UfMeKIi7SbwuFthl+m/tEUiecDM3M\nKla5DMdWaMnwKUlnAotJ2ga4E7ivxaMyMzNrQ4Umw18BHYGvgYuBl4DzWzooMzNrH6qKfGRNoXet\nmAtckD7MzKzCVdRA3TUk1dtzNCJ+1zLhmJlZe1IubYaFdqDpnfN3J2Bn4NmWC8fMzNoTUUTJsFUi\naZ5Cq0lPzn0uqRdwXYtGZGZm7YaHYwMiolrSyk0vaWZm5agiq0klHZ/ztAOwMfBZi0ZkZmbtRkV2\noAE2zfn7O+BN4KSWC8fMzKzt5Z0MJXUA7o4IX2RvZmZA67YZSjqCpF/KnhFxv6QngP4kY2QDjIiI\nywrbev3yToYRMU/SOXjEGTMzy6FW6B8qqT9wFPBczuQAToqIB1p6e4UOBDBO0qZNL2ZmZpWgNe5a\noaSHzXXACdQZE5tWujKj0GQ4GPivpNclvVjzaI3AzMws+wpOhPlVq54C/DcixtYz70JJ4yTdJmnF\nltqPQjvQnNJSGzYzszLQxM16xz52P688/mCtad98NbOR1WktYB9gi3pmHxIRH6XL/RR4EFi78KAX\nllcylHRbRBwYEY+1xEbNzKw8NFXSG7L97gzZfvda0z586zUuPWaPhl6yFUknmbfT6tKlgWskLRMR\nf61ZKCKulPRnST0j4otm7kbe1aRrNHdDZmZmTYmI4RGxXESsFBErAs8DxwB/k9SnZjlJewOftkQi\nhPyrSaMlNmZmZuWlDS66r8k/nYCRkhZNp30G7N7gqwqUbzJcT9Ln9UwXEBGxZEsFZGZm7YcoYji2\nAjqERsTQnKcbFrShAuSbDCcAu7RWEGZm1j6Vy0Dd+bYZzomI9xt6tGqE1qjhV13JGquuSM+undlq\n8014afToUoeUOT5GtY0YfjFH7r0d263fn102WY1fHH8Ikye+s9Byr459kRMO3YOhA5dn+0H9Of7g\n3fh2zpwSRJwtPp9qq6kmLfSRNfkmwwyGbnfdeQdnnnEqZ59zHs+PHst66w1k9113pLq6utShZYaP\n0cLGvfQc+w47muv+8SiXj7iX7+bO5aQj9uKbb75esMyrY1/klB/vyyZbbsff73mc6+8dxT6HHE1V\nVaGXJpcXn08Lq0JFPbImrzM7Iga1diBWuCsuu4QfH30sBw87lNXXWIMrrhpO5y5dGHHD30sdWmb4\nGC3s4mvvYuc9D2DAKquzyuprc/YfrmLKxx8y4bVXFixz+e/+j/0P/wmHHH0iA1ZejX4DVmboznuw\nSMeOJYy89Hw+1aOYUmH2cmHBI9BYRsydO5exY15m26HbLZgmiaFDt+eF559r5JWVw8coP19+OQNJ\ndOveE4AvplXzv3Ev0b3nkhyz/47suunqHH/wbox7+fkSR1paPp/q10oj0LQ5J8N2qrq6mnnz5tGn\nT99a0/v07cuUTz8tUVTZ4mPUtIjg0t/8kvWGbMKKqyaXE3/8wSQA/n7FH9nzgCO49O//YPW1B3Li\noXvy4fsTSxhtafl8Km/tNhlKmi+pW6njyJqIyORdpLPEx+h7fzr3VCa9M4ELLr1uwbT5MR+APQ88\ngl1+dACrrrkuJ531W/qvtAoP3n1zqULNrEo/n6rSO90X+siaQscmzZKKHgigV69edOjQgalTp9Sa\n/tnUqfTp27eBV1UWH6PG/fm803nuyUe5+rZ/0avP0gum9+qd/D1g5dVqLT9g5dWY8vGHbRpjlvh8\nalgGc1vB2m3JkKQJ9nRJYyS9KemgBTPqlBolfSapv6SBksamrxkraYaksyXtXGf615KGlWSv8tSx\nY0cGDR7CqMe/Hy42Ihg16jE22XSzEkaWHT5GDfvzeafz3//8i7/c9ABLL9uv1rxllu9Prz7LLHS5\nxeSJ7y60bCXx+VS/pA2w0JJhqaNeWHsuGQLMi4jB6W08XpL0dERMZuFSYwBExDhgEICkbYBrgGsj\n4hPgoXT6wSR357inbXaheCf+/BSOPvIwBg8ewgYbbsQVl13C17NnM+zQw0sdWmb4GC3sT+eeyqMP\n3s0fh99K5y5d+Lx6KgCLd+3GYot1AuDgo37GdVdcyCqrr82qa67LyHtuZfLEd/j9X24sZegl5/Np\nYW0wHFubaO/J8FqAiJgo6SmS0c5vZuGOu7WeS1obuB7YJU2ENdO3Bc4FtoyIWQ1t9IzTTqZ79+61\npu27/4Hsf8CBzdiVwu2z735Mq67m/PPOYeqUKaw3cH3uH/kwvXv3btM4sszHaGH33nY9kvjpIT+s\nNf1XF17JLj86AID9Dz+Oud/O4fLf/4qZM6azyhprc/mIe1m23wqlCDkzsnI+3XH7bdx1x221ps2Y\nMaNNY6ghCq9izGAuRBHts+lN0nxghYj4IH1+L/CPiLhF0lygT81o5pK+BNaOiMmSlgWeBI6KiCdz\n1rcOcD9JgnyzgW0OBl5+9oWXGTR4cKvun1WGVyZNL3UI7cb6A3qUOoRMGztmDJttPARgSESMae3t\n1Xwf/vqmkQxYY92CXjvpzVf59bBdoY1izUd7bjMEOAJA0gCSG0E+lU5/B9g4nbcX0CX9ewmSm0Ge\nUycRLgfcCxzRUCI0M7Py1Z6rSQPoIGkMSbL7WU0pETgZuFzSTGAkMC2dvhewOknHmzPSdQwnuXlk\nL+CS9GaSQZIwa9+e2czMailmQJksVpO222QYER3SP8+tZ96/gdx+4TXL3Jg+6nN+y0VnZlYZirlu\n0NcZmplZ2cleaiuck6GZmRVNFHFpRatE0jxOhmZmVjRJBQ9Hl8Xh65wMzcysaFUUfllCFi9jcDI0\nM7PiFVEyzOIQNFlM0GZmZm3KJUMzMyuarzM0M7OKlwzUXWgHmlYKphmcDM3MrGjuQGNmZlYmHWic\nDM3MrGhuMzQzs4pXLiPQZLHq1szMrE25ZGhmZkWrQlQVWNYrdPm24GRoZmbFUxH9YbKXC50Mzcys\neEr/FfqarHEyNDOzoqmIkmEGr6xwMjQzs+KVS5uhe5OamVnx9H3pMN9HU7lQ0sOSXpE0VtKTktZP\np68i6RlJEyS9IGnNltoNlwzNzKxorVRNum9EzEyW1Z7ADcD6wF+B4RFxk6S9gRHARoVtvX4uGZqZ\nWabUJMJUD2C+pN7ABsAt6TJ3A/0krdQS23TJ0MzMipbUehbamzSPZaQRwLZAALsA/YCPI2J+zmKT\ngf7AewUFUA8nQzMzK1oVUNVIdnt85D2MGnlPrWlffTmzgaW/FxGHAUgaBvwROJuF82iL9cRxMjQz\ns2Zo/DrD7Xbdm+123bvWtLf+N46f7LNdXmtP2wf/CnwALCOpKqd02I+kdNhsbjM0M7OiFdqTtKkO\nN5K6S1om5/meQHVEfAa8DAxLp+8DfBARza4iBZcMzcysGVphBJruwF2SOpG0F04FdkvnHQfcIOks\nYAZwRMEBN8DJ0MzMilalxtsMG3pNQyJiMrBxA/PeAjYrbGt5xtQaKzUzM2tPXDI0M7NmKLyaNIu3\nrXAyNDOzonmgbjMzq3h5DDVa72uyxsnQzMyKViVRVWBRr9Dl24KTobWK+fOj1CG0C+sP6FHqENqN\nqTO+KXUImfb5V3NKsl2XDM3MzCCb2a1AToZmZtYshfcmzR5fZ2hmZhXPJUMzMyuaL60wM7OK5w40\nZmZmZZINnQzNzKxorXDXipJwMjQzs6K5zdDMzIxM1noWzJdWmJlZxXPJ0MzMiucONGZmVuncgcbM\nzCqeKKIDTatE0jxOhmZmVrQyqSV1MjQzs2Yok2zoZGhmZkVzm6GZmVkRF91nMBf6OkMzMzOXDM3M\nrGhl0mToZGhmZs1QJtnQydDMzIrmDjRmZlbxfNcKMzOreGVSS+pkaGZmzZTF7FYgX1phZmYVzyVD\nMzNrlix2iCmUk6GZmRWtXDrQuJq0nRt+1ZWsseqK9Ozama0234SXRo8udUiZ8szT/2XfvfZglRWX\nZ4lOHRj5wP2lDimzfC4t7MXnnubHB+/DRuusxIDeXXj0oQcXzPvuu+/4/Xm/YsetNmTNFXqx0Tor\nccpPj2LKp5+UMOK2pyIfja5TukzSREnzJa2XM32SpDckjZU0RtK+LbUfTobt2F133sGZZ5zK2eec\nx/Ojx7LeegPZfdcdqa6uLnVomTFr1izWGziQSy79C8riz9GM8LlUv9mzZ7PWOutxwR8vXej8+frr\n2bz+2nhOOv0s/vX481xz4x28985bHD2sxb6f24fWyIZwF7A5MKnO9PnAfhExKCIGR8RdLbIPuJq0\nXbviskv48dHHcvCwQ5PnVw3noYdGMuKGv3PqaWeUOLps2GHHndhhx50AiIgSR5NdPpfqt812O7DN\ndjsAC58/Xbt246a7Hqg17fwLL2GPHbfik48/ZJlll2+zOEupNS66j4inAbTwL9hiruTIi0uG7dTc\nuXMZO+Zlth263YJpkhg6dHteeP65EkZm7Y3PpZYzc+YMJNGtW49Sh9JmatoMC300w42Sxkn6m6Re\nLbQbLhm2V9XV1cybN48+ffrWmt6nb1/eemtCiaKy9sjnUsuYM2cOF55/NnvsvT+LL7FEqcPJjAfu\nuZMH772z1rQvZ84odnVbRsSHkjoAvwVGALs2L8JEJpKhpN2BC4E5wDpAj4iY1cjy89NlZrZRiO1G\nRLhtzFqEz6X8fffddxx/5MFI8Js/XlbqcNpcY2fJ7nvtx+577Vdr2mvjx7LnDzYveDsR8WH6/zxJ\nlwIt9mstK9WkxwHnpY2iHRtLhKmKb/zp1asXHTp0YOrUKbWmfzZ1Kn369m3gVWYL87nUPEkiPIiP\nP/6Qm//xYOWVClunA83Cm5G6SOqeM+kgYGwzIq+l5MlQ0mXAlsDvJD2TdqXtJmlgTvfZsZJmSDq7\n5mXA6em8NyUdlLO++ZK65Tz/TFL/htYnaec607+WNKxtj0LhOnbsyKDBQxj1+GMLpkUEo0Y9xiab\nblbCyKy98blUvJpEOPn9Sdx2z7/o3qNnqUNqcyryX6PrlIZL+gBYDnhY0ltAH2CUpFckjSPJG4e2\n1H6UvJo0Ik5KryO5OCIekDQvnT4OGAQgaRvgGuBvOS+dFxGDJa0IvCTp6YiYzMKlxmhkfddGxCfA\nQ+n0g4FTgHtaY19b2ok/P4WjjzyMwYOHsMGGG3HFZZfw9ezZDDv08FKHlhmzZs3i3XffWdATcOLE\n9xg/fhxL9lyS5fv1K3F02eFzqX6zZ81i0sR3F5w/k9+fyOuvjadHz570XXpZjjv8QF5/bRx/v/Ue\n5s6dy2dp6bpHzyXp2LFjKUNvM6KIi+6bmB8RxzUwa3BhW8pfyZNhDtX5P3kirQ1cD+wSEZ/mzLoW\nICImSnoK2Aq4ue7rm1jfJznTtwXOJWmgbbSa9ozTTqZ79+61pu27/4Hsf8CBje5gS9tn3/2YVl3N\n+eedw9QpU1hv4PrcP/Jhevfu3aZxZNmYl19i5x2GIglJ/PIXpwFw8LBDGX7N30scXXb4XKrf+FfG\ncMCeOy44f35zzpkA7H3AIfz89LP4z8MjkcTO22wMfN/Oevt9D7PxZlu0Wlz/vPsO7r+n9iV2M4vv\nlNIs5XLXCmXh2itJo4BLIuL+3M4xkpYFngSOiognc5afD6wQER+kz+8F/hERt0iaC/SJiC/SeV8C\na0fE5EbWtw5wP0mCfLOROAcDLz/7wssMGtxqP1DKwvz5pT+v2oOqqix+LWTT1BnflDqETHt13Fh2\n224zgCERMaa1t1fzffjAY8+yzsBBBb32tXFj+WEbxpqPkrcZNkTSEsCDwDm5iSvHEelyA4AtgKfS\n6e8AG6fz9gK6NLY+ScsB9wJHNJYIzcxsYa3RZlgKWUmGUc/fewGrk3SUqengckzOMh0kjQH+Dfys\nppQInAxcLuklYCAwrYn1/RjoBVySM3231tpRMzPLnky0GUbE0Jy/O6R/3pg+6lu+Zplz65n3b2C1\nnEk1yzS4PuD8QuI1M7NUMSPKZK9gmI1kaGZm7VO5dKBxMjQzs6KVy/0MnQzNzKwZyqNs6GRoZmZF\nc8nQzMwqXnmUC7NzaYWZmVnJuGRoZmbNksVqz0I5GZqZWdGKGVEmiyPQOBmamVnxyqTR0MnQzMyK\nVia50MnQzMyK50srzMys4iUlw0LbDLPHydDMzIpXJvWkvs7QzMwqnkuGZmbWLBks6BXMydDMzIrm\nDjRmZlbxfNG9mZlVPFFEybBVImked6AxM7OK55KhmZkVrVzaDF0yNDOziueSoZmZNUPhHWiy2Gro\nZGhmZkUrl2pSJ0MzMytamYzG5mRoZmbNUCbZ0MnQzMyKVi4X3bs3aRm44/bbSh1Cu3DnHT5O+fD5\nlJ9/3n1HqUPIhJo2w0IfWeNkWAbu8pd8Xu664/ZSh9Au+HzKz/333FXqEDJDBT6yyMnQzMwyRdIq\nkp6RNEHSC5LWbO1tOhmamVnxCi0W5lc8/CswPCJWB/4IjGiFyGtxMjQzs6KpyH8Nrk/qDQwBbgGI\niLuBfpJWas39cG/SwnQCmPDmG6WOo5YZM2YwdsyYUodRy/yIUoewkBkzpjN2bLaOU1UGexJk8XwC\n+PyrOaUOoZaZM2fw6rixpQ5jgXfemlDzZ6e23O6EN98ouB2wie/QfsAnETE/Z9pkoD/wXoGbypsi\ng19aWSXpINJfK2ZmGXVwRNza2huR1B94A+hS5CrmAKtFxOQ66x0M3BIRa+ZMexE4IyKeKHJbTXIy\nLICkpYAdgUnAN6WNxsyslk7AAODhiJjWFhtME2KvIl9eXTcRpuvsDbwNLFlTOpT0CbB5RLhkaGZm\nlUHS48CIiBghaR+SUuFGrbpNJ0MzM8sSSasBNwBLATOAIyLif626TSdDMzOrdL60wszMKp6ToZmZ\nVTwnQ6soUgYv7Ms4H7PC+Zi1P06GFST3A5p2X64okhRpI7mklST5/G9CnWPWv9TxtAd1jtlASV1L\nHZM1zV8GFUJSVc4H9HjgTEmLljisNlPnC+qnwM1kdwD9TKhzzI4nGS/SGlHPMXsE6FHaqCwfToYV\nIufi1c2B9YALI+Lb0kbVdnK+oI4GjgaWB1Zx6bBhOcfsKOAEYH1JK0jqUNrIsivnmB0HHAi8D7Tq\nmJrWMvxFUCEkVUlaD/gv0DciPquEkmGdquFjgJ8C+wLPA4vVGf/Q6pD0E+B4YG/gWYCImFfSoDKo\nznl2APAz4GDgZZIfXjXzPB50RjkZlrHcD2hEzI+I8STJYDdJW0fEt+Xc0F+nanhVYDawe0S8TXLu\nz0nnbS+pVUe3aC9yS8qSVgbmAXtGxBskw33V1DBsnf64qnh1qkbXBaYDO6ZDjc1JnyNpT2CXcv7M\ntWf+lVKm6nxAdyAZP3B8RFydVnM9IukHEfFU7rLlIt2nmi/uI4BNgONy9nNxoIukg4FfATuXJtLs\nqHPMDiOpTj8tIiIt0XQnOWaHAL8AdildtNlQ53N2NEmtw+4RUTN28bfAIpL2A85L55XVZ61cOBmW\nqZwP6AnAAcBzwJ8lHRsRf0kT4hOStoyIZ0oZa0tLS4Q1X+pHA78h6SxzuqRZaTXfxyRfTksC+0bE\n+yULOAPq+VL/I/Al8CtJcyPiO0kTgbOBFYADIuKD0kWcDTnH7BjgZGBpknvvvZeeZ98AfwKqgb3T\nWgnLIFeTljFJ2wO7A0NJGvLHA/+W1CEiLiNp1/i8hCG2ipxEeDJwBLA18B/g65z2rneBtYCjW3vM\nw/Yg50v9FOAwYCvgqYj4JueYfQpsDhzjY/a99AfnsSR3tPkX8F3OMRsDzAR+HBGvlyhEy4OTYXmb\nDYwATgT2IKmimQscKWm5iLgybQsqC5IOk3RV+nc3kpuEHhQRbwJrkAz6i6QNSX4cbF1O+1+MOh0/\nlgRWBQ6JiFeBgek0JA0CXgW29DGrdcwWIWlX3SttI+xJen8/SdsAnYHdKv2YtQdOhmWigUb5KuAa\nYJ+I+EHaYWYYSXIsq/de0i7Az4G/SlonImZGxCkRMUlSd2AJ4Ju0jfAi4LGI+KiUMWdBTolwa5K7\nA5yQHrPeJB1mvkrbCP8E/DsiPixdtNmQc8wOBFaNiKsj4v206aEbSRvhAcClwH8j4tMShmt58l0r\nykCdNrIfktzg81VgLEmD/q9J2s36kJQQDy2nai5JSwA3ATeStNGMBP4VEbvlLHMTMBnYhqQjzasl\nCDWTJHUG3iOp4jsq58v+ZuBNko4yx/qY1SZpBLAFsHNEvJVOG07S0Wg54PiIeK2EIVoBnAzbOUlb\nklRd/S4dWeVnwNPA6sALJPcEW5uk3bAauCmtNiwb6fWSfwLWJKmWOgL4BzApIvZMl3kynb9Vue1/\noerrPSypL0m76nMkiS8kjQWWJTlmE0oQauZJ+guwHcnlJxMk/RkYRlIFX9HnWXvjZNjOSdoUuA/4\nO8kv0vMiYoqkrUg+lM9HxHWljLEtSPoZcC4wMiIOS0s7rwBvRMSekrYD3ouIiSUNNEPS6s9/RcTn\n6fMlgZeAUcBRwJ7AuIh4r3RRZouSIda+jojrc6ZdQ5IQdyPptTzT1cntT1m1G1WatHr0OZIeo/sA\n2wJ90+lPAf8D9qmQi3z/CfwQ6CHpSpL2rnWALSRdHxGPOREu5DBgvKSeAGlSPIGkZP1/wD8rPRHW\n89mZDlyX/pCocRawGHAZ8LYTYfvkZNgO1YwSEhHz08skXiAZB3ERYFe+Hxi4mqRbd9kPuxYRk9Mf\nBmeQjAV5LklnhmWA35YytiyoM7LMIgAR8QPgKeBlSUulsxchaV++vZKHqlMidwSjrpIWj4hbSdrd\nR0g6NF18G+BKkktO5pYmYmsuV5O2Y5L2AlYGHo2IVyRtDNxCctnAMyTVNkdExLgShtnmJK1C0pnm\nv8AvK/lLHUBSl4iYnf59HMn1lV2B30TEu2lHmY1J7rCwMzA0IiaVKt4skDSg5hhIOp2ko8zKwO8j\n4hZJOwO3Ao+SXHs51O2q7ZuTYTsl6cck1TOPkVSRHhsRd0lan+QD+iBJIqjIbt2SViK5+HlyqWMp\npfQSiTdJqozXBq4guQTlRJIqv2si4sn0fFqE5EL7ir0mLq0W7U4yGMXpwOPAcJKalz2ATYFnI+JS\nJWOzdgc+qPQfD+XAybCdqDNcVg/gIOD+iPhQ0rHAqcCv0oQ4EJgVEe+UMGTLCCUDRP8NuJOkN/Hz\naVXphcA6EbFTSQPMkJrLlCRtC9xPcnnSlRFxRzp/P5LrVLd0AiwvHpu0nchJhMcBm5EMojxe0scR\n8VdJAVwt6buIuLeUsVq2RMR9kmYD/ya5dOL5dKzRs4AnJS3vTh+1r9eNiFGSNiO51dduwB3p9Dsl\nHURyze6kUsVqLc/JsB2RtA/wE5IBpoeQ9J58n6Sa5hpJc0nGHzWrJSIeSUfpuVHSeJKexnuRXJf5\nVUmDy4C05qVm4IojSa4TPEzSD0h+MEwAbgc2BAYBFT96UblxNWk7kY4ssytJNdczaSeR64AXSapx\nJpUyPmsfJO0K3ENSZToHuKLSOljVpYXvcnIB0AFYPSI+l7Q58BDJQOW3AP8opxGcLOFLKzKqnuub\ntiQZFX8TSV3T9sAjgB2Ao+Q7aFseImIkSYlwR5IOVhWdCKHeu5xsQ9IJ7au0xPgM8AOS8W2vcyIs\nT/4CzaicNsKhJKOonCHpS5IL61+V9ExEvCdpj3Tx70oZr7UfETFS0koRUdHVo0puYLxxRByv2nc5\nmSRpDWDJiPhU0hYkHWlWjIg5pYzZWo+rSTMqLRkuSjJe5PvAqekwa78j6Sb/N5I7L8wuYZhm7VLa\nfvpb4HBgXu6A2krucjIa2IhkkPITSO788nEJQrU24mSYIQ0MoLwUyT0JpwJnRsRUSZcDfYEjI2JW\nCUI1a7dU+F1OjvXdJ8qfk2EGSdoXmAiMSa956gHcTTK02nFpCbF3RHxW0kDN2iHf5cTq4w402bQr\nyV0oBqZjj04nuah+Z+DkdJoToVkRIuJb4B1gMMmdTN4hGVlmTUn3pYudT9Ke6ERYIZwMS6zOAMqL\nAUTE4cCTJO2C66ezlwGuBYZHxLw2DtOs3PguJ1aLq0kzIr1P2nrAtxFxYjrtMmATkruQbwjs5CHW\nzFqOpNWBS4EJJNcXzgRW8Oes8jgZZkDas+0iktsPXQy8GhF7pfN2BbqQ3GT1rdJFaVaefJcTAyfD\nkksH2V6VZGSZcWnj/tMkl1Mc6OsHzVqf73JibjMsvY+AU4ABsKBxf0tgIMlwa2bWyiLiPSfCyuaS\nYQZI2pHkuqeNaxrt0xLicm7ENzNrfU6GGSFpN+Aakuua3HhvZtaGnAwzRNJewB+ANd1WaGbWdpwM\nM0bSEpU+gLKZWVtzMjQzs4rn3qRmZlbxnAzNzKziORmamVnFczI0M7OK52RoZmYVz8nQzMwqnpOh\nlS1JkyS9IWmspNfS22S1xHrvknRo+vd5kg5sYvmBkvYvcluLS6r3LgqSzpV0cR7ryGu5el53vaQT\nC32dWXu0SKkDMGtFAewXEa9K6g+Ml/RURLyWu5CkDsXeMDkizs1jsUHAHsAdRWxCJPthZq3IJUMr\ndwJI70gwAVhN0tZpSfFaSWOAPSUtIekaSc9LekXScEmLQHIDWEnPSHpV0r1AtwUrzyk9Seoo6Y/p\ncq9I+pek3sB5wDaSxki6Kl12Q0mPSXpR0suS9slZ57GSJkh6Gfh5XjsprSPpKUkvpft2Vp1F+qfb\ne13SPyX1TF+3iKTfp/s9RtLtkroXd6jN2i8nQ6sIktYFVgfGpZPWAG6IiMERcTfJzZWfiohNImJ9\noANwUrrsTcDfImJd4Gxg6wY2cxbJvSkHpesYFhGfAecAo9JtHZ8mm78CB0XERsAOwEWSlpG0DvBr\nYMuIGAJ0znMXJwLbRcQGwAbAPpI2ypm/BXBARKwFfAj8Pp1+OvBVut+DgdeA3+a5TbOy4WpSK3d3\nSPoamA0cERHvSloeeC8ins5Zbk9gE0mnps87AXMldQXWB0YARMRrknJfl2tX4IyaQdYjYloDy20G\nrNWllDsAAAGpSURBVAQ8JEnptPkkyXpd4F8RMTWdfjVwZh772QW4WtL66bqWT+N+MZ0/Mk3MkNwd\n5e6c/e6WUzLtSJJYzSqKk6GVu/0i4tV6ptc3GPredW+flSbDlm6zE/BaRGyx0IykBFt32Xz8DqgG\nBkZESLqbJKE3pGafBPwsIv6T53bMypKrSa3c5ZtM7gN+IakDgKQeklaOiC+BscBh6fS1gc0bWMf9\nwEnpjZmR1CudPhPIbYd7FlhR0nYLgkx6nC4CPA7sKKlPOuvYPOPvCXyQJsLVgR/Umb9z2n4J8GOg\nJvndB5wsqXMaR2dJa+W5TbOy4WRo5ayQEt3JwDfAK5LGkSSLFdJ5hwHHSBoPnA882cA2/gC8DYxJ\nO+bckE5/DFgs7VRzVURMJ6lSPSu97ON/JG14VRHxP5ION0+nHWi+zjP+3wBHSnqFpJT4WJ35TwO3\nSXoj3a+aDjZ/AEb/f3t3TAQgEARBcB3hXwGFKxJCFPx0O9ho6qLb9ny7723XzzY4mhdOAOS5DAHI\nE0MA8sQQgDwxBCBPDAHIE0MA8sQQgDwxBCBPDAHIE0MA8l6H8TKqUSiecgAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Compute confusion matrix\n", "cnf_matrix = confusion_matrix(correct_label, pred_label)\n", "np.set_printoptions(precision=1)\n", "class_names = ['number','fizz','buzz','fizbuzz']\n", "# Plot non-normalized confusion matrix\n", "plt.figure()\n", "plot_confusion_matrix(cnf_matrix, classes=class_names,\n", " title='Confusion matrix, without normalization')\n", "\n", "plt.show()" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.13" } }, "nbformat": 4, "nbformat_minor": 0 }