{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a Learner for inference" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide_input": true }, "outputs": [], "source": [ "from fastai.gen_doc.nbdoc import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we'll see how the same API allows you to create an empty [`DataBunch`](/basic_data.html#DataBunch) for a [`Learner`](/basic_train.html#Learner) at inference time (once you have trained your model) and how to call the `predict` method to get the predictions on a single item." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide_input": true }, "outputs": [ { "data": { "text/markdown": [ "
Note: As usual, this page is generated from a notebook that you can find in the docs_src folder of the\n", "fastai repo. We use the saved models from this tutorial to\n", "have this notebook run quickly.
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "jekyll_note(\"\"\"As usual, this page is generated from a notebook that you can find in the docs_src folder of the\n", "fastai repo. We use the saved models from this tutorial to\n", "have this notebook run quickly.\"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vision" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To quickly get acces to all the vision functionality inside fastai, we use the usual import statements." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from fastai.vision import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A classification problem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's begin with our sample of the MNIST dataset." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mnist = untar_data(URLs.MNIST_TINY)\n", "tfms = get_transforms(do_flip=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's set up with an imagenet structure so we use it to split our training and validation set, then labelling." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (ImageList.from_folder(mnist)\n", " .split_by_folder() \n", " .label_from_folder()\n", " .add_test_folder('test')\n", " .transform(tfms, size=32)\n", " .databunch()\n", " .normalize(imagenet_stats)) " ] }, { "cell_type": "markdown", "metadata": { "hide_input": true }, "source": [ "Now that our data has been properly set up, we can train a model. We already did in the [look at your data tutorial](/tutorial.data.html) so we'll just load our saved results here." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18).load('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once everything is ready for inference, we just have to call `learn.export` to save all the information of our [`Learner`](/basic_train.html#Learner) object for inference: the stuff we need in the [`DataBunch`](/basic_data.html#DataBunch) (transforms, classes, normalization...), the model with its weights and all the callbacks our [`Learner`](/basic_train.html#Learner) was using. Everything will be in a file named `export.pkl` in the folder `learn.path`. If you deploy your model on a different machine, this is the file you'll need to copy." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "markdown", "metadata": { "hide_input": false }, "source": [ "To create the [`Learner`](/basic_train.html#Learner) for inference, you'll need to use the [`load_learner`](/basic_train.html#load_learner) function. Note that you don't have to specify anything: it remembers the classes, the transforms you used or the normalization in the data, the model, its weigths... The only argument needed is the folder where the 'export.pkl' file is." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(mnist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can now get the predictions on any image via `learn.predict`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category 3, tensor(0), tensor([0.9494, 0.0506]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It returns a tuple of three things: the object predicted (with the class in this instance), the underlying data (here the corresponding index) and the raw probabilities. You can also do inference on a larger set of data by adding a *test set*. This is done by passing an [`ItemList`](/data_block.html#ItemList) to [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(mnist, test=ImageList.from_folder(mnist/'test'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tensor([[9.9267e-01, 7.3297e-03],\n", " [1.3017e-01, 8.6983e-01],\n", " [8.2184e-01, 1.7816e-01],\n", " [8.9358e-05, 9.9991e-01],\n", " [9.9973e-01, 2.6567e-04]])" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preds,y = learn.get_preds(ds_type=DatasetType.Test)\n", "preds[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A multi-label problem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's try these on the planet dataset, which is a little bit different in the sense that each image can have multiple tags (and not just one label)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "planet = untar_data(URLs.PLANET_TINY)\n", "planet_tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here each images is labelled in a file named `labels.csv`. We have to add [`train`](/train.html#train) as a prefix to the filenames, `.jpg` as a suffix and indicate that the labels are separated by spaces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (ImageList.from_csv(planet, 'labels.csv', folder='train', suffix='.jpg')\n", " .split_by_rand_pct()\n", " .label_from_df(label_delim=' ')\n", " .transform(planet_tfms, size=128)\n", " .databunch()\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, we load the model we saved in [look at your data tutorial](/tutorial.data.html)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18).load('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can export it before loading it for inference." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(planet)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we get the predictions on any image via `learn.predict`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(MultiCategory agriculture;partly_cloudy;water,\n", " tensor([1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 1.]),\n", " tensor([6.2213e-01, 3.1655e-01, 3.6730e-01, 1.0397e-01, 5.3315e-04, 4.6302e-01,\n", " 1.8985e-01, 9.5472e-02, 3.0821e-01, 9.9055e-01, 3.4830e-01, 1.3109e-01,\n", " 2.0182e-01, 5.8467e-01]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we can specify a particular threshold to consider the predictions to be correct or not. The default is `0.5`, but we can change it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(MultiCategory agriculture;artisinal_mine;bare_ground;cloudy;haze;partly_cloudy;primary;water,\n", " tensor([1., 1., 1., 0., 0., 1., 0., 0., 1., 1., 1., 0., 0., 1.]),\n", " tensor([6.2213e-01, 3.1655e-01, 3.6730e-01, 1.0397e-01, 5.3315e-04, 4.6302e-01,\n", " 1.8985e-01, 9.5472e-02, 3.0821e-01, 9.9055e-01, 3.4830e-01, 1.3109e-01,\n", " 2.0182e-01, 5.8467e-01]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict(img, thresh=0.3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A regression example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the next example, we are going to use the [BIWI head pose](https://data.vision.ee.ethz.ch/cvl/gfanelli/head_pose/head_forest.html#db) dataset. On pictures of persons, we have to find the center of their face. For the fastai docs, we have built a small subsample of the dataset (200 images) and prepared a dictionary for the correspondance filename to center." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "biwi = untar_data(URLs.BIWI_SAMPLE)\n", "fn2ctr = pickle.load(open(biwi/'centers.pkl', 'rb'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To grab our data, we use this dictionary to label our items. We also use the [`PointsItemList`](/vision.data.html#PointsItemList) class to have the targets be of type [`ImagePoints`](/vision.image.html#ImagePoints) (which will make sure the data augmentation is properly applied to them). When calling [`transform`](/tabular.transform.html#tabular.transform) we make sure to set `tfm_y=True`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (PointsItemList.from_folder(biwi)\n", " .split_by_rand_pct(seed=42)\n", " .label_from_func(lambda o:fn2ctr[o.name])\n", " .transform(get_transforms(), tfm_y=True, size=(120,160))\n", " .databunch()\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As before, the road to inference is pretty straightforward: load the model we trained before, export the [`Learner`](/basic_train.html#Learner) then load it for production." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18, lin_ftrs=[100], ps=0.05).load('mini_train');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(biwi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can a prediction on an image." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(ImagePoints (120, 160),\n", " tensor([[-1.2336e-03, -2.0357e+00]]),\n", " tensor([-1.2336e-03, -2.0357e+00]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.valid_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To visualize the predictions, we can use the [`Image.show`](/vision.image.html#Image.show) method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img.show(y=learn.predict(img)[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A segmentation example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we are going to look at the [camvid dataset](http://mi.eng.cam.ac.uk/research/projects/VideoRec/CamVid/) (at least a small sample of it), where we have to predict the class of each pixel in an image. Each image in the 'images' subfolder as an equivalent in 'labels' that is its segmentations mask." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "camvid = untar_data(URLs.CAMVID_TINY)\n", "path_lbl = camvid/'labels'\n", "path_img = camvid/'images'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We read the classes in 'codes.txt' and the function maps each image filename with its corresponding mask filename." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "codes = np.loadtxt(camvid/'codes.txt', dtype=str)\n", "get_y_fn = lambda x: path_lbl/f'{x.stem}_P{x.suffix}'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The data block API allows us to uickly get everything in a [`DataBunch`](/basic_data.html#DataBunch) and then we can have a look with `show_batch`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (SegmentationItemList.from_folder(path_img)\n", " .split_by_rand_pct()\n", " .label_from_func(get_y_fn, classes=codes)\n", " .transform(get_transforms(), tfm_y=True, size=128)\n", " .databunch(bs=16, path=camvid)\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As before, we load our model, export the [`Learner`](/basic_train.html#Learner) then create a new one with [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = unet_learner(data, models.resnet18).load('mini_train');\n", "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(camvid)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can a prediction on an image." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To visualize the predictions, we can use the [`Image.show`](/vision.image.html#Image.show) method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMsAAADFCAYAAAD68QZDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzsvdmzJceZ2PfLzKpz7tobAC4zFEGC4AICDYAgCaIB9AKSM5IsKUaSQw5LT/aLXx3hR/8JjvCD/wmFIxSW5ZGGQ4+GRDeAJkCQQxINgMtwsDRIEECj+3b3Xc5SVZnphy+3qnNuuyP0oDsR5+u4fe+pU5WVlZXfvinvPStYwQr+/0H/157AClbw9wVWyLKCFdwlrJBlBSu4S1ghywpWcJewQpYVrOAuYYUsK1jBXcIKWVawgruEFbKsYAV3CStkWcEK7hKq/9oTAPg//8N/9C5EEnjv8fIHvWMewjcAKAClUKp3BPAopXvnxJOUUuk8X4xdgkKhtArnxhGR+4dTvXfEoXU4r9IKo/N88mw8eSSVrotgtMw1PqtzTs5T9K5TxaBpPbxP83fOY50t1ix/n57Rp0Upnkx+xVWI6+zjQw+P9VYlrwnhvXnKeyn29/a4ubMDwCPX/pzJ/i0++tKTgFDqyXtVWJBy8Lz+cS/gfbkg4BWoYnXT5YP3qTXHviDn1FvHufdXrxB5hG1bTF1z8M0/xdS1XP3KffxP//v/oFgCK86yghXcJRwJztJal6i1K6lhouQ+E0VIHCXQ6XAonlEQhUUCKpTPl1TSpzHjZ+WVEK40jMIrlbkROjGswBgSN0qcJV7v+0TPegeuP82Sass9PPI4Oj2bR/UovRwvn9WHp4+c0+FdWMuS2vqSig+4A0POMpyfz1eF/xY4S8Gxm6ZhOptwZv48AL9/4jkmu7dRk/3ekpfvseRwxWF6X6bFVb2vURScJi1o4NbgnetzKKXwTvae7To5Zi2HwZFAFusszpXig0tihEDcHfGXQveXSY6mQ/GlqiVngVcKPVjTfIISxPQer1RxVbE5w7syijSO7iFwQFulZKOVzxY2cBzLkokEIEiC7Gmj4nUKcL259hAlzjC8fLkmE52ILArVR5ywSsuQBV+uzRCpfCYCiYB4XPHOnHXc3r3NYzf+I7f39wCY7O/S2RYVKQyerc9ZeUuFNFWKxgdXq/jAg3kPnl9lQljC5v0WvNxPkKV/qbOWZj6n+tlnwjO2HAZHBFky9hNl7R5JFigZhSNs1GJxlm6gdEWgQ2qIQKr30vFqQfz1ylNigkahAaV90lkip4mbnYAQPQqdNm85ePjl8tHIIRICIfpbmnm8ZzFA3GRps/pFrrLAZSi55eCZI9Isg/SO+hsb7xOyNk3L6Wt/zgd/+D0EgjCdHKCU6HblOMspmvy5eX+XESZ9X77DguoVU9m6v0tvPYGzQYcM3yjF9YefhaZFd8JRtDkcJY4EsjgnVAnIyhwF1x2cr8qfnvKehyhPLpEsSWuZTSVltLzYp5Ple1W8IB04Sil2aaUwSkXJqbi/KkRMV1D5wgjR44oFlyjm4rxfMB64AjmsdWEdsxi0iCz0DA4lQeqhReIaxXm9z4vIORzDO49C087bxH1ta9FGoSvTe44BsUct0skeLNW+wxdbn+36cymoVRTD4px3Hj2Pa1twmdPX4/Gh910p+CtYwV3CkeAs0FfeMxseymGZi6ieKFKKtL7gSKIUR91D+SBS+Sy7C1NWPdas0nd5bppMfTJnyaZjo1XQWwq67f1SS2053yiq9fTYQA1LszCA1rp3Tl/scjjn0rkucOie8SDqGnmxZamXcYchdfe+991Q7IljZE4Pl+vzfNa/3eduLotqKvxbBgdXTXnzQ89LXCOwoyiybd7fpWeMcOK1H+I3jqG8Sd8plLCM+G6rIy6GGa1xQVQBiDb0RSUuI0hEmCyaCJJ5XyxrHCKrI2ET9L0fImeVF8Ux4319QISwaQtlPiFZEKVKv8/yLNTDXztkXYCBSAUkvS7pQgOEiggSLsIF40JfJCkesZjI0qkWXy79WuWnScscxVKjGK+Nqesa57s0b62La5QQmKFetd9DlDusl1rUtXrTjv9HAmIt3jmUjogdxu9TqsPudkSQxWh0oViGvxZeRE+uX6KrJCdlbzP0l3pBkR2gTTTBlosYESPK3pEXldc578GREAro6RBhxDB+qV/5oHvkzxGhh7DAIaCwIialL58bN3mPcxREyAWy0dstC6pzUqh75lwlm89aQYSu62jbhq4Ta9JkMuEbe9/nt9+4QBfMsiY8u9YDCaHg9EIIMwctX2cf2f0Cd8uki+K34tQbLwGg6zF9DFPBigbt134PwPjXX+IwWOksK1jBXcKR4CyVMcGXQKIeJbVTKlqnwuf8TXEsy0DZHDr8DEPWouLfpfyNiFyRA2iinlJQxHhuISL5BZ2FdD4gFLXwS8h1Q6vVotChte6JQpGgljpL/ntw/0P0kbx8cc4D7lKwEucd1lratgHEL9Z1LW3T0LRzAObzOU/PL9I1ck4zb3jvy0/BZJZNxUl0HkoFPhke969WidoXswn6X3xbkbPmdy4inU5WVWU0KM3J155HmREA1XgTpau+LKEUOI/+6afkWTcLdWAARwJZ6iojS1YUC2m1/Dt8LlmpnB91luzgi8iR46582gQla+97uAE92Dqqr48U2zHrWuFmUcToTSCNEwwKA7HLleKEKrdJPmdgApAxnE9i2KJGHm/YP1g6APOz9ZStvCmjtNZaZrMD9oNzcT6fcWZ+kWY2p50LcrRNw422wQV/he06JvsHSb9L8wFOXrkEwK3HLiwRN1Xxf3+e2b8kERWqEClF4tbJX9V50U92Hv82n/rbnwAw3tzAOZ/EwkKrSfpgFCOXwZFAFqV8tvT4oQxdUPIet1ELG9ojDk6VHHxhU0ZioeX7cKN0Tg95RK1YGL8nHwfKV27WuJ8zN4mn9je6C467EoFjxEK6Lt17YIRIU8kcJXO4vp6TeEUPCRZBKQkcTd8WCO6sLNze7i5ffv/fsXtLAiLn8xnvW7tgF+k/qfidDr8znLpyKT9LmPre8e/0nz15e3XxLDJf52x/HbyjC5tetx1Kaz75y1cZbx8D4HJ1jq7rOOMvpUWTIbNu2TbzpXOFI4IsbduwFp1BhUhQmlfVAFEyxcpLG15x/ivGYGVWELiuT+ekIeKi+97+SlBKNC5sTOcKBTuIEslMPRgXCmXe5WMuIUpkNYFiDrnpYC5pLZI3XMSJ6AD1RDGnGGUwXAq7KXZ5GTLSBJFqf2+Pmzeup40URaLe+gcn6pBTeEAVivnJ1y8V4nJ8Fs3vT343jKNFwdc6fU6IEuZoncN1ls66ZGDAe5y1CcH1vOMz7/yC9RMn+OnWnwJgwnrHu568comd02flNYVx5s1s6ZrLLFewghXcFRwJznKwv8co5BMYk23sScFeyln6RgDvg6nWuSR/WhcDMuNJQf7vHeyLK0tpeTjVJl3IpaDBYa5I6VvJZuy+TlQGVyZ9pZBnhBpnnUGxyF2Ha+QVOBzexTCanHPTF46yuNYzVAwe13vPwYHoKLdv3WQ2mSwo5h7PzUfPA1mkKsc48dqlHnfceew8Nx/7NvcEU67SmvdP/AkojY7mYp8drADOdThn5b0G6m8DB3ExirhYOaVk/7QfbrG+uckr688xLnQdoysuqacBOK9eBiQc6eax3wHQtUdcDHvk4z/nnc1/DcD6+kbxTVYSfPnZh0BK8ou3zge27LARWazr+TkIyvWifR4OlVUovOE+b/CFPR4QYyFGbaBgJz9Kf1rJ0haf0hcInZTbaFWLw+reEIBOYlhSrIZQiHeFZJM9/87RWUvbtuztCbJ8Y/evmKg89o3TZ0ne93CPnUcvcPLKC8lHorWITt6DCwq1wwCK66fPAbD3boVvWiFyARGctYIcUeR1QWwqiE7eFaqHuAqN0YIsm9vHeVV9V8R7nRERrZN+fMmd4ZFwTxssfS78XgZHAlmuffABt46L8ljXIypT4fBpL0jEbWGKDTK9VypbMaxbRJbAWbIxpnBaFR62ctNHSuy9T5wkXJCMA73QjpI0q77XfgH/etyof176VNwyU2XVU73kNKEYJT7YQuEt9ZHS4QeFdSo8sFKSNQjQtC1N1zLZP+BgbxeA2XSC956d0+eLGYtF6tSVF+SI1tx+4k+4583INQxKSWRG18n9t376A97dOp+IgPPzzJGL1AKhOrq4Vx8O4/6mqlnf2gbgAwdrG8EJmRAq6EQReULIvnD5QG60WRw7wJFAlhvXP+aLv/93APx+439kc3MTX7xUZV1vhbJYkq1bXWdTqH8ZH1VaWqKlqdyeWRHPFGohjyYp9sVGROGV72+8gTI9FHIicVymBC8LRSkRu3yh4PEuzLUcx/U5qSqfO/yxzHihUDQBWW7v7rG7t8tkf59v3v4rAA6s5caj5xLXqOsx97x5WRBi6zgAtx5/jpHWHDz1T9K9vBMP//RAlOZmNsf+XZdvnBxG0EeBkisO3kW8TuU/5XaaejRiY2sLgF0rHGTorxPrXxEhED5XlfhivD5cjV8p+CtYwV3CkeAss8kBV99+B4Cdk9dQ+tNU9YieqDL0sQRl2tqon4QIW0dBXfte7BR4WSZMKEnmKgnbQqGH9EUaNTGn/imD89XiofwMy49notm/2BXmZh/Fud51Qa/qjR99VnlEveTG3jvaVij+/sGE6bTBWRK1vfX4cyhrMSExary5zWh9K6y3rP/JK8/jnQ32enDOsnP6LOCTaGPqCqVyCjkM9L448Z5+MojdKy+Mzw2M1kZsbG7zoZWzq7qWZ9c5ii9IysmY4IErV+Y88vCIek3OibrTMjgSyKLwTPYlL/sr7/973qr/NcdPnurZ4yMLhcIa432hmGYRaeiwi+DDvWSvl3LdoniygCwDhdwtIFJSqMIv1RMBi0uLDZEPLtxq4J8ZHFpAlrTBepJfYU4rP/YIAzRtl8Sw2awBr9C6SsiitJHcdCfe+a0f/wWtkuDHuLm899wMinsauGvRWmOMWDodBqW6Qj9hCXjKL5cEIRTfK+pgRV3b2OQDpxkHa6ogSl9witJ2FMOUD+9RKbYfkJuYn/7xskkBRwRZRqOappkCsPPxNR5a+7/57ei/ZzxeAziMtvThMF2g+EusN/0NFAlvGcoyjA5ySzZ9tNAUDKp300NTciNHKr8f3HBBSo+IMbzZkLOprKcMEeQw8Hhm8zkHkwkA39j/a+q6QuP56NFnZIhbOyjg1GvPA2C1SVx6JyJIIC46Dxy4gkqcRZmaYw8ccOu3cWrDN0TWY4rPiccO9BjvHfXaOgBrW1uMqZOlS/QrRXlZ/K2XIFHhAT90rVY6ywpWcJdwJDjL+vo6XZCZpwd7/OG993h8+3v84tQ/BYLsXNqAA5RhIqWEvxB0mShRNjtrotwar+wPHsM3wkmU+ep9R9hySGbqJTLE0LwcpfP0/1IJr5TB8lx7jKTIC0lspmRgDhhY8KxzTCYTdm+LmbhtGwkh8Y7ZLIS3oIU7+DyQj2ZEl8NrkmGrmJwnB5fWozVMVaOwvbn3w31YAD/4IubgjMfrrAfr1wdWUVcqc40eh+jLuL3o8eH97sBZjgSy1KMR4zWJDZtN5+zt3mLn44+ZjA8A2NoWZ1beeLLFhvswstO+X6GELI75VGbIJ4U5njG04iZz8rKNf+hTLeoZ8X7FbBMSLhXLh/bRoZg5EMF6v5cL+jjyBnHecfPmLa59dI1HPv5zOWYqbOe5/vCz+EDACObVnccuAHDyykVZQ9yCESTHxvlCogr6QF1R1SPu3/s+AO9uncvfD0WshQft30dpw9rmFu83cnxjq+oHhC4N8It6UCmq2aXnLIMjgSxKG+qRIIu1llkz5ebOdR7f+E8A/HrtX2HqutChXX4RhTLvlZKgvdLZUd4HAjLRK1nknMP7/rneF8XZfB9Zeu9V0TumBl8tcoXFE5frWkPNtuQZBSL2XTn5Y/IdFRstpGtHFclay+3dPfb29odbESipdBUIRrGxwtxOhXD7nUfPB+4W1yh8/9pFzJpEZRw8/S+p6pEYDEA2tBtqiEPIRC2OrY1hPF5jY3ubtRjek6Icykv7c0lrFBFaK+IjZaZ5xIvsKaWpglVj7MdMp3Mme7t8/OGHABwc32Nr+3iyYsSEqRJk30SVMg5ML5U/Jwz3oZdEFf4r47dyHbMlotKQcxSUXQ1PKc5VvfdXcMnC0jcYuS+pLAzeh5jC7BdOVinCYTqdsb9/wLemF4sNLI48ZSpMVROvPv7T79PNhNM7X6zkomUj/brnyiWo6vSs91y5RPPFb6XaXJ/dfZ6rW+fjhMOFAwRPo3lUsHSNxutsnzjJ+3NHPQ5zVKGa22A+PfF5sF7RrO4zVVuy7hlWCv4KVnCXcDQ4i6lSOdYaz9ramOlszrUP/gDA4/f+Bb8c/QvW1jeBmLHS11miHj+Msh1o/gEGKboFq8j6ijg409+l3JxEpyVOgN6ty5vTs1H0s6jLzM1irDsZEtKzDu6dTOMefHbexnsqLzFkALdu32Y+mwmnCNcZpdG64t43L6Pr7JS8+bXv0E4ksNI2U+59/YW4EMumO9Cd8hfVaBwKR8C1h87g37IDp6T8l4pWeBH/vPfUgSOtb26ysblFPbM5WjkuRnxFh3CIXoJckFSuXJlz+pE6LdthcCSQRVcVPkarKs94fY2us8znElN0/dpHPD7+Hm9+6l/KBdGpN9xMA8NW/tj3wpXrkZ2LfetJT+n34L0rNvRAFqZ3aQI1XHlf+KMXxL7+LJYmUS25V94jMZu0f8EwwsB7nxKkDg4OeGp+iU4pqqBXmGrEJXWGZ9sXkmimTC1xYEWN4p3T5zj1+gt3dOPErFAT5mBtx8nXL/HeE98BQB/cRmEPeba49k7GMDXjEJG+feIEV6eNiIlFJZihelgcHfwZdB9V+vaDpqgPf6KjgSxK4ZPndcTa2jq265hOxXS5d+smH9c1ky2hbOsbmyhtFvWWsOoqUdIBbS/DQRa8/EtsZwWVWtBr8OD7CNaDJUznMCj1Cr/gEi1GLzAqP5cqjvVJu0QeFw+CwlrLdCZEaDad0sxnVFWd9JMX63MoJz1uoqf91OsvcO3BJzj1+osAfPTg13AKbpw+x/678t7827JOG/8g5rB7PnroGU698SImKuZdi9cOUwXCWFVs3j9bKKjnvS+8/A6FYry2lszEV6ctVTXK4Utpfe5U9mPJOUUOTTx/WThQhJXOsoIV3CUcDc6iNZeUhFZo5TmnL+FcxySGds+nXP/wAx4/JabkK+bPRH8p2EZf7i2EmSX9SETsGfAUdSdO43v2mcNyUnqwRLbIOotK98vcxx92Gf0zSL5GNfApFYEhy3y4eOdo25YboRPXt2YXmSP+jyRhhYsu8RTn/cvp76+qjjLHROoJQGt9Gtt7x62/y8+68dmOZtZQr4uOpEyDdZ5Tr4u5+aMvfYtD8xKT6qWoRyPWt7b5iv8pADeqs0Ek1Mt1vcWP6WiP92rVMx/LwSMuhoFHG3kRRisuq/OcsT9ga0uWcn9vn8l0wo2PrwHwxOj7vDH+F4u7QS1/1r64tnwZFy2xfcWcnhjmh6ckJ+fgsRY+xiiCw0S0iILLXllPHQmIooZTKf8IomDqBeMc86Zhdzd66zvq0Rij8zaIeo/SGro8+Kk3XuTa48/JOQe3UzZjF0sfWYezNk3AA83bmu7hc9z/+zfkOq1Dqw4Ruz7xq5e5+scPLVmsoq60MaxvHeOL3Su8OJaiFkZXoKKjOl9Tmomjrro0ajk57IIhodg029W/Bf7n4RXAEUGWnoVCaXRdc9me48nNvwYk7bPrLPu3bwFQ1SPmxyaMxmuUpT6B4E7Lfy8uVqDGpXGgtCKFGUGhs0BPZ4lf9qjUQFhehgwJ1e6gy5Q88DAa1wvFUXe44QDatmV3d49nGtE9GqUYr68vvVQpuIj0fqxwaKOTn0NpA86htE6OShd9UXmEoFPoNFdjqkDQZJxqBPf96mX215/pESIJZ5H3Ohqv8aXuFcZbx9KxqHsMmP8A3Yb/5zXKOotCG4UtMk7vtIxHQmfxzqUf6UOiqKqKtbU11tbW2NzaYn19jG3n2HbOzevXeOLW9+iahl6lHJWL4WVJrFDOo+jUM5AEC5F3xY/PlSIP+wlXx5+4VfoiWviuuP8dxzz0XoN/xcYs7ze8zoV5Wiep1l3bsb+3T9s0tE0jhbIhcKAiz0RFbhTHDeZd78C7lF1o6hFam37cWE9eFY57/fRZrp8+izJiUVNGoYxi7xvfpapGfHb3eUjrIwp9XY2oqxFf4W9Y29jkxfpserExuqJffKS/HlFMjFbN+M4SoUwGHiVm8zTESsFfwQr+i+FIiGGqsLMKlRTl7UUjSv/Z9ZeYz9exe5IgdrB3m9s7N5iOD1hbX4+D5LEC9FXwyL7lvyxiDfh3EoD6QkXpdxmMmJ+jsCUsFwOWaUyq90UpzfnCLlpKiqWusjifgZPJSwwYwLxpmE6nKcIbLQU/lM5lT720AiDXKgCs5eajZ+FgNzynFDk0VcWxL4ip+PqvFb4sleDzCpatMkpTtqlrbn/9u0z3dvF/14ZpK6q65p6HxHE5/t06L9ZnMYP8lMRRe8acocjle41007sv135BjD9cDjsSyNIrLBBesPTykAd5sXqWJ9d/kJTJpm3Zu32TJ9a/x1sn/o2MYaocFh9hoPWWcmkpI/cj2QsUK3buYcjSv18eKL2gwt+y/DX0j8b+Mr6YVPTBlgjiD0shLKwAEeVnczGU7Ozc4ExzkTaIW0bVOO/RpV+jawGF6yzn3Y9kSA833YXePZQCU1VUo5BNqSwKm+cUrYseTv78hwC4T0kWYrwX3lONarTJZZa0MZz8csX9770GQL22Ht6tzqvtPN7ZQDyiHrOUEvXoR5z80FByJ9GrhCMhhingAi9zgZfDfvOhbL2U8VRa81J9ltF4zGg8Zjwe08yn7Fz/mIP9fQ7291O0aJLpSz2BPjUS+Tx/79IxR1/uD8fc4ndSCM739C3vyu990n1cusfhPy7WTQ59J0XGdqQw+IEOEz8P9aKod8XPnbU0TUPTNOzvHwBiiq1Ho+B47D/r2e4FXNemFGJZVE9uHqVQ6KDgK+rRmHo05tgDqqfnlJDX1qGUFA23XceJ157H1DW6HnH8C5rjX9Dc89Aam8dOUNUjqnrEi+YZtNLFpi7N41mPu9OGL1SUeCT95AZZw447i3AkkGUFK/j7AEdCDKOQK6MopVFJfrQ+GIB1DNEe07Yd7WxGG4pXe+fw2gUaM9BbCn3IJ50ly0YDYSocXzza03Pi55JkFfkAfb9NPn/YC7MUDdMXA1Eu0c7CUedDh7IexSwy/7zIsrRtyyyEtzzdSEG8aiShLba1OWcn6hXOc0FdJjfADlDWLVOhbIAniWGSp2JzPkiamE9cyjuHqetecRFdVZhqBCE27dO/fZXtk6fE+kUsejeYiwp5/eVaqWKB4n0H4m/YRcX7Ltpt3MEZGeFIIItGJWVW68DmVXw02WCmqnipkuIIT48uUlWWqlovYnmy78EVi0HRzqEU0ZJBAXq/8we/wLqH5yzoMIVicZj+vfR+5ecCUUr8Ed1n0XWaICS+ld9472mahr1dialz1uaNBjgVzPUDrEtZpElBt4NqlxIvNjnzzzAhD6ka1Rx7YMrN3+RJR7FwJ9RDPv7h34rpOObsOIfRGlNVfOo3Pwdg8vQ/4cRvf5KDOJUOukmPKiTCNGw56ANiOmcTAYhNVbXSAyLgs25cqMyHwZFAFucsNijvrLlgociKl0JhjMGEkPEfqecwSnHs+L0cC9U9tM7Or3IxhojhgxKeKfoiEqRrB8fTkfhrmYJdnCKbfFCX0i9zkhaXq+Q2XfDOq/IcD2XVzsgJs2FB0XUd83nDk5MfANB4H7pwFSvUMyHJOM4FvSlyAOc48bMfcv2rUlD75GsXcUhBbRN62uvKBKfhYI1cJnrWWpTJtYajLnjyF3+NCtzu3jdfhNFagQR3sE95jwtO0a5teKa7hLcxoqALOpJmvC4BmJdH5xn2q0Qv63y2HI4EsoBPfTaenj1PVdf8eOMCLlIgJVShquWzMZpKa9Y3N9LLclHpLUctFGO5SzyeP/kSCYrvl/jz+/sg3quUn3qm47h1fS/FJFnHVA+Fhjcjo0w2SafPKBaYTLp9/mLeNBwcHCRRVSSVbCaO89VKJdHIOpu4cbZQyoaPHbusMihtOf6zH3Bw5s/klIBgC49RciwvTatMHd5Z19I1c/R8SixiwcZaEKnjsy4uUTle7NT11PQHHEz2Q8iNFMvz3mOqKkUMnKsu84I+W0hcoYa0VpLVCRxeYm+l4K9gBXcNR4KzqEI0aeczbNfSjVqG4kLq16hr6kqjK518Sq6w3S/jLoTR/JJz4nXxHPm94GHsUcvFcfriTI8blXJUYAmqJ8KpHiuL12YJa0EQy58K2ax8Au9EX5lMJuii5w1Fk9Kk0wWTtVwXZH2lso4UZMKoR+i6xrdB3wnrXlVSuQUdnIuF6TlOcefhZ9m4eoUuJPV98MVvYvduY7qWLrzbtmlQqsLr8D61L/xn/f3gvKUNY80O9pns3e6t0TA2TSnFc+oVLvJUOCMUASwU/DsJY0cCWVBQByXMO0/btpyZXMSESORLPCXvK5mDJBgsNrkBkBq68vVQBOiJYeG/w+XghT8Wxyv+Hl7r+x/j4+XLVQ8NF+6VYfG1qRTWH5PashEiSfYxwtiKHvjU5GKSH1LBjyCqRGOHbZu8Rs6BVmhTp8IS3lp0VVOFclV2PqPF080nae6mHlGN1jj2eSlqsftW6Q8hzKnj/QeeYD6V6pftdIKzlp3T5/jkb34MiHPZVHWqq9wbIC2JfNYhBRokw1Mpk0SsG4+eD5VncluSkGPNBfUKABd5img1zKt9OLocDWQhi/DGSLh3O5/hAgIxkhzxbPhSeBTW2ZQWrAI1FNVl+aZeggcLkBBq2ZotMfuqAUcajLT4nV9ElWXQs4YFFpL2TKzaohjwmuKzc+lh4l4xA6FboXDec+PhZznxi+cBMbaM1jfEcx6yJ+28QWmFCeWqXNeCDl73+N7qmmpi0GB8AAAgAElEQVQ8TtegGvCe/asV1RdD75fphK5tk86ktcE7L6m8RdlVpbU4pRnQpMz2iV2XI9c0VY2pKq4/8mx/HfDJnO2CIzUaTs7zMpd4iufUj2kGJv9lsNJZVrCCu4QjgiwS9+ORnHFjfK/Yw3n/MmVodTT3WpvDKHLIiMvhJU7CtONPVF+GITFRrShF+RKWhkEE1p1DQBavWzZWFAEXftL8wjOW//zgqtKhGj8WVDf+bYzmlbULaKNDcl2wl8U5ay1jBN3DOYc2FbqqJQzFVOGz6YXE7Dx2gdhFOIb6GGOoqjqFqUgsl4CzLvxI7JipKvmpR1SjMSacr5SWhlTB+tYzsvsla1asvzEGXVXixwk/tx7/tug7Mf3DZl9RHPQ8LwuHDlmTd2ItR0IM84O3LVxZpezJHAMUe384tBJlNFYqUaHLZBlQd0dhpzinfC093Sgd649U+jJyElYcc3DuQI/P7yoq6Wr5XHvX+Z5oGPqO9WYTnztXBlLoylCPalSX1xFIVSBFh4nxAfJdVVWYmHdSiL0uxMgB3PPGizRa6h+ffO0iAPtP/lNMZVKxxO3Pe3bfDhs5FKioRmNGaxtJF+q6Dm1sIJImzdF7xwUvQZwXeapPCNIyZ6UdRNe5/cSfoEMDVVU8b/Th2a7DmGpQhiqcHUXso55WbK3FmOyEAkQejpVOvOYCL/NDzshHpNyqs10KP9fKkCswBkgbrL9jVe9TPjVfdljtyj6Ichg/ZKqdRhzqPr63tXuw4HpbrFjdV3QFq9PMh+9YBWebyPRxlwW0KJDGOXHc7X9TesXf96uXSSnLaawccCn3krkopQvEU8GHknu65KQ8GcfUI+rxOPVr0brFOou1bSpBNPSNLYdSecmbXCuVnJLRqWrbNvcd7Vrq0Xhx7VXRCVodLmwdCWRpuw5jYqh3KETgHbm2roTDXECsGM+rZ/GQWTuADnkZBWchXV1Cdu0tfhfOWLLPVYEYh73GuInkHLVkw4ere9y+zwbLTIWFuS2YN4sNPYwLUGCUClaluBEImz535/LOcfLKxYQsMXJYKcUlLR57py1n1A8yNdci0ilddEdWcjzGiplqhDYt3tv0TFVdcd8vL6dwmw+++CRtM6dr59lC54LYGWPWens33D+J0sViKILIFddfnvP6I2e575eX5VgQAzNF9fl/HZFuuOgZjojOsoIVHH04Esgi9nGdzIZKGbwn+FGsUC8hNxDlWS+iWswvz3keENW/nPfB4s+CAp0V7cw64geXzxuIeYs59+WX9H+UX8rKxFBwJ6qWW3uXwmpPwhtyUyUKa2VMb2oqnux9MC/L2p66cilVxMf7zEkDx1BKJUvJC/oZ4S4qG2ZO/uJ5UCoZE7TRbN3foZWiXt+gXt+gqsfc+tp32Dl9jp3T52TtouIdlym8y2ikueBfzo7lvmpL5IDR+XjPm5cXF7Iw5MR4sVRvwOf3HfNZjrzOok2VH9CpgDhFEYSilwoIOz3rXmSkKn7k/iQP5BcdfgWj7e/TgeK9IFstSnOFU3DJ+UlwWhS9hgGYMtbCaf179ebbb0AUfQxL71/oFToq1/FcR9qIEDNUh/W3hCglAkVWem2IwzqvLzNL+kJ+N0rlFnRVXePdmBNf8lTBP+PxHP/ZD9J0PvrKGbSuUMakdnuf+s2ruRhF8WSHrVHaIkpx+2vfRu/elGucqFPWdWn9ozUsG2XCevVw63Bd6WggS1WljSicwoMv+pWXKaWAbVuatkNvbXK2k7I+P7Lfxajg3Cqp6ABK5ElnLV2g0uK0eNqyvXpY6dV8TTHA4M9hnksfmfoNYvMeXUSapKcqhdYqWbcAGtuIIzfoB3VtMKYKGZpxLoESW8d5dTndf47Hhdx9q4NuMKAaxlSosbyzbr2RIFdNCuMXSm6JAo1W8ly6UKp9mF9KPTaSRXspGHdK6N1dESLTQ7PXzoKyeE/y8oPGOY9KQZoZ0eP+2u3+zcJ9IhwJZJFpy2TbztI0LUZrRjGnARX1YvmswfuO+XyWCoqfMRcldJ8q50v4vnUsesJL6Kv78Y8lHOLQj8spUfn9MqQ9DBlU7+/eKenInSLKy2u10tTGUIVIiGY+z6IX4H0VaoDlOK7or6JpsLGwBUo2cECydt7grRXveww78xJBEbmPqQ26WsOj0sZ3IfX61uPCRZSVskeTdw0b98u9JF170FHMwzl+xEX/rTjJpQuktUkdljtalBNRMVrfjDY9jpkkFufw1vXHXgJHQmdZwQr+PsDR4CyliKHFRdhYh+oE20ch6jQ5oJTURPauo5lJUN7t3T0e3fp/2Nw+xo/Xvw2ISNe0LbYTqjUajRmFQg19KBJNY2YVhTx8h6n3PSZ3Tlnq6x35D1U8m+qd0R8ji1hk+4HPnDFFEoRzjIaq0lyupKTU1/grwKd4qtQPXpFNwFZSlqOzF5A4sLLbWvLXOFzw8Lmg52z/9P8F4OZjFzBVRdO0SexTSirvm4IzpEiNFMhpg/9M3lnbquSofMYXBgitedE8y/ngTvB4Tr3xAh99+VvhXsINtTYSDY1Uo8HnQFLbdSnx8Pb8vwtTmnAYHAlk8eQgQa01xhicdXThYOUiEmUZUyuPwuGdLOpkf5/5bM7B3h4P6H8LSLh327ZJDLj3E5/ijU/8GbrSC9Va8+a9GxQJF1EggO8P1PfRxD9iiEw+Wopfi5AHL6008XLvPM5G8UV0iBi9bYysZW0MVYyEwGNMjtQVv1S4Q6GzJN1d9xHYxXJFTkSXruvQPuhD0wnrL/9FSjSztsPU69hullJ9jVYBwfKa+eDcjIgrViubCFx2pmS9QgE4OKcu5/k7Ea/uffMlAK5/VQjEySsXE3FU4f5dG8TJpuH6w8+gf/JJbCup15NPfLDkPQgcCWSBgoprjakrrHJ5A4XQi5w5GL5xFlXlDlEHe3vs376dtAQf4sNiqP98NksmUV3oNf0Q7TiRO03Wpx3b13WGus8AaQrlO5+mFs5fMF96egP54rxYMG82n9K1Ldvb24AU9ZASQmRkcS45HdNI3ic8B3IoiHPpQ0x/iETn40fOcuLnP8Bal+Yq+f02IVhgG2itU6cxGTc7RSHWCQOlx2HeGyitMjciWthUb9OnQhORI/nIZeX+97z5kjitTZUeTowZjib0/WmmE9qDCfvr79BoyYsZzQ5/8SudZQUruEs4EpzF+yJPHaGYdVWlsIiq0sLKI/8OQXzOWYIVUKin93Sd5cYj59K4p167hA/tn2eTA55pX+Bl8xw65e4HSp4dDWEiS7hNpGJKZavt0F9z+MelpyZa2HPFDLid6puIo+MuOh5BYuOsnTObixjknMdUJtQuiNVNZKxyrV3p0AXpqBb1k2g1S48vf538xfPCXLVCxVYhlYEiGevk6y9w8M0/Fc4SubhSoRhGXhFJ9KpThf5qNAqxXIEbhAjl0mIYF6PUFyWLtiJ3DVdcf/hZjv3sr7GtrMnOo+doZnOme5Kg5m3L2s//iPF91+iawH1t5oJDOCLIkhdQU4S+F34WpYoCR0qjTYX3nhvBmbW7N+X27QPRUXyMRFbcevxCap4zn07Yv32LRs9Zr0JVmPgG4q2WMluR42O5psPqjRyqdQxtwD2xahD8GRBXJcUh3z9d4ZxUSlEq+SjqusbacTqvC2WPHD4hVD0eY7ucMOeVT6biGFOlvGfn0fN451OBimT+Ls3wRgczfW6AqrRCk0U+HxTx/LAqnBcRrOK+Ny9LedYwx85UeN8WcrmYhHum5KEIHO+vshHixiNncV3Hxw+dYXYg+ojeuUbXtMwmIoaNxyNun/qAWpkikPJwlDgSyGI7myiUrG3MZsv9OC6pM5xFisQFsgYqV+5QWmFdF4IDs5KuFHz8kCh79/3yJa59+AFfV9/j9fE/B8SRNdQR8hbtkfsF85iCvqGgvBjKmnu9+bB4uP9ngUi9b5LOI8Sja9tsDVOK9fW1FIWN92ilmDctT06eB2DX+54PQykTIoh8qu5y85GzKCuNim6ErMN7rrwgHKkIpKxGNc7qxG17XBBR8Mv05TAltNbJGnfPmy9JdHKPs8fHLnwg+BSeIt/EEJb8LN5KWFR8jqaZSV+ftk3+IudbnGuZXJU5zrTFmDm2LZI0QkDvMjgSyNJ34eWQlXKPlmZSCdmQFm02SmZKi0LXFVURQ43c+CLbtmF/d5f1zU3sKXGepZCPtIHyDu+FGNHfEIpCz0/Hy3N87949UHcwDBT3LnFTGhiFZ9UK7w2KLlmoosUpckpTV9R1zcFkyu3bUv0+0pBITFyIOLj52IWU8+GdFyz32cS8+43vcu8vL2NtdGZ61jY3cbajC0XHveuQMJkgIoWYL6VNyqfXShD01OsvxQcJ7za//xT1FMPq20aeN0UMxMZJLjk54/289+wEEdw1bTLwxOv23hYOHdNBtDFoM8YbTR0cl6o+HFlWCv4KVnCXcCQ4i5gBo51dlDvvfS4G4fspplHOti5TS1PVjMZjVOAwULDrcNL1R85x35svMdnb55lG5PFX6++ijelrISpaQKMimY/3T+vL0aUIFeOEF44l7tPnIMk3l2RAn0y11jkUpBgvrRXOiVKtAhPtOlm3GMi4vrbG3t4BT9z+K67ti0I7XltDa4P1mRrvPHoBigJ5Hpcq5EfDwHhrk4On/hu2f/qfAWhnc+HImKy8E9J3E2fxnPjFD9n9+p+keYNkWapQ1EJeuU/Girgg3rvsP7I+cY3EEQsRTKV1FHPyySsiqt98/AKx2mb24Si8dSnnZvvBCj0eY372x2n/ud5G6MORQJZ+CdW82OjI9iVy9qIKmZLKcb76McZrYnCSqWC0tgaUyBJz88Nna9Ba0cxnzCaygexaRz0akWTkJC8PBSP6yOIJSmU+pPqYkdXaZBiINar61rBl62GLmlzeWrkgKMFGVajKUJtcE2veKLq2zaKKtXxj/wd8tLuXrFqus1DptDFunD4X8u9tzxooOe1VEsNOXbmENhU26JWSr9+lQMg8bwdEc5RY5KLiD3DqtUsS7l+ubNj4N05LIXBrLZs//ssUYwayF2IKh6ynWENl3Hgs1kIIa1SNcM6inE8VZ1So7bD1QDAwjMaMNzfx6+s0TYgYCNbEZXAkkEVMwPJAPjy0xyU5XKmIE3mZL6kznK1fxcTSO15TVYbO6FQMDqQMjgrI4+jYefQC977xAvuhi9jTW5f42cY/LixSQsG8MQXVCl8tUcRLRBqGzkddI1qstM49TvrIme/hnaezncj3YZM5cmGINC4e6yxtI5uqaxtsUHIBvnbrr7hx4yaT/f2B4zBbloRSB8dkkY47GteYynDPG8GgMh7LOyjCY5x1mLowjsTQdz0IpQFOBWrvPRKwqEIkAJobp5/Ftg0uWKystUwffibl6d/3y5fRJuY7LRKwUtuVewTz9msX8dZy85GzwfQMW19oMWYNndKaK7rO4ptWCA3gXEbSIax0lhWs4C7hSHCWrmnRwWQX226U5qAcap8py3O8gtM19/5SLCs7Dz+TKunn6ApPrN4IYinyQNe2TA9EDJtNJvhjhcgTWitopXIr63B9z8Lci/PKn/P3MV9DipjLs2lMyDpMvo6YsBb9I7TYedsz8YpvxGEC1a7rSsyiTUvbiDXKhMIUX7slesWt23vM5zOMKayIzuKcdA+Wz9KJSyuFCtRXPpvAvdKjIPpQ5LRauFRt+icVvhAdKsecvHIpVfdzwQ9y/WEx5Tvb0d7aoZ1NsF0oXq4Uo/VNKhMrTVZi1aS0DhZ2wmIdSwUxl7nqabvUG9uY4Dh1nafrOuFAJ/4AwPaHJzgMjgSyHBxMMLXEBlW6SuJ5MnV6xXn/ChBYpe9wqGCeDSKXVsGkmpXMcHXh0JL6Urcef47jV6UfyMH+AU0zz4GEoQ2C0SYrpkqcpQmCyFXmlcTPpZ4Se39UsWpi0W5BFxtLoWhD4GDXdsyms+DQk9G6GFRoAvJYi9aa0bhOxUjW1tbo2o6D9yVqNvaRNFrzcXDcoip0tQapOISk80oSWNYHfIwgKI0NPq+1VtJzclijxuPQ0VJhdKiZTK6RrOHjrzwlFS0RZBFF3jN9r06j1A92nPy5tMlgY1ucjQW6xDiwfL1cZ+o6+93C2Sd+8TzXHnoqzFvjbb+kVuc8FMlmt04c8UDKtmlylOmownvXS1dXCzTOi9mo2HAiLkdvct9ckMI7lEJhMPjkvJtOJnxz/695qY7UVuR4bXSipDoWbisUdRUV9d7YqrhGdJXITdI4KtbeVb1jqrB8eQVNm8PUic68IvjTaNHNIiJJKLyjbaO/RTN9+h+JzpJaTBT9U8LAMR5R60wYTl55Qbzxdd7A4lSKTkkpQ+Vduf5yTuLiVR3mnbeY7Vq2f/J9Pg4RwcYYtNbsvzdCq6gryHMmPHWhX0/xTqXMkZPKMKnzm2W0sZHC8WODIus6Tv5CGsBeP30Oby02jG7xmL/5I26c/AM+OC6PfLdi71wRkk0I2c7OpEU5KNCNYBoEsdhMHvxGePF9RdBHi0kQr7SugwVMwkTm0ylPtULJLnEm3M+nzVnXtXSoWhDL+vFKEuEbqWhErszZbMgBtzbXCB6PxoXSH/ujRONXyGevhPInh6NWgRMomjb2J7mIc54PnE332nz1rzDTKS48/943/3Hg1tEBG8c2nArKvELhxXuYxS5ClIXOIo/tLPPpPHnH5XeOQq6qnEoco469c9x+4ruMw4oZUzN3sPW5CXtvyXXHHgiImzzSYhLvdZT2HoejmTd08ykANx5+lvVj23zqb18lvIAQwT4qxHnJYYmKusMkE30yJg39AwWsFPwVrOAu4UhwFudcigyNudy9tIuBoi6hLwAuN/f0kmNdV1UvdMPjy9olgKce1YzX1gBY31yXOKY4Ti0xSF3TMA9UclTVvVx2IMyxiPUKekyS/ZGSp50t4peieRWVdJdYYziKU97GiOLchiNS+HlMrHIOrae0XcfjN/8SgA/29nAO2mQClYxDidCu0ySVd1nUUIr7fvmjFDGcnyMmk8lp1lqa1hLZoe06XGdpZ00v69BUutAPhfs42+WWDyhMVSezskZ6hfq65sSX+z1kohHiE7/5MYqiUGCAm4+eZ3YwoZ0KZzl4y7P2sE2mX+UkhOnG6bNJalHzOcFLKWvkPco7MZsXIVKHwZFAFjzs7Ur8Ujufs31si3ptXPhL6HdqSNhSJBJ5uO+Nl1i7dYuPviQKXfJLFztaKbj39RdQG9IdVyslFWViT8tKBnPOFrb3DqMVG2shbkjrZGPxyfQmR1KkNArlFJ21tEFUadpWFPO67nm1behVD9A0DfNGCkusjdfCtMUAMA9K+3wu8VJPzS5x89ZtAG7fvEU9GnHr8ecAEUs7a9HVOPksTvzieW4/fp773pSqLc6Lw04X1XOixdBZm0Q8aYzUJREl1vuybWlFdKCijhNju1zIfA19XpTi3l/+KJU98iH+TGmNa4v2ds6lpqnW2tCgF3pxYNaisOgQwlAZh29bPv7SE7JmoVgGzYyYuqyUxXmVIxg83DrxB9xslpCl1/hpAEcCWbRSzCdCIdysoVISOKfGMXuuQmuN63LHP5+QJVu6tBZrV0otfUSoUwzR3zl9nlOvX0IZk6jNbDaHwpT7TPsiptK86J8WjzeSYTmtDHUI/6hGI7QxqUA5ZAU/qbhigxUTaNhDznuMkXFS8yY8rnPMgwm4aVuauRg8Sp3Fhkr0AOfcj9BaszeZMjkQ69f0YMKtx7+d8ts//MrTYrbVLsna3rXc8/qlpATHTEels5lePI7QNR2Nj0q3ZC5GD/rOYxfEVKkU97wppai0GQtSBGuUzD/UgCt6rZRF4H2MlPDiVIXQ+6UwZV9/5GzQO1w2tzuHn0+hm6ODhfTY5zqwHmsDgaMRs32lGdWBk2jH3Cm62K/FhxAd26GITbFWOssKVvBfDEeCs+A8dBGzPe1kBigIoRy27Ritjamr3BtdxW73g3gRVfQ0VypJa4CIJpHKRdNxM5tLYbZwfdt1WKd50l9M11Vzw8v751KuxNbWNqO1cU8ejz3mY/hNXdUYo6nrKukxYmoW7hfFHmstXdfRhJikruuwnRxrYw2uEANWh/bXL6vzKDQP3/7zJCreOH2OLbKo0rYt1x8+xyd+/TKxE3BVGbTJxSHwOUM1hfrbwK2VToGsNx49L2FDMfwnLOk9b7yIqWOBDFPEa8Wz5O+0RsG5fCK0qbh5+rwUkVAaXUWndOizEjmvd8wn+6J/ubxHpBCfpTKRJUpUbQrtty1aG7SvsD764gzKVNniZR2+a8DbLKodddOx67okK8a8lG46Y7YfKieuTVnf3GB9XbIbU8GCJQklpdn45JVLQT6ObJ+QquGz+dCJmJLip7xUY7QFIlirOWcu87PJn6axx50ELeaSPR1VXTNeC+bdqs5VFQPUdU0vAxRh7fVoxHrQoUDMztPJJKcMGyNm71SVRdE2LQUdQGnNbDpNep73nnvfvIgejwsRw+CLOacOBPhU8cTaUIROaRG3CIaSsvCdkuxFYwwmbPJhvxg8i4GsIWBWl71YorMqimpW2nWrULXHe8/sYJ/dt7I4WdUV3iu2P+8hteXTYlDxct3+ezUGxbHPe5poFq40TqtUEWjvLY/vGlThJtB3EMOOBrK0Xc+FErlBnJybNezPGtpNob7jjTVG4xqPSh5jKevT9YIU4++dR8/LJy8VY+5986XC99HhG8UoKNNaG7SCrssh8j4YAaZTqQDivKdpWxHvC0q+tr6ewr/jnJTOXvuyiHUZpmGqjjb2b/cO5x3W2aTXrG9u4g8mycuvPDzdvcStIlpbaS3KcBi3Ho2YfOsfcuKtnxQVIYUiR90nJk9d++rZXrDjjUfOBWKUlfcY2RBfkgqpvrbJHnSlVeI0kOt9lSnBSqms4LtY5TIbanbfho3PNin40dQjpr8boVSTLJZdJ0ll++/VnPpKDPfXKNVBCnUSfnrznWx53PyCg9ay927Mt++kQhCFrnI4rhwNZKmUSmKR14i1yXt0Yf0w2sBMkGVmLe28pl4bUY2CE0ybtHGzaCS56gdXc63brc9Z6dnxqx+lsbuuYzQO1qBgJKidw6caXDKfZJYNIfSmqnL4ipEWbTFP3ysllqaCizjvwmZtaaJC3zSivEYupJU0My2QziOWvVS3SxtRgo1O65ZLA4VhtOYTv7rMr8/+rzzyN/9HuFdLO2/yOnnJt1dtx/WHY+NSUXqdd+y/my173uvUW8oBxx90XD99jhM/v5TmqY1O8XSQOUkSe7w0e3WNEB3btbSzKa5r2H07nGIt+29rTnxJPtfjNaraikO3cBMoD5ufs+h6U86ra5y1aT02P9dy8K4WR2SYz/7VSuoOuGjlCw1ZIXHxOzCWlYK/ghXcLRwJztK0LVe3xT/w+f1LKAO6yN/AOsb1GJeUcMu8bWmmc0wtJmeJCzLBDCyXXfvqWfbfUngiRXLs/FZx7PNtKpf0yd+8jCuchFFUquuaKhgUpBysZ5QSqzqcD8GVMcMTJ2JSENU8irptRJkP83HO0bYt8/mcg33Jp3ly8kNerp9lc2sLgI3NTax1mMokpX8yndJZmzkLhpgtWqX8do3XKokvWmvJR/e5xYQ0rIUUl6YU0/fGPXOp9w7vFN4pnM8FJ2J1+/hsXSPKcoxFU4DxnqrO/SoVnlqrpCN9+JWn6KZ7yQXgreXmb5rwnn0ax7ncB9J7z7EHFTd+ZfAu67XSeSFzLaUNIpSEiGKCeBj12zi4z4XR8SEDVef3fyfWciSQpXM56jOli3qVQtK9MlTjcQ71bhuJS7Lz3E6haahGI25//Tsc7IvvoWtami7HmEWxoOuyajxeW2O8sVE4CUXoqSpDPRZRaH1jHU+OcWraThyLVZV0hnY2YzpvIPg9zN6+BBw6x5np84D4a5q5+FFmAanemjc8dN8Of/SZTwPwy+P/nM52Aclk9DPNJSiikF/UzyTFOQaPSudhn5DFOcf+7h7b3SX2b0ti1Y1HL4SIbBnn4GqV9IocP9WvqA/grNQrjn4nlGLvbc2pr3rwsce80I1IhLQWn8lIeVwIv3fTA7FqBQIz/f0aSnV4iSHP6+99oWc5lDFiAHIxRWHE8S/WuZINcOr1F7jx8NksBoZuyb3SsOU9iDosPY/30s6GAY4EsqybChPDDHwIuSiCCz0K1sap8oY68HgHtmlRRha17VpufuVp6slMamYBe1clxyOr+/ISdt/RbDwSdRTNaDxK92qbhq61WO1CXSZZS1PXKB9aN1iLxVPpXB6o6zoe3/lL9oJH3YUW1c463nW5bq+parSpEwUcrxlGo3HWfUK3LumrEgNAg6UuPNcz7gXmzvVybtCSX542mbViVdKGj74s6dhuMkEZw/T3ITLAUKQU+3SddzbkvmQChs+6IIi+4W3HrcfEeHLyFxfZeeQZ9CwUsHMWN5/h6VK4kXKSdOzDs1fG0GqN7YremNEAEje0syit2f6cZ/fvZD1sSIUuud3NRy+AdUX0dIjbSePFnZCJZy8XJh7icFjpLCtYwV3CkeAsta4YBfFhVFWMqlqqEKYkHU/nPZWJPoyK2pjgloyyrhZHnu0SJcHHotA5vCKe3QWRom1byUIMedmOQLm8Rwen4Ldmz/OK+nYK65/NpuA85th26jRVVTEfPXtEx6EUaYoxszaUKx00XCJTbe8co7oG71NF+rqTvJXpREQ821natqWdz5MZVs3meOeZz2ZpHIhmVnnq3bc8VQW6ij6MzBkjlXVdi+3aXHstPIsCyoLeLhTRi07Y3ScuYHwW1bq2pWvmOG8ZBfFxYzzCeU8bxqnub5n/OofDyK10cAPkYFhdGTFVx/3Qddz6LWzdb5P+k+of6KyfqMRdwuAp3CbeK+o7hSvSH85bjgSyVMbwub2LAFil6LxHFVlwnfPYgwPG4aG191TG0GkjvRWQQnHQ18+kGF9WHiEGOigx9mEAACAASURBVGZT9Xw6Yz6bs7YZ9CMEqZy1zGc5D+Px6fd4JfR9eWLn+7RNwz3dKV7/5D8DYHt7i59Mv8Njc+lP0jSd6A/WosPGvf7VZ5K5Ob6ok6+/hLUuIa9C0oat7TgzE11nfzLDWsuNj28AguA3Hz1P13bYEOWQyEGBdAfvVegqF5UTf4aNakYiHs7luDPbNuK0U6QATG0MlanSZtFGU1UV4/VRil/zzqK8p4lRF13L3rsa41NoHJPKsXG/Td3alO3YfgBu/V2dN2lU2hMOO1HetUGFODCpdtmy+1bFyS8HB6srTOjxt85iW7EpcqnamM1qzJ1txgGOBLKYyiRqY71sKu89BMp+4sol7NRhg+w/qiqUDp7cQNmq0RitoKqqtDj+/jm77+T7xAxHpUibo5nPme7up36JTdPguk6qWxblR/Wo5qGN/wuA3du7dF3L2mjMs6ckkPDV0XeoqipxH7lUHHBd8Kn42RxHhy+yHndOP8v6Wz9J3EcpSTVw1nEQKtDcvLGDtS5VpLn2lWfwt3ZDpG/mtqXAvfeuCWEhOfgUgqskWrmQcBdFaNQK1NWapELXdU4HNiY0ySWsB2x/XkL2MwcT4hatWAfv1ZgKDB4Ve1h+pqF1CmWiMi2RAlpni50gdNY0vXWY4NjNUegqhdxEo4t10rgocwshSL7UUQgXFaxGaRU4WdSRjjhn8YX4cv30WZq2pbMdVXjIj0MxiqjMfvJXP8Jogx6P2HlCQlDWRjWf+NVlxqOKj0Jt442f/IC9zWeT+KAUaB9Kf4cX+PGXn0b96jLzYEFzoWBFzDsH6byrqoqda9cBEcOU0swmk2QCnldznmkusZ/uJXW8tl/9Pu1MzNvXHz6Lt0a83FEx9yIqxXCTGCXw6M73eOe6cJLrH32MB3YeCZEIqfh5NnnKS1YchFx2pUKOvPM4ItXVOKWIxc+1FqpqqjpZ0ZQ2xHoCcd+IocKmPbf5OUvbhQ3rCnHWduy/k8UgHaIpUki8qSmYBsrnemAq9bkU3j4JjuT6Sy5xidIIAlKDLRVidE5iv2LYitZIoXB6oqYMn7mYdDUuilrcQQxbKfgrWMFdwpHgLCVmRz3De8/B1VAVRYkStvHZ6Nw6g64qcUwFDjH2Nce21vj1k/9LSrbi6wdsTw/YC6KY9hKxSgiWBLC+o53NaXwQlbwLxaVzyzWjNJNv/il7gYus//j7NPOG/f199IfXAHh49h/YO5jRxUrlqmLYpvqe119IUbVRMb75tW9jbY47++pHf05Vaf7wh4947/6vAzC550AU14EyTpHP45zj4F0xlcv9YyeCglIq4RyxL71EIVcoXSVxznsJy/G28HUULUEAbv8dbH1OCoHvhzCVzknAaSzWp1WI/tbZKbv3noZiLFPpUOqoSVG/PklN2QFsrcQOpgzLopBfui4VAclOSrC92LTUBiNFT4uYZq3tm5EPgSOBLF3T8P7JPwFgcrXDfKZj/2pFVbwi7WE3xnhpxcbnLb6zVJW80FNvvIj/xEm6tuO+6d8A8GEQHVIkqROxxAP77+Q0Wv/VZzgVe5F4n3wP0bLjrKXSJkU9Hzz5Dxld/k/MpjM+/qrEVH3iV5elFUMtPozR+lYYPzf4IcjHSpukfKI1Nx49jw8VSG7dvInr5rz/wJO0wcEpfo5SCMg9XaKF6ODtCqV8X8GNgZupKVRNPR4z3ghzS3XWfDIwxFYRPa+6UgutNfbflo0Zy6ym6i4J6RzO6+CLykaAMhJbiInu6REiuGUisPuWYny6i8638Mxx6fqRBz3LV8j4lIiEUsTLIwhOerylQKgjjix14Qn3wN7VCpQn0SAV9JoiPXjvXVj/TJtyrv/w4JNsffAaD1z+37j6hSeBoPQpCWeAGGW7GAW7/65hcvw7pJv9HrY+57j5NbF+3fvGCxx7+XvMv/5dQIpu7zz+bcm2DDng793/BJ/621eIdau8c4F7KMn0g5Tr71UMmodYAP2jh54GoJ1OmU/3sbNpz2oj2JGpv9hBYf/dGN4i8n+ZS48S2X28LuH/1XidE7f+AUxUmuPNE3/Adrnskg0burfcURdIyx9SIbxPTXJjf/m0tqF3ZFestQ8Bo5F4OedEt/K5dUR+R3GFJBhWm6JxEgrvLc6pZMyxXUcN3BOI3kdfOSOWvmJOw0J8wZIgxyMX5XA4EshS1XUKZcEFm7fKcVcUCV0QKI/z7F+t2Lo/h7a/87mvo7WiDSKNUo6q1mx/PoR//1aulZpSkQLrUCMsW36U1lTj3Izn2sPPMnrrp8nvoWox/3aU4RFBbCk3T/AZ5ChfqX6P9+joM/Ci6JabxXa5KQ+ER8+4Em/H/tW+2IXKhbGjB9uYinsfDsiytsHW3/x7dib/LQA3T/whVOAsCEjMjygNSN6By8U5tNHRxp7n5GTD5ZoIEmVRij3J9xHHdQ6vbE8Jzy3Es8Vq722oRobYMkDadks5pL0gIZz8koT63zgdjCDzuVg8S1E03b9Yozw7AMwdYvRXCv4KVnCXcCQ4i9cmRRR7pUTk8mTOooQTZOrnkph78F6oXPJgSOTyOl9GUCgDsVNhbK110hliLFIvHbYUJxBi++FXzlCHKOBRiFLN1n4Z59bjz7H9zs/SHAMpKxRTjXcKXWVOZoIirgvlVZuCYyToeVvZj8p8mTWn9OAqxfEvGk6+Lr6gW9/4R3z00Bn0q8GDH8owOVdG4maRJbXFi8NHbmx0MLsWsWhhDFUwqCTeRHMuWUyMkIpQxEfD9jkkpPrTOXpYsiKNU4m177+jWDvd5TkHs7hSCh+ry6R1yvoRJadJn5fDkUCWK2tnUt2wLsjLkcsDhTMqKmrRCpJMJ0x/X3PiwVCHN5wtLF2x927oTOy7gIQ5SDMF2aUSp1L/d/8tiDWT1z4DPrTgA3Cd69c+JiIdGelCzWUxCEXErAAbHGxy3qnXX+DmY+dTWrUZjajtWq6jRpDji8jg/atVWIscJJjeebH5tFKY0YiYRN02LfrVT3Lz+O/Dc8SgySw+hgXuhbbgrFTyrAorlNbYpu31kIl6SwTJyc9Rv0aZZOmU2/T1x7CSYYiY6CZju67LyV9BDHfaoYL1sWnmTPdzoyJd1Rx/0LP3bk6ic54eMkTkGbYKOQyOBLJ02qQNXpYvjfM3WuLAvI0bIS5yQf2d5+BdidRd/wex4aboNc6HerjRHOlccmbJS+kr/MNekAdXpSbv8QdzQbkhxCaiyfKiQ0h9QSW9JnmLb6Zi3TpkJvr0OXZiTggdyovuvh3PcQTXe6a2HkmTDaC1oRrVmNEaNx57DoDtV/8zt+y/ygUFXezn4rMJFhe4scv7yoNTQBd1LzEm2M4mE7yzsQRqpOyhZnEyTkjd4ayT5Pco6lYRdU7WYZz1tH5OF0rfyrEY25aLwCvv2XtnxKmvhvJR43WcGXPsy1LPGKRGmCB0TCtw6fmzZn+4NWyls6xgBXcJR4KzjLeO0YYCz1JsLVnb5QStUF7hfA6kAyfZgTHXo7CiRD3GWpfDV4iWmSBrx5sPuEi0KvnBcV9yNiv3VqhgkYLtByQLMTpEa11jTOyzKGTrxiNnJSzEWXwIgcnPGj/qJFNFZnNwtcJjMFUMpbFB7Ck4a6COZUWYkw+t49EpXuv6I8+y9/YHmRu46IzLJZGiUzD6TWTsOKUwtifEVGULlQQ8lsU5JIyl1H0SVxk6VRUpWjgFUfrMxXBdCk+Kk1T4wF3ju5XxIhfpvnUd/eqnaR/7Hbe335VzWkuZKRmvGRoaD4MjgSzHbn6anWO/A4J+MozhCWy/xyDDWqWPA99JBOchlVolmmEH8rnqV8MnRKJGPcKHgfbfleuqsUQ7T2cWFfpeHlw1bD8AHz0UnZQvU1kPXa4H3M1nCYHvC/4ApQ3XH72QUob33gHbOWyXy/OoIL6luCcvgYdd4eDLOlMwFFQVuhpJekOIBHZtg219EteiHqS0ooqt44wJbTLMYoZh4fBUStFMp9g2Vq0UY0NCA+cg9H+JIyREKV9k6ffIZxYKfzQSFOfF5yx0T9DgFTePvQ/AxqV78Oyx+7dNfoIkusfPeRrpjnfAmiOBLO0Tf4B3ovJohJIUBMg5HzqCZSuGUDtV4FOBLD1fg4bU4EYa5yyzM8VjWovOIGEpuT+J6yw+equtxVSVlCtNpjaA7B+59tAzGK04+fMf8LtQX8C8a+g6Uay7TTnmjMG+o1LPENEfSj8AyXoXgw0jQVE+38+Hkj4xJ//kl2uO//z5XlUUo+DTRrP7uDhbp+9LydXjXyBZB2NtYqV1yjjtWotzNnnrm/mcW79paWazhCwqWRFzBZYF+d8HKp70MwVky+TiWwnnREJRWP5yWalsqFH41Cjp1on3ZW26PI9CvRv8Udz1qFvD8C4VXtNak9TEJBpYFKZYKwW+b8UoiVYZeToajQjZwLTO4n0LgxfZY8NaSgzpqk7FqbPzLIgGXZe+ywUTFLP362QaFeua49bWcyl81zbSJNV1XSrP41rwSlEXRcCjtzyZIDyht0wsuxQdnZaomcYOvie+JOv4x2/9FLO9EXJRYs3kiqqq+KPrfwvA9a+fEyeoc1JcL6yj9UG6ie+k1mirs8VyPqeZNZL7knL2fSbc9InXEOI3KWViKAcVhgutqoKDqN73QuTkmERp5AKCKXK8bLgU+dYAIXri9h04y0rBX8EK7hKOBGf59C9+yO9OSGxWpwLn7JmFg6m4IFaq54mJMZJC3XJVG5Ucb1BQu75Gn0y8eSwHg9TastaudQ7VtSil2X4gjBJK86TCdMqBrvGGHOHczIL+4rGkSaIozNGqbKOXJXjliwJ+XoppmLrGhDzEYw9Kobk/+u1PAVg/cYKqlnYSuWADdNaneKr/r71ra70sueq/Vfv8u9sZZ2I0ARVUSOIMJoqoL0KIEF/8OvkkIvhZfFNfVIIZFSGokUTHCBIYkzCX9HT3/+xdy4eqda06pw/zdIRaM/x7n32pXVW71rXW5Y1/+OsmXh2Hma7ZMnjK+I/9jP3lCzy+aI6dP/me6GFpf0bfEro/0QMo/BO5EAf3o5aZ33Sli+9gHr41y1wN747vi7rwnYthfNQQ0dekLLPPi6jg2Xd3sbIJP2pblKcKK8LZw2i1UE2bpgIoRm1bc/UPyav3AwXVshSCuuWo2m9GD5zq1p8nT8F84M3faOP4+P2W++wJgLe7KPAJMz7hXhRInRNamLMGqDGwobbuqTMWqWWpzceBctrw+a+cNF3T02fP8Mv//vd4+oUvAAC++wffAlDwu//859g7sp7PO/az1YvZJZ9zsKoRPn3+HGA2ZHl8heP8Ch//hy1E93n6c0LAdKodkngFnm1cIm4yTPcD1F8P6AaHPn7v0Swbmn7vrDrLYzPsRIKqHheXJURcu3gXyHI+Duy7TJZT4pXYtfBY0ysKqKqar+14T15ppBQAJ8k3RmqQ1omnAmwPTZcBUGuPnwBQji4PE6UpZDVDq84iZlKxUHH7uBuAZ12u34nwadlaWxKTsT0AxCCJIWdfg0YWhyCqKKqML/zmCW+89RZ+5QfvAQBO2wPoyTN0vMA73/5TnPcDP3k8m/v9fuDYd+ydMP30t7/R3p3N5y+et8XXud1H39+baVg5QTe/Bk7f/2bC7HCjT3h8htMjLM8IQnV0cO8Tz+TqkIUr96pp0sxk0SfXmta+d1q6DktnWbDgRrgLzvLDt79pbKRbOjxl0I0tb/nqB95M3MQyh//dGiI6gzFmttjt7t5hVaVYS1BI4r9SKOz71L7PUbwPlSTo7uLd59990mpc1or6r5b9fttOvXy37f1wrVraWzcJg4hT0apYtc/1S197hl97/5/w9OfeBJUW9fjBV7+BN9/7K0188cFXv950jd1CDbgeQE9QBwD8+ALKrdz3eP7fW6PcshHYxS6lzMfez1FiGyMMl8mdJH9a5kN0DZnWA1o2XcUwViclt78Z5ox6vy9oVNq5W7kKcCfIEjyK1SvMDUN3fW1C0Xe4rTZ9g6YYmrLKzJoBpLp3GPvewY+Hmnepm01jRkxprj+jSMIaVoutBXVxF91oOwA+gGMHddv/wRWVe7FT6WL3+1ITrPcucAe0UYv7AfCr338P5ekznM87zj0j/ccffogf//rvWFzM809aodRjh48xef7DKEzk7CctGK3tR2l6oe5hnevNiCgKYJir+A53kIwr8myyHA97TczZfYv6/yJOd+9m560x7QxND2+CO0EWBM4yVQwdYnA1FwWfmlNSpqrV6jhCLUZmdDcWt0BabiDri+NawX3c2ewrmm7C+yNEkuX9HKwv3CMF82KkzDkofthwf/+3lBar/gvvNmR5/JcDL189x76f8b89k83x0Ucx7REzPnmfFKnbKQa5WvWl50dm/y40nYhSIBujBKQLE5a+j78WjWWRsBkBZAuZCHe6I28xIKne6SyGVLrR5zKf4NT4rRxF4C6Q5dgPZyCR3Vp/R2P3pBNaurmDW2wFAOoK3+ESROzH3qPlOtcoBHAB8YFM7uSnUa9quYAgLF8U7BbW2piBiykXcRGihB7BmFBKASNSZ2nblE/jitKrjQq+/PFf4qcv/wQA8D9f+v1e5+VAfdGSfv/sfbGW2eKVuB9dIz2FkHoGnDYMVb06shLg3F1aQdwrOnMj6s7S5MetJx0nCKNnb1qLHCqhl81RIiiVTcQeIODbtUJ417nNUvAXLLgR7oKzVGbNFF8KqRtEZpfKWbg0GdXHTxB1/yWT0ffzGcxs8fXlBOY9BCB1su70khGMPjpdqAIhvQGnTIreKCESX5D5RV4HEIi2HUmijS9+acfnvnfg+M5fAAB+9LU/ElKuMejNjYeVa+jeENjcO1h0j/aOrqfH4C9R5rVz40zIZq8HFg4RTvK4N+nFqT5w/2yTqr1i4Y5dH5Vjeu4VBBLxpE5Osql5edQOL/OWu0AWAIENl1KaGEO2hNt/3mmxn1VHxiaGtD2FzpoPCUftG5Cnh94uTYQh1xVBQI9Pw3XWyGGFvoCljzQ4CI6oaKqaU2j7R/7iO+3cV77/d/jg69/C23/7ZwCAH0FClB2K1dYn7Y54JXiVqTKYWMd1eFHGLxgGuDh9oK/CopZG6lKwiX3XxBcTvWh6p988VELprgaK08cWg7qbLkhHmn8VOTOSOB0SHU8FWa+M4y6QhaszAbNYohAIEMKGn82InKOtmRZDJF5fBGICPXd3k1rrINtma4y92I7CRDJQUZUjolDItRvi152i3B41Y4FUL57l+xKn5w9/74/xamf8vKux2WR0gkjSQwFRcm35bruNPJchPAEh589q6XMtVoWB5oJ/keo0BGvz5hRzhwjCfb0Owv0+Ma5QtShOexCGXl76yHquHHnmNOEdIaz4ikKzdJYFC26E++AsgEbKVQAVNNrJmW0vhHqWybKFrCi16xJm2JEs6i4yEJEATQnJRFbfigs+Ey7HUFGxoITk5UJRCUjUtOI4dhc05VKdyj19r+XFq9b2j88Htv0f8V/vft2uN3MVlLPI/pIX9zdJq0H6HNgSfM+gC7CddPvG4Ce2S4oFEimpt/m5E24ZoidtT40PVxJEN4UruLCa/1HkkuMUgMnIylr6jOt+D085GZzoqNzP6VH3L4Y5WVZk4SAPCzsXbl4IwBYyq58eTjgz4+BqHzl7+4my5+R9Yi8xiwho8r5AK6fd+ys7yLKLDWhkpdQ0CYql6j5dz3HmW6gRwIkh/ViCr45KwFEtGz23VEhEBOq1V0wENPFOrQcyt8fRN2hNGZtoBFNo+mEUJ2Wc4TATmiBPt2dl7kPSETc29t9QPLB90IsflkjmMuZgPHB+Zeh6ndvV1zm6hiEO7gJZ4gag2P2hE1/6JBT1FG5eqX6xnh5OvaZKFqJtkhsxLmglFzoN7ZYgE/UlAq9YXDi5arYAvE5k9UBiQZwgJydLgec2DOMkHoiopbHt72lpuUQP6nI+mcVsezi1nATi2uIwNVf3MvphCOqzRubV05a003XkxqxX+nfYXWqYYQ4vB8DKVdXDu2cf9ZbH1MPJS7s947RZWMXRe+32kEYPBDR9yCHZteCvu0AWFSsgC6ORPNvM21qChKC09c8grixHJzcEZdHUP7xXnltyPIC5e/2mzTD1MUtKZ/UJE6j1ads2rWJl1bzSgnSUTL2SidSczWBDThiyemw79jOomjXQLyTpF9EZXDbbSBWKyWzhBynPcxhQci8ZZLWEJ3rOs08/VkXE4uZ4bIgkh5r7Ro2YGYHjjBzyXnbdlph8TajHmgRwMAyFPov04SjZBVgK/oIFN8J9cBZvFkZHfGfnr/VAIYvBr1xbnjk2J0nsMGVRlO5SwN5uX0z58wREOQmiHG2xKi2aUqh/OZ26DhOVWQaNhMmJxAQCbxs8jWK9IQoZsX9NjidNBtHmpnFhGT8DtDsZ3kQvNVlf0uzdC0cBJ3Rk/O03Cp27D2CSgXGN/gZ3vqh7k/MNS7rPmDHS6ZPa4Yrq6tlP++vv7z/sjigqz+AukMVnLSQiPDycwLVYGYTjADPpEvfihFX5nX0ktH0QnVC2XW0nfmUDDvWcYN6a0xJCyOZmm7bqF0Zvx6wvHXG8LxLL57EahiPXN/FDdbZSwOUE1izyzVug9sz1bY6EUNyorSYIIdeTRcb2qi7hzRTz+A10/8jvIXni5YwpI5nxz0ygY5U6ydYjekjQ2Cfthx+XLI/X48p9IMs7j3+DH/1iK2b0+a+0LCQf/oDxaS9l/fJVDyMVD19wT3niJpmNmtr8lkDIAL8WJCsKBW7Sdoe7zOwp4LbhQbK9ENRFxLiPoIenovZOec6QoXM5v0jl/qQsU2kGjXpI7ZeG8GEdJe7kG7X7Rr5hQ/ecNQOByNdd7GNxz2l/FDF6HL3TNc365LiGIlDuYxzGmPLQCCxg0ZOB5UydPz2rd63Kp76CLUtnWbDgRrgLzvLmG8/wW/u3AQAfvfFNEAif+/JLfPpdE1WaU6IXXRKbJkCq8GbxlsITIltLQoTYFyl1HcSwzlnUZb1vSBafJTMpGiw/IwEcZO0kZUOoZj6vViPAh+NfBdW1xOytegX0d+zUdTBjklBsz0mpM2PbJDU3niz+UPwb9jpGUSmfELGJE5fy4vUlYTSKynPGcwnuAlneeutNddL79PTQ8wE7G3opzTM5BwilDa/ZOLPIy960CrTSEU6voMmDW09OJymEZMH5iTdBziG4V0T7Ja+/xI7FH4yIZC1TppXgqzXvJ01ATdJKJnxHQ3+vA4O5iWLtlycmote5/SlA9bykIQRdDO6YLiHJ9KQ32ph3QLX0jO5v0qM+o04H3AmyHMeBV3vLdvj8+XOcz2c8Pp51YcveSEALVSc8laBg07ctA6eE9gnToqyQQp1pI4GAU7EsmbWaxc7nAwjA8XC8RVYpjcLxRMH0m4AEtzdzYkMYzx0SSzW1oo9fdrD9MwOVwHBClHVfSrClIkK8xyGL10280WOEGdfhdJkQbvJqnhphCIWL25Qe14H2aeItcQvcBbK8fPkSH/Tw2POLlzhqxSf/6ah9muNgStQJNOuTk8zgC+ZUbsm2NWIQUCV1eAeRK0LUrC4xa33uUz5HFxBm9rTnOCMiErqHg2TIxwbeNnjv5SlqcgUOv6jHXoeFFEYTCZFVJOvIUnPEYRanymiY0+9i3Nj/ngIDF2MlPIoVAlXnG6bW1XhfJEH9WU9wryDPUvAXLLgR7oKzfO/0hzj+zdVTR8b/SHkaxaYLZNvHwbPeDXS5v5sygy9aeL7HkpxOSnE0I+ZExFOWTpFainx+MfIuU3sveTBQQ0vtPSo8idnciToxO076m5Tn8CtvHCqHcGZ5ajoB/BhLLhSI+Iy2Gb9j5l8zE8NrExTpJ/XZZUoXl53EQIwxejPOQpAyXgN3gSzHHuVf1Qk8Hx/mjuMCo6ZMh+I5LH5XtiCY207/xU9IhG1rlidfbjuo8DQRHfoHvKinDD8NSS6qpFm2DrqHLOx5NKYaPyZ6TLA8qdjqRC/97ZBF2wzN2SHlRXfbAhxIDEXxNUpgHvkTmSP00hSyF+d1Fydm+V9CFPy4rhhO7gJZZkU4A21hYFh0ebkKkri2ytZMlyYjsxY3Mvyh0HQpGx4eHnC4HWFp19SkS1xt7Gf8VPJcVKyH8XPirMwxAlS8lMn0gpHKOy7hzmn/Q3+SEoyIQOlxey4jYiJu3NuL3ym2d0l74/GUzQlhvAeNu2ix3m6QydrROJ6oe13TWe4DWdySygxF7gAcZfOUXbmIcSczyLTFYtkmtcavtlVKTyEkzxJaFkefkXGgmvNRhBXERvsCXUsrJH8azv5N8GOR43L1o9pD7U8QwyZIEM6oBSvfZ4ue503EoRG1kuUTq5gvBz4TGHzbHBa6fOvx3QD1gDh5V0s7FfwAc9vMANUkWczabrAU/AULboT74Cxs3OQC0QAhik7c4zQ0nkO4hfMOFk9h3eAsfcBOTlXfMGVUOencpU4PhGroPbm/7ShnaJw9IzIHRarquSnxJfI6Qnguio8EKzPo1JPwztjNqDNgoMieh3ZpoGfTBIDTQ6txKbVoeD+7Un/WkezxQDpm15WJTx0IFqRXuJm3efZN8rj8hcus5S6QBTBZ8dIOa3BTYNMjPItvMqtHhAIqJxQY2+8vc8V7kguI2NrcIhv3KTIaxGf9z2G96bF9bC++6LF//3xG+gt8XybGBD9vEzHskq6ThcHBqJR1EUh5qbCiwZV1o3DHGaUUnB7asttOG/bzDpzPFkYAREIQjsex5XFoRLm4Bx1+buXb5u9qbV/b4b8bZPEL076n14INoepxoKJZurSUtOM8uk9XGTjOTq/p7QZkkR7Yu4p0IAjpnFBFLiTSFqxcl5d7lv+zITbu3s+eTjoSxg89bL9lHYa7nD/hkfm9BMfpnBRAw70y4nb16GZ3ANiOI1SBLqVVBthOJ83TfOx7D8mwvrP+CcNIw0/9J+59BiL72DBMoAAABudJREFU9ARWHruNSy+dZcGCG+FuOIun2ww0Hy9Kdzg5taCLXHq1cxRHhqJIIExFRK7RyqI/pU3HdThfdG9pV0ala8pVEiWcMf1m1IniXBBxwvUr5psLJtOZuP96GONnpoGIbo8rw34cwHEoFz09PKCcGqfZeuz8VjZUrlpnxkqTZ34uOoytgJA+y0sTdkdoR5jKtQ1wD3eDLJR+ZIk4mneN/6rIxYBJvQ5JvIwuTbCfHh50WfhrrkVRvs1VPd37Gm7uujoRX+wES1CZ25QMuo+IU65RXQj9xgJC7eKrF0NGH7gmLg6dTD1vBMx3U94vSkJDlGuGkXa/bSaeHx9BZ2pe3b32DJWCQptm4yzb1lI4ueoIYXnX/L6JeJ2pQ/qAkVxe7v9dIAvNPmKSxWnbdBi1122PKUbbkDPX8GItz6ieiv+O0vdVaPM9xY7ptBrjoBF/KCJMuF/Pc4vETNfCSMVp1FNb4cTacNPphqXUnUmtVa9jpFEojZGOezKtCmDo47joZtgpC7oh13E+q85C1Kowi15zOm2oPT+chJm3HNZSwfoyh5ZuqFzAcVzuhpvgTpDFH08UzUKgsqmZuNbEcgGEZahru01m5CNpZvKqdPdNNtZ7u5TOOARMHy85CGj/KCxEO8G2QhUIseYSkWy1+ZvyArefnG9zyD8PN+iTEta7E5TZn/NcO6JLaCuA9NVZIo++oKkZBDZFllPPiWZBbLXsxm00GQeShOC4ieO+mWOPcFkMWwr+ggU3wl1wFmDOUbyJsbJLqFddvt4pd7FW21keTweqGWyQGHIvJo9iZqOWQV3kkbJyyC7jOI6TqRvXGOncOLSoM4X3J253QRBt/zvZPUtX4dnMQINjp8yLnRuGEFhR6MVFaJvCjmPUA8d+bkaAhycAoKZmejyraCYbybYsRo7p1dd85RZJ7D6QJQnn3JWyzplxUHNq9I6NYwhPa4iQLUUXpsFW2aAv5QWU57f2Gwhx4YXHVLQysXC85t6Yk3AHfWIGgyAWX+LFsbRKZ46rQzNkYuioV10yUES9J4x32lfLW5nfIProXlsNzHKYY6vs1Tx5+hRHz3iz7zuO8w7zNiaASAPVAFkXRrxmtohrjhF3gSyhKA8sWZsloE6KO8F7PxhMuMT0fcgfm+LiSg1rZUbxMsiNzd7hF/yMa1wmw+7f2bl2r3kzsP3r1Qx2GOJe5ccnFjTyStRsLLkbk55dxtpZQwYzRMyPMzc9RnTWrW9klm0DUddtHgoKFezdleaovU5pgbo/CSE2qYRHenoFW5bOsmDBjXAfnIWlTkfP8igWEppQcgDB4hTiNRpXeZ38Ociul4hqdpP4LHCDw2PScizgSY1GwgEELohngUE0MS34KGI+1EEoE654kfl5C5gcyjebvMA3fKEvUmlglBjsGwg33vemq5wenuhmJkoByDLggACm0sRJHxLQyhG45kUP5PB7BneBLJXrmIbVKwSzD5BiJNxDw605S0rAlvQBvaYQJfA5BLk+qSGfBWYiXqMb7NQa6fMk+cJkLJzPDC7eHBbJZAsFwS7rFfdLCAVB76THkCNn/t6kT81jcGw9EFGLeJX9mVqgFRjQtxcOyaJ/aNuxJoz84f9HyOKjACHcxH0cHx/eDuRPQJZL4wyx5BlZpt+7l1e6rvpEURf9g2fFPf+a9dEN1SsDZjuIVisNzJpQ8gF5B2yyhtplnt80IMpkMtJjMy0r+8g4meBiTN2QN6YrHx6BclmOWivqfoSNS+jGpU+MHgkDMgJdgbtAlhApKblxySPChMOksQmqRYyhRJAEQa6xAL8IJxrtBZgt9uGegJj+g02S/DlECB6/kCFm6pxXLk0IQZxPTbqH7FGcxb7JWGYmRLKnfAW1S7H77XIBbScVp6iXPiRXSIqZcRyHbUp31xfuCAIAx7mJZspFek41dmtCj4NHs8zB65FlKfgLFtwId8FZABglyWKShwnVzibYIJkkWcqpirjMNYQKZVFkAlOlxisa+T5/0l8c0zEBUf8YXzw03h91yv9Ukcrz2oSnMfGd+0tA2BtSbmGiUMwK0zhG2bZu4m1ekdu2oZxO2LqX5HY6YdseQowLUS/PDi86AfvjGedXLwEALz/5Gc7HS+yPZ+yPrwCgcRU+nPJuCUwCN+dRF5WMmzqOC0A3JT5YsGDBEsMWLLgVFrIsWHAjLGRZsOBGWMiyYMGNsJBlwYIbYSHLggU3wkKWBQtuhIUsCxbcCAtZFiy4ERayLFhwIyxkWbDgRljIsmDBjbCQZcGCG2Ehy4IFN8JClgULboSFLAsW3AgLWRYsuBEWsixYcCMsZFmw4EZYyLJgwY2wkGXBghthIcuCBTfCQpYFC26E/wNUjv91vY/RhgAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img.show(y=learn.predict(img)[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next application is text, so let's start by importing everything we'll need." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from fastai.text import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Language modelling" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First let's look a how to get a language model ready for inference. Since we'll load the model trained in the [visualize data tutorial](/tutorial.data.html), we load the [`DataBunch`](/basic_data.html#DataBunch) used there." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "imdb = untar_data(URLs.IMDB_SAMPLE)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_lm = load_data(imdb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like in vision, we just have to type `learn.export()` after loading our pretrained model to save all the information inside the [`Learner`](/basic_train.html#Learner) we'll need. In this case, this includes all the vocabulary we created. The only difference is that we will specify a filename, since we have several model in the same path (language model and classifier)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = language_model_learner(data_lm, AWD_LSTM, pretrained=False).load('mini_train_lm', with_opt=False);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export(fname = 'export_lm.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's define our inference learner." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(imdb, fname = 'export_lm.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can predict with the usual method, here we can specify how many words we want the model to predict." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'This is a simple test of the new standards surrounding 1 / 10 performances on a lightweight road . This study contained other drives'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict('This is a simple test of', n_words=20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use beam search to generate text." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'This is a simple test of the quality of the English - language version of the English language . \\n \\n The English'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.beam_search('This is a simple test of', n_words=20, beam_sz=200)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classification" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's see a classification example. We have to use the same vocabulary as for the language model if we want to be able to use the encoder we saved." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_clas = (TextList.from_csv(imdb, 'texts.csv', cols='text', vocab=data_lm.vocab)\n", " .split_from_df(col='is_valid')\n", " .label_from_df(cols='label')\n", " .databunch(bs=42))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again we export the [`Learner`](/basic_train.html#Learner) where we load our pretrained model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = text_classifier_learner(data_clas, AWD_LSTM, pretrained=False).load('mini_train_clas', with_opt=False);\n", "learn.export(fname = 'export_clas.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's use [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(imdb, fname = 'export_clas.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can predict with the usual method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category negative, tensor(0), tensor([0.5082, 0.4918]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict('I really loved that movie!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tabular" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Last application brings us to tabular data. First let's import everything we'll need." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from fastai.tabular import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll use a sample of the [adult dataset](https://archive.ics.uci.edu/ml/datasets/adult) here. Once we read the csv file, we'll need to specify the dependant variable, the categorical variables, the continuous variables and the processors we want to use." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "adult = untar_data(URLs.ADULT_SAMPLE)\n", "df = pd.read_csv(adult/'adult.csv')\n", "dep_var = 'salary'\n", "cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country']\n", "cont_names = ['education-num', 'hours-per-week', 'age', 'capital-loss', 'fnlwgt', 'capital-gain']\n", "procs = [FillMissing, Categorify, Normalize]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can use the data block API to grab everything together." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (TabularList.from_df(df, path=adult, cat_names=cat_names, cont_names=cont_names, procs=procs)\n", " .split_by_idx(valid_idx=range(800,1000))\n", " .label_from_df(cols=dep_var)\n", " .databunch())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define a [`Learner`](/basic_train.html#Learner) object that we fit and then save the model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/html": [ "Total time: 00:04

\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
epochtrain_lossvalid_lossaccuracy
10.3283250.3675150.845000
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "learn = tabular_learner(data, layers=[200,100], metrics=accuracy)\n", "learn.fit(1, 1e-2)\n", "learn.save('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As in the other applications, we just have to type `learn.export()` to save everything we'll need for inference (here it includes the inner state of each processor)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we create a [`Learner`](/basic_train.html#Learner) for inference like before." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(adult)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can predict on a row of dataframe that has the right `cat_names` and `cont_names`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category >=50k, tensor(1), tensor([0.3528, 0.6472]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict(df.iloc[0])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "jekyll": { "keywords": "fastai", "summary": "Intermediate tutorial, explains how to create a Learner for inference", "title": "Inference Learner" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 2 }