From 019a12365e1427993f1ca6749008c21e7fc2f380 Mon Sep 17 00:00:00 2001 From: Arnaud Van Looveren Date: Thu, 2 May 2019 18:15:21 +0100 Subject: [PATCH 1/3] add mnist trustscore example --- doc/source/examples/trustscore_mnist.nblink | 3 + doc/source/index.rst | 3 +- doc/source/methods/Trust Scores.ipynb | 6 +- examples/trustscore_mnist.ipynb | 712 ++++++++++++++++++++ 4 files changed, 721 insertions(+), 3 deletions(-) create mode 100644 doc/source/examples/trustscore_mnist.nblink create mode 100644 examples/trustscore_mnist.ipynb diff --git a/doc/source/examples/trustscore_mnist.nblink b/doc/source/examples/trustscore_mnist.nblink new file mode 100644 index 000000000..af71b621d --- /dev/null +++ b/doc/source/examples/trustscore_mnist.nblink @@ -0,0 +1,3 @@ +{ + "path": "../../../examples/trustscore_mnist.ipynb" +} diff --git a/doc/source/index.rst b/doc/source/index.rst index a86e1aeda..6e1a39adf 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -.. mdinclude:: landing.md +.. mdinclude:: landing.md .. toctree:: :maxdepth: 1 @@ -39,6 +39,7 @@ examples/cem_mnist examples/cem_iris examples/trustscore_iris + examples/trustscore_mnist .. toctree:: :maxdepth: 1 diff --git a/doc/source/methods/Trust Scores.ipynb b/doc/source/methods/Trust Scores.ipynb index e4989af77..0137b57a2 100644 --- a/doc/source/methods/Trust Scores.ipynb +++ b/doc/source/methods/Trust Scores.ipynb @@ -33,7 +33,7 @@ "\n", "Trust scores can for instance be used as a warning flag for machine learning predictions. If the score drops below a certain value and there is disagreement between the model probabilities and the trust score, the prediction can be explained using techniques like anchors or contrastive explanations.\n", "\n", - "Trust scores work best for low to medium dimensional feature spaces. When working with high dimensional observations like images, dimensionality reduction methods (e.g. auto-encoders or PCA) could be applied as a pre-processing step before computing the scores." + "Trust scores work best for low to medium dimensional feature spaces. When working with high dimensional observations like images, dimensionality reduction methods (e.g. auto-encoders or PCA) could be applied as a pre-processing step before computing the scores. This is demonstrated by the following example [notebook](../examples/trustscore_mnist.nblink)." ] }, { @@ -126,7 +126,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "[Trust Scores applied to Iris](../examples/trustscore_iris.nblink)" + "[Trust Scores applied to Iris](../examples/trustscore_iris.nblink)\n", + "\n", + "[Trust Scores applied to MNIST](../examples/trustscore_mnist.nblink)" ] } ], diff --git a/examples/trustscore_mnist.ipynb b/examples/trustscore_mnist.ipynb new file mode 100644 index 000000000..a5b7e477d --- /dev/null +++ b/examples/trustscore_mnist.ipynb @@ -0,0 +1,712 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trust Scores applied to MNIST" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is important to know when a machine learning classifier's predictions can be trusted. Relying on the classifier's (uncalibrated) prediction probabilities is not optimal and can be improved upon. *Trust scores* measure the agreement between the classifier and a modified nearest neighbor classifier on the test set. The trust score is the ratio between the distance of the test instance to the nearest class different from the predicted class and the distance to the predicted class. Higher scores correspond to more trustworthy predictions. A score of 1 would mean that the distance to the predicted class is the same as to another class.\n", + "\n", + "The original paper on which the algorithm is based is called [To Trust Or Not To Trust A Classifier](https://arxiv.org/abs/1805.11783). Our implementation borrows heavily from https://github.com/google/TrustScore, as does the example notebook.\n", + "\n", + "Trust scores work best for low to medium dimensional feature spaces. This notebook illustrates how you can **apply trust scores to high dimensional** data like images by adding an additional pre-processing step in the form of an [auto-encoder](https://en.wikipedia.org/wiki/Autoencoder) to reduce the dimensionality. Other dimension reduction techniques like PCA can be used as well." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using TensorFlow backend.\n" + ] + } + ], + "source": [ + "import keras\n", + "from keras import backend as K\n", + "from keras.layers import Conv2D, Dense, Dropout, Flatten, MaxPooling2D, Input, UpSampling2D\n", + "from keras.models import Model\n", + "from keras.utils import to_categorical\n", + "import matplotlib\n", + "%matplotlib inline\n", + "import matplotlib.cm as cm\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from sklearn.model_selection import StratifiedShuffleSplit\n", + "from alibi.confidence import TrustScore" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_train shape: (60000, 28, 28) y_train shape: (60000,)\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()\n", + "print('x_train shape:', x_train.shape, 'y_train shape:', y_train.shape)\n", + "plt.gray()\n", + "plt.imshow(x_test[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Prepare data: scale, reshape and categorize" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_train shape: (60000, 28, 28, 1) x_test shape: (10000, 28, 28, 1)\n", + "y_train shape: (60000, 10) y_test shape: (10000, 10)\n" + ] + } + ], + "source": [ + "x_train = x_train.astype('float32') / 255\n", + "x_test = x_test.astype('float32') / 255\n", + "x_train = np.reshape(x_train, x_train.shape + (1,))\n", + "x_test = np.reshape(x_test, x_test.shape + (1,))\n", + "print('x_train shape:', x_train.shape, 'x_test shape:', x_test.shape)\n", + "y_train = to_categorical(y_train)\n", + "y_test = to_categorical(y_test)\n", + "print('y_train shape:', y_train.shape, 'y_test shape:', y_test.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "xmin, xmax = -.5, .5\n", + "x_train = ((x_train - x_train.min()) / (x_train.max() - x_train.min())) * (xmax - xmin) + xmin\n", + "x_test = ((x_test - x_test.min()) / (x_test.max() - x_test.min())) * (xmax - xmin) + xmin" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define and train model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this example we are not interested in optimizing model performance so a simple softmax classifier will do:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def sc_model():\n", + " x_in = Input(shape=(28, 28, 1))\n", + " x = Flatten()(x_in)\n", + " x_out = Dense(10, activation='softmax')(x)\n", + " sc = Model(inputs=x_in, outputs=x_out)\n", + " sc.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])\n", + " return sc" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input_1 (InputLayer) (None, 28, 28, 1) 0 \n", + "_________________________________________________________________\n", + "flatten_1 (Flatten) (None, 784) 0 \n", + "_________________________________________________________________\n", + "dense_1 (Dense) (None, 10) 7850 \n", + "=================================================================\n", + "Total params: 7,850\n", + "Trainable params: 7,850\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sc = sc_model()\n", + "sc.summary()\n", + "sc.fit(x_train, y_train, batch_size=128, epochs=5, verbose=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluate the model on the test set:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test accuracy: 0.8869\n" + ] + } + ], + "source": [ + "score = sc.evaluate(x_test, y_test, verbose=0)\n", + "print('Test accuracy: ', score[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define and train auto-encoder" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def ae_model():\n", + " # encoder\n", + " x_in = Input(shape=(28, 28, 1))\n", + " x = Conv2D(16, (3, 3), activation='relu', padding='same')(x_in)\n", + " x = MaxPooling2D((2, 2), padding='same')(x)\n", + " x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)\n", + " x = MaxPooling2D((2, 2), padding='same')(x)\n", + " x = Conv2D(4, (3, 3), activation=None, padding='same')(x)\n", + " encoded = MaxPooling2D((2, 2), padding='same')(x)\n", + " encoder = Model(x_in, encoded)\n", + "\n", + " # decoder\n", + " dec_in = Input(shape=(4, 4, 4))\n", + " x = Conv2D(4, (3, 3), activation='relu', padding='same')(dec_in)\n", + " x = UpSampling2D((2, 2))(x)\n", + " x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)\n", + " x = UpSampling2D((2, 2))(x)\n", + " x = Conv2D(16, (3, 3), activation='relu')(x)\n", + " x = UpSampling2D((2, 2))(x)\n", + " decoded = Conv2D(1, (3, 3), activation=None, padding='same')(x)\n", + " decoder = Model(dec_in, decoded)\n", + " \n", + " # autoencoder = encoder + decoder\n", + " x_out = decoder(encoder(x_in))\n", + " autoencoder = Model(x_in, x_out)\n", + " autoencoder.compile(optimizer='adam', loss='mse')\n", + " \n", + " return autoencoder, encoder, decoder" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input_2 (InputLayer) (None, 28, 28, 1) 0 \n", + "_________________________________________________________________\n", + "model_2 (Model) (None, 4, 4, 4) 1612 \n", + "_________________________________________________________________\n", + "model_3 (Model) (None, 28, 28, 1) 1757 \n", + "=================================================================\n", + "Total params: 3,369\n", + "Trainable params: 3,369\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ae, enc, dec = ae_model()\n", + "ae.summary()\n", + "ae.fit(x_train, x_train, batch_size=128, epochs=8, validation_data=(x_test, x_test), verbose=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calculate Trust Scores" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize trust scores:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "ts = TrustScore()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The key is to **fit and calculate the trust scores on the encoded instances**. The encoded data still needs to be reshaped from (60000, 4, 4, 4) to (60000, 64) to comply with the k-d tree format. This is handled internally:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reshaping data from (60000, 4, 4, 4) to (60000, 64) so k-d trees can be built.\n" + ] + } + ], + "source": [ + "x_train_enc = enc.predict(x_train)\n", + "ts.fit(x_train_enc, y_train, classes=10) # 10 classes present in MNIST" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now calculate the trust scores of the predictions on the test set, using the distance to the 5th nearest neighbor in each class:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reshaping data from (10000, 4, 4, 4) to (10000, 64) so k-d trees can be queried.\n" + ] + } + ], + "source": [ + "x_test_enc = enc.predict(x_test)\n", + "y_pred = sc.predict(x_test)\n", + "score = ts.score(x_test_enc, y_pred, k=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's inspect which predictions have low and high trust scores:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "n = 5\n", + "idx_min, idx_max = np.argsort(score)[:n], np.argsort(score)[-n:]\n", + "score_min, score_max = score[idx_min], score[idx_max]\n", + "pred_min, pred_max = np.argmax(y_pred[idx_min], axis=1), np.argmax(y_pred[idx_max], axis=1)\n", + "imgs_min, imgs_max = x_test[idx_min], x_test[idx_max]\n", + "label_min, label_max = np.argmax(y_test[idx_min], axis=1), np.argmax(y_test[idx_max], axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The image below makes clear that the low trust scores correspond to misclassified images (mainly 1's as 8). Because the trust scores are significantly below 1, they correctly identified that the images belong to another class than the predicted class." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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jRoAAACAgViy0BNg8TvssMO62Zvf/OZu9r3vfa+b7bTTTndqTkCy4YYbdrMPfehD3exFL3pRN9thhx1m3H/hhReu8rwAAIA+V9QAAAAADIRGDQAAAMBAaNQAAAAADIRGDQAAAMBAaNQAAAAADIRVn1glG220UTfbZpttullrrZv1Vo9Jkuc+97kz7j/ppJO6xwC3tf3223ezF77whd1sUt0Cd97ee+/dzXbcccdu9pvf/Kabvec977lTcwKSpUuXdrPly5d3s2XLlnWzqppx/0EHHdQ95pBDDulmwLrBFTUAAAAAA6FRAwAAADAQGjUAAAAAA6FRAwAAADAQGjUAAAAAA6FRAwAAADAQlufm99Zff/1uduCBB3azScv8TnLxxRd3s+985zuzOiew0qS6Bdasv/qrv+pmhx9+eDdbsqT/q1lrrZvtvPPOM+5/3vOe1z0GuK1JS3Dvueee3WxSbfay+9znPqs+MWCd44oaAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCMtz83tPe9rTutlb3vKWOR/vFa94RTe74IIL5nw8WBvts88+3ez5z3/+rM75qU99qpv97Gc/m9U5YW10wAEHdLO3v/3t3WzSEtyTVFU323vvvWd1TlgbTfrZeOCBB3az+9///t1s0hLck1x99dUz7j/xxBNndT5g3eCKGgAAAICB0KgBAAAAGAiNGgAAAICB0KgBAAAAGAiNGgAAAICB0KgBAAAAGAjLc69jJi07ePjhh8/5eJ/+9Ke72be//e05Hw/WRrvssks3+6d/+qduNmkp3xtuuGFW57zlllu6GayNdtttt2526KGHdrMNN9xwzudy7rnndrN99913zseDIdt888272Z577tnNdthhhzmfS28J7iTZb7/9Ztx/zjnnzPk8gLWHK2oAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgLM+9Ftp000272amnntrNHvCAB8xqvElLEk5a8vvGG2+c1XiwNtp555272cknn9zN7nnPe3azm2++uZu94hWv6GbnnXdeN4N1zU477dTNNt5441md87rrrutmZ511Vjd79atf3c2uuOKKWc0FFqtjjjmmmz3rWc+ax5kk+++/fzc75ZRT5nEmMLNHPOIRM+7ffffdu8ccccQR3ew3v/nNnZ4Tk7miBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABsLy3GuhZz/72d3sgQ984JyP9853vrObfeMb35jz8WCxWn/99bvZaaed1s0mLcE9ydlnn93NPvGJT8zqnLA2mlQPk5Yuna2vf/3r3ew5z3nOnI8HQ7Z06dJutnz58m62bNmyOZ/LihUrutnLX/7ybjbpZzjMl8c+9rHd7P3vf/+M+x/3uMd1j3nAAx7QzQ477LBudo973KOb3Xzzzd3s8Y9/fDdbsqTftnjyk5/czSbZeuutZ9w/6ffuSf/vPe6442Y1jx5X1AAAAAAMhEYNAAAAwEBo1AAAAAAMhEYNAAAAwEBo1AAAAAAMhEYNAAAAwEBUa60fVvVDFtQBBxzQzd7xjnd0s0nLA09y8sknd7OXvOQl3ezGG2+c1XgDcl5rrb/W3QJRm8N117vetZsdf/zx3Wyvvfaa1XjnnntuN9t111272Q033DCr8QZEbXI797rXvbrZUUcd1c323HPPbrbxxhvPai5f+9rXutnznve8bnbZZZfNaryhaK3VQs9hJmpzuE499dRuNqk214Qzzzyzm+2+++7zOJO5pzYXj4c97GHdbJ999ulmk/5/ONv/Ay4Gk36nvfLKK7vZihUrZtx/wQUXdI/55S9/2c3233//bjZJrzZdUQMAAAAwEBo1AAAAAAOhUQMAAAAwEBo1AAAAAAOhUQMAAAAwEBo1AAAAAAOxZKEnQLL11lvPuP+Zz3xm95hDDjmkm812+bVJS4m+8pWv7GZrwRLcsFo23XTTbnbcccd1s9kuwf2d73ynmx144IHdbC1YghtmtNlmm824/zOf+Uz3mJ122mnO5zHp599b3vKWbrbYl+CGns0333zG/cccc0z3mGXLlnWz1ma3cvPVV1/dzSYtofuVr3xlVuPB6tpiiy262emnn97NtttuuzmdR1V/1fbZ1t83v/nNbnbppZd2sy996Uvd7Ktf/Wo3u+SSS7rZ5Zdf3s2GzhU1AAAAAAOhUQMAAAAwEBo1AAAAAAOhUQMAAAAwEBo1AAAAAAOhUQMAAAAwEJbnnie9JbiT5N///d9n3P+whz2se8xsl0ubZNLSiVddddWcjweL1cc//vFutscee8zqnJ///Oe72d57793Nrr322lmNB0PXW4I7ST772c/OuP9Rj3pU95jZ/ty8+eabu9kb3vCGbjZpKVFYzHpLcCfJhz70oRn3P+tZz5rzeUxagnu//fbrZqeccsqczwVW19ve9rZuNtdLcE+yfPnybvbe9763m33/+99fE9NhClfUAAAAAAyERg0AAADAQGjUAAAAAAyERg0AAADAQGjUAAAAAAyEVZ/m0I477tjN/u3f/q2b3e9+95tx/3rr9ftot9xySze75pprutk973nPbgZrqw022KCbbbPNNt3s7LPPnnH/tttu2z1mUm2eddZZ3WyvvfbqZr/97W+7GSxms1nZKUke/ehHr4npzOiAAw7oZh/84AfnbR4wFJNWCZ3r1Z2OPvrobnbiiSd2s3POOWdO5wFz7Xvf+95CTyHJ5BXSdt999262zz77dLPPfe5zd2pOjLiiBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABsLy3DPYaKONutljH/vYbrZ8+fJutv3223ez1tqM+yct83vSSSd1s7e+9a3dDNZFu+66azc7/fTTV/t8k2rzjDPO6GYvfvGLu5kluFkXHXnkkd3sMY95zGqfb731+n9/mlS3k5YnPe6441Z7HrAYLF26tJtN+p122bJlczqPFStWdLPPfvaz3cwS3Cxmxx57bDc788wz53EmfUcddVQ3m/Q7reW554YragAAAAAGQqMGAAAAYCA0agAAAAAGQqMGAAAAYCA0agAAAAAGQqMGAAAAYCDW2eW5n/jEJ3azN7zhDd1sr732WhPTmdE111zTzSYtwf2jH/1oTUwHBu2II47oZpOWEJyNffbZp5udeuqp3ezXv/71nM4DFoNJ9fLc5z63m7XWVnusSUtwf/e73+1mJ5988mqPBYvdpCW499xzz242m9o8+uiju9mkJbhPO+201R4LFoNJdfTTn/503uZx3/vet5s94hGP6GZnnHHGGpgNU7miBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABmKtXp5755137mann356N9tss83WxHS6zjzzzBn377HHHvM6DxiC9ddfv5u9+93v7mavetWrullVdbMf/vCH3eypT33qjPsvv/zy7jGwLtp333272ZFHHtnNJtX7bHz/+9/vZk972tO62TXXXDOn84C5tsEGG3Szbbfdtpu97W1v62bLli3rZrNZgjtJrr766hn3n3jiid1jzjnnnFmNBfNl0hLyr3vd67rZpJ9Ja8KSJf3/2j/ykY+ccf9rX/va7jFLly7tZuedd96qT4xZcUUNAAAAwEBo1AAAAAAMhEYNAAAAwEBo1AAAAAAMhEYNAAAAwEBo1AAAAAAMxKJfnvuJT3xiN5vvJbgvueSSbvbSl760m1nejHXNpPqbtITnbrvtNqvxvvWtb3WzN77xjd3MMtyw0qTafMYzntHNNt5441mNd/PNN3ezM844Y8b9+++/f/eYK6+8clbzgCGYtAT3j3/843mcSfLRj360m/V+97bJZ2FdAAAFtUlEQVQEN4vZgx70oG729a9/vZtNWtb7M5/5zKzmsvXWW3ezpzzlKd3sSU960oz7q6p7zPve975utnz58m7G3HBFDQAAAMBAaNQAAAAADIRGDQAAAMBAaNQAAAAADIRGDQAAAMBAaNQAAAAADMSiWJ57o4026mZveMMbutlsl+CetCTo0Ucf3c2OP/74bnb++efPai6wWO2www7d7IQTTuhmj3vc42Y13oEHHtjNjjvuuG52xRVXzGo8WBvd+9737mYPf/jDu9kmm2wyq/FuvPHGbjbp5/sxxxwzq/FgsXrb2942r+NN+n33zW9+cze7/vrr18R0YEE95znP6WYvf/nLu9m+++7bzZ75zGfeqTmtrl/96lcz7v/CF77QPeaggw5aU9NhFbiiBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABkKjBgAAAGAgNGoAAAAABqJaa/2wqh/Oo1122aWbffGLX5zz8Y488shu9vrXv37Ox2PQzmutPXahJzHdUGrz/ve/fzc788wzu9l2223XzW655ZZuNmkJ7ne9612zOieLltqcpUnLhR5wwAHdbNLy3LM1acnht771rXM+Hmtea60Weg4zGUptLl26tJstX768my1btmzO53LooYd2M8vyrn3U5vx72MMe1s223HLLbvboRz96VuPddNNN3ewDH/jAjPuvv/76WY3F3OnVpitqAAAAAAZCowYAAABgIDRqAAAAAAZCowYAAABgIDRqAAAAAAZCowYAAABgIAa1PPeOO+444/7TTjute8yk5YEnOeSQQ2aV3XzzzbMaj0XLEsATfPrTn+5me+65ZzebVEezXYKbdY7anOCBD3xgNzv77LO72b3vfe9ZjXfDDTd0s8MOO6ybnXDCCd3s4osvntVcWFiWAJ7sGc94Rjc744wz5ny8o48+upu95jWvmfPxGC61CcNkeW4AAACAgdOoAQAAABgIjRoAAACAgdCoAQAAABgIjRoAAACAgdCoAQAAABiIJQs9gal23XXXGffPdgnuK664opsde+yx3cwS3HBbW2655Yz7n/CEJ3SP+dnPftbNjjzyyG52xBFHrPrEYB13t7vdbcb95557bveYTTfddM7n8dWvfrWbvf3tb5/z8WCx+vCHPzyr42666aZudtRRR3Wzgw8+eFbjAbCwXFEDAAAAMBAaNQAAAAADoVEDAAAAMBAaNQAAAAADoVEDAAAAMBAaNQAAAAADMajlub/85S/PuP/SSy/tHrPVVlt1s0lLIF5++eWrPjFYx2288cYz7t9iiy26x0xaEvSYY465s1MCknzyk5+ccf8mm2wyq/Ndd9113ex973tfN1PTsGq23HLLbnbLLbd0s4suuqibvelNb7pTcwJgeFxRAwAAADAQGjUAAAAAA6FRAwAAADAQGjUAAAAAA6FRAwAAADAQ1Vrrh1X9ENYN57XWHrvQk5hObYLanOR1r3tdN9tggw262fLly7vZihUr7tScWDe01mqh5zCTodTm05/+9Fkdd+2113azc845Z7bTYR2iNmGYerXpihoAAACAgdCoAQAAABgIjRoAAACAgdCoAQAAABgIjRoAAACAgdCoAQAAABgIy3PDZJYAhmFSmzBAlgCGYVKbMEyW5wYAAAAYOI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIHQqAEAAAAYCI0aAAAAgIFYcgf5L5JcNB8TgYHabqEn0KE2WdepTRieodZlojZZt6lNGKZubVZrbT4nAgAAAECHtz4BAAAADIRGDQAAAMBAaNQAAAAADIRGDQAAAMBAaNQAAAAADMT/D1X82nJnoNUcAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(20, 4))\n", + "for i in range(n):\n", + " ax = plt.subplot(1, n, i+1)\n", + " plt.imshow(imgs_min[i].reshape(28, 28))\n", + " plt.title('Model prediction: {} \\n Label: {} \\n Trust score: {:.3f}'.format(pred_min[i], label_min[i], score_min[i]))\n", + " ax.get_xaxis().set_visible(False)\n", + " ax.get_yaxis().set_visible(False)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The high trust scores on the other hand all are very obvious 1's:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(20, 4))\n", + "for i in range(n):\n", + " ax = plt.subplot(1, n, i+1)\n", + " plt.imshow(imgs_max[i].reshape(28, 28))\n", + " plt.title('Model prediction: {} \\n Label: {} \\n Trust score: {:.3f}'.format(pred_max[i], label_max[i], score_max[i]))\n", + " ax.get_xaxis().set_visible(False)\n", + " ax.get_yaxis().set_visible(False)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparison of Trust Scores with model prediction probabilities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let’s compare the prediction probabilities from the classifier with the trust scores for each prediction. The first use case checks whether trust scores are better than the model’s prediction probabilities at identifying correctly classified examples, while the second use case does the same for incorrectly classified instances.\n", + "\n", + "First we need to set up a couple of helper functions.\n", + "\n", + "* Define a function that handles model training and predictions:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def run_sc(X_train, y_train, X_test):\n", + " clf = sc_model()\n", + " clf.fit(X_train, y_train, batch_size=128, epochs=5, verbose=0)\n", + " y_pred_proba = clf.predict(X_test)\n", + " y_pred = np.argmax(y_pred_proba, axis=1)\n", + " probas = y_pred_proba[range(len(y_pred)), y_pred] # probabilities of predicted class\n", + " return y_pred, probas" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Define the function that generates the precision plots:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_precision_curve(plot_title, \n", + " percentiles, \n", + " labels, \n", + " final_tp, \n", + " final_stderr, \n", + " final_misclassification,\n", + " colors = ['blue', 'darkorange', 'brown', 'red', 'purple']):\n", + " \n", + " plt.title(plot_title, fontsize=18)\n", + " colors = colors + list(cm.rainbow(np.linspace(0, 1, len(final_tp))))\n", + " plt.xlabel(\"Percentile\", fontsize=14)\n", + " plt.ylabel(\"Precision\", fontsize=14)\n", + " \n", + " for i, label in enumerate(labels):\n", + " ls = \"--\" if (\"Model\" in label) else \"-\"\n", + " plt.plot(percentiles, final_tp[i], ls, c=colors[i], label=label)\n", + " plt.fill_between(percentiles, \n", + " final_tp[i] - final_stderr[i],\n", + " final_tp[i] + final_stderr[i],\n", + " color=colors[i],\n", + " alpha=.1)\n", + " \n", + " if 0. in percentiles:\n", + " plt.legend(loc=\"lower right\", fontsize=14)\n", + " else:\n", + " plt.legend(loc=\"upper left\", fontsize=14)\n", + " model_acc = 100 * (1 - final_misclassification)\n", + " plt.axvline(x=model_acc, linestyle=\"dotted\", color=\"black\")\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* The function below trains the model on a number of folds, makes predictions, calculates the trust scores, and generates the precision curves to compare the trust scores with the model prediction probabilities:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "def run_precision_plt(X, y, nfolds, percentiles, run_model, test_size=.2, \n", + " plt_title=\"\", plt_names=[], predict_correct=True, classes=10):\n", + " \n", + " def stderr(L):\n", + " return np.std(L) / np.sqrt(len(L))\n", + " \n", + " all_tp = [[[] for p in percentiles] for _ in plt_names]\n", + " misclassifications = []\n", + " mult = 1 if predict_correct else -1\n", + " \n", + " folds = StratifiedShuffleSplit(n_splits=nfolds, test_size=test_size, random_state=0)\n", + " for train_idx, test_idx in folds.split(X, y):\n", + " # create train and test folds, train model and make predictions\n", + " X_train, y_train = X[train_idx, :], y[train_idx, :]\n", + " X_test, y_test = X[test_idx, :], y[test_idx, :]\n", + " y_pred, probas = run_sc(X_train, y_train, X_test)\n", + " # target points are the correctly classified points\n", + " y_test_class = np.argmax(y_test, axis=1)\n", + " target_points = (np.where(y_pred == y_test_class)[0] if predict_correct else \n", + " np.where(y_pred != y_test_class)[0])\n", + " final_curves = [probas]\n", + " # calculate trust scores\n", + " ts = TrustScore()\n", + " ts.fit(enc.predict(X_train), y_train, classes=classes)\n", + " scores = ts.score(enc.predict(X_test), y_pred, k=5)\n", + " final_curves.append(scores) # contains prediction probabilities and trust scores\n", + " # check where prediction probabilities and trust scores are above a certain percentage level\n", + " for p, perc in enumerate(percentiles):\n", + " high_proba = [np.where(mult * curve >= np.percentile(mult * curve, perc))[0] for curve in final_curves]\n", + " if 0 in map(len, high_proba):\n", + " continue\n", + " # calculate fraction of values above percentage level that are correctly (or incorrectly) classified\n", + " tp = [len(np.intersect1d(hp, target_points)) / (1. * len(hp)) for hp in high_proba]\n", + " for i in range(len(plt_names)):\n", + " all_tp[i][p].append(tp[i]) # for each percentile, store fraction of values above cutoff value\n", + " misclassifications.append(len(target_points) / (1. * len(X_test)))\n", + " \n", + " # average over folds for each percentile\n", + " final_tp = [[] for _ in plt_names]\n", + " final_stderr = [[] for _ in plt_names]\n", + " for p, perc in enumerate(percentiles):\n", + " for i in range(len(plt_names)):\n", + " final_tp[i].append(np.mean(all_tp[i][p]))\n", + " final_stderr[i].append(stderr(all_tp[i][p]))\n", + "\n", + " for i in range(len(all_tp)):\n", + " final_tp[i] = np.array(final_tp[i])\n", + " final_stderr[i] = np.array(final_stderr[i])\n", + "\n", + " final_misclassification = np.mean(misclassifications)\n", + " \n", + " # create plot\n", + " plot_precision_curve(plt_title, percentiles, plt_names, final_tp, final_stderr, final_misclassification)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Detect correctly classified examples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The x-axis on the plot below shows the percentiles for the model prediction probabilities of the predicted class for each instance and for the trust scores. The y-axis represents the precision for each percentile. For each percentile level, we take the test examples whose trust score is above that percentile level and plot the percentage of those points that were correctly classified by the classifier. We do the same with the classifier’s own model confidence (i.e. softmax probabilities). For example, at percentile level 80, we take the top 20% scoring test examples based on the trust score and plot the percentage of those points that were correctly classified. We also plot the top 20% scoring test examples based on model probabilities and plot the percentage of those that were correctly classified. The vertical dotted line is the error of the classifier. The plots are an average over 2 folds of the dataset with 20% of the data kept for the test set.\n", + "\n", + "The *Trust Score* and *Model Confidence* curves then show that the model precision is typically higher when using the trust scores to rank the predictions compared to the model prediction probabilities." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "X = x_train\n", + "y = y_train\n", + "percentiles = [0 + 0.5 * i for i in range(200)]\n", + "nfolds = 2\n", + "plt_names = ['Model Confidence', 'Trust Score']\n", + "plt_title = 'MNIST -- Softmax Classifier -- Predict Correct'" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reshaping data from (48000, 4, 4, 4) to (48000, 64) so k-d trees can be built.\n", + "Reshaping data from (12000, 4, 4, 4) to (12000, 64) so k-d trees can be queried.\n", + "Reshaping data from (48000, 4, 4, 4) to (48000, 64) so k-d trees can be built.\n", + "Reshaping data from (12000, 4, 4, 4) to (12000, 64) so k-d trees can be queried.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAa8AAAEeCAYAAAA9/ZrRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzsnXd4lFX2+D8nISH03juKIFIs2LAAiq6KyoK7iooKFlzL13WVXXXtHYXdlf2JLqyiWEFdC3ZBRXcVBRQUBVFAlBJ6J4GQ5Pz+OO+EYZiUSSaTTDif55lnZu6973vP2+5577nnniuqiuM4juMkEykVLYDjOI7jxIorL8dxHCfpcOXlOI7jJB2uvBzHcZykw5WX4ziOk3S48nIcx3GSDlde+yki8jsR+UZEskVERaRvRctUGRCRZSIyo6LlgMJlEZGrReQHEdkVXLv2InJX6HfCBa2CiMiwyOciWppTcZSL8hKRvsFFVhF5tJAyTUUkJygzIyJvRpC+VETSo2wbelB7RalzZETZeiJym4jME5HNIrJdRH4WkddF5PKgzLAweYv7zCBBlET2Uu73IOBFYAtwLXARsDA4h3eJSP04HUKlQEQaiMgdIjI7OI85IrJCRP4jIoNFRCpaxpIiIv2AccAPwB+wa7euQoWKAxFtRuizXUS+EpE/ikhqRctYFsrybInIQSLyWPDCsiN44fxRRCaIyJHlIW+iCXsBO7Sk21QrT4GAncAFInKjqu6KyLsIECC3iO07AFcBY0tTuYjUBWYDHYFXgIlATvD/eOCPwBPAp4E84dwKdImSvqY0ssRKDLKXhr7Ytb9eVb8Oq/Mq4E7gaWBzKfddqRCRo4A3gKbAVOB5YCvQCjgD+A9wDfBYRclYBJ2ByCgCpwTfl6rqxlCiiNwHjAIin7Nk40XgHaxtaAkMAx4BDgFGVJxYADwLTMaew1jpSymeLRG5DHgca0tfBOZhbeZBwDnAFSJyiKouKIVMlYn22PlZhh1jsZS38noNOB8YCLwUkTccu0lPLmTbbOBn4DYRmaiq20pR/xVAJ6yR3kcBikhzAFVdCiyNyLsc6KKqz5Wi3nhQItlLSWjbjUWWSnKCc/QmkAH0UdX/RRS5V0R+AzRIuHAlIMoLHwTXLlxxBf9zKfpFMGaC3k51Vc2K536L4evwZ05EHgcWApeLyO2qGvXlUUTSgFRV3VlegqlqHpBXXvuPRET6AxOABcBvVHVVRP4twP/FsT4Baqnq9kLy65SyHS4fVDXuH+wtQ4GRwDfAuxH5RwX5vwW2AzMi8mcE6WcH5e6NyL8rSO8Vrc6wtH8Fad1KcQwz7PTE//yUsP6YZQdOBKZh5sBs4GvgsogyGuWzDHsjjJZ3V8Q574q9CWcCWcCHQOegzOCgzuxgnyOiyHge1gP6FeslrAdeB3pElBsA5ANPRqTXBhZhPeDmxZyPvwUy/yGGc7gsyv14KjAFe8HJxt6cP8AUYuT2hwAvAyuD41sNfAwMCCuTEZzPRcE53AzMB0YXJgv2Zhrt+oTyQ9enfcQ+6gEPAYsDedZhb/AdI8oNC7bvD9wOLAF2A8MSdL/3JeL5Dct7Jcg7NuJYDwH+DqzAlErfsG36B9doM9Zr+baw+wB7UfwhOD+Lgeuxl2uN2OewyLQgPR34C9ZjyMKevznAtUH+04Vcu7uKOSdfYc9A1xjOYy3gweD6he6/Z4B2hZzvYZjlYUFQPvS8zwjuv5DlZyNh7SHWM74qkDELa68/BvoVItc5wT43B+UXAf8Mzl3ovEa9twv7lHfPC8zc9XcRaaWqK4O0S4G1wFtFbaiqU0Xkf8CfRGScqq6Ose4lwfdwEblJ7e00WYhJdhE5C+vprsYa7W3AEOAJEemoqrcGRS/ClMwg4E+Y8tiOKYO6EelgD304k4LyDwBNgBuB90XkduBhzMQxEbgMGC8iC3TvHs+1wAbsjXI1cABmDvpMRA5X1Z8AVPVtEXkEu/bTVHVysP1jWI/0jBLcD+dgJp5JxZQrjmFAQ6wRWIGZHC8HPhSRfqr6XwARaQR8FGzzL+AXoDHQCzgaeDvIG4c9A89gjW+14JhOKkKGddi1GwGcwB5zdqFmbBGpB3wOtMWuyfdAC+Bq4EsR6aWqv0RsNgZIA/6NmVcXFSFTuRP0Bg4M/q6PyH4ee5kIvaRkBtuMwM7/F8D9wA7M3Pq4iBygqn8O2//1wD+wl+y/AjWxl+61JZQvHXgfUwYfAM9hyrI79pw9CoynZM9W+H47AIcD/9USmgSD3uf7wHGYwvkbdl9dBZwaXO8VEZtdDzTCrvdqYHlYXm3gE+AzbBilaVjes5hV7RXgKaA6cCEwTUQGq+rUMLnux87tAuxcZ2LP/TnAHdiwzQNBmQnAf4NNix6iKe+3qODE7AL+GuTVwLTvmOB/oT2v4HfvYF//Csu/i5L1vBpgb/ganIhXgJuwMaOUYo5hBhXb8yqx7EAq1lBuBlqGpadjN14e0CnK+WsfsZ+o6RF5bwISln5dkL4VaBOW3oTATh+xn1pR9n1wcI88FpGejr3BbsHeAC8K6hpTgvNXJyj7bYznfVmU+zGazM2wRuidsLSQpeDcYurYGL5djLI8He2+jHbtsLHibKBnRNl2wfV6OixtWLD9IqBmBdzvoef3DkzhNwF6YI2qAjOjHOsMoFrEfloE990LUeoYGzwLHYP/9THFtiD8mIHWWLtUbM8L63Ep8ECU+lKiyLzPs1XI+TgrKP/PGM7hFcE2D0ekDwjSn41yvjcCTaPsa0aQf1+UvEFB3oiI9GrY8/ozQRvBHivbR0BGRHkJKxeSZ1hJj7fcXeVVdQNmJhoWJA3GTBkTS7j955hZ6bLASy6WujcBR2Bmky2Yph+FafYlInJqLPtLJDHKfgTB27WG2cVVNQfrDaVg447x4J8a3G0Bobekqapa8NamquuwhrBTxHHtAHujFpG6ItIY61Uswnon4WVzMDOjYL3Kx7CH45YSyFk3+N5awuMqlJDMgdy1gx5WHvBlhMxbgu/TA4ebwtgCHCIi3coqW2EEPZYLsbfalSLSOPTBGuwvMHNoJI9rYse4Irkbux/WYr2hS7H247dRyj6i+1okfof1Ap4MP+bguN/EnoX+QdlTsZ7WuPBjVuudPF9CeS8ENgH3RGaoan4J9xGN0ty/gzAz44MRcryNmTQHikhkm/+MqhbVyxwTJW0oZtl5PeL81sfOcXv2PPcXBt+3aMR4pAYUf1jRSYTZEKxb+baIHI/djLM0Nu+YW7A3kQexRrzEBI3ozcDNQaNzLHAudgFeE5Geqro4ln0WRmCmqRGRHHJjbhKRnq2qWyiCGGTvEGzyfZTdhNI6luwoimVpxP9NwffPUcpuwt7yCxCRw4B7sTetWhHl99mHqi4RkRuwN/Bs4HxV3V0COUMPfZ0SlC0SETkAMz/9BntA9xIxTNZPROQZ7EXtQhGZDUwHpkTc79djZpf5IrIUGyt4E3izjA1eOE0wq8epFO5KH62uH0tagYg0wXr9IfJUdZ2I1MBeUMPZoqrZJdjtBGzMUDEl+6NGOKcUI+vBwff0IupoFnyHnokfopQpafvUCZgX2TDHgdLcvx2AVcGLbyTfA4divdpwZVXU9V6nqtE8Iw8O5CrKrNcs2Hcn7Fp+U0TZUpEo5fU+NoB9J9APs8GWGFX9QUSewjyOji52g8L3swEbZ3tLRJZjNtYhwH2l3WcEY4FLItJCiiWyYZ7Ent5osSRA9pJSmLdVYekFc6hEpC3WE9iKKbBFWAOlmBNI7UL2cVbwXQNzHy/2ZUNVt4nIL0AXEalRwoZzX+FFagcy1wpknI+9deZjL1V7jVOp6iUiMho4HRubuhG4VUSuV9VHgzJviE0mPgPog/UELgP+KyL9gx5nWQmd9+lY772kxNLrms3eLye/YG/d52EvrOEMx0yexfGTqhaleMKJJmvouC8mGAOLQuQLWGXku+D7sHKup6jrXVieYC9EFxSx7Xdhv0MOGHElIcpLVfOCN9JbsLfnF0uxmzuxk/UQZo8tK18E363isK8QD2MDtuGEnApOiUhfRemJlD30MB4SpWzXiDJFEfcbLIJBmII6W1U/Ds8Iepb7uIaLyP9hY0mjMJPz0yLSQ1ULa5jCeRUbIL8Ie6MvDSdj840uVdW9GuRgbtU+qOp32MM7OpiU+iUwKnA60qDMRuxeeS4w8Y3Cxk8GYj2PsrIOGwOtG4MyiJUL2dvSEHpBeJ997/doVoHy4Kfge30Jjjv0THTBvGbD6UrJ+BF7Qaqu0ac2hIjp2VLVn0VkLnCciHRR1Wi9w0iWAqeJSP0oPaau2EtjpNNLafgJm2f2hRbiVh/Gj9iLXE9gVhHlYm57Ehke6l+YPfsPqhrzOEQwljMWe1M9oyTbiMixUviM9pANPW6T+1R1gapOj/jsDD6R6UXWG6PsX2POHcPD538F3kd/xm6MN0pwCKEbsWEJypaGUO9sr4gWInIFe+aehaf3BEZjZrVbsZ5mXeDZKLb7aDyMNeIPi8ix0QqIyKkiMqQUMp9KxBidiDSMlCtoRH7GxlYyRCQ18roGCm1u8Dcu5z4wPz4PHCUiv4tWRkSaRkuPoY7PIu7pz4L0zCj3e0leNuLBS9hL0N2B+XIvxKLWVA/+TsMU7jUiUjOsTGuK7lWE8zzmXHVblLrC75nSPFs3Bd+TJcq8zuBeul5EQor2daxNvzmi3OlYD25qnMzSzwT1PBgtU0Sahf19Ifh+QKJHSwqdo5jPT6LMhqjqr5jHTVl4CHMVLmlIlAuxBv1tTOtvwMYBzsDMlwsooeNIBVBi2YOe7bWYU8NsEZmAmbbOA47BPKF+2reKfQj16B4Skecxr63vgp5EPHgXM0U8KxY2bBPm1nsGNjWg4H4UkVpYNIOtwNDgoZsrIjdh7rY3UcjDE0JVV4vImZji/p+IvM4es2VL4DTMe7MoM/b/CKYfBKa+FdjYwUWYCbF7WNmLMdf+1zDT5m7sZes3wEuqmh0orkwRmYoprLXsiSSzCRv7ihe3Yuf3JRF5Cbu+OZip7wxsjs6wONZX4ajqCrFIMU9gIc+excyZTbBr9VusF7JMVTeJTfEYA3weWIdqYmG3fqJkJruxmFn7NrFQTR9gz80hmIk75BwS87OlqtPE3P4fBxaJSHiEjQOx8f8DgJDjz9PYsMVNwb36aVDuamx86q8lOJ5iUdVXgmGca0XkcGw4Yz3mpXlsUGfHoOwsEXkIe16/FpEp2PPUAXOuOQqzECzA2qyrRSQ093Gtqn5EYZTULTGWD0VMOIxStkhX+Sjl/8QeG2pxrvLdsDGhzzAzXU5wguZiirRuEXLNoGJd5WOWHWsop2GN886g7GVRyt1F4S7xf8HMD7uJPkm5fUT59uHlopzDZRFpJ2IKYVtwg74dHOteZTHFnI/N5wrfXrCHZTdwdAnPZUPM7Bxyu8/BlNArmAkzvOyyKPdjD+A9TLlsC2Q9gQi3dUypTcIU147gOnyDjXtVD8qkY0o39EKyK6hzImHTGYqQZa86i7umWGN8O6ZoswP5F2IOMEeHlRtGlAm4Cbzf+1LyNqPQ+zeszHHYy9za4HqvwnrwN7Kvy/aV2PhraScpZ2AvCt9jz91mbDzw6pI8WyU43s6YAvsRe/nbGcg7HjgsomxokvLS4LjXYs5B7Qo538MKqXMGEc9ulDIXYd7GofZmGWaqPy9K2fOxtmxb8Gz8gI0hp4eVOQOzIu2kBJOUQz72juM4jpM0+JIojuM4TtLhystxHMdJOlx5OY7jOEmHKy/HcRwn6UiYq3yiady4sbZv376ixXAcx0kqvvrqq/WqGhnOrtJRZZVX+/btmTNnTkWLEVeWL7e4t23atKlgSRzHqaoEYdUqPVVWeVVFLrrIlnCaMWNGxQriOI5TwbjySiJuu22fCDSO4zj7Ja68koj+/fsXX8hxHGc/wL0Nk4ilS5eydGkyrObgOI5TvnjPK4m49NJLAR/zchzHSZjyEpGJwJlYpOB9lj8PQuOPxYIzZmEBI78O8i5hz5ID96nqpMRIXbm4++67K1oEx3GcSkEie15PA49ia8FE43RsyehO2DpJjwNHi0goIngvLNLwVyIyVaMvdV2l6dOnT0WL4DiOUylI5HpenwZrzBTGQOAZtTD3X4hIfRFpgYXun6a28iwiMg1bh6k0qzEnNYsWLQKgc+fOFSyJ4yQBmg9bfoZdW0EEJAUQ+43AlqWwdh7k765oScvMzz/DL7/AId2gSWOgTmvoMaKixSpXKtOYVytgedj/FUFaYen7ECzcNgKgbdu25SNlBXLllVcCPuZV6cnPhXXzIXutNaA7N0NutjWekZ+8XZC9HrLW2Xf2etBcIFRGbH9Z6yB/F9b4Bo2w5ln53Vl70iWscS5orFMiGu/gPyl7l92rTCoFDX1I1mjbikDONti20uRMCTs2UiAldc/vUHpKamz/JcXkSQnbT2Hb5GyFDd/D7h3Bp7hV6iFikexyI7T4VGgVqtAawuGrUsk+P4pGgv22U2iXDrIYdDHsbnAY6a68kgdVnQBMAOjVq1eVW6jsgQceqGgRqj6qsGO1vZVvXWYNsqTaZ/d22LUZdm6Crb/A9lV7GnfVIG8jZK0xZRULKWmQ0QCqN4DUtKBFU/tOSbX0tNoUrMOq+VZvvQMgrdbe6QqQb9tq/p700P4KyoX9hr3Lqgb7IMo+8oE8WypU8yGtDrTpCynVTKGG6tX8Pf/JD0uL8inIVzvnGiZ/UfsoOM48+59aHRp0MplS06FhZ6jRlALVERxDbk4+eRnNqN7hWMhowJezUnjuxTQ0H2rVUmrXhnPP2U3nzsrq1cKXs1KpVUupXh3mzkth0Y8pjPxTDh06KC//pxr3PpDOtu1C3TpKnTpKvbow4fFsGjWEjz9J5a13qvHi5DQ2bRbatMnnmKNyuf2WXaSkwPkX12TxkhSys/dorJP65vKvcXYPHd+vFhs3Cq1aKm1a53Pggfkc3zuXE0/IQwSefCqNUaMzeP3lHZzUz65ltfQq1bRHpTId4UogPO5R6yBtJWY6DE+fkTCpKhG9e/euaBEqBzs3Q84WyN1pn7ywb7AGKmsdZK8zRSMp9p212vK3rYANCyE/J+y1V8Mawbyi65dUqNXCPoC14kD1elCnLdRoBE0OhbptgBTIqA/Vatlrcn5eWMOr1uDXaGqKKzXN/ktqRIW6p+cTngZBeiUn6oK3WkyZwvJ1n7SdO6H7oWls2y7UqqnUqgW1asFZZ+Xz55GCpKYybBh8/z1kZdn7xpIl8Mc/wu23w/rlcMwJkJEB1atbmd27oWmL6qRkwEcfwR/+sLc4devCoN+lU70ObNkBtetAu/awfbt9li6DXzPrsGErvPwaPPMMnHQSDB0KvXun0KhROvn56eTlwfsfQG6u1bljB2zdCvn51dBqdVCF666DlSth+XLh119TmPwSpKalc/pZJuuo0dC7N/Q7tRZ16sZ0ZZKahK6kHIx5vVWIt+EA4FrM2/Bo4J+qelTgsPEVcHhQ9GvgiNAYWGH06tVLq1psw++++w6Abt32OX3JS34u7FgDOzJh3bewbp4pIs2zvNwsM//kbLfv7av2KKESERhW0utCzeANPKMRNOgM1aoH+YFSCJm4ajU3JVS3vfVq8nNNnrTapmTS65qiSU3f0+sqqE6SQ6FUAvKDTlNenjXaqlCnDuzaBevXmwJq1Mga9sxM+PZb+PRTO8UrV0JODowfD5s3w+jRsGmTNebZ2fY54QS49FLb/6mnQtu2ts/cXOjQAU47DXr2tO3efhsuuABatzY5cnJMPrD9L14M27aZnJ06QY8ekJpqZfLyID3drJoavAPl5+/Jy801BZuaCmlpUL8+VCui2xC5bU6ObZ+dbf9zcy2vUSOYMQMuvNCU43nnmRxlRUS+UtVeZd9T+ZIw5SUiL2I9qMbAGsyDMA1AVf8VuMo/ijljZAHDVXVOsO2lwF+DXd2vqk8VV19VVF59+/YFkmzMS9VMcKtnw/rvYPtKU1TbM808l72Ovd6m02pBtZpBDyQl+F/D0tJqBoqnk5nRqmXYJyXdFElqOgXz7ms2hdotTdlAMC6SFoyNEJgCEzPW4VgDvHq1Ndrr18OkSfDSS/Daa9aL+fvfTRFFMn++Nfh33GHlq1WzW6pWLejfHx56CGrXNoVQvfoe5RGuREK/Q+Tn237S0+0WiByDqszs3m3KffNmU6Qidj6bN4eOHeNTR7Ior0R6G55fTL4C1xSSNxGYWB5yJROjR4+uaBGKJncnrJ8Pq2bCik9gyy+w9WcbBwJTGDUaQ80mUKMJNDw4+N0UajUzpdT0UEjNoMBUFhqsL3AsSIIWZj9g1y6YPRtatrQezZIlZoJbu9aUyY4dVubPf4YBA+C992DgwD3bp6VBnz6wYYMprz59TAHt2GFKpUEDa6hDPYlBg6z3dOSR0LChKaCGDU2Jhd8Spbk9kumWSkuzT+3ae3qoOTnWY93fSKjZMJFUxZ5XpWLXVlj3Daz9GtYEn40L94wX1WkL9TpC7RbQuAc0O9zGgdJrU+C1FjLTuZmt0rF1KyxYYA3lYYeZOe6oo+y7dm349Vczo/3pTzBiBGzcCIMHWw8gOxtq1rSe0KWXQr9+tr/p083klZICZ5wBBxxgprRIU1t+/r5muNCnRo2iTW77G6p2HapXt0888J6XE3fmzZsHwKGHHloxAmRvhPlPwPdPwcYf9qTXaAwNu0KPK6Fxd2h2BDQ62Ex6bp6rdKharyY7297emza19M8/h1dfhWnTbHwJzMlg/Hgr37atKZXsbDjkEOst9expaU2bwhdfWI8pNbDMhpSMiDWsRxyR+GOt6ohYz3V/xHteSUTCx7w0H358xSZybl8JP75sLuDNj4KWx0OT7tD0CGjQMRhPSnNFVYl54AF44QX44Qcb8Ac48EBzgti92wb8v/4aevUy89zBB1tv66CD9iik1NQ940TVqvnlrop4z8uJO4888kjiKsv8EqZfbWZBSTGHiY4DoOswaH2imf+85arUbNsG//ufjRVt3WoOEw0bwhVX2BhJzZr21r57tymi22+Hbt2gWTP7nxrpse84lQjveTl7s3kJzPk7fPsv89g7/AY45OLAm6+6ef650qqUZGfDBx/AO+/AzJnw3XfWQxo/Hk4+2ZwbQl55fgmdwvCelxN3Zs+eDcCRRx4Z/51vXgKf3wkLX7Bxqi4XwFG3mAdgalr863OKJScHFi40x4Xu3c3UN3kyrFoVmshqn5NPtkmq33wDv/2tOVQcfrhNwj3iCDjlFBuTcoXlVCVceSURf/7zn4E4jnltWAA/vwdLpppre2p16H65BfRs0iOYN+Ukkm+/heeeM9fyhQvNO2/YMDPpZWdbhIZI1q41U1/t2jZ/6pRTzDwYmsfkOFURV15JxKOPPlr2nezOhgWTYN7jsD5wKavbAQ67FroMhWaHudJKIFlZ8P77No8pL89cyNesgeOOs7Gpgw4yB4qMDBuH+ugji6xQs6aZBFNTLb1+fUvr3r2ij8hxEoMrrySiTGGhVGHhc/DJXyy8UqOuZhZsf7q5tafXCcIlOeXJli0WNWLNGnMtf/ZZc5g47DDrJY0bZx6AnTpFD/VTBRdLcJxS4corifj888+BUgToXfeteQ6u+swmDPcZA+1PM4/BVLctlReZmfDuu+bZd9xxUK8ePPighTQCmwB87LFw9dXWc0pPh7PP9svhOCXBlVcS8de/WnjHmMa85k+E6X+woLLH3g09LrfAsx7VotxYsQJuuMEm/IbmUz30kIVHOvNMCwrbooVN8G3a1EyCrrAcJzZceSUR46NFLi2MNV/BnL/BDy9Cq+PhpEehwUGQVqP8BNyPycoyJbRjh/Wy1qyBiy+2nlRurjlUiEC7dnDMMR7iyHHKij9CSUTnzp2LL5SfB5/dDrMetIjsPa+GY+6A2s3KX8D9kM8/h1GjbE7VB8G6TFdcYZEpevbcs/xFfr65vKekeC/LceKBK68k4pNPPgGgT58+0Qvk58Gb58LiV+HAc+C4e6DhQba8iBM3tm6F11+HCRPgs89MQf3+9+bKXqMGXHaZpdUI6+R6tArHiS/eqiURd955J1DEmNcnI01xHXEDHHWzBcz11/y4sHPnniU6pk2DSy6xhQv/+leLnN6q1Z5I6I7jlD+uvJKIiROLWNLsh8nw9SPQ+XzoNdIVVxnJybEJvx98YJErVq6E4cPhqqugTRtbGLFfP/MgTPMAJI6TcFx5JREdC1sqddtK8yhs3AOOvdNiErriKjX5+eZUMXeueQV27w5HH21u7c2amev7kUf6KXacisSVVxIxffp0APr3778nUfPhvUsgLwdOeBDqtt2z1L1TLLt2mUv7/PmmrJ5/HjZtshiBf/gDnHuueRGmpNi4lY9dOU7lwJVXEnHfffcBEcrr63/Crx/CMbdDy2PdFb6EbNwIr71mk4aXLDGPwK5dzWuwdes9E4fdpd1xKif+aCYRzz777N4Ja7+B/94MrU6AbpdD9foVI1gS8t13cPnlFoZp0iQ47TQLbFu9uveuHCcZcOWVRLRp02bPn+xN8MZvIb0uHHc/1GrmgzBFoGrLiSxYYPOwmjSBt9+2CcV16/qpc5xkwx17k4j33nuP9957z/58cBlsWwH9HrHAuh5UNyrZ2bYYY9eucMEF8OabFgWjfXuL4F6vnisux0lGEtrzEpHTgLFAKvCEqo6KyG8HTASaABuBoaq6Ish7GBiAKdxpwB+1qi4DXQijRtnpOq1bbVj8Ghz+J2hxDNRoWMGSVU6mTjX39o0boUsXeOABuOgi8yB006DjJDcJU14ikgqMA04BVgCzRWSqqi4IKzYGeEZVJ4nIScCDwEUi0hs4DugRlPsf0AeYkSj5KwOTJ082+9fH50CNJnDwUKjVwoPshvH11zaZuEULW/b+iCNMYZ18si3QmJFR0RI6jhMPEtnqHQUsVtWlqpoDTAYGRpTpCnwU/P44LF+BDCAdqA6kAWvKXeJKRvPmzWm+/UvInAk9r4K6rd27MOB//4M+fUxZ3XabBcpt3Rr+9S9ze2/Z0hWX41QlEqm8WgHLw/6vCNLC+QYYHPweBNQRkUaqOhNTZpnB531VXRiGPZncAAAgAElEQVRZgYiMEJE5IjJn3bp1cT+AiubN11/lzX/+Aep1gIN+DxluLvz6azj1VDjhBFi4EEaONPf3unVt4cYOHWxSseM4VYvK5m04EnhURIYBnwIrgTwRORA4GGgdlJsmIieo6n/DN1bVCcAEgF69elW58bC/3TMStqzhrCv+DbVb7tcBd/PyYPVqmDIFZs2y9bOGD7fQTbVq+fwsx6nqJPIRXwmE+XrTOkgrQFVXEfS8RKQ2cI6qbhaRK4AvVHV7kPcucCywl/Kq0uTl8Mp5m6Bhb2jTF6rXq2iJKoScHLjuOjjwQFsr69xz4ZxzoGNHG9PywLiOs3+QyEd9NtBJRDqISDowBJgaXkBEGosUeB/cgnkeAvwK9BGRaiKShjlr7GM2rNIseYvG1TbT+KiLLXbhfhgCat06OOUUc31fssTSWrWCbt2gcWNXXI6zP5Gwx11Vc4FrgfcxxfOSqn4vIveIyNlBsb7AIhH5EWgG3B+kvwIsAeZj42LfqOqbiZK9UvD9U7y6qA6vztsN6fvXIE5+Pjz6KBx0EHzxBdx/P9x8s41nNW8ONWtWtISO4yQaqapTpXr16qVz5sypaDHiQ9Y6GN+Svk81gvoHMuPT/1W0RAkjLw9mzID+/W114ltvNeeM+vV9crHjlAci8pWq9qpoOYrDh7WTgR9ehPxc3pj0D2jXv/jyVYCFCy3m4KWXmsv7c89ZKKcWLSz+oOM4+zc+SpAM/PACNOhEvY69qdewSUVLU66owjPPQK9eEFp7U9Xc4du1c8XlOI7hyquys/UXyPwS2p/OlDc/YsqUKRUtUbmxZYv1tC65xMI5vfyyTSxu184C6bqZ0HGcEG42rOwsfNG+O57F4/fcCwjnnXdehYpUHmzZYqsVL1pkS5Vcd515EjZo4ErLcZx9ceVV2fnhBWjcHRp24Z133q1oaeLO7t0WOHfTJlu5uGVL6N7dFFfduhUtneM4lRU3G1ZmNvwA6+dDh9Mhoz41a9akZhXxC8/Ph2XLoHdvePppC+F05pnQs6crLsdxiseVV2Vm4fOAQMczoVoNnnvuOZ577rmKlqrM7N4Njz9u3oPffmuKa9s2C+vUsaMrLsdxisfNhpUVVVg0BZr1gvoHQEoqTzzxBABDhw6tYOFKT04O/OUvMHasLRA5bpx9t2plystxHKckuPKqrKydB5t/gmPuLIhjOG3atAoWqmxkZ8N//wv/7//B734Ho0ZBbq7N46oi1lDHcRKEK6/Kyk+v2CKTHU6DVFuIKi0trYKFKj3btsHKleYC//zz5pQhYm7wvs6W4zix4mNelZVfpkGjblC3bUEQ3qeffpqnn366YuUqBRs2mCfhZ5/ZUiW9e++Zv+WKy3Gc0uDKqzKycxOs+QpaHgvpe7wXklF5bd0Kv/kNvPCChXwCW+W4aVNI3f8C4zuOEyfcbFgZ+fVD0HxodTxU29M1mTFjRsXJVApycmyRyK++gn/+EwYNMvNhvXq+urHjOGXDlVdl5Of3oVpNaH5k0q6WnJMDTz0FTz4JF18MAwbAjh3W46pfv6Klcxwn2UnOlrGq8+t0U1wZjfZK/ve//w3AFVdcURFSlZi8PFixwkI99egBf/6zLRTZvr0H1nUcJz74mFdlY9Ni2LrMxrvS9vYfnzJlSqUPzLtrF3zzjUXQuPFGeOUVSEuzeVyuuBzHiReuvCobPwfxC1v3hdS9W/vp06czffr0xMtUAnJzrac1dCicfLJ5GIL1wpo1MwXmOI4TL1x5VTZ+fhdqt4YGBxW4yFd2duywtbeOOw5eew0uuMAWjdy2DRo1MgcNx3GceOJjXpWJ3F2w4hOLZVh93xb/scceA+Dqq69OtGSFsnkzXH+9rXrctSu8+KLFJ8zOth5X/fq+pInjOPHHe16ViVWfQW4WtDphn/EugDfffJM333yzAgSLTl4erFtnPazhw+GNN6BNG5t43LGjr8XlOE754T2vysTSd0CqQevj9hnvAnj33cqznpeqLWkC8Mgj9j8729bj8qjwjuOUN97zqkwsex+aHgY1m1f6LsuoUXDiiRZBIzcXdu6Etm1dcTmOkxgSqrxE5DQRWSQii0Xk5ij57UTkQxH5VkRmiEjrsLy2IvKBiCwUkQUi0j6Rspc72zNhw3fQqjekRw8/MXbsWMaOHZtgwfZGFf79b/jrX+HQQ01ZqVqcwho1KlQ0x3H2IxKmvEQkFRgHnA50Bc4Xka4RxcYAz6hqD+Ae4MGwvGeA0ap6MHAUsLb8pU4gP79n31Fc5EN8+OGHfPjhh4mTKYLcXLjrLrjqKjj+eHj4YUhPtx6Xz+FyHCeRJHLM6yhgsaouBRCRycBAYEFYma7ADcHvj4HXg7JdgWqqOg1AVbcnSuiEsewdi6jRuBukRp8UNXXq1AQLtQdVuPVWU1innw7332+ehM2be4Bdx3ESTyKVVytgedj/FcDREWW+AQYDY4FBQB0RaQQcBGwWkVeBDsB04GZVzQvfWERGACMA2rZtWx7HUD5oPvz6EbQ8HqpXzsB/69fDueeasjrtNGjY0OIUVvKhOcdxqiiVzWFjJNBHROYCfYCVQB6mZE8I8o8EOgLDIjdW1Qmq2ktVezVp0iRhQpeZtfNg50Yb74riIh9izJgxjBkzJoGCGU8/DcuXm+IaMMBc4F1xOY5TkSRSea0E2oT9bx2kFaCqq1R1sKoeBtwapG3GemnzVHWpquZi5sTDEyN2Avg1CPnUoneh410AM2fOZObMmQkSynj4YZvD9cILtg5XrVo2+dgVl+M4FUkizYazgU4i0gFTWkOAC8ILiEhjYKOq5gO3ABPDtq0vIk1UdR1wEjAnYZKXN79+BHXbQb12RYaE+s9//pNAoWDaNLjlFjMTXnqpOWe0aOGKy3GciidhPa+gx3Qt8D6wEHhJVb8XkXtE5OygWF9gkYj8CDQD7g+2zcNMhh+KyHxAgH8nSvZyJT8XVn4OzY8q1EW+Ili7Fi66yDwJ77/f4hO2amVLmziO41Q0CY2woarvAO9EpN0R9vsV4JVCtp0G9ChXASuCNV/B7m3Q4mhIzSiy6KhRowC4+eZ9psjFnauvho0bbUmTVq18jMtxnMqFh4eqaH4JxruaHwOp6UUWnTdvXgIEgu3bbS5X//4WbLdxY1dcjuNULlx5VTTLZ0C9jlCnVbFLoEyePLlcRVG1qPA9e0KnTtbjatbM53E5jlP58BGMiiRvN2TOtPGutNoVLQ333w8XXggffGBBdhs1gjqVZxjOcRynAFdeFcnqWbB7B7Q4BtKKDwx47733cu+995aLKG+8AXfcAWefDb/5jcUsbNy4XKpyHMcpM6U2G4pIfSKUn6puLLNE+xOh8a4WRxU5vyvEokWLykWMBQtg6FA4+GC4+24zF/rqx47jVGZiUl4i0g74F+bSHu5dIIACPjoSC8s/hgYHQc1mkFL8pXjuuefiLkJ+Pvz+9xZY99FHLTq8Ky7HcSo7sfa8ngLqA5cBqzCF5ZSGvBwzGx70O0ivuPGurCwzF+bnm2dhgwYVJorjOE6JiVV5HQUco6rflYcw+xUrP4fcbGh+NFQrPJ5hOHfcYVPi7rnnnriIsHq1LSZ5+OEWPSOZwkE6jrN/E6vDxs+Ar9wUD379EBBo1qtE410Ay5cvZ/ny5cUXLEn1v5pL/Pjx5iLfsqVHz3AcJ3mItef1R+BBEblaVReXh0D7Dcs/hoZdoEajQtfviuSpp56KS9XbtsGZZ8KOHXDSSeZVmFYyERzHcSoFsSqvN7Ce1yIR2QXkhmeqat14CValyd0Ja2ZDlwsTPr8rLw/OOw++/x6eeAK6dLFFJR3HcZKJWJXXteUixf7Gys/MYaP5UZBeq8Sb3XLLLQA8+OCDpa565Eh4912480449lg3FzqOk5zEpLxUdVJ5CbJf8etHICnQvOTjXQAbNmwoU7U5OTaHa8QI6321bAk1ip8b7TiOU+mIeZKyiFQHLgS6Yq7y3wMvququOMtWdVn1GTToDNXrQ0rJB5smTJhQ6ipVYd06GDQIcnMt9FNdN/I6jpOkxGQwEpGuwE/A34GjgWOAR4AfReTg+ItXBdF8WDsXmvSAtFoJC9c+YgRMDJb2rFnTlJfjOE6yEutox1hgLtBWVU9Q1ROAtsA3mBJzimPjIsjZCo0D5RUDI0eOZOTIkTFX+cMPpriWLbP/vhqy4zjJTqxmw+OAI1V1ayhBVbeKyK3AF3GVrKqy6nP7btIzpvEugOzs7FJVedttkJEBl19uY17VfCEcx3GSnFibsZ1YeKhI6gV5TnFkfmkRNeofUOzik5GMGzcu5uo++ABefRWuuAI6dDAl5jiOk+zEajZ8E/i3iBwnIqnB53hgPDA1/uJVQVbPgsbdbX5XOdvudu6E4cNNaV15JTRsWK7VOY7jJIzSRNiYBPwXyAvSUjDFdX0c5aqa5O6EDQug6yUxze8Kcf31doofeaRkw4s7d8LDD5tXYatWFr/QcRynKhDrPK/NwEAR6QR0CZIXeqioErLma8jfbZ6GqeVrv/v5Z5vX1bu3RYz3hSUdx6lKlGroXlV/wlzmnVhYNdO+mxwa83gXlLzHtWQJHHII3HuvrYzcti2k+kprjuNUIYpVXiLyT+AWVd0R/C4UVb2umH2dhrnbpwJPqOqoiPx2wESgCbARGKqqK8Ly6wILgNdVNflCVa2eBTWbQp1WkFJ+2uTuu+376KOhaVOPouE4TtWjJD2v7kBa2O/CKHJhShFJBcYBpwArgNkiMlVVF4QVGwM8o6qTROQk4EHgorD8e4FPSyBz5WT1rFLN7wpxzTXXAEV7Hf70E7zwAlxwAXTq5EF3HcepmhSrvFS1X7TfpeAoYLGqLgUQkcnAQKwnFaIrcEPw+2Pg9VCGiBwBNAPeA3qVQY6KIXsjbF0GBw4utfKqUYIu1C232DyuK66wKBo+GdlxnKpImaerisiBwApVLW6eVysgfCXFFViIqXC+AQZjpsVBQB0RaQRsAv4GDAX6FyHLCGAEQNu2bWM4igRQMN7VI6Z4huGMGTOmyPwlSyxi/OWXW6/LvQsdx6mqxBrb8AERuST4LSIyDfgRyBSRY+Igz0igj4jMBfoAKzGX/KuBd8LHv6KhqhNUtZeq9mpS2da0z/wCEJvjVcLFJ2MhL8+WNnnvPYtj2KBB3KtwHMepNMTa87oQOC/4fTpwKBac90JsfKoos+JKoE3Y/9ZBWgGqugrreSEitYFzVHWziBwLnCAiVwO1gXQR2a6qN8cof8WxehbU72grJ0vpFtAaMWIEsG90+awsGD/eVkdu0QLq1IHqsUWechzHSSpiVV7NMHMfwBnAS6o6S0Q2AnOK2XY20ElEOmBKawhwQXgBEWkMbFTVfOAWzPMQVb0wrMwwoFdSKS5VWDMHWveBtJql3k2jQkLBX3YZTJliqyJ36uRzuhzHqfrEqrw2AO0wBXYqEFIg1YAiXQNUNVdErgXex1zlJ6rq9yJyDzBHVacCfYEHRUQxr8JrYpSvcrLlZ9i50YLxViu933q0FZTnzIHJk+GqqywMVPPmPqfLcZyqT6zK6z/ACyLyI9AQU0Rg5sNio2yo6jvAOxFpd4T9fgV4pZh9PA08HYvQFU7IWaNx91JNTi6Km26y8a1LL7WVkWvXjuvuHcdxKiWxKq8bgF+wNbz+oqo7gvQWwOPxFKxKkfmFLX/SqEupPQ0Bhg8fDsBTTz0FwLRp8NFHpsDatPGVkR3H2X+INbZhLuayHpn+j7hJVBVZPQsadYW0OmWaeNWmTZu9/u/eDccfDxde6BHjHcfZvyhJeKjDgXmqmh/8LhRV/TpuklUV8nbDum+g85BST04Occ899xT8zs83B43x422cKy3+3veO4ziVlpL0vOYAzYG1wW8lunOGYo4YTjjrv4W8XTY5uVp8Isnn5cGYMdC3r0XRqFcvLrt1HMdJGkqivDoA68J+O7FQEFmjZ5nGuwCGDh0KwNlnP8fNN8Pf/mZu8u5d6DjO/kZJYhv+Eu23U0Iyv4TqDaBO2zJH1ujcuTOqcN990L49nHWWTUh2HMfZ34g1PNS1IjI0SvrQIPqFE8nq2dCke6lWTo7k9ttvp2fP25k/3wLvNm1qIaEcx3H2N2Jt+q5n7+C6IZYBfyqzNFWNXVth04+2DEq1siuvvDyLGt+uHQwc6HO6HMfZf4lVebXG5nlFsiLIc8JZPQvQILJG2YMNnnPOENatG8Kf/gRNmvhYl+M4+y+xTlJejUXTWBaRfjiwPh4CVSlCzhqNupXZWQOgW7dDOfBAOO00jxrvOM7+TazK6wXgnyKyA5gRpPUDHgGej6NcVYPVs8xRo3YzSClbN2nqVOjX72batLEJyT6vy3Gc/ZlYldedmLv8+9g6W2Cmx5eB2+MoV9VgzVfQ7PAyT07evBkuuQQOOwwmTPBel+M4TkxjXqq6W1XPBzpjy5lcAHRR1SGqurs8BExatq2EHZnQuCdUK/0yKAB//7spsKysc7jhhnN8rMtxnP2eWHteAKjqTyKyFVgXrL3lRJIZn8nJWVkwbpxF0zjmmGM9hqHjOA4xKi8RSQPuB64CagAHAUtF5CHgF1V9LP4iJimrZprSanhwmZZBeeIJ2LjRImkMHDjSJyU7juMQu6v8ncBZwFBgV1j6LGBYnGSqGqyeDQ0Ogox6ZYokv2YNHHEEHHusz+tyHMcJEavyOh/4g6q+AYSbC7/DemEOQH4erJ1rkTXKMDl51y64+GKYONGiaQwceDZnn312HAV1HMdJTmId82pJ9EnK1Uqxr6rLhoWwezs0ORTSapRqFwsXwvffQ/fu1uOqXRtOPvnkOAvqOI6TnMSqcL4HTmTfScrnAl/FQ6AqQchZo1GPUjtr/OUv8Omn8PHHtm6XCPzxj3+Mo5CO4zjJS6zK627gORFpg63d9XsR6YK5zA+It3BJS+YXkF4HGhxQqkjyX30Fb70F11wDrVpBzbJ52juO41Q5Yp3n9SbWyzoVG/O6E+gEnKWq0+MvXpKyeraFhEovnYfF7bdD3bowfLgtNhni9NNP5/TTT4+TkI7jOMlLiXteIlINU1pfqmqf8hMpydmdDRsWQPfLSuWs8emn8O67cP31Fj2+WtgVOuuss+IoqOM4TvJSYuWlqrki8irQBdhQmspE5DRgLGZyfEJVR0XktwMmAk2AjcBQVV0hIocCjwN1sbBU96vqlNLIUO6smQOaZ84apZjftWQJHHQQDBsG9evvnXf11b5kmuM4DsTuKv8NcGBpKhKRVGAccDrQFThfRLpGFBsDPKOqPYB7gAeD9CzgYlU9BDgNeEREIpr2SsKqL+y7UbeYlVd+PpxwArz2GrRuvXevy3Ecx9lDrMrrLuBvIvJbEWkjIg3DP8VsexSwWFWXqmoOMBkYGFGmK/BR8PvjUL6q/qiqPwW/VwFrsd5Z5WP1F1CrOdRpFVMk+fx8mDwZdu60iPGRvS6A/v37079//zgK6ziOk5zEqrzeBroDr2Lu8uuCz/rguyhasfcqzCuCtHC+AQYHvwcBdUSkUXgBETkKSAeWRFYgIiNEZI6IzFm3rjhxyonVc2zl5BidNV57DS68ED78EBo3jr7Q5Hnnncd5550XJ0Edx3GSl1gNU/3KRYo9jAQeFZFhwKfASvYsvYKItACeBS6JFhBYVScAEwB69eql5SzrvmStg22/QuffxxRJXhXuvRfatoXf/Abq1Yte7oorroiToI7jOMlNiZSXiNQERgO/BdKA6cB1qhrL6skrgTZh/1sHaQUEJsHBQZ21gXNUdXPwvy7W87tVVb+Iod7EEVo5ucmhMU1O/uAD+OYbuOceaN4cUmLtDzuO4+xnlLSZvBsLvPs28CJwCub9FwuzgU4i0kFE0oEhwNTwAiLSWERCMt2CeR4SlH8Nc+Z4JcZ6E0fmFyAp0OiQmCYn338/NGsGgwdTZNT4vn370rdv37LL6TiOk+SU1Gw4GLhMVScDiMjzwGcikqqqeUVvagSu9tdiqzCnAhNV9XsRuQeYo6pTgb7AgyKimNnwmmDzc7GwVI0CkyLAMFWdV0L5E8PqWVD/QKjRyJRYCdi4EVassAC8LVtGH+sKMWzYsPjI6TiOk+SIavFDQyKSA3RQ1ZVhadnAQaq6vPAtK45evXrpnDlzElehKoxrAG37Q//xULNR8dsAO3bAzz9b7MIuXYpWXo7jOOWNiHylqr0qWo7iKGnPKxXIiUjLjWH7qs/mJbBrCzTpAWkZJdpk7VrYsMEUV4sWxSuu3bt3A5CWVvqVmR3HcaoCJVU+ggXkDV+AMgP4t4hkhRJUdf9dbGrVZ/Ydg7PGDTfARx/BtGkWy7A4TjnlFABmzJhRSiEdx3GqBiVVXpOipD0XT0GSnswvoVoNaNCpRMrrxx9hyhQYMgSaNClZNI3LL788DoI6juMkPyVSXqo6vLwFSXoyvzQvw7Q6ZgcshhtugPR0GDEiejSNaAwdOrSMQjqO41QNfEZRPMjdBeu/gybdIb34SPIffwxvvw1/+AN07GhKrCRkZWWRlZVVfEHHcZwqjjtcxIO18yA/B5r0hNTqxRafMsXmdV100d7rdRXHGWecAfiYl+M4jiuveJD5uX03Ln4ZlLw8uPFGuOwyi2GYUTLHRACuuuqqMgjpOI5TdXDlFQ8yv4QaTaB2S0gp+pRmZtqUsDp1THnFggfldRzHMXzMKx6snm3zu4oZ71q+3BaafP99qFkztl4XwJYtW9iyZUsZBHUcx6kauPIqK9kbYctSaNwdqhWtvJ58ErKzoWvX2Ma6QgwcOJCBAyOXQHMcx9n/cLNhWckMAtw3KXq8SxUmTYKjj4YOHaznFSvXXXddKYV0HMepWrjyKiuZXwBiPa8ilNeMGbBsGVx1FTRsWKKpYPswePDg4gs5juPsB7jZsKxkfgn1D4CM+pBSeHDCCROgVi1bbLJ2bIssF7B+/XrWr49lCTXHcZyqife8yoIqrJkNrfsWuXJyfj5ccQUcd1zJQ0FF43e/+x3g87wcx3FceZWFLUth5yabnJxWuPLavh1at4ZWrUoeCioaN954Y+k3dhzHqUK48ioLq2badxHOGrt2wSWXwPDhcMghUKNG6as766yzSr+x4zhOFcLHvMpC5kxIzbBI8oUor+eeg9dft3W7GjQonaNGiNWrV7N69erS78BxHKeK4D2vspA5K4gkXxNk3/cAVRg7Fg44AI491qJqlIUhQ4YAPublOI7jyqu05OXA+vnQ5QJIiz45+aOPYP58uOce8zAs6wLIN998c9l24DiOU0Vw5VVa1n4DebvMWaPavgNZqjBmjK2QfOaZNrerrJx22mll34njOE4VwJVXaQlFkm/SI+p419at5qBx+OFQr17ZHDVCLF++HIA2bdqUfWeO4zhJjCuv0rLqS6jRGGq3gpS97YGq5qBx3XWwc2fZHTVCXHTRRYCPeTmO4yTU21BEThORRSKyWET2GcARkXYi8qGIfCsiM0SkdVjeJSLyU/C5JJFyR2X1LGjcw0yGEZrp00/NwzCUXFZHjRC33XYbt912W3x25jiOk8QkrOclIqnAOOAUYAUwW0SmquqCsGJjgGdUdZKInAQ8CFwkIg2BO4FegAJfBdtuSpT8e7FzE2xZAgecBen7xnq66y5z1DjlFGjevPQRNSLp379/fHbkOI6T5CSy53UUsFhVl6pqDjAZiFzfoyvwUfD747D83wDTVHVjoLCmARXnvVAQSb4npFbfK2vWLAvCe/nlkJ5etogakSxdupSlS5fGb4eO4zhJSiLHvFoBy8P+rwCOjijzDTAYGAsMAuqISKNCtm0VWYGIjABGALRt2zZugu/DqsIjyY8aZQF4zz3XPAzL6h4fzqWXXgr4mFdlID8/n/Xr17N582by8vIqWhzHKRGpqanUr1+fxo0bk5KS3DEqKpvDxkjgUREZBnwKrARK3DKo6gRgAkCvXr20PAQELJJ8vY5QvR6k7DmFmZnw1ltw8cWmwOLZ6wK4++6747tDp9SsWLECEaF9+/akpaUh8fDIcZxyRFXZvXs3a9asYcWKFeX7gp8AEqm8VgLhPt6tg7QCVHUV1vNCRGoD56jqZhFZCfSN2HZGeQpbKKqwZg60PnGfyck//gjt28M555jiimevC6BPnz7x3aFTanbs2EHnzp2T/u3V2X8QEdLT02nVqhWLFi2qaHHKTCKfvNlAJxHpICLpwBBgangBEWksUhBn6RZgYvD7feBUEWkgIg2AU4O0xLN1GezcAI177rUMiiq0aQPTp0PHjvHvdQEsWrSoStx0VQVXXE4yUlXu24T1vFQ1V0SuxZROKjBRVb8XkXuAOao6FetdPSgiipkNrwm23Sgi92IKEOAeVd2YKNn3YuVn9t2kO1Tb46yxZIlNTG7QwEyG1asXsn0ZuPLKKwEf83Icx0nomJeqvgO8E5F2R9jvV4BXCtl2Int6YhVH5pfmYdiw817OGjfeCF99BR98AE2blk/VDzzwQPns2HEcJ8moGv3HRLI6FEm+VkEk+Z9/hnfegdNPt3GueISCikbv3r3p3bt3+ezcceLE+vXrEZGYLAR33XUX3bp1Kz+hYmT16tWceuqp1KpVq8AZp3379owZM6bI7WrXrs3TTz+dAAkdV16xkLcb1n1j8QzT9kxOfuwxyMuDIUMsjmF5mZS/++47vvvuu/LZubNfMGzYMESEyy67bJ+8m266CRHhzDPPrADJSsaMGTM488wzady4MTVq1KBLly783//9H8uWLYtrPWPGjGHVqlXMmzePzMxMAGbPns3VV18d13qc0uPKKxbWzbNI8o17QJp1r3Jy4JlnoG9faN3aosiXF9deey3XXntt+VXg7Be0adOGl156iR07dhSk5ebm8swzz1Rq9+nx48dz8skn06hRI15++WUWLlzIk08+SX5+Pvfdd19c61q8eDFHHHEEnTp1onnz5gA0adKEmjVrFrOlkyhcecXCqle6Y7wAABu0SURBVLDIGkEw3unTYe1aOO88c9LIyCi/6kePHs3o0aPLrwJnv6BHjx506tSJl156qSDt7bffJiMjg759++5VNj8/n3vvvZc2bdpQvXp1unfvzhtvvLFXmdmzZ3PEEUeQkZHBYYcdxpdffrlPnQsWLGDAgAHUqVOHpk2bcv7558e0KviKFSu47rrruOaaa5g0aRL9+vWjffv2HHfccYwbN24vc96rr75K9+7dqV69Om3atOH+++9Hdc+0z/bt23Pfffdx5ZVXUrduXVq3br3Xc9W+fXveeOMNnnnmGUSEYcOGFaSH17N48WL69u1LRkYGnTt35q233tpH7pUrVzJkyBAaNGhAgwYNGDBgAD/99FNBfshcOnnyZA444ADq1KnDb3/7W9avX7/XfiZNmlRwTM2aNeOSS/aEd92yZQsjRoygadOm1KlThz59+jBnzpwSn9tkxZVXLGR+ARmNoE7rAuXVrZtNTO7dGxo1Kt/qjzzySI488sjyrcQpE3377vt57DHLy8qKnh8aIlm/Pnr+lCmWv3z5vnml5bLLLmPixD3+TxMnTmT48OH7TLYeO3Yso0eP5qGHHmL+/PkMGjSIwYMHM2/ePAC2b9/OgAED6NixI3PmzGHUqFGMHDlyr31kZmZy4okn0q1bN2bNmsX06dPZvn07AwcOJD8/v0Tyvvzyy+Tk5BS6IGv9YG7KV199xe9//3sGDx7M/PnzGTVqFA8++CCPPvroXuX/8Y9/0L17d77++mtuuukm/vKXvzBz5kzAlHH//v0599xzyczMZOzYsfvUl5+fz6BBg8jPz2fmzJlMnDiRu+66i127dhWUycrKol+/fmRkZPDJJ58wc+ZMWrRoQf/+/cnKyioot2zZMqZMmcJrr73GBx98wNy5c7n11lsL8sePH8+VV17J8OHD+fbbb3nnnXcKxgdVlQEDBrBy5Ureeust5s6dy4knnshJJ51UYO6ssqhqlfwcccQRGnee6KQ6pZ/q1hWqqpqVpfrDD6rLl6v+9JNqXl78qwxn7ty5Onfu3PKtxCkRCxYsiJrep8++n3HjLG/Hjuj5Tz1l+evWRc+fPNnyf/1137xYueSSS3TAgAG6ceNGzcjI0B9//FEzMzM1PT1df/nll4L8EC1bttS777474hj76IUXXqiqquPHj9d69erptm3bCvKfffZZBfTjjz9WVdXbb79dTzrppL32sXHjRgX0yy+/VFXVO++8Uw855JBC5b7qqqu0bt26xR7fBRdcoP369dsr7c4779RWrVoV/G/Xrp0OGTJkrzIHHnig3nvvvQX/BwwYoJdccsleZdq1a6ejR49WVdX3339fU1JS9JdffinI/+9//6uAPhVc0CeffFIPPPBAzc/PLyiTm5urDRs21ClTphTIVr16dd28eXNBmfvuu08POOCAgv+tWrXSm266Kerxfvjhh1qrVi3NysraK71nz5760EMPRd1GtfD7V1UVm7pU4W14cZ/KFh6q8rJzE2z+CTqcURBZ429/g7lz4Z57oFmz8nPUCHH99dcDPs+rMlPUpalZs+j8xo2Lzm/Tpuj8WGjQoAGDBg1i4sSJ1K9fn759++4z3rV161ZWrVrFcccdt1f68ccfzzvv2IyXhQsX0qNHD/5/e/ceVlWVPnD8+4IgIokXkLzlJRUkxxR41ErLvDxDV2ysbKy0sWwqS395y5oeu4w2NelPu41dbNRxGjMzS530N9pFNLWMIg3xTqZoSU2mJirK+/tjb4iDiKAczoX38zzngbP3Pnu9m30471lrr71WVNSvHZguueQSj+0zMjJIT0/32KbIjh076Nq16xnjVa3YaG/Z2dlcc801p8T7xBNPcPDgQeq5F6U7derksU3Tpk3Zv39/hcooKqdZs2Yef7Nu3bp53ACckZFBTk4O55WaE+nIkSPs2LGj+HnLli2Jjo4uM5b9+/eTm5tLnz59yowjIyODI0eOEBsb67H86NGjHmUEI0teFbXXnTm5cRcIrc3hw05zUMuWzpQnVTVnV3mmTZvm/UJMjTF06FCGDBlCVFQUTz75ZKVeW5mxHAsLC7nmmmvK7GYeFxdXoX20b9++OJk2bdq0wmWXVDLmsFJjt4lIhZswK6qwsJDOnTvz5ptvnrKuYcOGVRJLYWEhcXFxrFq16pR19bzZe8wP2DWvisr9xLmvK6YjhIbzxhvOQLx33ulMfeKNETVK69y5M507d/Z+QaZG6NOnD+Hh4fzwww/079//lPX16tWjadOmfPLJJx7LV69eTWJiIgAdOnRg48aNHj0X161b57F9UlISWVlZtGzZkrZt23o8StdKTufGG28kPDycp59+usz1Bw4cKI6nrHibN29e4bIqokOHDuTm5rJ796+TXXz22WceSScpKYnt27cTExNzynGXTF7lady4Mc2aNeODDz4oc31SUhLff/89ISEhp5TR2FujJfgJS14VtW8t1G8HEQ04VhDKyy87g/Bedpkz9Ul1WL9+PevXrz/zhsZUgIiwYcMGcnJyqH2ab19jx45l8uTJzJ07l61btzJhwgRWrVpV3Clj0KBB1KpVi6FDh5KVlcXy5cuZNGmSxz6GDx/Ozz//zMCBA/n000/ZuXMnK1as4O677+bQoUMVirVFixZMnTqVF198kSFDhvDxxx+za9cu1q5dywMPPMDYsWMBGD16NCtXruTxxx9n69atvPHGG0yZMoVx48adw1/qVH379iUhIYHBgweTmZnJ2rVrefDBB6lVYubZW2+9lbi4ONLS0li5ciU5OTmkp6czevRojx6HZ/KnP/2JadOmMXXqVLZu3UpmZiZTpkwpjuOyyy4jLS2NpUuXkpOTw9q1a3nsscfKrI0FE0teFaGF8F0GxHaG8Cg+/BAyM2HoUAgNdcYyrA5jx44t/ic1piqcd9555TYvjRgxgrFjxzJu3Dg6duzIwoULWbBgARdffDHgjCixZMkStm3bRlJSEmPGjOGZZ57x2EdR7S0kJITU1FQuuugihg8fTu3atU+bNMty3333sXz5cvLy8hgwYADx8fHF3dgfffRRwKmJzJ8/nwULFtCxY0fGjx/P+PHjq/z+yJCQEBYuXEhhYSHdunVj8ODBPProox7HExkZSXp6Om3atOGmm24iISGBIUOG8NNPP9GgQYMKl3Xvvffy0ksv8dprr9GxY0dSU1PJysoCnC8g77//Pr1792bYsGHEx8dz8803s2XLlrNuXg0UUtELoYEmJSVFq+xeh7yv4R+/gR5/4WSn+1n9WRRz58J99zkdNSrYbH/OikbX8KdhdGqq7OxsOnTo4OswjDkr5b1/RSRDVVOqOaRKsw4bFbF3tfOzcRd+ORpOkyYwYYIzinyJTkJeZ0nLGGMc1mxYEXvXQO36EN2a114PIyMDCgqc0TS8OaJGaWvWrGHNmjXVV6Axxvgpq3lVxL5PIfZifjxUlyeeFHr1guRkcIc8qzaPPPIIYPd5GWOMJa8zOfoT/LQVWl3Fa/9owKFDMGyYs6q6OmoUeeWVV6q3QGOM8VOWvM7EvTn5ZEwXps+IIDkZEhOdxBUaWr2hxMfHV2+Bxhjjp+ya15m4Nyf/5+vufPttCEOHwokT1dtRo8jKlStZuXJl9RdsjDF+xmpeZ7JvHdRvz568+iQkwJVXOrUub82WXJ7HHnsMsGtexhhjyas8WgjffU5h66u5MgWuGgCHDzsDqPpCySksjDGmJrPkVZ4fsqDgEHtOpFBAXeSY01xYnd3jS2rTpo1vCjbGGD9j17zKk+vcnDzksasY9VAkBQVQiVFdqtyKFStYsWKF7wIwxhg/Ua3JS0RSRWSLiGwXkVOmRBWRC0TkIxH5UkQ2iMjV7vIwEZktIhtFJFtEHq6WgPeu4XhIAz7emEi/fkJkpO9qXQATJ05k4sSJvgvABDQRKfdRNE6gNxw9ehQRYcmSJWfc9osvvuDaa68lLi6OiIgIWrZsyU033URubq7X4jOBp9qaDUUkFHgJ6AfsAdaLyCJV3VRis0eBt1R1uogkAu8DrYCbgNqq+hsRiQQ2ichcVf3Gq0Hv+5QN+7tS7zylT58QGjXyamlnNGfOHN8GYAJayWnhlyxZwrBhwzyW1TlNL6SCgoJT5pzylr1799KnTx/S0tJYtmwZDRo04JtvvmHx4sUcPnzYa+UeP36c8PBwr+3fVL3qrHl1Bbar6k5VPQ68CaSV2kaBoiGuo4G9JZbXFZFaQB3gOHDQq9Hm/xcObGNRRg8G3HCcqChnJlxfatGiBS1atPBtECZgnX/++cWP+vXrn7IsOjqazZs3IyLMnz+fK664goiICGbPns3LL79MTKmeSsuWLUNEipPKjz/+yKBBg4iNjSUiIoK2bdsyffp0AFq1agXAddddh4iQkJBQZozp6enk5+fz+uuv06VLF1q1akWvXr2YMmWKx32Ou3fv5pZbbqFRo0ZERkaSnJzM6tWri9e/8MILtGnThvDwcNq3b8/s2bOL1xXVAl999VWuv/566tatWzwZ58aNG0lNTSUqKoq4uDhuu+028vLyzvEvb7yhOjtsNAN2l3i+B+hWapvHgf+IyANAXaCvu/xtnES3D4gEHlTV/5YuQETuBu4GTpnSvNLcm5NX51zKiD9C/fpQicljvWLZsmUApKam+jYQU7aP/gf2Z1ZvmY07w5VVP8P2+PHjmTJlChdffDG1a9dm0aJFFXrNtm3bWLp0KTExMezcubN4ksj169dzwQUXMGfOHPr27esx71VJ559/PseOHeO9997jhhtuKHPG5oMHD9KzZ09atWrFokWLiIuLIzMzk6IZMubOncuYMWN47rnn6N27N0uWLGHo0KE0bdqUfv36Fe9nwoQJPP3000ybNo3Q0FB2797N5Zdfzv33389zzz1Hfn4+48ePZ8CAAaSnp5/Nn9F4kb/1Nvw9MEtVp4jIJcAcEemIU2s7CTQFGgCrRGSFqu4s+WJVfRV4FZwpUc4pkr1rUEIY8UgT4juEERV1TnurEkWzyFryMt42atSoMmdXLs+uXbtISUkhJcWZTaOotgUQGxsLQP369Tm/nEFBe/XqxejRo7n55pupV68eXbt2pVevXtx6663FrQ6zZ8/mwIEDvPvuu8U1yLZt2xbvY/Lkydx5553cc889xcfy2Wef8cwzz3gkr9tvv93jOt+4ceO49NJL+fOf/1y8bNasWTRp0oQNGzbQqVOnSv09jHdVZ/LKBUq2eTV3l5V0J5AKoKprRSQCiAEGActUtQDYLyKfACnATrykcO9aCuq2J6VrbU5EhlKJOfO85s033/R1CKY8XqgB+UpRAqqM4cOHc8stt7Bu3Tr69evH9ddfT48ePSq9n8mTJ/PQQw/x4Ycfsm7dOl5++WUmTpzI0qVL6dmzJ19++SXJycnFiau0zZs3M2rUKI9lPXr04KmnnvJYVvoYMzIyWLVqFVFlfFPdsWOHJS8/U53XvNYD7USktYiEA7cApdsivgX6AIhIByACyHOX93aX1wW6A5u9FqkWUrA7gzXfdOeX41E0bOi1kiql6NqEMd5Wt9So0yEhIZSeuLagoMDjeVpaGrt27WLkyJHs27eP3/72t9x7771nVX5sbCwDBw5k6tSpbN68mSZNmjBp0qSz2leR0k2QpY+xsLCQ/v37k5mZ6fHYtm2bR43N+IdqS16qegK4H/g/IBunV2GWiDwpIte7m40GhonIV8Bc4A51/mNeAqJEJAsnCc5U1Q1eC/aHLGrLIVZk90DCI33eUaPI4sWLWbx4sa/DMDVQbGwsBw4c4OjRo8XLMjNPvb7XuHFj7rjjDubMmcPf/vY3ZsyYQWFhIbVq1UJEOHnyZKXLjoiIoHXr1sUdQ7p06cIXX3xRfD2ttISEBD755BOPZatXryYxMbHccpKSksjKyqJ169a0bdvW41FWbcz4VrVe81LV93G6v5dcNqHE75uAy8p43WGc7vLV4oevVhMD1G/bkYi64Zzm2nK1mzJlCuD02DKmOl166aWEh4fz8MMPM3z4cDIyMnjttdc8tnnkkUfo3r07iYmJHDt2jHfffZf4+HhCQkIICQmhefPmrFixgm7duhEREVFms9+CBQtYtGgRAwcOpF27dpw8eZKFCxfywQcf8Ne//hWAwYMH8+yzz9K/f38mTZpEkyZN+Oqrr4iJiaFnz56MHTuWIUOG0LlzZ6688koWL17M/Pnzizs8nc7IkSOZOXMmgwYNYsyYMTRq1Ijt27czb948pk+fbl3p/Y2qBuUjOTlZz9bGZ4fo/sdjdPnbO/XnA4VnvZ+qlpeXp3l5eb4Ow6jqpk2bfB3COZk/f746//6esrOzFdCNGzeesu6tt97SCy+8UCMiIvTqq6/WmTNnKqCHDh1SVdUJEyZoQkKC1qlTRxs2bKjXXXedbtmypfj1b7/9trZp00Zr1aql8fHxZca1detWveuuu7R9+/YaGRmp0dHR2qVLF33hhRc8tsvJydEBAwZovXr1NDIyUpOTk3X16tXF659//nlt3bq1hoWFabt27XTmzJnF6/Lz8xXQxYsXl3n8aWlpGh0drXXq1NH4+HgdMWKEnjhxovw/aIAp7/0LfK5+8Bl+poeonlunPH+VkpKin3/++Vm9dtfjHdjxQxta3fUKF3Rs7jc1L+M/srOz6dChg6/DMOaslPf+FZEMVa18j51qZmMblqJH/kvL8zZzPLoTYVF1/SpxvfPOO7zzzju+DsMYY3zOjz6a/YOEhnL8sqnE/9KGeg18OJBhGZ5//nkAfve73/k4EmOM8S1LXqXVjubkRX/k5JZcIiL96wLte++95+sQjDHGL1jyOo3wyAjCI0J9HYaH6OhoX4dgjDF+wa55lSG0Vij1Gp3n87EMS5s3bx7z5s3zdRjGFaydnUxwC5b3rdW8yhBeJ5zwOv7VZAgUj9A9cOBAH0diwsLCyM/PJ9Jf7mA3poLy8/OrbYobb7LkFUDef//9M29kqkXjxo3Jzc2lWbNm1KlTp8zRz43xJ6pKfn4+ubm5xMXF+Tqcc2bJK4DYt3z/Ua+eM+3c3r17Txnjzxh/FRYWRlxcXPH7N5BZ8gog//znPwG47bbbfByJASeBBcOHgDGByJJXAJkxYwZgycsYYyx5BZDly5f7OgRjjPELlrwCSDD0EDLGmKpg93kFkFmzZjFr1ixfh2GMMT5nySuAWPIyxhhH0E6JIiJ5wK5z2EUM8EMVhRMo7JhrBjvmmuNsjrulqsZ6I5iqFLTJ61yJyOeBMKdNVbJjrhnsmGuOYD5uazY0xhgTcCx5GWOMCTiWvE7vVV8H4AN2zDWDHXPNEbTHbde8jDHGBByreRljjAk4lryMMcYEHEtepYhIqohsEZHtIjLe1/F4g4i0EJGPRGSTiGSJyEh3eUMRWS4i29yfDXwda1UTkVAR+VJElrjPW4vIp+75nici/jcL6TkSkfoi8raIbBaRbBG5JNjPtYg86L63vxaRuSISEWznWkT+LiL7ReTrEsvKPK/ieN499g0ikuS7yKuGJa8SRCQUeAm4CkgEfi8iib6NyitOAKNVNRHoDgx3j3M88IGqtgM+cJ8Hm5FAdonnzwBTVbUt8BNwp0+i8q7ngGWqmgBcjHP8QXuuRaQZMAJIUdWOQChwC8F3rmcBqaWWne68XgW0cx93A9OrKUavseTlqSuwXVV3qupx4E0gzccxVTlV3aeqX7i/H8L5MGuGc6yz3c1mA/19E6F3iEhz4BpghvtcgN7A2+4mwXjM0cDlwOsAqnpcVQ8Q5OcaZ9DxOiJSC4gE9hFk51pV04H/llp8uvOaBvxDHeuA+iLSpHoi9Q5LXp6aAbtLPN/jLgtaItIK6AJ8CsSp6j531XdA4M8V7mkaMA4odJ83Ag6o6gn3eTCe79ZAHjDTbS6dISJ1CeJzraq5wGTgW5yk9TOQQfCfazj9eQ26zzZLXjWYiEQBC4D/UdWDJdepcw9F0NxHISLXAvtVNcPXsVSzWkASMF1VuwC/UKqJMAjPdQOcmkZroClQl1Ob14JesJ3X0ix5ecoFWpR43txdFnREJAwncb2hqu+4i78vakpwf+73VXxecBlwvYh8g9Mc3BvnWlB9t2kJgvN87wH2qOqn7vO3cZJZMJ/rvkCOquapagHwDs75D/ZzDac/r0H32WbJy9N6oJ3bKykc5yLvIh/HVOXcaz2vA9mq+r8lVi0Chri/DwHeq+7YvEVVH1bV5qraCue8fqiqtwIfATe6mwXVMQOo6nfAbhGJdxf1ATYRxOcap7mwu4hEuu/1omMO6nPtOt15XQQMdnsddgd+LtG8GJBshI1SRORqnGsjocDfVXWSj0OqciLSA1gFbOTX6z+P4Fz3egu4AGc6mZtVtfQF4YAnIr2AMap6rYi0wamJNQS+BG5T1WO+jK+qiUhnnE4q4cBO4A84X1yD9lyLyBPAQJyetV8Cd+Fc4wmacy0ic4FeONOefA88BrxLGefVTeIv4jSfHgH+oKqf+yLuqmLJyxhjTMCxZkNjjDEBx5KXMcaYgGPJyxhjTMCx5GWMMSbgWPIyxhgTcCx5GRPARKSViKiIpJT13JhgZcnL1CgiMsv9cFcRKRCRnSIy2R3vz6+JyMci8mKpxbuBJkCmD0IyxmdqnXkTY4LOCuB2IAzoiXMDb13g3sruSETC3RkIfEJVT+IMwGpMjWI1L1MTHVPV71R1t6r+C3gDd+oIEUkUkX+LyCF3or+5InJ+0QvdmtsSEXlIRPbgjB2IiISLyFMisktEjrk1uhElXlfR/Y4UkVwR+UlEZopIZNF64AqcudeKao6tKtJMeKayjQlElryMgXwgzB3INB34Gmdut75AFPCeiJT8X7kC6IQz1E4fd9lsYDAwCuiAM9HhASgeILUi++0JdHTXDwRuwJk8E/fnWmAmTjNhEzynuChTJco2JqBYs6Gp0USkKzAIZ9bZe4GvVPWhEusH40z4lwJ85i4+CgwtGhdPRNrhDPZ7laouc7fZWaKYiu73IHCP2xSYLSLzcZLjX1T1ZxE5DhxxB9st2s+ZDrGiZRsTUOybl6mJUkXksIgcxanNpAMPAMnA5e66wyJymF9rNxeWeP3XpQZ07YIzwPFHpymvovvd5CauInuBxmdzgGdRtjEBxWpepiZKB+4GCoC97pxPuM1o/wbGlPGa70v8/ksly6vofgtKrVPO/QtmRcs2JqBY8jI10RFV3V7G8i+Am4FdRQmtgjJxksSVwLIy1p/tfks7jjNVT2VUVdnG+BVrNjTmVy8B0cA8EekmIm1EpK+IvCoi553uRaq6FWcOpRkiMsCdzLSniNx+LvstwzdAV7eHYUwFO1xUVdnG+BVLXsa4VHUvznTxhTg1qCycD/9j7qM8g4F/Ac8Dm4FZOEnjXPdb0mSc2tcmIA9nwkFvHpMxfssmozTGGBNwrOZljDEm4FjyMsYYE3AseRljjAk4lryMMcYEHEtexhhjAo4lL2OMMQHHkpcxxpiAY8nLGGNMwPl/Exjf/Sec2b0AAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "run_precision_plt(X, y, nfolds, percentiles, run_sc, plt_title=plt_title, \n", + " plt_names=plt_names, predict_correct=True)" + ] + } + ], + "metadata": { + "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.6.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From ef87ea6d03d9b01675d32e8fae0ee3cd494f83e0 Mon Sep 17 00:00:00 2001 From: Arnaud Van Looveren Date: Thu, 2 May 2019 18:23:31 +0100 Subject: [PATCH 2/3] add comments notebook --- examples/trustscore_mnist.ipynb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/trustscore_mnist.ipynb b/examples/trustscore_mnist.ipynb index a5b7e477d..03bed15c0 100644 --- a/examples/trustscore_mnist.ipynb +++ b/examples/trustscore_mnist.ipynb @@ -407,6 +407,13 @@ "label_min, label_max = np.argmax(y_test[idx_min], axis=1), np.argmax(y_test[idx_max], axis=1)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Low Trust Scores" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -447,7 +454,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The high trust scores on the other hand all are very obvious 1's:" + "### High Trust Scores" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The high trust scores on the other hand all are very clear 1's:" ] }, { @@ -490,7 +504,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let’s compare the prediction probabilities from the classifier with the trust scores for each prediction. The first use case checks whether trust scores are better than the model’s prediction probabilities at identifying correctly classified examples, while the second use case does the same for incorrectly classified instances.\n", + "Let’s compare the prediction probabilities from the classifier with the trust scores for each prediction by checking whether trust scores are better than the model’s prediction probabilities at identifying correctly classified examples.\n", "\n", "First we need to set up a couple of helper functions.\n", "\n", From a9ca6a0a0554078cf8b4eb1bf81b48999f12b848 Mon Sep 17 00:00:00 2001 From: Arnaud Van Looveren Date: Thu, 2 May 2019 18:33:04 +0100 Subject: [PATCH 3/3] rename notebook --- doc/source/methods/{Trust Scores.ipynb => TrustScores.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/source/methods/{Trust Scores.ipynb => TrustScores.ipynb} (100%) diff --git a/doc/source/methods/Trust Scores.ipynb b/doc/source/methods/TrustScores.ipynb similarity index 100% rename from doc/source/methods/Trust Scores.ipynb rename to doc/source/methods/TrustScores.ipynb