diff --git a/Blogs/BorealisGradientFlow.ipynb b/Blogs/BorealisGradientFlow.ipynb new file mode 100644 index 0000000..483bd0e --- /dev/null +++ b/Blogs/BorealisGradientFlow.ipynb @@ -0,0 +1,401 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyP9fLqBQPgcYJB1KXs3Scp/", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Gradient flow\n", + "\n", + "This notebook replicates some of the results in the the Borealis AI [blog](https://www.borealisai.com/research-blogs/gradient-flow/) on gradient flow. \n" + ], + "metadata": { + "id": "ucrRRJ4dq8_d" + } + }, + { + "cell_type": "code", + "source": [ + "# Import relevant libraries\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import expm\n", + "from matplotlib import cm\n", + "from matplotlib.colors import ListedColormap" + ], + "metadata": { + "id": "_IQFHZEMZE8T" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Create the three data points that are used to train the linear model in the blog. Each input point is a column in $\\mathbf{X}$ and consists of the $x$ position in the plot and the value 1, which is used to allow the model to fit bias terms neatly." + ], + "metadata": { + "id": "NwgUP3MSriiJ" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cJNZ2VIcYsD8" + }, + "outputs": [], + "source": [ + "X = np.array([[0.2, 0.4, 0.8],[1,1,1]])\n", + "y = np.array([[-0.1],[0.15],[0.3]])\n", + "D = X.shape[0]\n", + "I = X.shape[1]\n", + "\n", + "print(\"X=\\n\",X)\n", + "print(\"y=\\n\",y)" + ] + }, + { + "cell_type": "code", + "source": [ + "# Draw the three data points\n", + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.show()" + ], + "metadata": { + "id": "FpFlD4nUZDRt" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Compute the evolution of the residuals, loss, and parameters as a function of time." + ], + "metadata": { + "id": "H2LBR1DasQej" + } + }, + { + "cell_type": "code", + "source": [ + "# Discretized time to evaluate quantities at\n", + "t_all = np.arange(0,20,0.01)\n", + "nT = t_all.shape[0]\n", + "\n", + "# Initial parameters, and initial function output at training points\n", + "phi_0 = np.array([[-0.05],[-0.4]])\n", + "f_0 = X.T @ phi_0\n", + "\n", + "# Precompute pseudoinverse term (not a very sensible numerical implementation, but it works...)\n", + "XXTInvX = np.linalg.inv(X@X.T)@X\n", + "\n", + "# Create arrays to hold function at data points over time, residual over time, parameters over time\n", + "f_all = np.zeros((I,nT))\n", + "f_minus_y_all = np.zeros((I,nT))\n", + "phi_t_all = np.zeros((D,nT))\n", + "\n", + "# For each time, compute function, residual, and parameters at each time.\n", + "for t in range(len(t_all)):\n", + " f = y + expm(-X.T@X * t_all[t]) @ (f_0-y)\n", + " f_all[:,t:t+1] = f\n", + " f_minus_y_all[:,t:t+1] = f-y\n", + " phi_t_all[:,t:t+1] = phi_0 - XXTInvX @ (np.identity(3)-expm(-X.T@X * t_all[t])) @ (f_0-y)" + ], + "metadata": { + "id": "wfF_oTS5Z4Wi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Plot the results that were calculated in the previous cell" + ], + "metadata": { + "id": "9jSjOOFutJUE" + } + }, + { + "cell_type": "code", + "source": [ + "# Plot function at data points\n", + "fig, ax = plt.subplots()\n", + "ax.plot(t_all,np.squeeze(f_all[0,:]),'r-', label='$f[x_{0},\\phi]$')\n", + "ax.plot(t_all,np.squeeze(f_all[1,:]),'g-', label='$f[x_{1},\\phi]$')\n", + "ax.plot(t_all,np.squeeze(f_all[2,:]),'b-', label='$f[x_{2},\\phi]$')\n", + "ax.set_xlim([0,np.max(t_all)]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('t'); ax.set_ylabel('f')\n", + "plt.legend(loc=\"lower right\")\n", + "plt.show()\n", + "\n", + "# Plot residual\n", + "fig, ax = plt.subplots()\n", + "ax.plot(t_all,np.squeeze(f_minus_y_all[0,:]),'r-', label='$f[x_{0},\\phi]-y_{0}$')\n", + "ax.plot(t_all,np.squeeze(f_minus_y_all[1,:]),'g-', label='$f[x_{1},\\phi]-y_{1}$')\n", + "ax.plot(t_all,np.squeeze(f_minus_y_all[2,:]),'b-', label='$f[x_{2},\\phi]-y_{2}$')\n", + "ax.set_xlim([0,np.max(t_all)]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('t'); ax.set_ylabel('f-y')\n", + "plt.legend(loc=\"lower right\")\n", + "plt.show()\n", + "\n", + "# Plot loss (sum of residuals)\n", + "fig, ax = plt.subplots()\n", + "square_error = 0.5 * np.sum(f_minus_y_all * f_minus_y_all, axis=0)\n", + "ax.plot(t_all, square_error,'k-')\n", + "ax.set_xlim([0,np.max(t_all)]); ax.set_ylim([-0.0,0.25])\n", + "ax.set_xlabel('t'); ax.set_ylabel('Loss')\n", + "plt.show()\n", + "\n", + "# Plot parameters\n", + "fig, ax = plt.subplots()\n", + "ax.plot(t_all, np.squeeze(phi_t_all[0,:]),'c-',label='$\\phi_{0}$')\n", + "ax.plot(t_all, np.squeeze(phi_t_all[1,:]),'m-',label='$\\phi_{1}$')\n", + "ax.set_xlim([0,np.max(t_all)]); ax.set_ylim([-1,1])\n", + "ax.set_xlabel('t'); ax.set_ylabel('$\\phi$')\n", + "plt.legend(loc=\"lower right\")\n", + "plt.show()" + ], + "metadata": { + "id": "G9IwgwKltHz5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the model and the loss function" + ], + "metadata": { + "id": "N6VaUq2swa8D" + } + }, + { + "cell_type": "code", + "source": [ + "# Model is just a straight line with intercept phi[0] and slope phi[1]\n", + "def model(phi,x):\n", + " y_pred = phi[0]+phi[1] * x\n", + " return y_pred\n", + "\n", + "# Loss function is 0.5 times sum of squares of residuals for training data\n", + "def compute_loss(data_x, data_y, model, phi):\n", + " pred_y = model(phi, data_x)\n", + " loss = 0.5 * np.sum((pred_y-data_y)*(pred_y-data_y))\n", + " return loss" + ], + "metadata": { + "id": "LGHEVUWWiB4f" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Draw the loss function" + ], + "metadata": { + "id": "hr3hs7pKwo0g" + } + }, + { + "cell_type": "code", + "source": [ + "def draw_loss_function(compute_loss, X, y, model, phi_iters):\n", + " # Define pretty colormap\n", + " my_colormap_vals_hex =('2a0902', '2b0a03', '2c0b04', '2d0c05', '2e0c06', '2f0d07', '300d08', '310e09', '320f0a', '330f0b', '34100b', '35110c', '36110d', '37120e', '38120f', '39130f', '3a1410', '3b1411', '3c1511', '3d1612', '3e1613', '3f1713', '401714', '411814', '421915', '431915', '451a16', '461b16', '471b17', '481c17', '491d18', '4a1d18', '4b1e19', '4c1f19', '4d1f1a', '4e201b', '50211b', '51211c', '52221c', '53231d', '54231d', '55241e', '56251e', '57261f', '58261f', '592720', '5b2821', '5c2821', '5d2922', '5e2a22', '5f2b23', '602b23', '612c24', '622d25', '632e25', '652e26', '662f26', '673027', '683027', '693128', '6a3229', '6b3329', '6c342a', '6d342a', '6f352b', '70362c', '71372c', '72372d', '73382e', '74392e', '753a2f', '763a2f', '773b30', '783c31', '7a3d31', '7b3e32', '7c3e33', '7d3f33', '7e4034', '7f4134', '804235', '814236', '824336', '834437', '854538', '864638', '874739', '88473a', '89483a', '8a493b', '8b4a3c', '8c4b3c', '8d4c3d', '8e4c3e', '8f4d3f', '904e3f', '924f40', '935041', '945141', '955242', '965343', '975343', '985444', '995545', '9a5646', '9b5746', '9c5847', '9d5948', '9e5a49', '9f5a49', 'a05b4a', 'a15c4b', 'a35d4b', 'a45e4c', 'a55f4d', 'a6604e', 'a7614e', 'a8624f', 'a96350', 'aa6451', 'ab6552', 'ac6552', 'ad6653', 'ae6754', 'af6855', 'b06955', 'b16a56', 'b26b57', 'b36c58', 'b46d59', 'b56e59', 'b66f5a', 'b7705b', 'b8715c', 'b9725d', 'ba735d', 'bb745e', 'bc755f', 'bd7660', 'be7761', 'bf7862', 'c07962', 'c17a63', 'c27b64', 'c27c65', 'c37d66', 'c47e67', 'c57f68', 'c68068', 'c78169', 'c8826a', 'c9836b', 'ca846c', 'cb856d', 'cc866e', 'cd876f', 'ce886f', 'ce8970', 'cf8a71', 'd08b72', 'd18c73', 'd28d74', 'd38e75', 'd48f76', 'd59077', 'd59178', 'd69279', 'd7937a', 'd8957b', 'd9967b', 'da977c', 'da987d', 'db997e', 'dc9a7f', 'dd9b80', 'de9c81', 'de9d82', 'df9e83', 'e09f84', 'e1a185', 'e2a286', 'e2a387', 'e3a488', 'e4a589', 'e5a68a', 'e5a78b', 'e6a88c', 'e7aa8d', 'e7ab8e', 'e8ac8f', 'e9ad90', 'eaae91', 'eaaf92', 'ebb093', 'ecb295', 'ecb396', 'edb497', 'eeb598', 'eeb699', 'efb79a', 'efb99b', 'f0ba9c', 'f1bb9d', 'f1bc9e', 'f2bd9f', 'f2bfa1', 'f3c0a2', 'f3c1a3', 'f4c2a4', 'f5c3a5', 'f5c5a6', 'f6c6a7', 'f6c7a8', 'f7c8aa', 'f7c9ab', 'f8cbac', 'f8ccad', 'f8cdae', 'f9ceb0', 'f9d0b1', 'fad1b2', 'fad2b3', 'fbd3b4', 'fbd5b6', 'fbd6b7', 'fcd7b8', 'fcd8b9', 'fcdaba', 'fddbbc', 'fddcbd', 'fddebe', 'fddfbf', 'fee0c1', 'fee1c2', 'fee3c3', 'fee4c5', 'ffe5c6', 'ffe7c7', 'ffe8c9', 'ffe9ca', 'ffebcb', 'ffeccd', 'ffedce', 'ffefcf', 'fff0d1', 'fff2d2', 'fff3d3', 'fff4d5', 'fff6d6', 'fff7d8', 'fff8d9', 'fffada', 'fffbdc', 'fffcdd', 'fffedf', 'ffffe0')\n", + " my_colormap_vals_dec = np.array([int(element,base=16) for element in my_colormap_vals_hex])\n", + " r = np.floor(my_colormap_vals_dec/(256*256))\n", + " g = np.floor((my_colormap_vals_dec - r *256 *256)/256)\n", + " b = np.floor(my_colormap_vals_dec - r * 256 *256 - g * 256)\n", + " my_colormap = ListedColormap(np.vstack((r,g,b)).transpose()/255.0)\n", + "\n", + " # Make grid of intercept/slope values to plot\n", + " intercepts_mesh, slopes_mesh = np.meshgrid(np.arange(-1.0,1.0,0.005), np.arange(-1.0,1.0,0.005))\n", + " loss_mesh = np.zeros_like(slopes_mesh)\n", + " # Compute loss for every set of parameters\n", + " for idslope, slope in np.ndenumerate(slopes_mesh):\n", + " loss_mesh[idslope] = compute_loss(X, y, model, np.array([[intercepts_mesh[idslope]], [slope]]))\n", + "\n", + " fig,ax = plt.subplots()\n", + " fig.set_size_inches(8,8)\n", + " ax.contourf(intercepts_mesh,slopes_mesh,loss_mesh,256,cmap=my_colormap)\n", + " ax.contour(intercepts_mesh,slopes_mesh,loss_mesh,40,colors=['#80808080'])\n", + " ax.set_ylim([1,-1]); ax.set_xlim([-1,1])\n", + "\n", + " ax.plot(phi_iters[1,:], phi_iters[0,:],'g-')\n", + " ax.set_xlabel('Intercept'); ax.set_ylabel('Slope')\n", + " plt.show()" + ], + "metadata": { + "id": "UCxa3tZ8a9kz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "draw_loss_function(compute_loss, X[0:1,:], y.T, model, phi_t_all)" + ], + "metadata": { + "id": "pXLLBaSaiI2A" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Draw the evolution of the function" + ], + "metadata": { + "id": "ZsremHW-xFi5" + } + }, + { + "cell_type": "code", + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "x_vals = np.arange(0,1,0.001)\n", + "ax.plot(x_vals, phi_t_all[0,0]*x_vals + phi_t_all[1,0],'r-', label='t=0.00')\n", + "ax.plot(x_vals, phi_t_all[0,10]*x_vals + phi_t_all[1,10],'g-', label='t=0.10')\n", + "ax.plot(x_vals, phi_t_all[0,30]*x_vals + phi_t_all[1,30],'b-', label='t=0.30')\n", + "ax.plot(x_vals, phi_t_all[0,200]*x_vals + phi_t_all[1,200],'c-', label='t=2.00')\n", + "ax.plot(x_vals, phi_t_all[0,1999]*x_vals + phi_t_all[1,1999],'y-', label='t=20.0')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.legend(loc=\"upper left\")\n", + "plt.show()" + ], + "metadata": { + "id": "cv9ZrUoRkuhI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Compute MAP and ML solutions\n", + "MLParams = np.linalg.inv(X@X.T)@X@y\n", + "sigma_sq_p = 3.0\n", + "sigma_sq = 0.05\n", + "MAPParams = np.linalg.inv(X@X.T+np.identity(X.shape[0])*sigma_sq/sigma_sq_p)@X@y" + ], + "metadata": { + "id": "OU9oegSOof-o" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Finally, we predict both the mean and the uncertainty in the fitted model as a function of time" + ], + "metadata": { + "id": "Ul__XvOgyYSA" + } + }, + { + "cell_type": "code", + "source": [ + "# Define x positions to make predictions (appending a 1 to each column)\n", + "x_predict = np.arange(0,1,0.01)[None,:]\n", + "x_predict = np.concatenate((x_predict,np.ones_like(x_predict)))\n", + "nX = x_predict.shape[1]\n", + "\n", + "# Create variables to store evolution of mean and variance of prediction over time\n", + "predict_mean_all = np.zeros((nT,nX))\n", + "predict_var_all = np.zeros((nT,nX))\n", + "\n", + "# Initial covariance\n", + "sigma_sq_p = 2.0\n", + "cov_init = sigma_sq_p * np.identity(2)\n", + "\n", + "# Run through each time computing a and b and hence mean and variance of prediction\n", + "for t in range(len(t_all)):\n", + " a = x_predict.T @(XXTInvX @ (np.identity(3)-expm(-X.T@X * t_all[t])) @ y)\n", + " b = x_predict.T -x_predict.T@XXTInvX @ (np.identity(3)-expm(-X.T@X * t_all[t])) @ X.T\n", + " predict_mean_all[t:t+1,:] = a.T\n", + " predict_cov = b@ cov_init @b.T\n", + " # We just want the diagonal of the covariance to plot the uncertainty\n", + " predict_var_all[t:t+1,:] = np.reshape(np.diag(predict_cov),(1,nX))" + ], + "metadata": { + "id": "aMPADCuByKWr" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Plot the mean and variance at various times" + ], + "metadata": { + "id": "PZTj93KK7QH6" + } + }, + { + "cell_type": "code", + "source": [ + "def plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t, sigma_sq = 0.00001):\n", + " fig, ax = plt.subplots()\n", + " ax.plot(X[0:1,:],y.T,'ro')\n", + " ax.plot(x_predict[0:1,:].T, predict_mean_all[this_t:this_t+1,:].T,'r-')\n", + " lower = np.squeeze(predict_mean_all[this_t:this_t+1,:].T-np.sqrt(predict_var_all[this_t:this_t+1,:].T+np.sqrt(sigma_sq)))\n", + " upper = np.squeeze(predict_mean_all[this_t:this_t+1,:].T+np.sqrt(predict_var_all[this_t:this_t+1,:].T+np.sqrt(sigma_sq)))\n", + " ax.fill_between(np.squeeze(x_predict[0:1,:]), lower, upper, color='lightgray')\n", + " ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + " ax.set_xlabel('x'); ax.set_ylabel('y')\n", + " plt.show()\n", + "\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=0)\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=40)\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=80)\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=200)\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=500)\n", + "plot_mean_var(X,y,x_predict, predict_mean_all, predict_var_all, this_t=1000)" + ], + "metadata": { + "id": "bYAFxgB880-v" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/Blogs/BorealisNTK.ipynb b/Blogs/BorealisNTK.ipynb new file mode 100644 index 0000000..d2062a8 --- /dev/null +++ b/Blogs/BorealisNTK.ipynb @@ -0,0 +1,1109 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Neural tangent kernel\n", + "\n", + "This blog contains code that accompanies the Borealis AI blog on the Neural Tangent Kernel." + ], + "metadata": { + "id": "Ao-2MW3o_SFN" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "_IQFHZEMZE8T" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.linalg import expm\n", + "from matplotlib import cm\n", + "from matplotlib.colors import ListedColormap" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Create some data and draw it." + ], + "metadata": { + "id": "1RYf0uIwA98m" + } + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "cJNZ2VIcYsD8" + }, + "outputs": [], + "source": [ + "# Input is one dimensional but has ones appended to incorporate biases\n", + "X = np.array([[0.2, 0.4, 0.8],[1,1,1]])\n", + "y = np.array([[-0.05],[-0.2],[0.3]])\n", + "\n", + "D_in = X.shape[0] # No of input dimensions (2)\n", + "I = X.shape[1] # No of data points (3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "FpFlD4nUZDRt", + "outputId": "b0cd7f72-4f63-4e19-ab3c-b6b274bbbad1" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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Q3HDDTckPWdDQ0OUlpZGfX19lJSUnNb8AEDnOBOv393mStPhw4djw4YNUV1d3bIvPz8/qqurY926dUmPcfDgwThy5Eice+65J1xz6NChaGhoaLUBAHSbaNq3b180NjbGoEGDWu0fNGhQ1NXVJT3GN77xjRg8eHCr8Ppd8+fPj9LS0patsrLytOYGAHqGbhNNp2vBggWxZMmSePrpp6O4uPiE6+bOnRv19fUtW21tbSdOCQB0VX1yPUCq/v37R0FBQezZs6fV/j179kR5eflJj124cGEsWLAgnnvuufj4xz9+0rVFRUVRVFR02vMCAD1Lt7nSVFhYGKNHj47Vq1e37GtqaorVq1fHuHHjTnjcfffdF/fcc0+sXLkyxowZ0xmjAgA9ULe50hQRMXv27JgxY0aMGTMmxo4dGzU1NXHgwIG46aabIiLihhtuiCFDhsT8+fMjIuLv//7v484774wf/vCHMWzYsJbPPp1zzjlxzjnn5Oz7AAC6n24VTVOnTo1333037rzzzqirq4tRo0bFypUrWz4cvmPHjsjP/83Fs4cffjgOHz4c1157bavHmTdvXtx1112dOToA0M11q/s05YL7NAFA99Or79MEAJBLogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBI0O2iadGiRTFs2LAoLi6OqqqqWL9+/UnXP/XUUzFixIgoLi6OkSNHxooVKzppUgCgJ+lW0fTkk0/G7NmzY968ebFx48a49NJLY8KECbF3797jrn/55Zfjuuuui5kzZ8amTZti8uTJMXny5Pj5z3/eyZMDAN1dXpZlWVsOmDFjRsycOTP+8A//8EzNdEJVVVXx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OY2mAQMGxIABA065bty4cfH+++/Hhg0bYvTo0RER8fzzz0dTU1NUVVWd8LiGhoaYMGFCFBUVxbPPPhvFxcUdNjv0KgUFEd/9bvNvyeXltQ6nvLzm/9bU+BA40KN1i880XXTRRXHVVVfFzTffHOvXr4+XXnopbr311vjiF7/Y8ptzO3fujBEjRsT69esjojmYPvOZz8SBAwfisccei4aGhqirq4u6urpobGzM5bcD3dOUKRFLl0YMGdJ6/9ChzfunTMnNXACdpNvcEfyJJ56IW2+9Na688srIz8+Pz3/+8/EP//APLV8/cuRIbNu2LQ4ePBgRERs3bmz5zboLLrig1WNt3749hg0b1mmzQ48xZUrEpEnuCA70St3iPk255D5NAND99Nr7NAEA5JpoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABJ0m2h67733Ytq0aVFSUhJlZWUxc+bM+NWvfpV0bJZl8dnPfjby8vLimWeeObODAgA9UreJpmnTpsVrr70Wq1atiuXLl8cLL7wQt9xyS9KxNTU1kZeXd4YnBAB6sj65HiDF1q1bY+XKlfHqq6/GmDFjIiLiwQcfjIkTJ8bChQtj8ODBJzx28+bN8Z3vfCd++tOfRkVFRWeNDAD0MN3iStO6deuirKysJZgiIqqrqyM/Pz9eeeWVEx538ODBuP7662PRokVRXl6e9FyHDh2KhoaGVhsAQLeIprq6uhg4cGCrfX369Ilzzz036urqTnjc7bffHpdddllMmjQp+bnmz58fpaWlLVtlZWW75wYAeo6cRtOcOXMiLy/vpNsbb7zRrsd+9tln4/nnn4+ampo2HTd37tyor69v2Wpra9v1/ABAz5LTzzR97WtfixtvvPGka4YPHx7l5eWxd+/eVvuPHj0a77333gnfdnv++efjzTffjLKyslb7P//5z8f48eNjzZo1xz2uqKgoioqKUr8FAKCXyGk0DRgwIAYMGHDKdePGjYv3338/NmzYEKNHj46I5ihqamqKqqqq4x4zZ86c+NKXvtRq38iRI+OBBx6Ia6655vSHBwB6lW7x23MXXXRRXHXVVXHzzTfHI488EkeOHIlbb701vvjFL7b85tzOnTvjyiuvjH/5l3+JsWPHRnl5+XGvQp133nnxe7/3e539LQAA3Vy3+CB4RMQTTzwRI0aMiCuvvDImTpwYn/rUp+LRRx9t+fqRI0di27ZtcfDgwRxOCQD0VHlZlmW5HqIra2hoiNLS0qivr4+SkpJcjwMAJDgTr9/d5koTAEAuiSYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEvTJ9QBdXZZlERHR0NCQ40kAgFTHXrePvY53BNF0Cr/85S8jIqKysjLHkwAAbfXLX/4ySktLO+SxRNMpnHvuuRERsWPHjg77S6d9GhoaorKyMmpra6OkpCTX4/RqzkXX4Vx0Lc5H11FfXx/nnXdey+t4RxBNp5Cf3/yxr9LSUj8AXURJSYlz0UU4F12Hc9G1OB9dx7HX8Q55rA57JACAHkw0AQAkEE2nUFRUFPPmzYuioqJcj9LrORddh3PRdTgXXYvz0XWciXORl3Xk7+IBAPRQrjQBACQQTQAACUQTAEAC0QQAkEA0RcSiRYti2LBhUVxcHFVVVbF+/fqTrn/qqadixIgRUVxcHCNHjowVK1Z00qQ9X1vOxeLFi2P8+PHRr1+/6NevX1RXV5/y3JGurT8XxyxZsiTy8vJi8uTJZ3bAXqSt5+L999+PWbNmRUVFRRQVFcVHP/pR/5/qIG09FzU1NXHhhRfG2WefHZWVlXH77bfH//3f/3XStD3XCy+8ENdcc00MHjw48vLy4plnnjnlMWvWrInf//3fj6Kiorjgggvi8ccfb/sTZ73ckiVLssLCwux73/te9tprr2U333xzVlZWlu3Zs+e461966aWsoKAgu++++7LXX389+9a3vpWdddZZ2ZYtWzp58p6nrefi+uuvzxYtWpRt2rQp27p1a3bjjTdmpaWl2TvvvNPJk/c8bT0Xx2zfvj0bMmRINn78+GzSpEmdM2wP19ZzcejQoWzMmDHZxIkTsxdffDHbvn17tmbNmmzz5s2dPHnP09Zz8cQTT2RFRUXZE088kW3fvj3793//96yioiK7/fbbO3nynmfFihXZHXfckS1btiyLiOzpp58+6fq33nor+9CHPpTNnj07e/3117MHH3wwKygoyFauXNmm5+310TR27Nhs1qxZLX9ubGzMBg8enM2fP/+467/whS9kV199dat9VVVV2Z/92Z+d0Tl7g7aei9919OjRrG/fvtn3v//9MzVir9Gec3H06NHssssuy/7pn/4pmzFjhmjqIG09Fw8//HA2fPjw7PDhw501Yq/R1nMxa9as7I/+6I9a7Zs9e3b2yU9+8ozO2dukRNNf//VfZx/72Mda7Zs6dWo2YcKENj1Xr3577vDhw7Fhw4aorq5u2Zefnx/V1dWxbt264x6zbt26VusjIiZMmHDC9aRpz7n4XQcPHowjR4506D/O2Bu191zcfffdMXDgwJg5c2ZnjNkrtOdcPPvsszFu3LiYNWtWDBo0KC655JK49957o7GxsbPG7pHacy4uu+yy2LBhQ8tbeG+99VasWLEiJk6c2Ckz8xsd9drdq//B3n379kVjY2MMGjSo1f5BgwbFG2+8cdxj6urqjru+rq7ujM3ZG7TnXPyub3zjGzF48OAP/GDQNu05Fy+++GI89thjsXnz5k6YsPdoz7l466234vnnn49p06bFihUr4he/+EV8+ctfjiNHjsS8efM6Y+weqT3n4vrrr499+/bFpz71qciyLI4ePRp//ud/Ht/85jc7Y2R+y4leuxsaGuLXv/51nH322UmP06uvNNFzLFiwIJYsWRJPP/10FBcX53qcXmX//v0xffr0WLx4cfTv3z/X4/R6TU1NMXDgwHj00Udj9OjRMXXq1LjjjjvikUceyfVovc6aNWvi3nvvjX/8x3+MjRs3xrJly+LHP/5x3HPPPbkejXbq1Vea+vfvHwUFBbFnz55W+/fs2RPl5eXHPaa8vLxN60nTnnNxzMKFC2PBggXx3HPPxcc//vEzOWav0NZz8eabb8bbb78d11xzTcu+pqamiIjo06dPbNu2Lc4///wzO3QP1Z6fi4qKijjrrLOioKCgZd9FF10UdXV1cfjw4SgsLDyjM/dU7TkXf/M3fxPTp0+PL33pSxERMXLkyDhw4EDccsstcccdd0R+vusWneVEr90lJSXJV5kievmVpsLCwhg9enSsXr26ZV9TU1OsXr06xo0bd9xjxo0b12p9RMSqVatOuJ407TkXERH33Xdf3HPPPbFy5coYM2ZMZ4za47X1XIwYMSK2bNkSmzdvbtk+97nPxRVXXBGbN2+OysrKzhy/R2nPz8UnP/nJ+MUvftESrhER//Vf/xUVFRWC6TS051wcPHjwA2F0LGYz/+xrp+qw1+62fUa951myZElWVFSUPf7449nrr7+e3XLLLVlZWVlWV1eXZVmWTZ8+PZszZ07L+pdeeinr06dPtnDhwmzr1q3ZvHnz3HKgg7T1XCxYsCArLCzMli5dmu3evbtl279/f66+hR6jrefid/ntuY7T1nOxY8eOrG/fvtmtt96abdu2LVu+fHk2cODA7O/+7u9y9S30GG09F/Pmzcv69u2b/eu//mv21ltvZf/xH/+RnX/++dkXvvCFXH0LPcb+/fuzTZs2ZZs2bcoiIrv//vuzTZs2Zf/zP/+TZVmWzZkzJ5s+fXrL+mO3HPj617+ebd26NVu0aJFbDrTXgw8+mJ133nlZYWFhNnbs2Ow///M/W752+eWXZzNmzGi1/kc/+lH20Y9+NCssLMw+9rGPZT/+8Y87eeKeqy3n4sMf/nAWER/Y5s2b1/mD90Bt/bn4baKpY7X1XLz88stZVVVVVlRUlA0fPjz79re/nR09erSTp+6Z2nIujhw5kt11113Z+eefnxUXF2eVlZXZl7/85ex///d/O3/wHuYnP/nJcf//f+zvf8aMGdnll1/+gWNGjRqVFRYWZsOHD8/++Z//uc3Pm5dlrhECAJxKr/5MEwBAKtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE1Ar/Luu+9GeXl53HvvvS37Xn755SgsLIzVq1fncDKgq/MP9gK9zooVK2Ly5Mnx8ssvx4UXXhijRo2KSZMmxf3335/r0YAuTDQBvdKsWbPiueeeizFjxsSWLVvi1VdfjaKiolyPBXRhognolX7961/HJZdcErW1tbFhw4YYOXJkrkcCujifaQJ6pTfffDN27doVTU1N8fbbb+d6HKAbcKUJ6HUOHz4cY8eOjVGjRsWFF14YNTU1sWXLlhg4cGCuRwO6MNEE9Dpf//rXY+nSpfGzn/0szjnnnLj88sujtLQ0li9fnuvRgC7M23NAr7JmzZqoqamJH/zgB1FSUhL5+fnxgx/8INauXRsPP/xwrscDujBXmgAAErjSBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJ/h99wnKhwwfyUAAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Support routines to run shallow network and compute derivative of neural network output with respect to network parameters." + ], + "metadata": { + "id": "QpM2sQA2DN9t" + } + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "_D4tHA_cfc7Y" + }, + "outputs": [], + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation\n", + "\n", + "# Derivative of ReLU\n", + "def ReLUDeriv(z):\n", + " return (z>0).astype(int)\n", + "\n", + "# Shallow network function\n", + "def shallow_network(X, omega0, omega1, beta1):\n", + " preactivations = omega0 @ X\n", + " activations = ReLU(preactivations)\n", + " output = beta1 + omega1 @ activations / np.sqrt(omega1.size)\n", + " return output\n", + "\n", + "# Sum of squares loss\n", + "def loss(network_output, y):\n", + " return 0.5 * np.sum((network_output-y) * (network_output-y))" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Initialize the parameters according to a normal distribution" + ], + "metadata": { + "id": "F6yRB4wrEnR-" + } + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "zkYRfFGEOhpu" + }, + "outputs": [], + "source": [ + "def initialize_parameters(D, seed=10, D_in = 2):\n", + " # Set the seed so we always get the same numbers\n", + " np.random.seed(seed)\n", + "\n", + " # Set weights in first layer according to random normal distribution\n", + " # But set last component (which computes biases) to zero\n", + " omega0 = np.random.normal(size=(D, D_in))\n", + " omega0[1,:] = 0\n", + " # Set weights in second layer according to random normal distribution\n", + " omega1 = np.random.normal(size=(1,D))\n", + " # Set bias to zero\n", + " beta1 = 0\n", + "\n", + " return omega0, omega1, beta1" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Routines to calculate the empirical and analytical NTK (i.e. the NTK with infinite hidden units) for the the shallow network" + ], + "metadata": { + "id": "mxW8E5kYIzlj" + } + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "fCNhfedhjLUA" + }, + "outputs": [], + "source": [ + "# Compute the empirical NTK for the shallow network\n", + "def compute_empirical_ntk(X1,X2, omega0, omega1, beta1):\n", + "\n", + " I1 = X1.shape[1]\n", + " I2 = X2.shape[1]\n", + " K = np.zeros((I1,I2))\n", + " preactivations1 = omega0 @ X1\n", + " preactivations2 = omega0 @ X2\n", + "\n", + " for i in range(I1):\n", + " for j in range(I2):\n", + " K[i,j] = np.mean(ReLU(preactivations1[:,i]) * ReLU(preactivations2[:,j])) + 1\n", + " K[i,j] = K[i,j] + X1[:,i] @ X2[:,j].T * np.mean(omega1 * omega1 * ReLUDeriv(preactivations1[:,i]) * ReLUDeriv(preactivations2[:,j]))\n", + " return K\n", + "\n", + "# Compute theoretical NTK for the shallow network\n", + "def compute_analytical_ntk(X1, X2):\n", + " I1 = X1.shape[1]\n", + " I2 = X2.shape[1]\n", + " K = np.zeros((I1,I2))\n", + "\n", + " for i in range(I1):\n", + " for j in range(I2):\n", + " x1 = X1[:,i]\n", + " x2 = X2[:,j]\n", + " norm1 = np.sqrt(x1.T@x1)\n", + " norm2 = np.sqrt(x2.T@x2)\n", + " if norm1==0 or norm2 ==0:\n", + " theta = 0\n", + " else:\n", + " theta = np.arccos(x1.T@x2/(norm1*norm2))\n", + " K[i,j] = x1.T@x2 * (np.pi-theta)/(2*np.pi)\n", + " K[i,j] = K[i,j] + norm1 * norm2 * ((np.pi-theta)*np.cos(theta)+np.sin(theta))/(2*np.pi) + 1\n", + " return K" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Compute empirical and analytical NTK for wide network with 10,000 hidden units and show they are almost the same" + ], + "metadata": { + "id": "WnxLPbWxLfK2" + } + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JKRtshxljG5y", + "outputId": "e441f49f-1911-40b8-a0b8-47673859b7b7" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Empirical NTK\n", + " [[2.03861529 2.05165862 2.08784793]\n", + " [2.05165862 2.1637655 2.26898074]\n", + " [2.08784793 2.26898074 2.64798733]]\n", + "\n", + "Analytical NTK\n", + " [[2.04 2.04888213 2.07923821]\n", + " [2.04888213 2.16 2.26003372]\n", + " [2.07923821 2.26003372 2.64 ]]\n" + ] + } + ], + "source": [ + "# Number of hidden units\n", + "D = 10000\n", + "# Random seed for initialized parameters\n", + "seed = 18\n", + "# Number of input dimension (2 as have appended a 1 to incorporate first layer biases)\n", + "D_in = 2\n", + "\n", + "# Initialize the parameters\n", + "omega0, omega1, beta1 = initialize_parameters(D, seed = seed, D_in=D_in)\n", + "\n", + "# Compute empirical and analytical NTKs\n", + "# When D is large, they should be similar\n", + "K = compute_empirical_ntk(X, X, omega0, omega1, beta1)\n", + "print(\"Empirical NTK\\n\", K)\n", + "K_analytical = compute_analytical_ntk(X,X)\n", + "print(\"\\nAnalytical NTK\\n\", K_analytical)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Compute Jacobian containing derivatives of network output with respect to network parameters for each input" + ], + "metadata": { + "id": "FEUz7p4vL1hZ" + } + }, + { + "cell_type": "code", + "source": [ + "# Get vector of derivatives of network output with respect to parameters\n", + "# omega0, omega1, beta1\n", + "# There are no offsets beta0 as they are incorporated by concatenating ones to each input\n", + "def derivative_vector(x,omega0, omega1, beta1):\n", + " preactivations = omega0 @ x\n", + " activations = ReLU(preactivations)\n", + " D = omega1.size\n", + "\n", + " dfdomega0 = ( np.ones((omega0.size,1)) @ ReLUDeriv(activations).T ) * np.concatenate((np.identity(D) * x[0,:],np.identity(D) * x[1,:]),axis=0) @ omega1.T / np.sqrt(D)\n", + " dfdbeta1 = np.ones((1,1))\n", + " dfdomega1 = activations / np.sqrt(D)\n", + "\n", + " return np.concatenate((dfdomega0, dfdbeta1, dfdomega1), axis=0)\n", + "\n", + "# Compute Jacobian of how network outputs change for each point given change in parameters\n", + "def get_jacobian(X, omega0, omega1, beta1):\n", + " n_param = omega0.size+omega1.size+1\n", + " n_data = X.shape[1]\n", + " jacobian = np.zeros((n_param, n_data))\n", + " for i in range (n_data):\n", + " jacobian[:,i:i+1] = derivative_vector(X[:,i:i+1], omega0, omega1, beta1)\n", + " return jacobian" + ], + "metadata": { + "id": "eVAHtfx6L0fg" + }, + "execution_count": 8, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Confirm that emprical NTK is just the product of the Jacobians" + ], + "metadata": { + "id": "vlIfcHabNnhw" + } + }, + { + "cell_type": "code", + "source": [ + "K = compute_empirical_ntk(X, X, omega0, omega1, beta1)\n", + "print(\"Empirical NTK\\n\", K)\n", + "K_from_jacobian = get_jacobian(X, omega0, omega1, beta1).T @ get_jacobian(X, omega0, omega1, beta1)\n", + "print(\"NTK from Jacobian\\n\", K_from_jacobian)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zml0O_LFNT5G", + "outputId": "bab5ab7a-68c2-4eaa-a6fc-90870a3cb016" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Empirical NTK\n", + " [[2.03861529 2.05165862 2.08784793]\n", + " [2.05165862 2.1637655 2.26898074]\n", + " [2.08784793 2.26898074 2.64798733]]\n", + "NTK from Jacobian\n", + " [[2.03861529 2.05165862 2.08784793]\n", + " [2.05165862 2.1637655 2.26898074]\n", + " [2.08784793 2.26898074 2.64798733]]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Compute prediction at training points, residuals, and parameters as a function of time during training process" + ], + "metadata": { + "id": "R5FdFM9WW3kj" + } + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "92qsV0-XeYzZ" + }, + "outputs": [], + "source": [ + "# Define time steps and count them\n", + "t_all = np.arange(0,100,0.05)\n", + "nT = t_all.shape[0]\n", + "# Create array for predictions at training data points as a function of time\n", + "f_all = np.zeros((I,nT))\n", + "# Create array for residuals at training data points as a function of time\n", + "residuals_all = np.zeros((I,nT))\n", + "# Create array for 3D+1 parameters as a function of time\n", + "phi_t_all = np.zeros((3*D+1,nT))\n", + "\n", + "# Precompute the Moore Penrose inverse\n", + "moore_penrose_inverse = get_jacobian(X, omega0, omega1, beta1) @ (np.linalg.inv(K))\n", + "# Store the initial vectors in a vector\n", + "phi_0 = np.concatenate((omega0[:,0:1],omega0[:,1:2],np.ones((1,1))*beta1,omega1.T))\n", + "# Compute initial network outputs at training points\n", + "f_0 = shallow_network(X, omega0, omega1, beta1).T\n", + "\n", + "# For each time step\n", + "for t in range(len(t_all)):\n", + " # Compute prediction at data points\n", + " f_all[:,t:t+1] = y + expm(-K * t_all[t]) @ (f_0-y)\n", + " # Compute residuals at data points\n", + " residuals_all[:,t:t+1] = f_all[:,t:t+1]-y\n", + " # Compute parameter vector\n", + " phi_t_all[:,t:t+1] = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * t_all[t])) @ (f_0-y)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Draw predictions at data points over time" + ], + "metadata": { + "id": "hIyny7ZKZFfK" + } + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "wfF_oTS5Z4Wi", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "outputId": "c311f0e2-f876-4c7c-933f-e24f68453e97" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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xmDt2rUICAgw6VyFhYXIyckx2IiIiKjpahBhKTk5GX5+fgb7HBwc4O3tjeTk5Cpf9/bbbyMqKgpPPfWUyedavHgxlEqlfgsKCqpx3URERNTwWTUszZ49GzKZzOh2+fLlGr33rl27sH//fqxYscKs182ZMwfZ2dn67datWzU6PxERETUOVh2zNGPGDEyYMMHoMWFhYQgICEBqaqrB/pKSEmRkZFTZvbZ//35cv34dnp6eBvufeeYZPPTQQzh48GClr3NycoKTk5OpH4GIiIgaOauGJV9fX/j6+lZ7XN++fZGVlYXTp0+je/fuAEQY0mq16N27d6WvmT17Nl599VWDfR07dsSnn36KYcOG1b54IiIiahIaxNVwkZGRGDx4MF577TWsW7cOxcXFmDRpEl544QX9lXB37tzBY489hq+++gq9evVCQEBApa1OwcHBCA0Nre+PQERERA1UgxjgDQCbN29GREQEHnvsMQwdOhQPPvggvvjiC/3zxcXFuHLlCtRqtRWrJCIiosZGJkmSZO0ibFlOTg6USiWys7Ph4eFh7XKIiIjIBJb8/W4wLUtERERE1sCwRERERGQEwxIRERGREQxLREREREYwLBEREREZwbBEREREZATDEhEREZERDEtERERERjAsERERERnBsERERERkBMMSERERkREMS0RERERGMCwRERERGcGwRERERGQEwxIRERGREQxLREREREYwLBEREREZwbBEREREZATDEhEREZERDEtERERERjAsERERERnBsERERERkBMMSERERkREMS0RERERGMCwRERERGcGwRERERGQEwxIRERGREQxLREREREYwLBEREREZ4WDtAmydJEkAgJycHCtXQkRERKbS/W7rfsdrg2GpGunp6QCAoKAgK1dCRERE5kpPT4dSqazVezAsVcPb2xsAkJiYWOsvm2onJycHQUFBuHXrFjw8PKxdTpPGPwvbwT8L28I/D9uRnZ2N4OBg/e94bTAsVcPOTgzrUiqV/ItvIzw8PPhnYSP4Z2E7+GdhW/jnYTt0v+O1eg8L1EFERETUaDEsERERERnBsFQNJycnzJ07F05OTtYupcnjn4Xt4J+F7eCfhW3hn4ftsOSfhUyyxDV1RERERI0UW5aIiIiIjGBYIiIiIjKCYYmIiIjICIYlIiIiIiMYloxYu3YtQkJC4OzsjN69e+Pk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\n" + }, + "metadata": {} + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(t_all,np.squeeze(f_all[0,:]),'r-', label='Training point 1')\n", + "ax.plot(t_all,np.squeeze(f_all[1,:]),'g-', label='Training point 2')\n", + "ax.plot(t_all,np.squeeze(f_all[2,:]),'b-', label='Training point 3')\n", + "ax.set_xlim([0,10]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('t'); ax.set_ylabel('prediction at training data points')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Plot residuals as a function of time" + ], + "metadata": { + "id": "wSMoLi5nZKYv" + } + }, + { + "cell_type": "code", + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(t_all,np.squeeze(residuals_all[0,:]),'r-', label='Training point 1')\n", + "ax.plot(t_all,np.squeeze(residuals_all[1,:]),'g-', label='Training point 2')\n", + "ax.plot(t_all,np.squeeze(residuals_all[2,:]),'b-', label='Training point 3')\n", + "ax.set_xlim([0,10]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('t'); ax.set_ylabel('residual at training data points')\n", + "ax.legend()\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "8QYKlzzUZLKP", + "outputId": "26959ce0-26c7-43fe-c7f7-7e271a337eae" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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hQsXanXtbdu2Ye/evVi+fLlR71uwYAFycnK02/Xr12v1+URERNQ0yDpmae7cuZg8ebLecwIDA+Hj44OMjAyd/SUlJcjMzKy2e23v3r24evUqXF1ddfY/8cQTePjhh7F///4q32djYwMbGxtDvwIRERE1cbKGJU9PT3h6etZ4Xp8+fZCdnY2TJ0+iZ8+eAEQYUqvViIyMrPI98+fPxz/+8Q+dfV26dMEnn3yCESNG1L14IiIiahYaxd1woaGhGDJkCF544QWsWbMGxcXFmDZtGp5++mntnXA3b97EgAEDsGHDBkRERMDHx6fKVqc2bdogICCgob8CERERNVKNYoA3AHz77bcICQnBgAEDMGzYMDz00EP44osvtMeLi4tx8eJF5Ofny1glERERNTUKSZIkuYswZyqVCi4uLsjJyYGzs7Pc5RAREZEBTPn73WhaloiIiIjkwLBEREREpAfDEhEREZEeDEtEREREejAsEREREenBsERERESkB8MSERERkR4MS0RERER6MCwRERER6cGwRERERKQHwxIRERGRHgxLRERERHowLBERERHpwbBEREREpAfDEhEREZEeDEtEREREejAsEREREenBsERERESkB8MSERERkR4MS0RERER6MCwRERER6cGwRERERKQHwxIRERGRHgxLRERERHowLBERERHpwbBEREREpAfDEhEREZEeDEtEREREejAsEREREelhJXcB5k6SJACASqWSuRIiIiIylOZ3W/M7XhcMSzW4e/cuAMDPz0/mSoiIiMhYd+/ehYuLS52uwbBUA3d3dwBASkpKnf+wqW5UKhX8/Pxw/fp1ODs7y11Os8a/C/PBvwvzwr8P85GTk4M2bdpof8frgmGpBhYWYliXi4sL/8E3E87Ozvy7MBP8uzAf/LswL/z7MB+a3/E6XcMEdRARERE1WQxLRERERHowLNXAxsYGb731FmxsbOQupdnj34X54N+F+eDfhXnh34f5MOXfhUIyxT11RERERE0UW5aIiIiI9GBYIiIiItKDYYmIiIhID4YlIiIiIj0YlvRYvXo1/P39YWtri8jISBw/flzukpqlRYsWoVevXnBycoKXlxdGjRqFixcvyl1Ws/fhhx9CoVBg1qxZcpfSbN28eRPPPPMMPDw8YGdnhy5duiAuLk7uspqd0tJSvPHGGwgICICdnR2CgoLw7rvvmmRNMqrZwYMHMWLECLRs2RIKhQJbt27VOS5JEt588034+vrCzs4OAwcOxOXLl436DIalamzatAlz5szBW2+9hVOnTqFr166Ijo5GRkaG3KU1OwcOHMArr7yCo0ePYteuXSguLsbgwYORl5cnd2nN1okTJ/D5558jLCxM7lKaraysLPTt2xfW1tb4/fff8ddff2Hp0qVwc3OTu7Rm56OPPsJnn32GVatWISEhAR999BEWL16MlStXyl1as5CXl4euXbti9erVVR5fvHgxVqxYgTVr1uDYsWNwcHBAdHQ07t+/b/iHSFSliIgI6ZVXXtG+Li0tlVq2bCktWrRIxqpIkiQpIyNDAiAdOHBA7lKapXv37knBwcHSrl27pEcffVSaOXOm3CU1S/PmzZMeeughucsgSZKGDx8uPffcczr7xowZI02YMEGmipovANKWLVu0r9VqteTj4yN9/PHH2n3Z2dmSjY2N9P333xt8XbYsVaGoqAgnT57EwIEDtfssLCwwcOBAHDlyRMbKCBCLIwIwyeKIZLxXXnkFw4cP1/n3gxretm3bEB4ejr///e/w8vJC9+7dsXbtWrnLapaioqKwZ88eXLp0CQBw5swZHDp0CEOHDpW5MkpMTERaWprOf69cXFwQGRlp1O85F9Ktwp07d1BaWgpvb2+d/d7e3rhw4YJMVREAqNVqzJo1C3379kXnzp3lLqfZ2bhxI06dOoUTJ07IXUqzd+3aNXz22WeYM2cO/u///g8nTpzAjBkzoFQqMWnSJLnLa1bmz58PlUqFkJAQWFpaorS0FO+//z4mTJggd2nNXlpaGgBU+XuuOWYIhiVqVF555RWcO3cOhw4dkruUZuf69euYOXMmdu3aBVtbW7nLafbUajXCw8PxwQcfAAC6d++Oc+fOYc2aNQxLDeyHH37At99+i++++w6dOnVCfHw8Zs2ahZYtW/LvoolgN1wVWrRoAUtLS6Snp+vsT09Ph4+Pj0xV0bRp0/Drr79i3759aN26tdzlNDsnT55ERkYGevToASsrK1hZWeHAgQNYsWIFrKysUFpaKneJzYqvry86duyosy80NBQpKSkyVdR8vfrqq5g/fz6efvppdOnSBc8++yxmz56NRYsWyV1as6f5za7r7znDUhWUSiV69uyJPXv2aPep1Wrs2bMHffr0kbGy5kmSJEybNg1btmzB3r17ERAQIHdJzdKAAQNw9uxZxMfHa7fw8HBMmDAB8fHxsLS0lLvEZqVv376VptC4dOkS2rZtK1NFzVd+fj4sLHR/Ti0tLaFWq2WqiDQCAgLg4+Oj83uuUqlw7Ngxo37P2Q1XjTlz5mDSpEkIDw9HREQEli9fjry8PEyZMkXu0pqdV155Bd999x1+/vlnODk5afuZXVxcYGdnJ3N1zYeTk1OlcWIODg7w8PDg+DEZzJ49G1FRUfjggw8wduxYHD9+HF988QW++OILuUtrdkaMGIH3338fbdq0QadOnXD69GksW7YMzz33nNylNQu5ubm4cuWK9nViYiLi4+Ph7u6ONm3aYNasWXjvvfcQHByMgIAAvPHGG2jZsiVGjRpl+IeY8I69JmflypVSmzZtJKVSKUVEREhHjx6Vu6RmCUCV27p16+Qurdnj1AHy+uWXX6TOnTtLNjY2UkhIiPTFF1/IXVKzpFKppJkzZ0pt2rSRbG1tpcDAQOm1116TCgsL5S6tWdi3b1+VvxGTJk2SJElMH/DGG29I3t7eko2NjTRgwADp4sWLRn2GQpI4xSgRERFRdThmiYiIiEgPhiUiIiIiPRiWiIiIiPRgWCIiIiLSg2GJiIiISA+GJSIiIiI9GJaIiIiI9GBYIiIiItKDYYmIiIhID4YlImqW+vXrh1mzZsldBhE1AgxLRERERHpwbTgianYmT56Mr776SmdfYmIi/P395SmIiMwawxIRNTs5OTkYOnQoOnfujHfeeQcA4OnpCUtLS5krIyJzZCV3AUREDc3FxQVKpRL29vbw8fGRuxwiMnMcs0RERESkB8MSERERkR4MS0TULCmVSpSWlspdBhE1AgxLRNQs+fv749ixY0hKSsKdO3egVqvlLomIzBTDEhE1SzExMbC0tETHjh3h6emJlJQUuUsiIjPFqQOIiIiI9GDLEhEREZEeDEtEREREejAsEREREenBsERERESkB8MSERERkR4MS0RERER6MCwRERER6cGwRERERKQHwxIRERGRHgxLRERERHowLBERERHp8f8Bz3KxOTDiEwgAAAAASUVORK5CYII=\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Plot loss as a function of time" + ], + "metadata": { + "id": "o2V9v-TlZQrZ" + } + }, + { + "cell_type": "code", + "source": [ + "fig, ax = plt.subplots()\n", + "square_error = np.sum(residuals_all * residuals_all, axis=0)\n", + "ax.plot(t_all, square_error,'k-')\n", + "ax.set_xlim([0,10]); ax.set_ylim([-0.0,1.0])\n", + "ax.set_xlabel('t'); ax.set_ylabel('Loss')\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 455 + }, + "id": "89H_zWQHZQZt", + "outputId": "4002e625-3763-40f9-d186-fc4fc07c6c7d" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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q633AbpYLpdLixcv1iOPPKKcnBxJ0o033qgXX3xR4eHhFk8HAEDVqlf3AULFeXl56a677tLOnTs1ceJEeXt766OPPlLXrl310EMP6fDhw1aPCABArUUA1XFNmzbVP/7xD33//fcaNmyYnE6n5syZo44dO+of//iHSkpKrB4RAIBahwCqJy6//HKtXLlSSUlJ6tGjh3JzcxUfH68uXbroP//5D+8tBgDAaQigembAgAHasmWLFi1apODgYO3evVu33HKLIiMjtXbtWkIIAAARQPWS3W7XPffcox9//FHTpk1Tw4YN9c0332jgwIEaMGDABb/PGgAA9RUBVI81btxYTz31lH766SdNmjRJDodDn376qfr27athw4bp22+/tXpEAAAsQQAZoGXLlnr55Zf1448/aty4cbLb7frwww/Vs2dPjRw5Ujt27LB6RAAAahQBZJDQ0FAtXLhQP/zwg0aMGCG3261///vf6tKli2677TaOCAEAjEEAGejyyy/X0qVLtXXrVt18881yu91677331KNHD8XFxembb76xekQAAKoVAWSwnj176r///a++/fZbjRgxQjabTStXrlSfPn00ePBgffnll1aPCABAtSCAoG7dumnp0qX64YcfNGrUKNntdiUmJiomJkbXXHONPvroI7lcLqvHBACgyhBA8AgPD9fixYu1c+dOjRs3Tt7e3tq4caOGDh2qLl26aNGiRTpx4oTVYwIAUGkEEM7QoUMHLVy4UHv37tUjjzyigIAApaen695771W7du30zDPP8F5jAIA6jXeDx3nl5+dr0aJFmj17tjIzMyVJDRo00NixY/Xggw/y7vMAgGrHu8GjxgUEBCg+Pl579uzRO++8o549e6qwsFBz585Vp06ddP3112vlypVyOp1WjwoAwAUhgHDBfHx8NHLkSKWmpmrdunW66aab5OXlpXXr1ikuLk4dOnTQzJkzlZOTY/WoAACcE6fAUCk///yz5s+fr4ULF+rIkSOSJIfDoTvuuEP33XefIiMjZbPZLJ4SAFDXVfXfbwIIVaKoqEjLli3Tq6++qtTUVM/6rl27aty4cRo1apSaNm1q4YQAgLqMAKokAqh6ud1ubd68Wa+99pree+89z8vmHQ6Hhg8frnHjxql///7y8uLsKwDgwhFAlUQA1Zzc3FwtWbJECxcuVFpammd9hw4dNHbsWP35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Nmnw4MEWT2a2vXv3Kisrq8z/qwIDAxUVFXXRf8stvxN0TcnJyZHT6fTcYfqU4OBgpaenWzQVXC6XJk6cqJiYmAu+mzeq1tKlS5Wamqqvv/7a6lGM9tNPP2nevHmKj4/X448/rq+//lp/+9vf5OvrqzFjxlg9nnEmT56s/Px8hYeHy263y+l06tlnn9Wdd95p9WhGy8rKkqRy/5afeuxCGRNAqJ3Gjx+v7du3a9OmTVaPYqTMzExNmDBBa9eulZ+fn9XjGM3lcql379567rnnJEkRERHavn275s+fTwBZ4N1339U777yjJUuWqEuXLkpLS9PEiRPVunVrfh/1hDGnwJo3by673a7s7Owy67OzsxUSEmLRVGZ78MEH9dFHH2nDhg265JJLrB7HSFu2bNHBgwd15ZVXytvbW97e3vrss8/0yiuvyNvbW06n0+oRjdGqVSt17ty5zLpOnTopIyPDoonM9sgjj2jy5Mm6/fbb1a1bN40aNUqTJk3yvDE3rHHq73VV/C03JoB8fX3Vq1cvJSUleda5XC4lJSUpOjrawsnM43a79eCDD2r58uVav3692rdvb/VIxrruuuv03XffKS0tzbP07t1bd955p9LS0mS3260e0RgxMTFn3A5i165dateunUUTma2wsLDMG3FLkt1ul8vlsmgiSFL79u0VEhJS5m95fn6+Nm/efNF/y406BRYfH68xY8aod+/eioyM1OzZs1VQUKCxY8daPZpRxo8fryVLlmjlypVq3Lix57xtYGCg/P39LZ7OLI0bNz7j2quGDRuqWbNmXJNVwyZNmqS+ffvqueee02233aaUlBQtWLBACxYssHo0Iw0dOlTPPvus2rZtqy5dumjr1q16+eWXdffdd1s9Wr13/Phx7d692/P13r17lZaWpqZNm6pt27aaOHGinnnmGV122WVq3769pk2bptatWysuLu7inqiKXqlWZ7z66qvutm3bun19fd2RkZHur776yuqRjCOp3OVf//qX1aPB7eZl8Bb68MMP3V27dnU7HA53eHi4e8GCBVaPZKz8/Hz3hAkT3G3btnX7+fm5L730UvfUqVPdxcXFVo9W723YsKHcvxFjxoxxu92/vRR+2rRp7uDgYLfD4XBfd9117p07d17089jcbm5rCQAAzGLMNUAAAACnEEAAAMA4BBAAADAOAQQAAIxDAAEAAOMQQAAAwDgEEAAAMA4BBAAAjEMAAag3+vfvr4kTJ1o9BoA6gAACAADG4a0wANQLd911l956660y6/bu3auwsDBrBgJQqxFAAOqFvLw8DR48WF27dtVTTz0lSWrRooXsdrvFkwGojbytHgAAqkJgYKB8fX3VoEEDhYSEWD0OgFqOa4AAAIBxCCAAAGAcAghAveHr6yun02n1GADqAAIIQL0RFhamzZs36+eff1ZOTo5cLpfVIwGopQggAPXGww8/LLvdrs6dO6tFixbKyMiweiQAtRQvgwcAAMbhCBAAADAOAQQAAIxDAAEAAOMQQAAAwDgEEAAAMA4BBAAAjEMAAQAA4xBAAADAOAQQAAAwDgEEAACMQwABAADjEEAAAMA4/x95pXQzeRmYGQAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Plot parameters as a function of time (almost constant with large width)" + ], + "metadata": { + "id": "eboxCz0dZW0s" + } + }, + { + "cell_type": "code", + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(t_all, np.squeeze(phi_t_all[20,:]),'c-', label='Layer 1 weight')\n", + "ax.plot(t_all, np.squeeze(phi_t_all[15250,:]),'m-', label = 'Layer 1 bias')\n", + "ax.plot(t_all, np.squeeze(phi_t_all[20305,:]),'k-', label = 'Layer 2 weight')\n", + "ax.plot(t_all, np.squeeze(phi_t_all[30000,:]),'y-', label = 'Layer 2 bias')\n", + "ax.set_xlim([0,5]); ax.set_ylim([-2.5,2.5])\n", + "ax.set_xlabel('t'); ax.set_ylabel('phi')\n", + "ax.legend()\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "q6yxIev6ZWob", + "outputId": "546bef23-955a-4115-f38b-5200f16dba88" + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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LIIOAAAwFkEHAAAYi6ADAACMRdABAADGIuigXktNTZXNZtP3339/1Tbr169XSEhIndUEAGg4CDoN3MSJEzVmzBiry6iU7Oxs3XffferUqZO8vLw0e/Zst4x799136/PPP3fLWAAAsxB04HYXL16scHlxcbHCwsL05z//Wb169XLb9nx9fRUeHu628QAA5iDoXIXT6VRpQaklkzsfVr1ixQr16NFD/v7+ioyM1LRp02S32yVJBQUFCgoK0muvvVamz44dO+Tv768LFy5Iks6cOaNx48YpJCREoaGhGj16tLKyslztL59Vio+PV+vWrdW5c+cKa2nXrp2ee+45TZgwQcHBwVXaj/3796tnz55q2rSpbrzxRh0+fNi17spLVydPntTo0aPVsmVLBQQEqH///tq9e3eZ8dasWaOOHTuqadOmatmype68884q1QMAaBj4Uc+rcBQ6tDdgryXbHmwfLG9/b7eM5eXlpcTERLVv315ffPGFpk2bprlz52rNmjXy9/fXPffco6SkpDIH+svzgYGBKikp0ciRIzVw4EDt3btXjRo10pIlSzRq1CgdOnTI9SOgKSkpCgoKqrUfw3zsscf03HPPKSIiQk888YRiY2P1+eefq3HjxuXa2u123XbbbYqPj5ePj4/+9re/KTY2VseOHVNUVJQ++ugjzZo1Sxs2bNCgQYP07bffau9ea95rAEDtIugY7uf3wbRr105LlizRH//4R61Zs0aSNGXKFA0aNEjZ2dlq1aqVcnNztXPnTtcZkK1bt8rhcGjdunWy2WySfgxCISEhSk1N1YgRIyRJ/v7+WrduXa39+vmTTz6p4cOHS5KSk5PVpk0bbd++XePGjSvXtlevXmUujf3lL3/R9u3b9X//93+aMWOGTp8+LX9/f91xxx0KDAxU27Zt1adPn1qpGwBgLYLOVXj5eWmwfbBl23aX3bt3KyEhQUePHlV+fr4uXbqkoqIiFRYWys/PTwMGDFC3bt2UnJysefPm6ZVXXlHbtm01ZMgQSdLBgwd14sQJBQYGlhm3qKhIJ0+edM336NGj1kKOJA0cOND1d2hoqDp37qzPPvuswrZ2u10LFy7UP//5T2VnZ+vSpUv64YcfdPr0aUnS8OHD1bZtW11//fUaNWqURo0apd/97nfy8/OrtfoBANYg6FyFzWZz2+Ujq2RlZemOO+7Q1KlTFR8fr9DQUO3bt0+TJ0/WxYsXXQf2KVOmaPXq1Zo3b56SkpI0adIk19kbu92ufv36aePGjeXGDwsLc/3t7+9fNztVCXPmzNGuXbv07LPPqkOHDvL19dWdd97pukk6MDBQH3/8sVJTU/X2229rwYIFWrhwoQ4cOMDX1AHAMNyMbLD09HQ5HA4tX75cN954ozp16qSzZ8+Wa3f//ffr1KlTSkxM1JEjRxQXF+da17dvXx0/flzh4eHq0KFDmamqNxTXxPvvv+/6+7vvvtPnn3+url27Vth2//79mjhxon73u9+pR48eioiIKHPztCQ1atRIw4YN09NPP61Dhw4pKytL77zzTm3uAgDAApzRMUBeXp4yMjLKLGvevLk6dOigkpISrVq1SrGxsdq/f7/Wrl1brn+zZs00duxYPfbYYxoxYoTatGnjWjd+/Hg988wzGj16tBYvXqw2bdro1KlT2rZtm+bOnVumbWVcrtNut+v8+fPKyMhQkyZN9Otf//qa/RYvXqzmzZurZcuW+tOf/qQWLVpc9flBHTt21LZt2xQbGyubzab/+Z//kcPhcK1/88039cUXX2jIkCFq1qyZdu7cKYfDcdVviwEAGi7O6BggNTVVffr0KTMtWrRIvXr10ooVK7Rs2TJ1795dGzduVEJCQoVjXL6c9cADD5RZ7ufnpz179igqKkpjx45V165dNXnyZBUVFSkoKKjKtV6uLz09XZs2bVKfPn102223/WK/pUuX6qGHHlK/fv2Uk5OjN95446r3BK1YsULNmjXToEGDFBsbq5EjR6pv376u9SEhIdq2bZtuueUWde3aVWvXrtXmzZvVrVu3Ku8PAKB+sznd+dCWei4/P1/BwcHKy8srd5AuKipSZmam2rdvr6ZNm1pUoXU2bNighx9+WGfPnq3Vm4o9mad/xgCguq51/P4lXLrycIWFhcrOztbSpUv14IMPEnIAAEbh0pWHe/rpp9WlSxdFRERo/vz5VpcDAIBbEXQ83MKFC1VSUqKUlBQFBARYXQ4AAG5F0AEAAMYi6AAAAGMRdAAAgLEIOgAAwFgEHQAAYCyCDgAAMBZBBx5l4cKF6t27d5X6xMTEaPbs2bVSDwCgdhF0GriJEyde9cct65tt27Zp+PDhCgsLU1BQkAYOHKi33nqrTmuYM2eOUlJS3D6uzWbTjh073D4uAKBmCDpwu4sXL1a4fM+ePRo+fLh27typ9PR03XzzzYqNjdV///vfOqstICBAzZs3r7PtAQCsRdC5CqfTqYKCAksmd/7O6ooVK9SjRw/5+/srMjJS06ZNk91ulyQVFBQoKChIr732Wpk+O3bskL+/vy5cuCBJOnPmjMaNG6eQkBCFhoZq9OjRysrKcrW/fFYpPj5erVu3VufOnSusZeXKlZo7d6769++vjh076qmnnlLHjh31xhtvVNje6XQqLCysTH29e/dWq1atXPP79u2Tj4+PCgsLJUnff/+9pkyZ4jprdMstt+jgwYOu9ldeurp06ZJmzZqlkJAQNW/eXI8//rji4uLKnSVzOByaO3euQkNDFRERoYULF7rWtWvXTpL0u9/9TjabzTUPALAeQecqCgsLFRAQYMl0+aDtDl5eXkpMTNSnn36q5ORkvfPOO5o7d64kyd/fX/fcc4+SkpLK9ElKStKdd96pwMBAlZSUaOTIkQoMDNTevXu1f/9+BQQEaNSoUWXO3KSkpOjYsWPatWuX3nzzzUrV5nA4dOHCBYWGhla43mazaciQIUpNTZUkfffdd/rss8/0ww8/6OjRo5KktLQ09e/fX35+fpKku+66S7m5ufrXv/6l9PR09e3bV7/97W/17bffVriNZcuWaePGjUpKStL+/fuVn59f4SWo5ORk+fv764MPPtDTTz+txYsXa9euXZKkAwcOuF637Oxs1zwAoB5wepC8vDynJGdeXl65dT/88IPzyJEjzh9++MHpdDqddrvdKcmSyW63V3qf4uLinKNHj650+7///e/O5s2bu+Y/+OADp7e3t/Ps2bNOp9PpPHfunLNRo0bO1NRUp9PpdG7YsMHZuXNnp8PhcPUpLi52+vr6Ot966y1XDS1btnQWFxdXug6n0+lctmyZs1mzZs5z585dtU1iYqKzW7duTqfT6dyxY4czOjraOXr0aOcLL7zgdDqdzmHDhjmfeOIJp9PpdO7du9cZFBTkLCoqKjPGr371K+eLL77odDqdzieffNLZq1cv17qWLVs6n3nmGdf8pUuXnFFRUWVe06FDhzp/85vflBmzf//+zscff9w1L8m5ffv2a+7vlZ8xAEDlXOv4/Usa1XqScoOsrCz95S9/0TvvvKOcnBy1bt1a999/v/70pz+pSZMmtbJNPz8/1yWeunb57IQ77N69WwkJCTp69Kjy8/N16dIl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Zs36xRoAAA1Pg3gyshUcjkLt3RtgybYHD7bL29vfLWN5eXkpMTFR7du31xdffKFp06Zp7ty5WrNmjfz9/XXPPfcoKSlJd955p6vP5fnAwECVlJRo5MiRGjhwoPbu3atGjRppyZIlGjVqlA4dOuT6EdCUlBQFBQVp165dla7N4XDowoULCg0NvWa7wsJCxcfH629/+5uaNGmiadOm6Z577tH+/fsrbH/hwgXFxcVp1apVcjqdWr58uW677TYdP35cgYGB+sc//qH//d//1ZYtW9StWzfl5OTo4MGDla4bANBwEHQMN3v2bNff7dq105IlS/THP/5Ra9askSRNmTJFgwYNUnZ2tlq1aqXc3Fzt3LlTu3fvliRt3bpVDodD69atk81mk/RjEAoJCVFqaqpGjBghSfL399e6deuq9Ovnzz77rOx2u8aNG3fNdiUlJXr++ecVHR0tSUpOTlbXrl314YcfasCAAeXa33LLLWXmX3rpJYWEhCgtLU133HGHTp8+rYiICA0bNkyNGzdWVFRUheMAABo+gs5VeHn5afBgu2Xbdpfdu3crISFBR48eVX5+vi5duqSioiIVFhbKz89PAwYMULdu3ZScnKx58+bplVdeUdu2bTVkyBBJ0sGDB3XixAkFBgaWGbeoqEgnT550zffo0aNKIWfTpk1atGiRXn/9dYWHh1+zbaNGjdS/f3/XfJcuXRQSEqLPPvuswoBy7tw5/fnPf1Zqaqpyc3NVWlqqwsJCnT59WpJ01113aeXKlbr++us1atQo3XbbbYqNjVWjRvxzAADT8H/2q7DZbG67fGSVrKws3XHHHZo6dari4+MVGhqqffv2afLkybp48aL8/H4MVFOmTNHq1as1b948JSUladKkSa6zN3a7Xf369dPGjRvLjR8WFub629+/8q/Vli1bNGXKFP3973/XsGHDariX5cXFxembb77Rc889p7Zt28rHx0cDBw503SQdGRmpY8eOaffu3dq1a5emTZumZ555RmlpaWrcuLHb6wEAWIebkQ2Wnp4uh8Oh5cuX68Ybb1SnTp109uzZcu3uv/9+nTp1SomJiTpy5Iji4uJc6/r27avjx48rPDxcHTp0KDMFBwdXuabNmzdr0qRJ2rx5s26//fZK9bl06ZI++ugj1/yxY8f0/fffq2vXrhW2379/v2bNmqXbbrtN3bp1k4+Pj77+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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Helper routines to run network using parameter vector directly" + ], + "metadata": { + "id": "PvAKER77a8Hj" + } + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "WQUPORoBVEbv" + }, + "outputs": [], + "source": [ + "def vector_to_params(params):\n", + " D = int((params.size-1)/3)\n", + " omega0 = np.ones((D,2))\n", + " omega0[:,0:1] = params[0:D,0:1]\n", + " omega0[:,1:2] = params[D:D*2,0:1]\n", + " beta1 = params[D*2:D*2+1,0:1]\n", + " omega1 = params[D*2+1:D*3+1,0:1].T\n", + " return omega0, omega1, beta1\n", + "\n", + "def shallow_network_param_vector(X, phi):\n", + " omega0, omega1, beta1 = vector_to_params(phi)\n", + " return shallow_network(X,omega0,omega1,beta1)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "cv9ZrUoRkuhI", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "outputId": "a33a32f1-47be-49d4-c61e-bf3183953a45" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ], + "source": [ + "# Define an array of points where will make new predictions\n", + "x_vals = np.arange(0,1,0.001)[None,:]\n", + "x_vals = np.concatenate((x_vals, np.ones_like(x_vals)))\n", + "\n", + "# Compute parameters at 6 different time points\n", + "phi_1 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 0.1)) @ (f_0-y)\n", + "phi_2 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 0.5)) @ (f_0-y)\n", + "phi_3 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 1.5)) @ (f_0-y)\n", + "phi_4 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 5.0)) @ (f_0-y)\n", + "phi_5 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 25.0)) @ (f_0-y)\n", + "phi_6 = phi_0 - moore_penrose_inverse @ (np.identity(3)-expm(-K * 5000.0)) @ (f_0-y)\n", + "\n", + "# Draw the function evolution over time\n", + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_0).T,'r-',label='t=0')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_1).T,'b-',label='t=0.1')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_2).T,'g-',label='t=0.5')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_3).T,'c-',label='t=1.5')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_4).T,'y-',label='t=5.0')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_5).T,'m-',label='t=25.0')\n", + "ax.plot(x_vals[0:1,:].T, shallow_network_param_vector(x_vals, phi_6).T,'k-',label='t=5000.0')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('Predicted output')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "source": [ + "The previous way of making predictions used the full non-linear model. Here, we make predictions using the empirical kernel" + ], + "metadata": { + "id": "SEn7WsKUfHi_" + } + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "nBSpVJA7hDnF" + }, + "outputs": [], + "source": [ + " # Make predictions directly using kernel method (linear approximation)\n", + "def kernel_predict_empirical(X,x,y,t, f_0, omega0, omega1, beta1):\n", + " K = compute_empirical_ntk(X,X, omega0, omega1, beta1)\n", + " predict = compute_empirical_ntk(x,X, omega0, omega1, beta1) @ np.linalg.inv(K) @ (np.identity(3)-expm(-K * t)) @ (f_0-y)\n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "8ZQFrsr1hKnr", + "outputId": "a0bdb8e6-514d-4426-b43a-f8a6f3761733" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ], + "source": [ + "# Get predictions at time 0\n", + "f_0_x = shallow_network_param_vector(x_vals, phi_0).T\n", + "# Get predictions at six different time points\n", + "f_0_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 0.0, f_0, omega0, omega1, beta1)\n", + "f_1_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 0.1, f_0, omega0, omega1, beta1)\n", + "f_2_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 0.5, f_0, omega0, omega1, beta1)\n", + "f_3_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 1.5, f_0, omega0, omega1, beta1)\n", + "f_4_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 5.0, f_0, omega0, omega1, beta1)\n", + "f_5_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 25.0, f_0, omega0, omega1, beta1)\n", + "f_6_test = f_0_x - kernel_predict_empirical(X, x_vals, y, 500.0, f_0, omega0, omega1, beta1)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "ax.plot(x_vals[0:1,:].T, f_0_test,'r-',label='t=0')\n", + "ax.plot(x_vals[0:1,:].T, f_1_test,'b-',label='t=0.1')\n", + "ax.plot(x_vals[0:1,:].T, f_2_test,'g-',label='t=0.5')\n", + "ax.plot(x_vals[0:1,:].T, f_3_test,'c-',label='t=1.5')\n", + "ax.plot(x_vals[0:1,:].T, f_4_test,'y-',label='t=5.0')\n", + "ax.plot(x_vals[0:1,:].T, f_5_test,'m-',label='t=25.0')\n", + "ax.plot(x_vals[0:1,:].T, f_6_test,'k-',label='t=500.0')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('Predicted output')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's do the same thing with the analytical kernel (i.e. with an infinitely wide network)" + ], + "metadata": { + "id": "8syQAEh0gnvB" + } + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "id": "uW3FL0rP3m9f" + }, + "outputs": [], + "source": [ + "def kernel_predict_analytical(X,x,y,t, f_0):\n", + " K = compute_analytical_ntk(X,X)\n", + " predict = compute_analytical_ntk(x,X) @ np.linalg.inv(K) @ (np.identity(3)-expm(-K * t)) @ (f_0-y)\n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "5aUwSdSn3ivu", + "outputId": "9e9f1ac2-d37c-4253-d21e-f1fa8d92cc90" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk0AAAGwCAYAAAC0HlECAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC6D0lEQVR4nOydd3iTVfvHP9lN0j0p0FIoeyMbAUEFUQERVFQEFMXXPXCh78/X+errFieKA1xMmSqCIgjKkL3LpkBL90iatJnP74/Tpi2UXUjans91net5cp4nT07SNPnmPvf53ipFURQkEolEIpFIJKdF7e8BSCQSiUQikdQEpGiSSCQSiUQiOQukaJJIJBKJRCI5C6RokkgkEolEIjkLpGiSSCQSiUQiOQukaJJIJBKJRCI5C6RokkgkEolEIjkLtP4eQKDj9XpJT08nJCQElUrl7+FIJBKJRCI5CxRFwWq1Ur9+fdTq6okRSdF0BtLT00lISPD3MCQSiUQikZwHR48epWHDhtVyLSmazkBISAggXvTQ0FA/j0ZCejr8+CPMng1bt5b3m0wweDDcfDP07w86nf/GKJFIJBK/Y7FYSEhI8H2PVwcqWUbl9FgsFsLCwigsLJSiKdDYvRumT4fvv4eDB8v7o6Phlltg1Cjo2RPktKpEIpHUOS7G97cUTWdAiqYagKLAP/8I8TRzJmRllR9LSoLbb4dbb4W2baWAkkgkkjqCFE1+QIqmGobbDcuWwQ8/wNy5UFRUfiw5GYYPhxtvhO7doZoSAyUSiUQSeEjR5AekaKrB2O3w009CQP36Kzgc5cfi42HYMCGg+vWTOVASiURSy5CiyQ9I0VRLKCoSwmnePCGkLJbyYxERIol8+HAYOFAklUskEomkRiNFkx+QoqkW4nDA8uVi+m7Bgso5UCYTXHcdjBwptlJASSQSSY1EiiY/IEVTLcfjgdWrRQRq3jw4fLj8WHCwsDC46y7o3VsmkUskEkkNQoomPyBFUx1CUWDzZpg1S6zCqyigkpPhnnvg7rshJsZvQ5RIJBLJ2SFFkx+QoqmOoijw99/w9ddCRJWtwtPrhQfUgw+KFXgy+iSRSCQBycX4/pZrriWSqlCpxJTcl19CRgZ89RV06QJOJ3z3nTDN7NJFHC8u9vdoJRKJRHIJkKJJIjkTZrPIa1q/Xphojh0LBgNs2iSm7BIT4aWXIDvb3yOVSCQSyUVEiiaJ5Fzo2hWmToVjx+DNN6FRI8jJgRdfFOLpgQdg3z5/j1IikUgkFwEpmiSS8yE6Gp56CvbvhxkzoHNnKCmBTz+FFi1gxAhYs8bfo5RIJBJJNSJFk0RyIWi1wtNp/XpYsQKuv14kkc+dC716ibyo334TfRKJRCKp0UjRJJFUByoVXHGFcBvfuRPGjRMr7f7+W7iMS/EkkUgkNR4pmiSS6qZ1a7Gq7vBheOwxCAoSBpoDB0KfPvD771I8SSQSSQ1EiiaJ5GIRHw/vvQcHD8Kjj4oVd3//DQMGwJVXipV4EolEIqkxSNEkkVxs4uPh/feFeHrkESGeVqwQ5pg33yxX20kkEkkNQYomieRSUb8+TJoEe/fCnXeKPKg5c6BVK2FVkJHh7xFKJBKJ5DRI0SSRXGoSE0V5lq1bxWo7j0dYFTRtCs8/D3l5/h6hRCKRSKpAiiaJxF+0aydW25VN1dls8OqrwjBz4kTIyvL3CCUSiURSASmaJBJ/c8UVwghz7lzo2FEUB37jDUhKgscfh/R0f49QIpFIJEjRJJEEBioV3HijqGe3aBF06yYKAb//PjRuLHKeUlP9PUqJRCKp00jRJJEEEioVDB4Ma9fC0qXC18npLM95uvtusQpPIpFIJJccKZrOkptvhrffFtUy3G5/j0ZS61GphJ/TypUi5+mqq8Qb76uvoHlzIZ4OHfL3KCUSiaROoVIUaU18OiwWC2FhYUAhEApASIioinHFFaJ17gw6nV+HKakLrFkDL78Mv/4qbmu1cMcd8OyzQkhJJBKJxEfZ93dhYSGhoaHVck0pms5A2Yv+6quFrFsXyqpVUFBQ+RyzGS6/vFxEde0qyo5JJBeFtWvhxRdhyRJxW6WCW26B556D9u39OjSJRCIJFKRo8gMnvugeD2zbBn/+Wd7y8yvfJygIunSBHj2gZ0/R4uP9M35JLWbdOvjvf0XieBk33ggvvAAdOvhvXBKJRBIASNHkB870onu9sGOHEE8rVogUlJyck6+TmCjEU69e0LevsOjRaC7++CV1gK1bhXiaM6e8EPDw4UI8yciTRCKpo0jR5AfO9UX3ekUpsTVrRFu7Vogqr7fyeWFhYirvqqtE7dY2bcQsi0Ry3uzcCa+8ArNmlYunESPgP/+R4kkikdQ5pGjyA9XxolutYtXdmjXw11+i0L3VWvmc2Fghnq66Cq69Fho0qIbBS+omVYmnIUPg6adF8p1U5xKJpA5wMURTjbMc+Pjjj0lKSiIoKIju3bvzzz//nNX9ZsyYgUqlYtiwYRd3gFUQEiIE0b//DYsXi9Ji//wjTJ8HDgSjUVTMmDEDxo+Hhg1FMvmrr8L27eXfexLJWdGmjXgzbdsmvDJUKpH31KePmB+eN+/k0KdEIpFIzkiNijTNnDmTMWPGMHnyZLp3787777/P7Nmz2bNnD7Gxsae83+HDh+nduzdNmjQhMjKS+fPnn/VjXgyleiIOh8jpXbZM+BmuW1dZKDVuDDfcIFrv3mKluURy1uzdC++8A9OmiTcbQLNmMGECjBkDJpN/xyeRSCQXgTo/Pde9e3e6du3KRx99BIDX6yUhIYGHH36YiRMnVnkfj8dD3759GTduHKtWraKgoCDgRNOJZGSIOq4LFsDvv0NJSfmxyEi4/nohoK65BoKDL8mQJLWBzEz48EP4+ONy34yoKHjwQdFO88NDIpFIahp1enrO6XSyceNGrr76al+fWq3m6quvZs2aNae838svv0xsbCx33333WT2Ow+HAYrFUapeaevXgnnvEjEpOjqjjeuedEB0tpva+/RZuukncvv56+PxzOH78kg9TUtOIixNzvkePwgcfiBBmbq4wzExMhHvvhZQUf49SIpFIApYaI5pycnLweDzExcVV6o+LiyMjI6PK+/z11198+eWXTJky5awf5/XXXycsLMzXEhISLmjcF4rZLKx3vv5aRKBWroQnnoDkZDHT8ssv8K9/Qf36whfq9ddh926/DlkS6AQHw8MPi2m7WbNEcWCHA6ZMgVatRO27FStkMp1EIpGcQI0RTeeK1Wpl9OjRTJkyhejo6LO+37PPPkthYaGvHT169CKO8tzQaEQu79tvC1uDHTuEPU+3buL4unXCFLp1a1Ha5cMPq/aMkkgAkRx3883CF2PVKhg2TCSN//wz9O8v3lhz5oDH4++RSiQSSUBQY3KanE4nJpOJOXPmVFoBN3bsWAoKCliwYEGl87ds2UKnTp3QVHCQ9JauGFKr1ezZs4fk5OQzPq4/cprOh/R0MZ1Xlgflcol+nU5Y9dx/vxBccrW55LTs2wfvvQdTp0Jxsehr1gyeekokjRsMfh2eRCKRnC11OqdJr9fTuXNnli1b5uvzer0sW7aMnj17nnR+y5Yt2b59O1u2bPG1oUOH0r9/f7Zs2eL3abfqpn59MU33yy9CQH3wAVx2mRBPM2YII822bUX0qbDQ36OVBCzNmsEnn0BqKjz/PERECCF1772QlARvvgl+yPOTSCSSQKDGRJpAWA6MHTuWzz77jG7duvH+++8za9YsUlJSiIuLY8yYMTRo0IDXX3+9yvvfeeedNWL1XHWycSNMngw//AB2u+gzmUR91/HjRWkXGX2SnJKiIpHr9O67cOyY6AsPh0ceES0qyq/Dk0gkklNRpyNNACNHjuTtt9/mP//5Dx07dmTLli38+uuvvuTwI0eOcFwuI6tE587iOy89XUSZWrcW4mnqVGEO3aaN+D6UuU+SKgkOhscfhwMHxGqEFi2EXcHLL0OjRvDkk5CW5u9RSiQSySWhRkWa/EFNjzSdiKKIci5TpoiFU2XRJ51OrNK75x5RykVdo+S05JLh8QgPjP/+VxQKBvHmGT1a5D21bOnf8UkkEkkpdd7c0h/UNtFUkcJCke80ZYqYxiujcWMhnsaNE55REslJKIqoCfTGG8IHA8Q879Ch8NBDom6QVN4SicSPSNHkB2qzaKrI5s3w5Zfw3XflieJarXAe/9e/ZPRJchrWrBHiqeIK1mbN4L77hCtrZKTfhiaRSOoebreb7du38+eff/L4449L0XQpqSuiqYziYpg9Gz77DFavLu9v0kQsoLrrLlltQ3IKdu8WK++mTQOrVfQFBcFttwnPi65d/Ts+iURS61AUhSNHjvDPP/+wbt061q1bx8aNGykus0wBKZouJXVNNFVk+3ZRouXbb8ujT2W5T//6F/TrJ6NPkiooKhLLNT/5pDzvCcSqhAcegFtvlUWCJRLJeWGxWFi/fr1PIK1bt47MzMyTzgsNDeWyyy5jxYoVUjRdSuqyaCrDboeZM0X0ad268v6mTUX06c47ISbGb8OTBCqKItzGP/lErDpwOkV/eLgIWT74oKgHJJFIJFXgcDjYvXt3JYG0e/duTpQtWq2W9u3b0717d7p37063bt1o0aIFRUVFMqfpUiNFU2W2bhXi6bvvymdg9HoYPlxEn664Qvo+SaogO1tYFkyeDIcOiT6VSlScfvhhuPpqGbaUSOooVquVlJQUdu3axe7du33t4MGDeKoo45SUlOQTSN27d6dTp04YjcaTzpOJ4H5AiqaqKSoSK+8+/xzWry/vb9FCRJ/GjpW+h5Iq8Hrh11+Fadivv5b3t2ghlmzecYdcsimR1FIcDgc7d+5ky5YtbN261SeOjpUZ51ZBWFgYXbt2rSSSYs8ysVaKJj8gRdOZ2bRJiKfvvxdiCkSJsptuEtGn3r1l9ElSBXv3wscfiwhUWdhSo4FrrxVzvoMHy1p3EkkNpaCgwFfCbPPmzWzZsoVdu3bhdrurPL9evXq0atXqpBYfH4/qPL9ApGjyA1I0nT1WK0yfLqbvNm0q72/eHIYNExY+PXqI70WJxEfZG2fqVGFfUEZkJNx+u8h/6tRJKm+JJIBJT0/nzz//ZPny5axYsYJ9+/ZVeV5ERASdOnWiY8eOtGnThlatWtGyZUsiIiKqfUxSNPkBKZrOjw0bhHiaPh1stvL+6GgRQBgyBAYOFFU6JBIfe/YI8fTNN6L2Txnt2ono06hRUFo2SSKR+I+MjAxWrFjBihUrWL58OXv37j3pnKSkJDp27OgTSR07diQhIeG8I0fnSmFhIeHh4VI0XUqkaLowLBaRurJwIfz8syhbVobJJCx87r1XWPjIQILEh8cDv/8uBNS8eeBwiH6NRiju8ePhmmtk2FIiuURkZmb6RNKKFStISUmpdFylUtGpUyf69etH//796dWrF5GX2NjWmeXEut6KdYMVy3oLGf9kcE32NVI0XUqkaKo+XC74+29YtEiYRx84UH6sQwdhIH3HHTL6JDmBggLheTF1qrAwKCMhQdT6GTcOEhP9NTqJpFaSm5vLH3/84Ztu2717d6XjKpWKDh060L9/f/r160efPn0uyhTbqXDlu7ButPpEknW9FcdRR6VzbNgYzGApmi4lUjRdHBRFCKjPPxcWPmWBhNBQsfLu/vuhVSv/jlESgOzcCV98Iabv8vJEn0oFgwaJkOXgwaL+j0QiOWdSU1NZsGAB8+fPZ+XKlSct9+/QoYMvktSnT59LFkny2DxYN5WLI+t6K8X7i08+UQWmliZCuoQQ0jUEpZVC4oBEKZouJVI0XXzy8kTljU8/hYq5g1deKQykb7hBfg9KTqCkREzbTZkCy5eX9ycmCt+nu++GS/irVyKpiSiKwo4dO5g3bx7z589n8+bNlY63adOGq666in79+tG3b1+iLrKPjNvqpnhvMfY99vK2045tlw28J58flBwkBFKXEEK7hhLcKRhtaPmXhUwE9wNSNF06vF5YtkysQl+0SNwGaNBABBHGj4f4eP+OURKA7N8vok9ffgk5OaLPZBKJ4488IjygJBIJAB6PhzVr1viE0sGDB33H1Go1vXv3ZtiwYdxwww00adKk2h9fURQcxxzYttt8wqh4jxBKzuPOU95PX19PSFchjkK6CqGki9Sd9rGkaPIDUjT5hyNHxOq7KVOEmTSIaNPw4aL6Rp8+MnFccgIlJaLm3aRJsG1bef+118Jjj8GAAfJNI6mTlJSU8PvvvzN//nwWLlxIdtmHKmAwGBg4cCDDhg1jyJAhxFRjTSyPzYNth42ibUXYtpVv3QVVezUB6GJ1mFqYMLUwYWxhFNNtl4VgqH/unm1SNPkBKZr8i8MBP/4ook+rV5f3t20r8n9vu00aSEtOQFFgxQp4/30Rsiz7iGvVCh59FEaPlgWDJbWegoICfv75Z+bPn8/ixYuxVfB+CQ8PZ/Dgwdx4440MHDiQ4GpYfaMoCvbddgr+LKBwZSHWjaV5R1UoDJVWhbGFEXMrsxBGZSKpuRFd+OmjR+eCFE1+QIqmwGHLFlH79fvvRRFhECvOBw4U34M33CC/CyUncOCAKNny1VflruMREWKlwUMPyfleSa0iIyOD+fPnM3fuXJYvX17Jfbthw4YMGzaMYcOG0bdvX3S6CxMnikehaGsRBSuFSCpcVYgrx3XSefp6esztzQS3D/ZtTS1NqA0Xv9akFE1+QIqmwKOgQMzCfPtt5RXowcFw443C//Cqq2TyuKQCFoso1/LBB1CWw6HXizfLhAkidCmR1ECOHDnC3Llz+fHHH/n777+p+JXepk0bn1Dq3LnzBZlKep1erButFK4sFELpr0I8lsqr69RGNaG9QgnvG05oz1CCOwSjj9Wf92NeKFI0+QEpmgKbvXvhu++EgDp8uLw/Lg5uvVV8J3bpIlNZJKV4PMJp9e23K8/3DhoETzwh1LZ8s0gCnOPHjzNr1ixmzJjB2oq/HIFu3boxYsQIbrzxRpo1a3bej+Ep8WBZa6HwTyGSLGsseIsrL2HThGoI6x1GeN9wwvqGEdI5BLX+4keQzhYpmvyAFE01A0URZcu+/174IObmlh9r3lyUMBs1Cpo29d8YJQHGmjXwzjswd2553lOHDvDkkzByJFzg9IVEUp1YLBZ+/PFHvvvuO5YvX+6LKKlUKvr06eMTSgkJCef9GM5sJ7k/55K7MJe8pXl4bZVFkjZK6xNI4X3DCe4QjEoTuD8ypGjyA1I01TxcLliyRAioBQuguIIHWvfuQjyNHAmxsf4boySAOHBAJI1/9VV5slyDBiJp/N57ISzMr8OT1F1cLhdLly7lu+++Y/78+ZSUlPiO9ezZk1tvvZWbb76Z+AvIzbPvsZOzMIecBTlYVlsqJW7r6+kJ71cqkq4Ix9TShEoduCLpRKRo8gNSNNVsrFaYP18IqN9+K/d+0mjECvSRI2HYMAgP9+MgJYFBbi5MniwSxzMzRV9wsDAIe+QRSEry6/AkdQNFUdi4cSPffvst06dPr2QP0KJFC0aPHs3tt99O48aNz+/6HoXC1YXkLswlZ2EOxXsrO2sHdwomamgU0UOjCe4UfMmK614MpGjyA1I01R4yMsTU3fffw/r15f16vbDyufVWUQvWbPbfGCUBgMMh3iTvvAO7dok+tVqsMnjsMbj8cpn3JKl2UlNT+e677/juu+8qFcONiYnhtttuY/To0eedzO0ucpO/NJ+chTnk/pSLO7d8VZ1KpyK8fzjRN0QTNTiKoMSgank+gYAUTX5Aiqbayb59QkBNn17+vQjCsmDwYCGgrr0WgmrP54fkXFEU+PVXIZ6WLSvvv+wyIZ5GjhSKWyI5TwoKCpgzZw7ffvstK1eu9PUHBQUxbNgwRo8ezYABA87LHsCR5iBnUQ65C3PJX5aP4iz/qtdGaIm6PoqooVFEXhNZqfRIbUKKJj8gRVPtZ8cOmDFDtAMHyvtDQkRwYeRIMZUn84LrMDt2CKfx774TzuMgXFUfeAD+9S+ZICcReDywahUcPy48wPr0EbkAFXA6nfz66698++23LFq0CEdptXKVSkW/fv0YPXo0I0aMOOfvG0VRsO+ykzM/h5z5OVg3WCsdD0oOIvqGaKKHRhN6eShqbeCscrtYSNHkB6RoqjsoCmzaJMTTzJlw9Gj5sehoUQP2gQdETVhJHSUnBz7/XFjUp6eLPoNBLM989FGx+k5SN5k7V7wHjh0r72vYECZNQrnxRtatW8d3333HjBkzyK2wvLdNmza+PKVzXfmmeBUs6yxCKM3LoXhfhfwkFYT2DCV6aDRRQ6NEEncdm1aWoskPSNFUN/F6xYr0mTNh1qzyvGC1WjiPP/ww9OsnU1vqLE4nzJkjVt1VTJDr3198cQ4efFKEQVKLmTsXbrqp3LqilIPAd8B38fHsO37c11+vXj1uv/127rjjDjp27HhOYkZRhFDKnplN1uwsnGnlRW5VehURAyKIHhZN9JBo9HF1e/pYiiY/IEWTxO2Gn34Si6r++KO8v00bIZ7GjAGj0X/jk/gRRRG29O+/L4okekodkps0ESvu7roL5OdG7cbjESsrSyNMecAshFj6u8JpJpOJG2+8kdGjR3PVVVehPceSBUU7isj6PovM6Zk4Uh2+fk2IhqjBUUQPiyby2ki0IbUzP+l8kKLJD0jRJKnIrl3w0UfwzTdQVv8yLk7kBd9/v7T0qdMcPSqm7T7/HPLzRV9IiKgs/dBD0lm1trJihYgwAj8AdwNlbkpq4CpgNHDjL78QfO2153TpkqMlZE3PIvP7TGzbygvuaoI1RA2NIvaWWCKuiUATJKOaVSFFkx+QoklSFQUFMHUqvPceHDki+kJDRc7TY48JISWpo9hsoq7PpElQYek4/fqJyNOIEdLXojYxfTrcfjtzgJGAF2gHjAFuB+qXnffDD3DbbWe8nCvPRfacbDK/z6RwZaGvX6VTEXldJHGj4ogaHIXGKIXSmZCiyQ9I0SQ5HS6X+Mx8441y64KgIBFcePJJOE//OUltwOsVjqrvvy8s6ss+akNCxJLMceOgRw+ZGFfTWbGCn/r350bADYwDpiCiTJVYvlwI5yrwFHvI/SmXzO8zyfslD8VV/rUc1jeMuFFxxNwUgy5SLuE9F6Ro8gNSNEnOBq8XFi2C11+HdetEn0Yj/J4mToS2bf07PomfOXJEzOl+/TUcPFje36IFjB0Lo0eLlVaSGsdvv/7K4GuvxYmILH0DVIoBqVTib3voUKXFAYpHIf+PfDK/zyRnbg4eq8d3zNzeTNyoOGJvja1VZpOXGima/IAUTZJzQVHgzz+FeFq6tLx/8GB47jno2dN/Y5MEAF6v8PH56iux+q6s1p1KBVdfLVYVDB8uXFYlAc/KlSsZNGgQxcXFDAdmApXSsMuiiHPmwPDhKIqCdaOVrO+zyJqRhTOjfOWbIdFA3O1xxI6KJbht8CV8FrUXKZr8gBRNkvNl40b43//Eoqqy/7Jhw0RfixZ+HZokELBYYPZsmDZNCKkygoPh5ptFBKpPH+FzIQk41q5dy4ABAygqKuK6665j3pgx6J98srJPU0ICvP8+9vaDxMq3HzIr1XrTRmqJvSWW2NtjCbs8rEYVw60JSNHkB6Roklwoe/eKnKepU0WgQaOBe++FF16QCeOSUg4eFNN333wjpnHKaNQIRo2CW26B9u1l/lOAsGHDBq6++moKCwu58sor+emnnzAajZUcwZ2GeLKONCFzejbWf8rdudVGNVFDo4gbFUfkNZGo9VIUXyykaPIDUjRJqotdu+DZZ2HhQnE7OBieeQYmTJCzMZJSvF746y8RfZozR0SjyoiNFVN4AwaIrcyB8gtbtmzhyiuvJD8/nz59+rB48WLMpashvW4vWTOyyPwuk/zf86EsTUkNEQMiiBsVR/SwaOmldImQoskPSNEkqW7+/BOeeqrcSLp+fXj1VZHOIk2kJT6Ki8Xqgu+/h99/L89/KqNlSyGgBgyAK66QJpqXgB07dtCvXz9yc3Pp2bMnS5YsISQkBAB3oZudt+wkf2m+7/yQbiEioXtkbJ135/YHUjT5ASmaJBcDr1eUaHnuOTh8WPS1ayem8QYNkrMwkhNwOITz+G+/ibZhg3gTlaHVQvfu5VGorl1BL7+kq5Pdu3fTr18/srKy6Nq1K7/99hthpW62JUdK2H79dmw7bKhNahKeSiBuVBymZjKE7E+kaPIDUjRJLiYOh3AYf/VVYZgJwrrnxRdh4EApniSnID9f+P6UiagDByof1+mgdWuRB9Whg6j506KFqDYtw5nnzN69e7niiivIyMigU6dOLFu2jIiICAAsGyzsGLIDZ4YTfbyedovaEdI5xM8jloAUTX5BiibJpSAvD157DT75RMzKgAgcvPgiXHONFE+SM3DokJjC++03WLZMvKGqwmCAZs3E1F6LFpWbrAFUJQcOHOCKK64gLS2Ndu3asXz5cqKiogDInpfN7lG78RZ7Mbcz0+7ndgQlSF+lQEGKJj8gRZPkUpKRAW+9BZ9+KsWT5DxRFEhNha1bYds2sU1JgX37wOk89f3i4oSgatRItMTE8m1ioli5UMc4cuQIffv2JTU1ldatW7N8+XJiY2NRFIVj7x7jwFMHQIHIQZG0ntkabahM8A4kpGjyA1I0SfxBZqYQTxUjT926CfEkc54k54XHIxLo9uyp3FJShFo/E2FhwneoYcNTb2uRsDp+/Dh9+/Zl//79NGvWjJUrV1KvXj28bi/7H95P+uR0AOrfX5+mHzRFrZXWAYGGFE1+QIomiT+pSjz16CFyoK68UoonSTVRWCgMxfbvh6NHRaTqyBHRUlPF8bMhPBwaNIDISLGar6yZzcJXw2Qq3zebISJCtMhIsQ0PF0ntfiY7O5t+/fqxa9cukpKSWLlyJQkJCbgtbnaN3EXer3mgguR3kmn4WENU8h8xIJGiyQ9I0SQJBKoST/36icjTFVf4c2SSOoHFIpyujx0ToqqqbUVPqQshLKyykIqMrLx/qj6zuVp+RRQUFHDllVeyefNmGjRowMqVK2nSpIlYITd4O7btYoVcq+9bETMsphqesORiIUWTH5CiSRJIZGSIunaTJ5enp1xxhXAX79dPRp4kfqRMWKWliciUxVLe7HbRbLbybVGRWDKalydWA16o6DKZhOlZ/foi2lW2Hx8P0dHlLSrqlG6yVquVgQMHsnbtWmJiYli5ciUtW7bEutHK9sHbxQq5enraLmpLaBf5fRDoSNHkB6RokgQiR48K8fTll+XiqU8feOkl6N/fv2OTSM4Ll0uIqPz8ciGVl1d5v6q+vDxx33PBaDxJSDkiIrh28WKWHz5MREgIKxYsoH2/fuQszGXX7bvw2ktXyP3UjqBEuUKuJiBFkx+QokkSyBw7Jgwxp0wRnk8gcp1eeQV69fLv2CSSS4KiiMhVZiakp5e3tDSxPX4ccnMhJ0e0KgSWF7gNmAUEA38AXYFjhtvZ77gbUBPRLJ82/1HQdm4FycnSPLQGIEWTH5CiSVITSEuD//0PPvus/Dvh2mvh5ZehSxf/jk0iCRgURUwLlgmonByUnBwe/+ILJq1ciU6t5pcOHbgqJ48DRwdzjJsAiGchzZiEmlIXdo1GCKdWrYTnVdm2ZUvpdxVASNHkB6RoktQkjhwRK+u++kqsMAe44Qb4v/+T4kkiqYq33nqLp59+GoAffviBW4bdwu7Ru8n5MQeAJnfYSGi5FVXKbmHPkJIihNepiI8vF1AVxVTDhjLp8BIjRZMfkKJJUhM5cEBEmb77rrxE2dVXw7PPipwn+dktkcC3337LmDFjAHjnnXd4aMxD7LhhB5bVFlR6FS2ntiTutrjKd1IUEdpNSYHdFYTU7t1iKvBUmM1CPDVvLlqzZuXb8PCL9yTrMFI0+YGyF/2JBU8woPUAeiX0IsQg6wpJagYpKSJh/PvvyyNP3brBxIkiAqWWfnySOsqSJUsYPHgwbrebJ554glcefIVt12yjeF8x2nAtbRe0Jbxv+LldtLCwXERVFFX795f/A1ZFTExlIVW237TpKVf6Sc6MFE1+oOxFZyIQBGqVmsviL6NvYl/6NupL78TeRJmi/D1MieS0pKbC22/DF19ASYnoa94cnnoKRo8WJckkkrrChg0b6NevHzabjdtvv53Jz01m+zXbcaY5MTQy0H5xe8ytzNX3gE6nCP+WlbPZu1e0ffvO7MbesGHVgqpxY5mMfgakaPIDZS/6bd/fxtrstRwqOHTSOe1i29G3kRBRfRL7EB8S74eRSiRnJisLJk0SJpkFBaKvXj147DG47z6Zwyqp/ezfv59evXqRnZ3N1VdfzYxXZ5AyOAVXjgtTGxMdlnbAUP8S/oqwWEQkqkxEVdzm55/6fhoNJCWdPN3XurXwp5Jz8FI0+YMTX/SjhUdZdWQVK1NXsjJ1Jbtzdp90n6aRTeneoDvdG3SnR8MedKjXAb1G/iKQBA5Wq7ApePddkZ4BEBIihNNjj4nPXImktpGVlUWvXr04cOAAnTp1Yv7r80m9JRWPxUNIlxDa/9oeXZTO38MsJze3soiquG+3n/p+0dHQoQN07Chahw4in0oXQM/tEiBFkx8404ueZcviryN/+UTUlowtKFR+SQ0aA53iO9G9QXd6NuxJ78TeNAhtcKmegkRySpxOmD4d3nwTdu0SfTqdmLJ76inxOSuR1AaKioro168fGzdupHHjxvz835/Jvjsbb7GXsL5htFvUDm2o/+venRWKIpLOT4xO7dkjtlXlT+n10KZNuYgq29biJHQpmvzAub7oBSUFrDu2jnVppe3YOnKLc086r0lEE65odAX9k/rTv3F/GoY2vBjDl0jOCq8XfvlFGGX+9ZfoU6lgxAh47jno1Mm/45NILgSn08mQIUNYunQp0dHRLPrPIhxPOFBcCpHXRdJmThs0Ro2/h1k9FBfDzp2wdSts2VK+tVqrPr9Ro5OFVOPGtWJ6T4omP3ChL7qiKBzIP8C6Y+tYe2wtq4+tZkvGFryKt9J5TSOb0j+pP1c2vpIBTQbI5HKJ31i9WoinhQvL+669Voin3r39Ny6J5HxQFIWxY8fy7bffYjKZmP3EbEz/NYEXYm6JodW3rVDra/kyUq8XDh8+WUilplZ9fmgotG8vRFSnTtCjhwg717DltlI0+YGL8aJbHBZWH13N8kPLWX54ORuPb6wkotQqNZcnXM7QFkMZ0nwILaJbVMvjSiTnwvbtwmV8xoxyr6c+feA//4GrrqoVP0QldYCJEyfyxhtvoNFo+Pqer0n4LAGA+HviaT65OSpNHX4j5+fDtm2VhdTOneUFLSsSHi7EU8+e4tdTjx4Bb4cgRZMfuBTmloUlhaw6soo/Dv3B7wd/Z3vW9krHm0c1Z0jzIQxtMZReCb3QqmvIvLukVnDggMh5mjq1/LO0Z08hnq65RoonSeAyadIkHnvsMQDeuvEtuswTtvgNJzQk+e1kVPLNezIul7BG2LJFtA0bYP16Me1XEa1WlBno21f8mrr8coiI8MeIT4kUTX7AH47ghwsO89Pen1i4ZyErDq/A5S0vMBkRFMH1za9nSPMhXJN8DWFBco245NJw7Bi89RZ8/nm519Nll8Ezz4jcJ00tSQmR1A5mzZrFrbfeiqIoPNHnCQavGgxA0otJNPpPIymYzgWXS0Sk1q4V8/crV4oPhIqoVGI675prYNAg8cvKzz5SUjT5AX+XUbE4LCw9sJSFexbyy75fKiWV69Q6rki6gqHNhzKkxRCSwpMu+fgkdY/jx4VR5qeflv/4bNoUnnwSxo6FoCD/jk8iWb58OYMGDcLpdDKqzSju3nk3KlQkv5tMwuMJ/h5ezUdRRD7UypWwapXY7t1b+ZyQEDGPXyaikpIu+TClaPID/hZNFXF73aw5uoZFexexcM9C9uTuqXS8XWw73zRetwbd5C8pyUUlJwc+/BA++gjy8kRfbCzccw/861+QmOjf8UnqJlu3bqVv375YLBYGJAzgmaPPoFFpaP5Zc+qPlwZkF42MDFi2DH79FZYsgezsysdbtBC1m4YPh65dL0lSuRRNwMcff8xbb71FRkYGHTp04MMPP6Rbt25VnjtlyhS++eYbduzYAUDnzp157bXXTnl+VQSSaDqRfbn7fALqryN/4VHKvTmSI5IZ02EMo9uPpnFEYz+OUlLbKSqCL7+Ed96Bo0dFn1oN118PDzwAAwfWuEU3khrK4cOH6dWrF8ePH6dzVGdey30Ng9ZAy29bEndr3JkvIKkevF7YvLlcQK1eXdk7qkEDuPFGIaD69r1oc/t1XjTNnDmTMWPGMHnyZLp3787777/P7Nmz2bNnD7GxsSedP2rUKC6//HJ69epFUFAQb7zxBvPmzWPnzp00aHB25pKBLJoqklecx+J9i1m0dxE/7/uZImeR79iAJgP4V+d/MbTFUHSauuUIK7l0uFzCpuCTT+CPP8r7mzQRTuN33SWMiiWSi0Fubi6XX345e/bsoWlwU94reo8QQwhtZrcheoh84/mVwkIhnubNg59+Er+0yoiNhZtugpEjxaq8avyFVedFU/fu3enatSsfffQRAF6vl4SEBB5++GEmTpx4xvt7PB4iIiL46KOPGDNmzFk9Zk0RTRWxOW3MS5nH1C1T+ePQHz6H8nrB9RjXcRzjO4+X+U+Si0pKCkyeLFbcFRaKPoNBfC7efz907y5X3UmqD7vdzlVXXcXatWuJ08fxofND4sxxtFvYjogrA2tFV52npERM482dC/Pnl8/tg6jfdPPNcMstwtLgAgVUnRZNTqcTk8nEnDlzGDZsmK9/7NixFBQUsGDBgjNew2q1Ehsby+zZsxk8eHCV5zgcDhwOh++2xWIhISGhRommihzKP8SUTVP4avNXZNoyAVCh4uomV3N3p7u5oeUNBGll5q7k4mCzCZ+njz8W0foyLrsMHn4Ybr1VJo5LLgy3282NN97ITz/9RKgmlEmeSTQNb0q7xe0I6yFXFwc0LpcQUDNniihU2S8sEGHpQYOEs+7AgecVpq7Toik9PZ0GDRqwevVqevbs6et/+umn+fPPP1m3bt0Zr/HAAw+wZMkSdu7cSdApPqlffPFFXnrppZP6a6poKsPlcbFwz0I+2/gZvx38zdcfERTBHe3vYFyncXSs19F/A5TUahQF/vlHrLibMQPKfpdER8O994roU0NZSUhyjiiKwr333ssXX3yBQWXgLeUtLou5jPZL2xPSMcTfw5OcCw4HLF0qBNSiRWCxlB9TqaBbt3IB1bWr8Ik6A1I0XYBo+t///sebb77JihUraN++/SnPq22Rpqo4lH+Ir7d8zdQtUzlqOerrvyz+MsZ1HMft7W4nwihD2pKLQ04OfPGFyH0qSxzXaMTn4V13weDBfrd3kdQQXnjhBV5++WXUqHmJl7iq4VV0+L0DphaB7VQtOQMul0geX7xYtG3bKh8PDYX+/WHAALj6amjevMr5/jotmi5keu7tt9/m1Vdf5ffff6dLly7n9Lg1MafpbPF4Pfx+8He+2vIV81Pm4/QIu2eDxsBNrW9i/GXj6duor7QukFwU3G6ROP7hh7BiRXl/VBTcfrsQUB07ytwnSdV89tln3HfffQA8zuPcknwLHX7vgDHJ6OeRSaqdY8fKV+ItWybKv1QkIUGIp6uvFt5QcWKlZJ0WTSASwbt168aHH34IiETwxMREHnrooVMmgr/55pv897//ZcmSJfTo0eOcH7M2i6aK5Npz+X7793y5+Uu2ZZar+uZRzbmn0z2M7TiWWPPJKxQlkuogJQWmTYNvvoH09PL+9u3hzjth1CixyEYiAZg/fz4jRozA6/UyhjE82OZBOvzWAUO8wd9Dk1wkFMWLx2PH48zDvWMt7n+W4962Bs/hHbgNHtxmcJvBYwZ3w3DciVEUmA30Hbqr7oqmmTNnMnbsWD777DO6devG+++/z6xZs0hJSSEuLo4xY8bQoEEDXn/9dQDeeOMN/vOf//DDDz9w+eWX+64THBxMcHDwWT1mXRFNZSiKwob0DUzZNIXpO6b7rAt0ah03tLyB8ZeN5+omV6NWSeMdSfXj8cBvv4lVd/Pnl+c+abXC9+nOO8VWJ50z6iyrV6/mqv5XUeIs4Xqu58XOL9JhSQd0UfJNcSlRFA9OZzZOZwYuV2bpNg+Px4rHY8Xttvr2RStCUdwoigdF8QJiq1KpAQ0qlRqVSgMIzyavtxiPx4bXa8PjseP12s95jDabmO6vs6IJ4KOPPvKZW3bs2JEPPviA7t27A9CvXz+SkpKYOnUqAElJSaSmpp50jRdeeIEXX3zxrB6vrommihQ5i5ixYwZTNk3hn7R/fP1J4Unc3elu7up4Fw1Cz87vSiI5V/LzRU7o11+LJPIy4uLE1N0990Bysv/GJ7n07Nu3jx5depBnyaMnPZnUexKdfu6ENlQWMa9OvF4nDscxSkqO4HAcweE4SknJURyOozgcx0oFUg7g9cPo1Gi1YaUtHI0mrMLtMDQOHdqDmWh3pVK8dhdNF+TXbdF0qanLoqki2zK3MWXjFL7b/h0FJQUAqFVqrm92PeMvG8+1za5Fq5YfXJKLw65dYvpu2jTIzCzvv/JKGD9emAsb5MxMrSY7O5tu7btxOOMwLWjB1Kun0nVBVzQmWSn6fHG58rHbd2O378Zm2+XbOhxHgLORBip0ulj0+jj0+nrodFFoNKFotSFoNCFoNMGlW7GvVusAEVESUSVVadTJWxqB8iCEmIJabUSjMaNWm9FozGg0Jt/+2ebZWgoLCQsPl6LpUiJFU2WKXcXM2TWHKZumsOrIKl9/g5AG3NXxLu6+7G5pnCm5aLhcwlB4yhSRF1r26RUVJYoFP/CAjD7VRux2O33a92HTgU3EE88P1/9A37l9UetlmsCZUBQFlyvbJ4rs9l2+fafz+Cnvp1YHYTAkYjAkEBSUgMFQ1hpiMNRHp4tDp4tGHcA/lut8Irg/kKLp1KTkpPDFpi+YtnUaOfYcQBhnDkgewPjLxjO0xVD0Grl2XHJxSE2Fr74S7dgx0adSwZAh8OijYkWyXHlX8/F4PFzf+XqWbF1CKKFMHzadQbMHodZKwVQRRVFwONIqiaKyfbc775T3MxgaYjK1xmxujcnUCpOpNSZTc3S6mBq/clqKJj8gRdOZcbgdLNizgM83fs6yQ8t8/bHmWMZ2GMu4TuNoGd3SjyOU1GY8HhF1+uQT+OWX8v527eCxx4R9gXQdr5koisK4vuOY+tdUdOiYNnwat86+FZW6Zn+ZXwiK4qWk5HCpMNpVaWrN47Ge4l4qgoIalwojIY7Efku02tr7vSZFkx+QouncOJB3gC83f8nXW74moyjD1988qjmDmw3m+ubX0zuxt4xASS4Ke/bABx+I1Xf20sU20dGiYPD994vSVpKaw3+G/IdXfnoFgElDJ/Hw/IdrfPTjXFAUL8XF+7FaN2K1bqSoaCNW6yY8HkuV56tUWozGplVEjlqg0dQ9/yopmvyAFE3nh8vj4ud9PzNl0xSWHliK2+v2HQs1hHJN8jUMazmMG1veiFFX9/6ZJReX/HzhOv7RR3DkiOjT6UQd0Mceg3P0uJX4gU9u/YSHZj6EgsKzVz/Lf5f+t1YLpnMRSCqVAZOpxUmRI6OxKWq1/EFahhRNfkCKpgvH4rDw24Hf+GnfT/y892ey7dm+Y2GGMO5ofwf3XHaPrH0nqXbcbuH3NGkS/PVXeX/fvvDkk8Lz6QILqUuqGUVRmDNuDqOmjsKFizHdxzB1zdRaJZjORSCp1UGYzR0ICelMSEgXQkI6YzK1Kl2JJjkdUjT5ASmaqhev4mV92noW7V3E99u/53DBYd+xrvW7cl+X+xjZZiRmvdl/g5TUSjZsgPffF95P7tLAZ4sWMGECjB4NRhnw9DuKovDHfX8w/PPhWLAwoPUAFm9bjEZTc20FhEA6gNW6QQqkS4wUTX5AiqaLh1fx8sehP/hi0xfMS5nnq30XZghjdPvR/KvLv2gb29bPo5TUNo4dE/XuPvsMCgtFX0wMPPigsCyIifHv+OoqiqLwzwP/MHzycNJJp2NiR/7e/TcmU80qvltcfACL5R8pkAIAKZr8gBRNl4ZsWzZTt0zls42fcSD/gK+/d2Jv7ut8HyNajyBIK5dASaoPqxW+/BLee6887ykoSJRqefxxUThdcmlQFIVt92/j1s9uJYUUGkU34p+d/xBbQwoOKopCQcEKUlNfpaDgj5OOS4HkH6Ro8gNSNF1avIqXZQeXMXnjZBakLMCjeACIMkZxZ8c7+Vfnf9EsqpmfRympTbjd8OOP8NZbsHGj6FOpYOhQkfd0+eXS7+liongVdt+3m/FTxrOa1YSbw1m3aR3Na4BqVRSFvLzFpKb+F4tlNSBWsAUHd5YCKQCQoskPSNHkP9Kt6Xy56UumbJrCUctRX/9Vja9iXKdxDG4+mFCD/JtIqgdFgZUr4e23het4Gd27wxNPiFIt2sA1P66RKB6FlHtSeG7qc8xnPgatgWUrllUqsB6IKIqXnJz5pKa+SlHRZkCsaIuPv4fExKcICmrk5xFKIEBE08qVK+nVqxfaEz493G43q1evpm/fvtUysEBBiib/4/F6WLx/MZM3TOaXfb+glNZE0mv0DGgygOGthjO0xVCiTdF+HqmktpCSAu++C998Aw6H6EtKEtN248ZBcLBfh1cr8Lq97LlrDx9+9yGf8ikqlYpZs2Zx0003+Xtop8TrdZCZ+R1HjrxFcfEeANRqMw0a3E/DhhMwGOL9PEJJRQJCNGk0Go4fP37SXHNubi6xsbF4PJ5qGVigUPaiX7d6NR3j4mhrNtPGbKaFyYRBrlW+5KQWpPLFpi+YtWsWe3P3+vrVKjV9G/VlRKsRDGs5jIahDf04SkltISsLPv5YtNxc0RceLswyH35YmmWeL16Xl5QxKcycMZOXeRmAd955hwkTJvh5ZFXjdltIT/+cY8few+lMB0CrDadBg4do2PAxdLooP49QUhUBIZrUajWZmZnEnLDEZO/evXTp0gWLpWqn0ppK2YvOTz+BuXwZvAZobjLRxmwWQspkoq3ZTFOjEa0UUxcdRVHYnbObubvnMnf3XDZnbK50vFuDbgxvOZzhrYbLHCjJBWO3i6jTu+/Cvn2iT6cTJVomTID27f07vpqE1+ll1+27+OPHP3iSJ3Hh4pFHHuH9998POC8mlyuXo0ffIy3tIzwesdRSr69PQsIE4uPvRasN8fMIJafDr6Jp+PDhACxYsIBBgwZhMBh8xzweD9u2baNFixb8+uuv1TKwQKHsRX9j1y4OqNXstNnYYbNReIqIml6loqnRSDOjkeYmU6VtvF4fcB8KtYVD+YeYlzKPubvnsvroat8UHkDb2LY+AdU+rr38G0jOG68XFi2Cd96BVavK+wcMEEnjAwbIpPHT4XV42TlyJ5sXbOYhHsKKlWHDhjFnzpyA8mJyOrM4evRd0tI+wuu1AWA0tiAx8Wni4kahVhvOcAVJIOBX0XTXXXcBMG3aNG655RaMFZzg9Ho9SUlJjB8/nujo2pVXUtWLrigK6U4nO2w2n4jaWdpsXu8pr2VWq2lmMtHCaKR9cDDtzWbaBweTYDDIL/Jq5Lj1OAv2LGDu7rksP7y8UgmXJhFNfAKqe8PuqFUyKig5P/75R4inOXOEmAJo21Z4Pd1xB4TIIEQlPCUedo7Yyf5f9vMQD3Gc43Tv3p0//vgjYLyYHI4Mjh59i/T0yXi9onhhcHBHGjV6nujoYajk50WNIiCm51566SWefPJJzOa64dh8Li+6V1E4UlLC3uJi9hUXs9du920Pl5RwqmyvMI2G9sHBtCsVUe3NZjoGB2MMoF9eNZW84jx+2vsTc3fPZcmBJZS4S3zH4oPjubHljQxvNZy+jfqi08glwZJz59AhUabliy/AJoISBAcLl/H774d27fw7vkDAY/ewY9gO0n9L53HV4+xR9pCcnMyaNWtOSvXwBy5XAampr5Ke/jFer/iMCAnpQqNGLxAVdb38UVtDCQjRVNeorhfd6fVyqKSEvXY7u+12thUVsc1mY7fdjruKP4FWpaJjcDA9Q0PpERpKz9BQkoKC5D/vBWBz2vh1/6/MTZnLoj2LsDqtvmPhQeFc1+w6bmhxA4OaDpJWBpJzpqAApk2DTz+FPXvK+3v3FuJpxAgw1MFZHY/Nw/Yh28ldnsvzmudZ41lDVFQUa9asoVkz/+Yber0u0tM/4/DhF3G7RaZ/aGgPGjV6gcjIa+TnbQ0nIERT48aNT/tGOnjw4AUPKpC42JYDTq+XFLud7TabT0httlrJdLlOOjdOpxMCKiyMHqGhdA0JwSSjUeeFw+3gj0N/8OPuH1m4Z2GlIsJ6jZ4rG1/JDS1uYGiLodQPkUukJGePosDy5UI8zZsHZemPMTEwZgzcdRe0aePfMV4q3FY326/fTsGqAj7QfcB813yCgoL4448/6Nmzp9/GVWZKeeDAE9jtKQCYTK1JTn6byMhBUizVEgJCNE2aNKnSbZfLxebNm/n111956qmnmDhxYrUMLFDwh0+ToiiklpSw1mJhjcXCWouFzUVFuE74U2lARKPCwugpo1HnjcfrYe2xtSzYs4D5KfPZl7ev0vGu9btya9tbGd1+NDFm/08lSGoO6eli2u7zzyEtrby/a1dRruW22yAiwm/Du6i4C91su3YbljUWZgXN4tMS4cU0e/ZsRowY4bdxFRXt4MCBCeTn/waAThdNUtLLxMePR62W7qW1iYAQTafi448/ZsOGDXz99dfVcbmAIVDMLYs9HjYVFQkhVVjIGouFdKfzpPPidDquCA9ncFQU10ZGEq3X+2G0NRdFUUjJSWHBngUs2LOAtcfW+o7p1DpubHUj93S6h6uaXCWTyCVnjdsNv/wCX38t3EvcpWsT9HpRrmXsWLjmGmFjUBtw5bvYds02rOutrDCv4CXbSwC89957PPbYY34Zk9OZxaFD/+H48SmAF5VKT8OGj5KY+Bw6XbhfxiS5uAS0aDp48CAdO3astT5N/hZNJ6IoCkcdDtaUiqjVpdGoivlRKqBHaChDoqIYHhNDiwBZoVKTyCjKYN7ueXy5+Us2Ht/o628U1oi7O93NXZ3ukkaaknMiOxu+/14IqG3byvtjYoTv09ix0LFjzbUucOW62DpgK0Wbi9gRuoMnip/A6XLy2GOP8d57713y8Xg8JaSlTSI19b94PCKPMTp6BMnJb2A0Jl/y8UguHQEtmt58800++eQTDh8+XB2XCxgCVTRVRbHHwwarlSV5efyUm8vWsqU8pbQ2mRgeE8Pw6Gg6BgfLabxzZPPxzXy5+Uu+2/YdhQ5hdKdWqRncfDCPdHuEKxtfKV9TyTmxdaswzfz+e8jMLO9v21bkP40aVbNcx0uOlbBt4Dbsu+2kRabxkOshCqwFDB8+nFmzZl1SLyZFUcjKmsmhQ89SUnIYgODgzjRt+h7h4X0u2Tgk/iMgRFOnTp0qfTEoikJGRgbZ2dl88skn3HvvvdUysEChJommEzlaUsLPubnMz8lhWUFBpShUgsHA0KgohkRH0y88XJaEOQeKXcX8uPtHvtj0BX+m/unrbxvblke6PcKo9qMw6WRUT3L2uN2wdKlYfbdgQXm9O7Uarr4aRo6EgQOhYQAHNe177WwdsBXHEQeWehYeVj/MkfQj9OjRgz/++KOSt9/FprDwb/bvn4DV+g8Aen0DmjR5jbi4O6TXUh0iIETTSy+9VOm2Wq0mJiaGfv360bJly2oZVCBRk0VTRQpcLn7KzWVeTg6L8/IormDCGazRMCgykqFRUVwXFUVUbUmsuASk5KTw4boPmbZ1GjaXiOxFGiMZf9l4Huj6AIlhiX4eoaSmUVAAs2bBt9/CX39VPtaypXAdHzAA+vULHANN62Yr267ZhivbhSfZwwT9BLbt3kbTpk1ZvXr1JfNistv3c/DgRHJyfgREMd3ExIkkJExAo5E/ZOoaASGa6hq1RTRVpNjj4Y+CAhbm5LAoN5fjFRLK1cDlYWEMiYpiSFQULUwmOeV0FhSUFPD15q/58J8POVRwCACNSsPwVsN55vJn6Fy/s59HKKmJHDggpu5++QXWry93HgfQaqFHj3IR1bWr6LvUFKwqYPvg7XgsHvQd9Pw7+N+s+HsFcXFxrF69miZNmlz0MbhceaSmvkJa2scoigtQEx9/D0lJL2Ew1Lvojy8JTAJGNHk8HubNm8fu3bsBaN26NTfccANaf/zHXmRqo2iqiFdR2Gi1sjA3l4U5OWw7IQ8qOSiIIdHRDImKok9YGDo5jXdaPF4PP+/7mQ/WfcCyQ8t8/dckX8NzfZ6jb6O+fhydpCaTny/8n377TbQDByofDwuD/v2FgOrdW0SlLvbi2Zyfcth18y68JV5C+oTwRvQbzJ43m5CQEP788086dep0UR/f63WSlvYxqamv4HbnAxAZeS3JyW9hNtcRMyzJKQkI0bRz506GDBlCZmYmLVq0AGDv3r3ExMSwaNEi2rZtWy0DCxRqu2g6kcPFxfyUm8ui3FxWFBTgrPD2CNVouD4qiptjYhgUGSnLvJyB7ZnbeXP1m0zfPh2PIhwOL0+4nOf6PMe1Ta+VETzJBXHokBBPS5fCH38IUVURnQ5at4YOHYSZZsuW0KIFNGlSPdYGmd9nsnvsbvBA5PWRfNHoCz785EN0Oh2//PILV1999YU/yClQFIWcnLkcOPAMJSVCPZrN7UhOfofIyAEX7XElNYuAEE09e/YkJiaGadOmEVHqypafn8+dd95JdnY2q1evrpaBBQp1TTRVxOp281t+Potyc/k5N5fsCi7lZrWawVFR3BIby7VSQJ2Wg/kHefPvN/l6y9c4PWIqtEv9Lrza/1UGJg+U4klywXg8sHGjEFHLlon9U7m/aLWQnFwuoipuIyPP7vGOfXiM/Y/sByDujjgWtl7IxOeEsfH06dO59dZbq+NpVYnFsp4DByZQWCgSvvT6ejRu/Cr16t2JSiU/hyTlBIRoMhqNbNiwgTYn1AHYsWMHXbt2pbi4uFoGFijUZdFUEa+isM5iYU52NnOyszlStrwHkUg+tFRAXRMRQZAUUFWSbk3n3TXv8umGT7G7RAX1Pol9ePXKV+W0naRaURRITRWWBlu3wu7doh7enj1gt5/6flFR0KgRJCaKbcX9hASIjlY4+moqh188DECDhxuw+rLV3HnXncDFNa8sKUnl4MHnyMr6AQC12khCwpMkJDyNVht8UR5TUrMJCNHUoUMH3nvvPa688spK/X/88QePPvoo27dvr5aBBQpSNJ2Moiist1qZnZ3NrKysSgIqRKPhhuhoboqJoX94OKG1MM/tQsmyZfG/v/7HJ+s/weERr92AJgN4pf8rdG/Y3c+jk9RmvF5RziUlRQioittjx05/XxUKD6v3c6NX1IPZ2D6Jf1rsZs6PQ/F63Ywd+xTvvPMmkZHVa8zpdls4cuR1jh59D0VxACri4sbQuPGrBAUFsAeDxO8EhGj65ZdfePrpp3nxxRfp0aMHAGvXruXll1/mf//7H7179/adWxtEhhRNp0cpjUDNys5mdnY2xyoIKK1KRfeQEPqEh9MzNJQeoaHEyrIuPtIsafx31X/5YtMXuLxi6vP6ZtczsfdEeif2PsO9JZLqpahIJJcfOSKiVBW3xw57GZOxhwEIB85JNGU+x4CrADtwBzANUGM0inp6oaEiOT00FMzm8mYyiW1wsDgvMlK0qKjyfbMZQCEz8zsOHnwapzMDgPDw/iQnv0NIyMVNMJfUDgJCNKkrrJ4qy8Uou0TF2yqVCk9Zee8ajBRNZ49XUVhrsTAzK4tf8vLYX8VUbZOgIHqUCqgeoaF0DA6u8yvyDuUf4pWVrzBt6zS8ilhT3iuhF0/3epohLYbIGncSv+Ip9rDrll3k/pQLGlA/14p1ITm88EIfiovziY29hgYNFpKWpicrq3oes2XLzTz66MO0bPk3APn5zdi06R3s9sFERqp84qpii4sTgkwiKSMgRNOff/555pNKueKKK855QIGGFE3nz+HiYpYVFPiKDO+y2znxzRai0TA4Korh0dEMiowkuA5P5+3L3cfbq99m6tapvoTxltEtearXU4xqNwqD1uDnEUrqGq4CFztu2EHhykLUQWpaz25NUdsiLr/8ctLT0+nRowe///47ZhEaoqQEjh8XBp2FhSIZvbAQbDaRS2WzlbeiIrHiLy+vvDmdeYwe/X8MHvwZGo2X4mIz33zzPD/++Bgu15nf/+HhouxMgwaVtzExEB0tWkyMiGrJoHftJyBE05EjR0hISDhpxY+iKBw9epTExNrlgCxFU/VR6Hbzj8XC2gotr6zcOxCkVnNdZCS3xsZyfVQUpjqaUJ5RlMEH6z7gk/Wf+Grc1Q+pz2PdH+NfXf5FqEG+DyUXH8dxB9sGbcO2zYYmVEO7Re1wtHDQu3dv9u/fT5s2bVi5ciWRZ7vk7jQoiofjx7/g4MF/43bnAqDX34rD8RZ5eQ0rCauKLTe3fFtScm6PGRZWWUiVbZOSoFkzaN5cJL/X8UB4jSYgRJNGo+H48ePExsZW6s/NzSU2NrZWTMlVRIqmi4dXUfjHYmFuTg5zs7M5UOFTz6xWMzQ6mpGxsQyKjKyTtfEsDgtTNk7hvbXvkWYVybehhlAe7Pogj/V4jFhz7BmuIJGcH8UHitk6cCslB0vQxelo/2t7vI299O/fn82bN5OUlMRff/1FgwYNLvixCgvXsG/fQxQVbQLAbG5L06YfEhHR76yvoSgiqpWeLhLd09LK948fh5wc0bKzhcCq6Kx+OoKCoGlTaNWqvLVuLQRVUNC5P1fJpSUgRJNarSYzM/OkWkKpqam0bt0a2wmO0jUdKZouDYqisLWoiJnZ2czIyuJwBQEVrNFwTUQEQ6KjuS4ykpg6Fld3epx8v+173lr9FrtzhAu/UWtk/GXjmdBzAo3CG/l5hJLahHWzlW3XbsOV6SKoSRAdlnaA+jBo0CBWrlxJbGwsf/31F82aNbugx3E4Mjh4cCKZmdMA0GjCaNz4ZerXfwC1+uJN03u9YvowO7tcSJWJqsxMOHgQ9u4VSfEVrOkqoVZD48aVhVTZvvyaCBz8KpomTJgAwKRJkxg/fjymChl3Ho+HdevWodFo+Pvvv6tlYIGCFE2XnjJLgxlZWczMyiK9Qm08FdDCZKJrSIivdQwOrhPeUF7Fy8I9C3lt1WusT18PiPp2I9uO5KleT9GxXkf/DlBS48lfkc+OG3bgsXgwdzDT/tf2aKI1jBgxgoULFxIaGsqKFSsuqDyK1+siLe0jDh9+EY9HOHDWqzeOJk1eR68PnOip2y1WDqakCJ+rsrZrlxBdp6J+/arFVGxs9VoxSM6MX0VT//79AZEI3rNnT/QVfu3r9XqSkpJ48sknL/jXR6AhRZN/KauNt6i0tMuWoqKTztGqVLQ1mysJqTZmc61dlacoCssOLeONv9/g94O/+/oHNBnAs72fpV9SP+kyLjlnsudls+u2XSgOhbC+YbRb2A51iJpx48Yxbdo0goKCWLJkCX37nr8Ra37+H+zb9zB2+y4AQkK60KzZR4SG1hx/MkUREamKQqpMTB0/fur7RURUnuZr2VK0pCSoA7/5/EJATM/dddddTJo0qc4ICCmaAossp5MNVivrrVbWWyyst1rJqiKGHqRW0yk4mK4hIXQJCaGd2UxLk6nWRaQ2Hd/E26vfZtbOWb76dj0a9uC53s8xuPlgKZ4kZ0X6lHT23rcXvBA9LJpW01uhNqh58skneffdd9FoNMydO5ehQ4ee1/VLSo5w4MCTZGfPBkCni6Zx49eJjx+HqhZZahQUVI5M7doltocOCbFVFXq9SDwvE1EVS9vIr5wLIyBEU11DiqbARlEUjjoclUTUBqsVSxULEtRAstFIW7OZNmYzbUwm2prNNDeZ0NfwqNThgsO8vfptvtj0hc9lvF1sO57t/Sy3tLkFjbp2iUVJ9aAoCodfPEzqy6kA1Lu7Hs0nN0etVfO///2PZ599FoCpU6cyduzYc76+x1PCsWPvkJr6Gl6vHVDToMEDJCW9jE4XUZ1PJaApLhZ5UmVCqsyJfe/e06/6i48vF1MVBZVc1Xd2BIRoOrF8yon88ccfFzSgQEOKppqHV1HYV1wsIlIWC5uKithps1WyN6iIVqWiWamYams2095spn1wMElBQahrWKQmoyiD99e+zyfrP8HqtAKQHJHMYz0e486OdxKslzW6JAKvy8vee/eSMVW4bTd6vhFJLyWhUqmYMmUK9957LwDvvPOOL6f1XMjN/Zl9+x6lpOQAAGFhvWnW7COCgztU35Oo4Xg8Im+qrJRNxbI2GRmnvp/RKFbwnSimmjcvc1OXQICIpscff7zSbZfLxZYtW9ixYwdjx45l0qRJ1TKwQEGKptqBoihkOJ3stNnYabez02Zjh83GTputyqgUQKhGQ4/QUHqGhtIrLIyeoaGE1BDzzfzifD5e/zHvr32f3GLhexNqCOWeTvfwULeHaBzR2M8jlPgTt8XNzpt2kv9bPmig+eTm1L+nPgBz5sxh5MiReL1enn32WV577bVzunZR0Q4OHnyGvLxfANDr40lOfpvY2NvkdPE5UFhYtZjat+/Uq/pAFFhu1w4uuww6dxbbhg3rZhJ6QIimU/Hiiy9SVFTE22+/XR2XCxikaKrdKIpCmsMhBJTdzvaiIraViinnCf8aWpWKHqGhXB0RwVXh4XQPDQ34ZHOb08a0rdOYtG4Se3P3AqBWqRnaYigPd3uY/kn95RdZHcOR7mDbdduwbbWhNqlpM7sNUddFAfD7779z/fXX43Q6GT9+PJ999tlZvz8cjjQOHXqBjIyvAS8qlZaGDR+nUaPn0WpDLuIzqlu43SJHqipBlZNT9X1iYsoFVOfOoiUm1n4hFdCiaf/+/XTr1o28vLzquFzAIEVT3cTl9bLTZmONxcJqi4W/CgsreUeB8I+6IiyMQZGRDImOplEAu915FS9L9i9h0rpJLDmwxNffJqYND3V7iNHtR2PWy7h+bce208a2a7fhOOpAF6uj3c/tCO0iPtf++ecfrrzySmw2GyNGjGDmzJlozmLhhNtt4ciRNzl27F28XlFvMjp6BE2avIbJ1PyiPh9JZXJzhXjavBk2bYKNG2HnTjENeCJRUZWjUZ07C++p2iSkAlo0ffvttzzzzDOkp6dXx+UCBimaJGUcKi5mWX4+v+fns6yggJwTYuTtzWaGREUxJDqariEhAZsPtTt7Nx+v/5ipW6Zicwkz2jBDGOM6jePBrg+SHJns5xFKLgYFfxawY9gO3AVujC2MtF/cHmNjIwC7d++mT58+5ObmctVVV/Hzzz9jMJy+1pvX6yQ9/XNSU1/C5RIhjtDQy0lOfouwsJ4X/flIzo7iYti+XQioMiG1Y0fVU3zh4ScLqeTkmpt0HhCiafjw4ZVuK4rC8ePH2bBhA88//zwvvPBCtQwsUJCiSVIVXkVhW1ERS/Pz+Sk3l78LC6lYmSFOp+P6qCiGRkdzTUREQFodFJYUMnXLVD5a/xH78/YDoELFdc2u4+FuDzMgeQDqWrQcvC6TOSOTlLEpKE6F0F6htFvYDl2UDhD1RC+//HKOHTtG165dWbZsGSEhp55OUxSF7OzZHDr0b4qLxfvGaGxOkyZvEB19g5zurQE4HEI4bdxYLqa2bYMKPsI+QkOhUychoHr2hMsvF6v6agIBIZruuuuuSrfVajUxMTFceeWVDBw4sFoGFUhI0SQ5G3JdLhaXGnD+mpdXKbk8VKNhWGkdvasjIgLO3qBs6u7Dfz5k8f7Fvv6W0S15tPujjOkwBpPOdJorSAIVRVE4+s5RDj51EIDoEdG0+rYVGqMQ8VlZWfTt25c9e/bQsmVLVq1aRXR09Cmvl5+/jIMHJ2K1bgBAp4slKelF4uPvQa3WXfwnJLloOJ3CDqGikNq6tWpLhORk6N27vLVoEZjTegEhmuoaUjRJzhWn18uqwkIW5uTwY3Y2aRV+vkVotdwcE8Pd8fF0DQkJuF/l+3L38fH6j/l6y9dYHKLERaQxkn91/hcPdn2QBqEXXqBVcmlQPAr7H99P2oei2HODRxvQ9J2mqDTiPZefn0///v3ZunUrCQkJ/P333yQkJFR5Lat1MwcPTiQ/fykAGk0wCQlP0rDhBJnkXYtxuYS31KZNsH49/P23iEidqBqio+Hqq2HQILjmGqhXzz/jPZGAEk0bN25k925RPLRNmzYXVIsokJGiSXIheBWF1YWFzMzOZnZWFpkVEgnamc3cEx/PHXFxROoC61e6xWHh681fM2ndJA4VHAJAq9ZyS5tbeLDrg/Rs2DPgBJ+kHHehm1237SJvsViYk/xuMgmPlwsiq9XKgAEDWLduHbGxsaxcuZIWLVqcdJ3i4gMcOvR/ZGXNAECl0lG//n00avR/AVUnTnLpKCyENWtg1Sr46y9Yt05M91WkUye49lohonr2BH85tQSEaMrKyuLWW29lxYoVhIeHA1BQUED//v2ZMWMGMTEx1TKwQEGKJkl14VEU/iwoYGpGBrOzsynxiiwog0rF8JgY7omPp194eEAlkHu8HhbuWch7a99j1ZFVvv72ce25v8v9jGo3ihCDjDQEEsUHitk+ZDv23XbURjUtp7Uk9uZygVNcXMx1113HihUriIiI4M8//6Rdu3aVruF0ZnL48CscP/4ZiiJMYWNjb6dx41cwGptc0ucjCWwcDhGF+vVX0TZurHw8LAwGDoQbboDrrhM1+C4VASGaRo4cycGDB/nmm29o1aoVALt27WLs2LE0bdqU6dOnV8vAAgUpmiQXg3yXix+yspiSns5Wm83XX1+v56aYGG6OiaFXWFhACaiN6Rv5eP3HTN8xnRK3SHQI0Ycwuv1o7u96P21j2/p5hJKCPwvYMWIH7lw3+vp62i1sR0jnclHrdDoZNmwYixcvJiQkhGXLltG1a1ffcbfbwtGj73D06Dt4veJ9GRFxDU2avE5ISO2cTZBUL5mZsHSpEFBLlggbhDK0WrjiChg2DG666eJP4wWEaAoLC+P333+v9I8GwuNj4MCBFBQUVMvAAgUpmiQXE0VR2FRUxBfHjzM9M5PCCgnkDcoEVGwsPUNDA0ZA5RXnMW3LNCZvnOwzzATok9iH+7vcz/BWwzFoT79cXVL9HP/yOHvv24viVgjpEkLbBW0x1C//O7jdbm699VZ+/PFHjEYjS5YsoU+fPgB4PDbS0j7l6NE3fPYBISFdadLkf0REnL50lkRyKjwe2LABFi2C+fOFZ1QZajVceSXcfjvceKOwO6huAkI0hYSEsGrVKjp27Fipf/PmzVxxxRVYLJZqGVigIEWT5FLh8Hr5LS+PWdnZLMjJqbQCr0xA3RIbS48AEVCKovDHoT/4dMOnzE+Zj0cR440xxXBXx7sY1X4U7WLbydyni4zX6eXAkwd8Cd8xI2No+VVLNKZymwuPx8Odd97Jd999h16vZ9GiRQwcOLCCWHoTlysbAKOxGY0bv0ZMzAj5t5NUK/v3w4IFMGcOrF1b3q/Xw/XXwy23iO1pHC/OiYAQTTfccAMFBQVMnz6d+vVFraK0tDRGjRpFREQE8+bNq5aBBQpSNEn8gcPrZWleHrNPIaBujo3l5piYgBFQaZY0vtj0BZ9v+px0a7nBbeuY1tzW9jZubXsrTSOb+nGEtZOS1BJ23rIT6z+iOHPSi0k0+k+jSmLH6/Uyfvx4vvrqKzQaDT/++CODB199klgKCmpCo0bPExc3StoHSC46Bw/CjBnw/ffC6qCMoCCRQH7TTSKZPDLy/B8jIETT0aNHGTp0KDt37vQtTz169Cht27Zl4cKFNGzYsFoGFihI0STxN2UCqiwCZa0goBoaDCICFRND9wAQUG6vm0V7FvHttm/5ed/POD3ldgtd6nfhtra3MbLNSGldUA3k/JRDypgU3PlutBFaWn3biqjroyqdoygKDz74IJ9++ilqtZoffphKz56ZUixJAgZFEY7lM2bA7NkiGlWGWg3duwvxdO21wqX8XGzuAkI0gfhH/P3330lJSQGgVatWXH311dUyoEBDiiZJIFHi8bA0P98XgTpRQN0cE8OtsbEB4QFVWFLIvJR5TN8xnWUHl/mm71So6NuoL7e3u50RrUYQZYo6w5UkFfG6vRz6v0McfeMoACHdQmgzqw1BjSrXPlQUhccff5xJkyahUql4771b6dLl9wpiKZlGjf5PiiVJwKAowgdqzhyRA7VjR+XjsbHCB2rQIBgwQBQiPh0BI5rqElI0SQKVEo+HJfn5zM7KYkFuLkUVBFTjoCBujY1lZGws7c1mvwuoLFsWc3bNYfqO6fx15C9fv1atZVDTQdze9naGthgqiwafAUe6g1237qJwVSEADR5pQPJbyaj1lX9+K4rCxIkTefPNNwGYODGYa64pAiqKpTtQq/1koCORnAVHj8LixaL9/jsUFZUfU6lE5GngQCGkevYUuVEVkaLJD0jRJKkJlAmomVlZLMzJweYtr4SXFBTE4KgohkRFcUV4OAY/l3E5UniEGTtmMH3HdLZkbPH1G7VGBjUdxIhWIxjcfDBhQWH+G2QAkrMghz3j9+DKdqEJ0dDiqxbE3lS1weS///0Er732LgCPPw5Dh0qxJKnZOJ3CkXzxYmFlsG1b5ePBwWI13jXXCCHVtKkUTX5BiiZJTcPu8fBzbi4zsrL4JS/PZ6IJEKzRMDAigiFRUVwfFUXMiT/NLjG7s3czfcd0ftj+AwfyD/j6dWodVze5muGthnNDixuIMdcu09xzwV3oZv9j+8mYmgGAuYOZNrPbYGp2cj1Aq3Ur//73eD78cD0ADz0Ed9zRgsTEiVIsSWoVx4/Db78JAfXbb5CdXfl4kybQv7+FL7+UoumSIkWTpCZj93hYlp/PotxcfsrN5XiFOngqoEdoKIOjohgcFUU7P07jKYrC1syt/LjrR+amzGVXdvlyGrVKTd9GfRnRagQ3tryxTiWR5y/PJ+XOFBxHHKCChKcTaPxSY9SG8mihy1VAVtZ00tK+4K23NjFnjuh/9NGG/Pvfk4iOvgGVSnOKR5BIaj5eL2zZIgTUkiUiIuV2A1gAKZouKVI0SWoLXkVhk9XKotxcFuXmsrliggCQaDD4BFT/8HCCNP77ok3JSWHu7rn8uPtHNh3fVOlYj4Y9GN5yOCNaj6BJRO0s6eEp9nDw2YOkTRLeS0FNgmg5rSXhvcMBUBQvBQV/cvz4l+Tk/IjLVcLbbwsXZoDXX3+QZ5750O+5bBKJP7BaYcUKWLTIwpQpfhBN52JYWduEhRRNktrKsZISfs7L46fcXH7Pz680jWdSq7m6dBpvSHQ0cX6cxjtccJi5u+cyd/dcVh9djUL5R1aHuA6MaDWC4a2G0zqmda0QCZb1FlLGpGBPsQNQ/776NHmrCdpgLSUlx8jImEpGxteUlBwERK7H66+HsGKFFY1Gw1dffcWYMWP8+RQkkoDAbzlNarX6rD+MPBVW8FwMPv74Y9566y0yMjLo0KEDH374Id26dTvl+bNnz+b555/n8OHDNGvWjDfeeIPrrrvurB9PiiZJXcDu8bC8oIBFOTn8lJtL2gnTeN1DQxkSFcXAiAg6hYSg8ZM4OW49zryUeczdPZcVh1f4bAwAWkS1YESrEdzR/g5axbTyy/guBK/LS+p/U0l9NRU8oI/X0+LLFkRcE0xOziIyMr4kL28pIMStRhNCcPBNPPHETpYv/we9Xs/MmTMZNmyYX5+HRBIo+E00/fnnn779w4cPM3HiRO6880569uwJwJo1a5g2bRqvv/46Y8eOrZaBVcXMmTMZM2YMkydPpnv37rz//vvMnj2bPXv2EBt78iqS1atX07dvX15//XUGDx7MDz/8wBtvvMGmTZto2/bsiotK0SSpayiKwtaiIhbl5rIwN5cNVmul45FaLVdGRHB1aUs2Gv0yzhx7Dov2LOLH3T/y28HfKhlpdmvQjTs73MmtbW8lwngJy6qfJ7ZdNnaP2U3RRjFlGn1LKBEv7qTAu4i8vKV4PIW+c8PCriA+fhxa7VUMHXoza9aswWw2s2DBAq666ip/PQWJJOAIiNVzV111Fffccw+33XZbpf4ffviBzz//nBUrVlTLwKqie/fudO3alY8++ggQ5QESEhJ4+OGHmThx4knnjxw5EpvNxk8//eTr69GjBx07dmTy5Mln9ZhSNEnqOmkOB4tycvg1L4/lBQWVSrqA8IS6OiKCK8LDaWs208JovOT5UBaHhZ/3/sz0HdP5Zd8vvgiUXqPnhhY3MLbDWK5peg3aAFs9pngVjk06xsFnD6I4FNRhLnRPz8TR68tK5+n18dSrdyf16o3DZGpKRkYG11xzDdu2bSMiIoLFixfTvXt3Pz0LiSQwCQjRZDKZ2Lp1K82aNavUv3fvXjp27Ijdbq+WgZ2I0+nEZDIxZ86cSuHnsWPHUlBQwIIFC066T2JiIhMmTOCxxx7z9b3wwgvMnz+frVu3Vvk4DocDh8Phu22xWEhISJCiSSIB3F4v661Wfs/P57f8fNZYLLhP+AhRA8lGI61NJlqZzbQymWhlMtHSZCJEe/FFS2ZRJj9s/4Gvt3zN9qztvv44cxyj2o1ibMextI9rf9HHcSYK9xwmZdxuileXRuq6rYOn3oLoXACCgy8jKup6IiOvIzS0q28F3OHDhxkwYAD79++nXr16LF26lHbt2vnradQZ7B4POS4X2S4XORVattNZ+bbLRbHXi0alQgNoVCq0KpW4XbZf2l/pGPj2tSoVOpUKnVottioV+gr7BrWaYI2GkLKm1ZbvazSElt4OOofUmtrIxRBN5/wJlpCQwJQpU3xOs2V88cUXvlp0F4OcnBw8Hg9xcXGV+uPi4nzlXE4kIyOjyvMzMjJO+Tivv/46L7300oUPWCKphWjVanqGhdEzLIznk5IocrtZWVjIb/n5rLdY2Gm3U+B2s6+4mH3FxSzIza10/4YGA61MJtqYzbQrbW3MZkzVGJmKC47j8Z6P81iPx9iSsYVpW6fx/fbvybRl8u7ad3l37bt0rNeRsR3Gcnu724k1V20QWd14PMUUFq4kN2cJWV/ZcH04FOxmCCqG+z9Fc+PfREUNJDLyWiIiBmIw1DvpGrt372bAgAGkpaXRuHFjfvvtN5KTky/J+GsrHkXhUHExh0tKOOJwkFq6TXc4Komk4goLJWoKGjhJUJ3t7Qitlni9nji9Hp2fDXEDiXMWTe+99x4jRoyoFA7+559/2LdvHz/++GO1D/BS8+yzzzJhwgTf7bJIk0QiOZlgrZbroqK4LkrUj1MUhUynk112OzttNnbb7aLZbGS6XBxzODjmcPBbfr7vGiqgUVAQjQwGsS1rpbcTg4LOy8VcpVLRKb4TneI78daAt1i8fzHTtk5j0Z5FbMnYwpaMLTz121Nc2/RaxnYYy+DmgzFoDdX10uDxlGC1rqewcBUFBcspKFiFkhoL7zwB2zoAoG5/mHrvZxB32XOVoklVsWHDBgYNGkRubi6tW7dm6dKlNGhQdzyrLhRFUchwOtlms7G1qIhtRUXssNlIsdtxnOWEi16lIlqnI0anI7q0xej15fulW7NGg0dRcCsKntLmVhQ8cNr+sttuRcFV1rxeXIqCs8J+iddLkceDtay53eX7Ho+vpJIHKHC7KRCmReeFCojR6ahvMFBfryderyeh9P8zMSiIRIOBhgaDXy1KLiXnLJquu+469u7dy6effuqL8AwZMoT77rvvooqL6OhoNBoNmZmZlfozMzOpV+/kX2QA9erVO6fzAQwGAwZD9X1wSiR1CZVKRT2DgXoGA1dGVE7Azne52G23s8tmY4fNxvbSlu1ycbikhMMlJVBYWOV16+v1JAUF0TgoiMZGo28/KSiIBIPhjL+EdRodQ1sMZWiLoeTac5mxYwbTtk5jffp6Fu1dxKK9i4g0RnJHuzu4+7K7z2v6zu0uwmJZQ2HhSgoKVmKxrENRSqf6XVqYORK+GQsuHSqTl6SXG5D42BWoNGeePvnzzz8ZMmQIVquVrl27snjxYqKiZKHjqlAUhWyXS0Q77Xa222w+oZTtclV5nyC1mialAj2xVAw0NBgqiyOdjmCNpkZMd3kVpVxUnSCozvZ2rstFhtOJB8hyuchyudhymseM0+lobDTSssJ0fCuTicZBQWhrUaSqRplbdu/enW7duvHhhx8CIhE8MTGRhx566JSJ4Ha7nUWLFvn6evXqRfv27WUiuEQSIGQ6neyz20ktnRrxtdLbZ5oWUQNNjUY6BgdXavX0+jN+we3K3sU3W7/h223fkm5N9/V3qd+FuzvdzW1tb6uyBp7HU4zNtg2rdUNp24jNtpMyO4AydLpYzEduxv7S9Tj3iNylyEGRNPu0Gcaks1t1+PPPP3PTTTdRUlJCv379WLhwISEhIWd139qMR1E4UFzMzlIRvttu9wmlwlNY36iBZkYjHYKDaR8c7JseTgoK8puNRiDjVRRyXC7SHQ6OO52kO52kOxwcdTg4UmE6036a/1G9SkUzo5FWZjMdg4PpHBxM55CQS1LCKSASwQFWrVrFZ599xsGDB5k9ezYNGjTg22+/pXHjxvTu3btaBlYVM2fOZOzYsXz22Wd069aN999/n1mzZpGSkkJcXBxjxoyhQYMGvP7664CwHLjiiiv43//+x/XXX8+MGTN47bXXpOWARFJDKIsalEWiDpWU+PJPDpX2OU/xERaj050kpJobjVX+6vV4Pfx28De+3PwlC1IW4PKKiIRRa+SW1jdyZ+u+NAv2YLVuwmrdgM22AzH5URmDoRHh4X0JC+tDiLY3Gf/VkvZhGiigi9bRdFJTYm+LPetoxeTJk3nooYfweDwMGTKEmTNnYvSTxYO/UBSF404nW0un07ZXEEklp/myTjAYaGY00sZspr3ZTIfg4GrPn5OIv0+e201qSQkHiotJKZuSt9vZY7ef8kdPgsFA55AQuoeE0CM0lC4hIQRX80KRgBBNP/74I6NHj2bUqFF8++237Nq1iyZNmvDRRx/xyy+/8Msvv1TLwE7FRx995DO37NixIx988IEvt6pfv34kJSUxdepU3/mzZ8/m//7v/3zmlm+++eZ5mVvm5qYRHh6FSqVDpao9oUaJpCbjLf1C3WmzsaWoyNf22O1U9VEdpFbTrvQXb1lrbzb7Pqy9XhfHclaxfO+nHM3+nVhtAY3NoKviX16niyEkpEuF1hmDQeQY5f6Sy97794qacUDc6DiS301GH312v67dbjdPPPEEH3zwAQBjxozhiy++QKfTnfuLVINQFIWDJSVstlrZXFTEpqIiNlutZJ5iWs2oVtO6dGFBa7OZ5kYjzYxGko1GjFIc+R2vonCkpIQUu50dNhubi4rYaLWyt7iYE4WHGmhnNtMjNJTuoaG0M5tpaTJdkJAKCNHUqVMnHn/8ccaMGUNISAhbt26lSZMmbN68mWuvvfa0K9NqImUv+k8/gdlc1qtGpdKhVutKRZTOdxtUKIoLr9eJojjxel0oihORTqdCpVKXJnuqS2+X9evQaEyo1Wa02jC02gh0ugi02vJWfju8UtNoQmrEPLtEcqmwezzsOEFIbSsqwlbpV69CfdJpRQo9NPtpo0oh1rMbjeI46XoWF6RYYa8V9hapaBDVn1vaP8jgFkPQacqFTPGhYvY/vp/cBWLVYFBSEM0/a07kwMizHntBQQG33XYbv5YWknvttdeYOHFirfsfd3u97CkuZlOZQLJa2VJUVOXUmhpoYTLR3mymbWlrFxxM46Ag1LXsdakLWNxuthQVsd5qZZ3FwlqLhaOOk//vABoZDD5R3NpkooXJRHOjkSid7oz/EwEhmkwmE7t27SIpKamSaDp48CCtW7empKSkWgYWKFQtmgINtU9olQkpg6E+RmNzjMZmmExiq9XKPAhJ3aXEkcW+3L84krea4qL1mB1bMSonJ54XYWYPLUhTt0Zl6kRMWFeaBCdxLH05c7d+zt9H//adG2uOZUz7MYxrNQ7jV0aO/O8I3hIvKq2KBo82oPFLjdGYzz7isW/fPoYMGcKePXswGo1888033HTTTdXy/P1JSamI3VRU5BNI22y2KqfX9CoV7cxmOoWEcFlwMJ1K84/ktFrtJs3h8AmoDVYrO202sk4RYQSI0GpFZLFURDUv3TYzGn3RqYDwaapXrx779+8nKSmpUv9ff/1Fkya1s+I4QK9e6QQHG1EUl6+JKFLl26CgVutLo096375AQVG8gKd0q5T2KaVRqWI8HhtudwFudz4uVz5ud3kTtwsqtPzSKJbXd87p0OvjMZlalIqpZIKCkggKakxQUBI6XXSt+yUrqbt4PPbS/KN/sFj+wWr9h5KSQwCYSxuASqXHYO6AzdCBVHUbNnia8WdxFLuLS1C8QBFQ5AEOAInUa/kmfdurcBXuYNeh+WTlrOfvqX/TaXEn6hfUByCkXwgtP26JufW5/cr67bffuOWWWygoKCAhIYEFCxbQqVOnanpFLg0eReFoSQl7SnNbyqbZdtntJ5mgAgRrNHQsFUaXBQfTKSSE1iaT9AWqgzQwGBgeE8PwmBhfX06pfckum8233VdczBGHg3y3m3VWK+tOKPMEYrVtc5OJpItQC/ecRdP48eN59NFH+eqrr1CpVKSnp7NmzRqefPJJnn/++WofYKCg0ZjR6QIrEVxRFLzekhOEVAFudx4lJUcoLt5HcfE+7PY9uFzZOJ3HcTqPU1Cw4qRrqdVmjMYmGI3NSqNTzXz7en09KagkAYuieLDZdvrEkcXyzykTtU2mloSEdCM0tBshId0IDm6PWl1uMTKudFvkdrPVZmOj1cpGq5VNRUXsstnIcDrJcAKaZtQ3PsUzC6DnWnGf7Agbn9z4C2vbLmfwro7crrqZa5tdS5A26AzjV/joo494/PHH8Xg89OzZk7lz557WGsXf5Llc7LXb2VNczB673be/7zSeR1FaLZeFhAiBVLptajTK6TXJKYnW6+mr19M3PLxSv93j4UBxMXuLi9lrt7O39L23t7iYbJdLrPJzOsFmq/YxnfP0nKIovPbaa7z++uu+kikGg4Enn3ySV155pdoH6G9qy+o5l6ugVETtxW7fQ0nJIYqLD1FSchinMx1OSssrRwiqZIzGpqUtuVRYtUKvj5OCSnJJURSF4uJ95Of/Rl7ebxQULMfjsZx0nl4fT2hod59ICg7ujE4Xft6Pa/d42FpUxKasQtzvZdL6Sxs6p7Bgmn0zfDsaSsoWtikeKD6OpiSd5qYgro5rzvBGXWhuDqGeXu8TCk6nk4ceeogpU6YA+FYH+9srzqsopDkcHCgu5kDpqihfKyk5rVmiXqWiael0SQez2SeQGhoM8rNCctHJL/Xo2mu3sz0rizc7dPC/5QCIf/b9+/dTVFRE69atCQ4OrpYBBRq1RTSdDq/XQUlJKsXF+0sjU/tKBdZ+SkoOc6L3TEW02nBMpla+Zja3xmRqRVBQI7nKUFJtuFy55Ocv8wklhyO10nGNJpiQkK6VokgGQ4Nq/ZJWFIWc+Tnsf3w/jlSRtBp6dTjO/9Vncz0XG61Wdths7LBZsZ3GWkqLQqMgI/XtdvY+8wyZGzagUqm456WXeOzxx0kMCqr2pdcVcXu9ZFXhvXPc6STN4eBQSQkHi4vP6JLdQK+nRYXE3LL9RtLzSBIgBEQi+Lhx45g0adJJ5mo2m42HH36Yr776qloGFiiUveibN2/GaDTi8Xhwu9243e6T9l0uF3a7HavVSlFRERaLhcLCQt/WZrPhcDhwOp2+rdvtxuv1luY1iaZWq33O5Kdqer3+tP0mk4kGDRqQkJBA/fr10Z7nh7DX6yyNSh0oFVVl270UFx/kVIJKrTYSFJSEVhuGRhNaujIwCJXKgFodhFYbil4fj14fT1BQIiZTK3S6iCqvJal7eL0uLJY15OUtIT9/KVbrRipGQ1UqHWFhlxMRMZCIiAGEhHQ6bQmSC6VoexH7H99PwbICAAyJBpq+15ToG0/OBSwvJWNjcdpOfsvYw26bHachFgwxoNLAgQPwf/8HGRlihcn//R/06OG7RrhWS4LB4GsROh3a0kKuZ9NsHg95Lhd5bjd5LheZpSIp3ekky+k8zc+gcrQqFY0MBpJLl/AnG400NRpJDgqiidEoE7MlAU9AiCaNRsPx48eJja1c5DInJ4d69erhvoAaN4FI2Ytek1Gr1cTHx9OgQQNfi4+PJzY21tdiYmKIj4/HZDKd9XU9npLSyNQubLbd2O27sdt3YbfvLU1QPzf0+nqlEavWvoiVydQcvT4elVeBVavg+HGIj4c+feAsP7SFGHXh8djxeu0Vtjbc7kI8nkLcbkuFfXG74r5KpSoVfHrUakOFJH8DWm3oSTYQZU2ni0Kvj0ejOfvXta5SXHyAvLwl5OUtoaDgDzyeokrHTaY2REYOICJiIOHhfdFoLv5yVme2k8MvHCb9s3TwgsqgIuHJBBo91wiN6exFg8fr4a8jfzF95yx+mLcQ67fp4PRCbDA8eRMRbXphMDekSGWiyHvxizRogDi9vlI9sfoGA/Gl5WqSjUYSDYZaVf5CUvfw6+o5i8Xii4RYrVaCgsqTGz0eD7/88stJQqo2ERwcjFar9TWNRnPSvkajwWw2ExwcTEhICMHBwYSFhflacHBwpWiQXq9Hq9WiVqtLv5RF83q9OByOc2pl0auyVlRUxLFjx0hLS8PlcpGWlkZaWtoZn2d4eDj169evJLDq1avnE1dxcXHUq1eP8PBwNJoggoPbERzcrtI1vF43JSWHcDiO+sSH11uC1+so3YrkdafzOA5HOiUlB3E4juF0ZuB0ZlBQsLzS9dSKHuNRBeNhF1orKDpQ1hjxdu6AEh9TYSWjE6+3pApxZKeqpOBLiUYThsEQj15fn6CgRIzGFphMLTCZWmI0JqNWX/ySAoGEonix2/dgsazFYllDfv4flJQcqHSOThdNRMRAIiMHEhFxtc848lLgdXpJ+ziNwy8dxlMo3jsxN8XQ5M0mGBufuyO3Rq2hb6O+rPpuFdYvjwGQ1CmJoNuDSLFNJX/9VN+5zWI70rvpjbRJ6EdwSBPSnC6sHo+vkGtZ85xwu2KhV7NaTYROR6RWS4RWe5JAitHr5RSaRHIenHWkqeyL/ZQXUql46aWX+Pe//11tgwsEanpOk9frJTMz0yegylpmZiZZWVm+lpmZSXFx8Vlf12w2k5CQ4GuJiYkn7Z9L1MrttmC3p2Cz7SqNWIlWbD8IqrOZTDhb1Gg0ZtRqExqNqXT6MKw0WlTVfpjPPFSIPieK4qhgXlqC222tYgWjaC5XNl6v/Qxj0mA0NiEoqBFabRQ6XXnTaqPQ6+thMNRHr6+PVhtWI5NpPZ5iLJZ1FBauorDwb6zWdbjdBZXOUam0hIZeTmTkNURGDiQ4uNMlz4tTFIW8X/LYP2E/xXvF/0Nwx2Cavt+U8CvCz/u6drudcePGMXPmTAAefvhh3nnnHXQ6HYfyD/mKBq84vAK3tzxaH2WM4vrm1zOgyQC61u9Ks6hmqGWuoERyVvh1eu7PP/9EURSuvPJKfvzxRyIjyx1u9Xo9jRo1on79+tUyqECipoums0VRFCwWC2lpaaSnp1cSWBWFVVZWFvn5p/eDKiMiIgKdTofX6z2pgRBeYWFhREdH+4RWpW39+kR0uwyHO53ihlDcEDxGULlB7RZbVUgE6jfeQaUxlLqyG0vzp0xVboV/1qUTHYqi4PFYcTjScTrTSyNrh7Db91BcvAe7PeWkaajToVYb0evr+0SUXh+HThddOg1YD4OhIQZDw9JVjf7LOXE6c7BYVlNY+BeFhauwWjeiKJWN6tRqIyEhXQkN7UFYWG/Cw/v51YDVtsvG/sf3k79UvL91sToa/7cx8XfFo9Kc/3tm//79jBgxgm3btqHVavnkk08YP358lecWlhSy5MASFu5ZyC/7fiG/pPL/WqghlM7xnelSvwtd63elS/0uJIUn1UghLZFcbAIipyk1NZXExMQ6809aV0TTuVBSUsKxY8c4cuQIR48erXJbVHT2QuB0GIA4oF5p6wY8BFTKMlu+HPr1q5bHu9QoioLTeRy7PQWHIw2XKxe3OxeXq6zl+Py1TozMnA6VSoteXw+tNrI0v6qsDE84Gk1wpaZWmyvcNp9w3HRG8eXxlGC376KoaKtPKNntKSedp9fXJyysD2FhvQkL64XZ3K609JB/cRe6OfziYY59eAw8oNKraPhYQxr9uxHa0AtbxbZo0SJGjx5NYWEhsbGxzJ49m759+57duLxu/j7yN4v2LmL10dVszthMifvkiguRxshKIqpL/S40CKnelYMSSU0kIETT119/TXBwMDfffHOl/tmzZ2O32xk7dmy1DCxQkKLp3FEUhcLCQtLS0vB6vWg0GlQqFRqNBrVajVqtRlEUioqKKCwsJCsr6yThdfTo0VPWMYwAngYeptTZ+Ycf4LbbLt0T9BMeT7EvD0xErdJwubJxuXJ84srhOIbDkc7pbCLOFRG9qyyo1GozanUQJSUHsNv3Vvl4JlMrwsIuLxVKfQgKCqyIiOJVyJiWwcGJB3FliShY1A1RNH2nKcbkc89bqojH4+HFF1/k1VdfBaBXr17MmjWLBg3OPy/L7XWzK3sX69PWsyF9AxuOb2BrxlZc3pNLTYToQ0gMS6RReCMSQxOpH1KfuOA4Ys2xxJnjfPvB+tppFSORQICIpubNm/PZZ5/Rv3//Sv1//vkn9957L3v27KmWgQUKUjT5D8fSpWRccw0ZQAZwBPgU2F16PBZ4FrhvyRKCBg700ygDD6/XjcuVicORfkIJHlGGx+Ox4fEU4fWKrWgn75+L8NJqowgObkdISPdSodQLnS7q4j3JC8SywcK+h/ZhXSdKMBhbGGn2QbNzKqx7KnJzc7n99ttZunQpIPKX3n77bfT66k/2d7gdbM/azob0DUJMHd/AzqydeJSzW/hg0pmIM5eKqeA4Yk2xhAeFE2oIJcQQQog+pNI21BBKiD6EYH0wZr2ZIG2QzLGSBCwBIZqCgoJISUk5qfbc4cOHadWq1TklE9cEpGjyIx4PJCVBWhqUvk09wHTgBeBg6WkNGjTg+eef56677rooX0x1kbISPRXFVGWRVYTHU0xQUAJmc/saU2rHmePk0HOHOP7FcVBAE6yh0QuNaPhIQ9T6C//y37hxIyNGjCA1NRWj0ciUKVMYNWpUNYz87Cl2FXOk8AiphaliW5BKRlEGmbZMsmxZZNoyySzKpNhdPZ/VRq0Rs96MSWfCpDNh1ol9vUaPV/HiVbwoKL59ryJ86c71mAoVGrUGjUqDRq1Bq9aiUWnQaXToNXoMGoN4fL0Zs87sG4dOo0NF6erkE7ZatRatWotOrSPUEEqEMYKIoAgijZFEm6KJMcdIUViDCQjRlJiYyEcffcTQoUMr9S9YsIAHH3yQY8eOVcvAAgUpmvzM3LlQVuW9wlvVBUwFXo6K4lhuLgCNGzfmhRdeYNSoUedt5impnXjdXo5/dpxDzx/CnS9Wp8WOiiX5zWQM9aunZMmXX37Jgw8+iMPhoGnTpvz444+0b9++Wq5d3SiKQpGzqJKIKhNVhSWFWJ1W0RxWLA6Lb79sW12CK9DRqrXUD6lPg5AGNAxtSIOQBjQIrbxfP6T+GesLSvxDQIimZ555hpkzZ/L111/7Ehr//PNPxo0bx0033cTbb79dLQMLFKRoCgDmzoVHH4WKgjwhAd5/n5LrruPzzz/ntddeIzMzE4BmzZrx73//W4onCQAFqwrY9/A+bFtF8U5zBzPNPmxGeJ/warm+3W7nkUce4csvvwRg6NChTJs2jfATiozWJjxeD8XuYmxOG3aXHbvLjs1VYd9pw+lxolFrUKvUqFChVql9TaWqfPtM56hQoaDg8Xpwe914FI9v3+114/Q4KXGXVBqLzWnD5rLh9rqFxyDKSVuP4sHlceH0OLE4LOSX5JNfnE9ecR55xXkop6nJWZFoU3SVwqphaEMahTUiMSwRo+7C8uQk505AiCan08no0aOZPXu27wvJ6/UyZswYJk+eXOumR6RoChA8ntM6gttsNj766CPeeustcksjT8nJyfz73//mjjvuQKfz/yotyaXFkebgwDMHyPo+CwBtuFZYCNwbj1pbPVMuO3bsYOTIkezatQuVSsWrr77KxIkTUUsn7RqP2+smoyiDNEsaxyzHSLOmiX3rMdIsaaRZRX9VKxqrItYc6xNQjcIaiST9sESf2Io1x6JRy9I01UlAiKYy9u7dy9atWzEajbRr145GjRpVy4ACDSmaahZFRUV8/PHHvP322+Tk5ADQpEkTnnvuOcaMGSPFUx3AU+Lh2HvHSP1vKl6bF1QQf088jf/bGH1M9fyoUxSFL774gkceeYSSkhLq1avH999/z5VXXlkt15fUDBRFIb8k/yRhVSaojlqOklqQitVpPeO1NCqNmAosjVIlhSWRFF7eGoU3kqsdz5GAEk11BSmaaiZFRUV8+umnvPXWW2RnZwOQlJTEc889x9ixY2tdRFQivsByF+Wyf8J+Sg6IX/+hPUNp9mEzQjpXn2lmYWEh9957L7NmzQJg0KBBTJs2rVaXkZKcP4qiUFBSQGphKqkFqZW2Ry1HSbOkcbzoOF7lzKtVo03RPhHVOLwxyRHJJEcm0ySiCYlhiWjVMh2hIn4TTRMmTOCVV17BbDYzYcKE05777rvvVsvAAgUpmmo2NpuNyZMn8+abb5KVJaZpGjVqxLPPPitX29Uiig8Us++hfeT9mgeAPl5P8lvJxN4eW62r+v755x9uvfVWDh06hFar5fXXX2fChAlyOq4W4/F4cLlO9sKqTtxeN7n2XN8qxwxrBulF6ZWmAy0Oy2mvoVVraRDagCbhTWgc3pgmEU1IjkymcURjwoPCL+r4/YVOp0NzmsLtfhNN/fv3Z968eYSHh5/kz1TpYioVf/zxR7UMLFCQoql2YLfb+eyzz3jzzTd9ppkJCQk8/fTT3H333RiNMkmzJuJ1eTn6zlFSX0rFW+JFpVeRMCGBxOcS0YZU369ur9fLe++9x8SJE3G73SQlJTFjxgy6d+9ebY8hCSwURSEjI4OCggJ/DwUAr+L1Jb5X1U73Va5Wq9Gpdeg0OrEt3deoNagIfKuQ0xEeHk69elVbnsjpOT8gRVPtori4mM8//5w33niD48ePAxAbG8uECRO4//775d+4BlG4tpC99+7Ftl2sigu/MpzmnzbH1PzsC0WfDdnZ2YwdO5bFixcDcPPNN/P555/X6tVxEjh+/DgFBQXExsZiMpkC2odMURRcXrEK0OF24PA4cLgdOD3OKh3jy1ChwqA1YNAYMGgNPr8rg9YQ8P5UiqJgt9vJysoiPDyc+Pj4k86RoskPSNFUOykpKeHrr7/mjTfeIDU1FRC/WB566CEeffRRoqOj/TxCyalwF7o5+OxB0iengwLaKC1N321K3Oi4av9iW758OaNGjeL48eMEBQUxadIkxo8fH9BfoJILx+PxsHfvXmJjY4mKClxn+7PB4/VQ4i6p1IrdxTjcjtNaKhi1Rkx6EyatMAw1ao0BubovNzeXrKwsmjdvftJUnd9E0/Dhw8/6gnPnzr2gAQUaUjTVblwuF9OnT+f1118nJUUUmTWZTPzrX//iiSeeuKBaYZLqRVEUsn/MZv8j+3EedwJQ7856NHmrCfro6s1Nc7vdvPLKK7zyyisoikKrVq2YOXMm7dq1q9bHkQQmJSUlHDp0iKSkpFo7da8oCg6Po5KQKnGJ/VOV4TFqjT7X9WBdMEad0e8/IIqLizl8+DCNGzcmKKiyyejF+P4+q0n/sLDymvKKojBv3jzCwsLo0qULIEoHFBQUnJO4kpwfiqKguBQUd/nW6/JWuq24hA7WhmvRRmjRGAPv10GgoNPpGDNmDHfccQfz5s3jtddeY9OmTbz33nt8/PHH3HnnnTz99NMkJyf7e6h1mpIjJex7cB+5PwkPLmMzI80/a05E/4hqf6xjx44xatQoVq5cCcDdd9/NpEmTMJvN1f5YksDG34LgYqJSqQjSBp3kZq4oCi6PC7vbXsm81OV1UewupthdTG6x+D9Uq9SYdCZRi1BnJlgfjE5zaW1dLvXf6LwcwfPy8pg8ebIvFObxeHjggQcIDQ3lrbfeuigD9RcXqlQ9Ng+OdAfOdCfOLCfufDeuPBfuPDfufDfuQjceqwdPUYVW7BHi58TmUs6reL06SI02QitEVJjYakI0qE1qNGYNGrPY14aK45owTfm5YVo0waXnmNXVZgoYqCiKwpIlS3jttddYtWoVIJIob7/9dl5++WUaN27s5xHWLRSvQtonaRx69hCeIg8qnYrEiYkkPpeIJqj6fwwsWrSIO++8k7y8PEJCQvjss8+47bbbqv1xJIFNWaSpquhFXcXpcfrc3ssc16uKSAVpg3yFnUMMIRfdBuF0f6uAyGmKiYnhr7/+okWLFpX69+zZQ69evXxuzLWFshc9JzUHM2bchaVCx+KptC1rriwXzkwnzgzRPJazqzZ+oah0KtG0ooHI/aCaH16lV6EJ1qCL1KGN1FbeRmgr9WnDtSgOBbel9HWyim2ZSARAAxqjpvL9IipcN0rnt0jZqlWreO211/j1118B0Ov1PPLIIzz33HNERFR/hENSGdtuG3vu2YNltVhqHXp5KC0+b4G5dfVHfBwOB8888wyTJk0CoHPnzsyYMYOmTZtW+2NJAh8pms6MoiiUuEt8AqrIWVRlTUKTzlRJRFV3gvmlFk3nLAHdbjcpKSkniaaUlBS83vMIg9QQ1jZai5nz+7BWm9UYGhjQx+rRRmnRRZQLDG2YiPpogjVoQ0RURx2kPkkE+VqFPrVOLfY1VYcnFUXBY/XgynUJUVdQ2vLdeGwevDYvHrvHt++2iuOeQo84r/Q+niIPZfmCilMRUbI89/m+lOf++hnV6KJ06KJ14vWL1vlul231cXr09UTTRmhRqS88ZNunTx8WL17Mxo0bmThxIr///jtvv/02X331FS+88AL33Xef9Hm6CHidXo68cYTUV1NRnAqaYA1N3mhC/fvqV8vf9UT27dvHyJEj2bx5MyB86V5//XX5t5XUSPr160fHjh15//33z/sas2fP5vnnn+fw4cM0a9aMN954g+uuu67SOSqVCqPOiFFnJNokFs64PW6szvIizxXrAWaQgVqlJtQQSpghjPCg8Es+lVcdnLNouuuuu7j77rs5cOAA3bp1A2DdunX873//46677qr2AQYSKoOqfAorVFM+fVW6rwnVoI8RX9y6OB36enoMDQzV6hdzTuNVlY439MIeX1EUvA6vEFk2ESly5YspxopTjWX7vr4CN+ogNZpQDZoQDdrQ0teqVBwCKB4Fj81z0rRl2b7iVvAWe3Ecc+A45ji7561Vide/TEjF6sWUY6i28jhKb1faLxOtFebJO3fuzNKlS/n111958skn2bVrF48++igffvghb775JsOGDavVuQ+XEss/FvbcvQfbDmEjEHldJM0/bU5Q4sX5tf/dd99x//33U1RURFRUFNOmTeP666+/KI8lkdQEVq9ezW233cbrr7/O4MGD+eGHHxg2bBibNm2ibdu2p72vVqMlwhhBhFFE4p0eJ1aHFYvTgqXEgsvroqCkwOeQbtaZCQ8KJzwovMYUND7n6Tmv18vbb7/NpEmTfD438fHxPProozzxxBOndeesiZSF9/Kz8gmPCff3cOoUFSNlrhyXb+vOdVfuyy6fEq2WCJgKMQUZrUNfX4+hvgF9vB5DQwO6xjpmb5/Nfz/9L1nZwmG8T58+fPDBB3Ts2PHCH7uO4rF5OPT8IY5NOgZe0EXraDqpKbG3Va+jdxlFRUU89NBDTJs2DYArrriC77//Xq6WlAA1d3ruzjvv9L2nyyhbBXi2jBw5EpvNxk8//eTr69GjBx07dmTy5MnnPTZFUSh2FVPgKKCwpBCby1bpeJA2iIigCMKDwjHpzt4XK+Bzmk4cEFCrl+JLy4GahdfpxZklBJQr0yVyy7KceKweX25Vxf2yPCu3xS2Ku54lduzMCpnFTNtMSrwlqFVqxg0bx3/f+S+xjWUNsnMh95dc9j20j5JDol5c7KhYmr7ftNptBMrYsmULI0eOZO/evajVal544QX+/e9/17offJLzp8ovYkUBu90/AzKZ4CxERGFhIddeey1t27bl5ZdfBkQecsUV8FVxxx13+ARRYmIiEyZM4LHHHvMdf+GFF5g/fz5bt249/+dwAi5PedTJ4rBU8ozSa/SEGkJ9uVCnm8YL+JwmEHlNK1as4MCBA9x+++0ApKenExoaSnCwrMIs8R9qvZqghkEENTz3X4eKVxE5XkWlU5BZLhzHxcpHR7oDR6qD4gPFFO8rxlRg4k7rnVzHdXzKp6xQVvDFvC+YM28OD0Q8wM09bya0Qyjm9maC2wdjbG6s9SsPz5Xig8Xsf2w/uYvE4hFDgoHmnzUn6tqLYyaoKAqffPIJTzzxBA6HgwYNGvDDDz/Qt2/fi/J4klqG3Q7++n4rKoKzsLwICwtDr9djMpmoV6+er3/Lli2nvV9FQZGRkUFcXFyl43Fxcb7yU9WFTqMjxhxDjDkGt9dNYUkhBSUFFDoKcXqc5NhzyLHnAJWTyYP1wX412Txn0ZSamsqgQYM4cuQIDoeDAQMGEBISwhtvvIHD4big8J1E4k9UahXaYC3aYC3UA5qd+lxXnovi/cUU7y+my64uLPtjGa9teI3DrsO8lv8a836Zx6O/PEoLxIIJlUGFuY2Z4E7BhPUOI6x3GMZk/xvD+QOP3cORN45w5I0jKA4FlVZFw8ca0ug/jS5a/l9+fj5333038+bNA2DIkCF8/fXXNd7tWSI5GwJ9FahWrSXKFEWUKQqv1+tLJrc4LBS7/7+9O4+Lstr/AP6ZGWZYHFZlLRSUFFAUQUUwrpb8xKs3NalcS7qgda9oikuSpV5Mc8EUlyK1cnm5pam31KsXMcyFUFG85oJKoLkMZsom+8zz+4OcHEWYQZgZhs/79XpewjPnPOc7nBfM13Oe55xSjZvJRRDBSmoFa3NrWMusYabS7z3DOrf23nvvoVu3bjh79qzGH5xXX30VY8eObdDgiIyV1EEKaQ8pbHpU/w+tLdoisjISyxYuQ/z8eFwsvYh/4B8Y6jwUkcWRkD+Qo/h0MYpPF0PxZfX/2GQuMtiGVidQtqG2kHeWP/VJSFMgCALu/vsurk66ivJr1Tf124fZw2u5F1r4NN7CkT/99BOGDx+Oa9euQSqVYvHixZg4cWKzTFjpGVhZVY/4GKrtZ1DXDNCj03MuLi7Iy8vTeD0vL09j5KoxicVi2FrYwtaiekqxUlmpfhqvsLwQFcqK6mUOKh9AAQVQBRQWFWLHsR0IcA/Ai61fVNdtDDonTUeOHMHx48efeBzXw8MDN2/ebLDAiJoaqVSKaR9Ow6i/j8K0adOwefNmfJv3LX5w+AH/ivsXXuvwGh6ceoCCowUoOlmECkUFftv+G37b/hsAQGItgU2ITXUSFWILeVc5pPZN75HcmpRcKcHViVdxb/89ANVTcV5LvdBqaKtGS15UKhWWLFmCDz74AFVVVWjXrh22bduGwMDARmmPTJxIpNUUmaHJZDIolZoL9OkyPRccHIyUlBSNe5qSk5MRHBzckGFqTSqRqkehAKC8qhxFFUUorihGUXmRemPiL898iVlHZ0EsEqOrS1f0btMbPVr1aPB4dE6aVCrVEx0CVG89YG1t3SBBETVlbm5u2LRpE9555x3ExMTg3LlzmPDhBKzvth4rV65E0IIgKEuVKDpZhIKjBSg4UoCC4wVQFipx/8B93D9wX30tCw8LyAPkkHeVwzrAGvIAOcxdzA347nSjfKDEtfnX8GvCrxAqBIhkIrhPdUebD9pA0qLx7kv47bffMGbMGPznP/8BUP1E0OrVq/kwB5k8Dw8PpKenIzc3F3K5HA4ODjpNz7333nvo3bs3lixZgoEDB2Lr1q04deoUVq9e3YhRa8/czBzmZubqtaEKiwsh3Bfwmu9r2H11N7LvZyPjdgYybmcAZQ3fvs5Pzw0bNgy2trZYvXo1rK2t8b///Q+Ojo4YPHgwWrduja+//rrhozQgPj1Hz6KqqgqrVq3CrFmzUFhYCJFIhIkTJ2LevHkae5kJSgHF54qrE6gjBSg6VaR+muxxMjcZrAOtYR1oDbm/HC38WsDCw6JRFn6sL0EQcHfXXVydfBXl1/+Yigu3xwsrXoDVC8821VCXw4cPY+TIkbh16xYsLCywfPlyREdHczqOtNZUlxwAgMuXL2PMmDE4e/YsSktLdV5yAKhe3PLDDz9UL265aNGiJxa3NBaP99XNwps4fO0wUnNTcejSIWRPzzbskgO//vor+vfvD0EQcOXKFXTr1g1XrlxBq1at8OOPP8LJybQet2bSRA0hLy8P06ZNw8aNGwFU/29wzZo1CAsLe2qdyvuVKM4sRvGZYhSdLkLxmWKUXCqpcf9BiVyCFn4tIA+oHpGyDrSGla8VxFL9P7FXklWCKxOu4H5y9YiZeWtzeC3zQqshjTcVB1TvgTl//nzMmTMHKpUK3t7e+Oabb+Dn59dobZJpaspJU3PTJNZpqqqqwrZt23D27FkUFxcjICAAo0aNgqVl01jRUxdMmqghHThwAOPGjcP169cBAFFRUUhISICdnZ1W9ZUPlCjOLEbRqSIUnS7Cg3MP8OD8AwgVT/4ai8xFkPtVj0RZdbCCZQfL6n/bWUIsa/hkqqqoCtc+voYbS29AqPxjKm7aH1NxVo37iLBCocCoUaNw6NAhANWL/K1cuVJjNI9IW0yamg6jTpoqKyvh7e2NPXv2wMfHp0ECMHZMmqihFRUVIS4uDqtWrQJQfQ/U559/jkGDBtXreqpKFUqvlFYnU6eLUHy6+l9lwVN2a5YAFm0sYNnOEpbtLGHRzgKWbf/82kyu262OqioV8jbkIeejHFTcqgAAOAx0gNcyL1h5Ne5UHAAcPXoUr7/+OhQKBVq0aIHPPvsMb731VqO3S6aLSVPTYdSLW0qlUpSVNcKdVUTNiLW1NVauXIlhw4YhKioKV65cweDBgzFs2DCsWLECjo6OOl1PLBWjhW8LtPBtAeeR1YvSCSoBZTllKMooQsnFEpRkVR+ll0uhLFai7JcylP1Spp5Ce5TUSVqdULW3hFV7qz//fcESEss/R4weLiGQ80EOSi5Wr5Rs4WkBr0QvtHql1TP8hLQjCAISExMxbdo0VFVVoWPHjtixYwe8vb0bvW0iap50np6bP38+Ll++jLVr18LMzDAb0eoTR5qoMZWWliI+Ph6LFy+GUqlEy5YtsXz5cowYMaJR7v8RBAEVtyqqVzb/4yjLLlN/Xdfefeatzaun+Npbovh0MQrTqrdSMnMwQ5sP2sBtvBskFo2/Wm9xcTGio6Oxbds2AMCIESOwZs0aTsdRg+BIU9Nh1NNzQPUilikpKZDL5fDz83vij9TOnTsbJDBjwaSJ9CEjIwNRUVHqvZ0GDhyIFStWwNPTU69xVOZX/plEXSlFyeXq0amSrBJU3X8yoRJbivH85OfhPs0dUjv9rCmVlZWFoUOH4sKFCzAzM8OSJUswYcIEPh1HDYZJU9Nh1NNzAGBnZ4eIiIgGaZyIqgUGBuLkyZNYuHAh5s6di7179yIlJQUzZ87EtGnTYG6un7WZpHZSSAOlsA7UXHNNEARU3q1UJ1AlWSUQy8Rw+6cbzF31t27Uzp07ERkZiaKiIri6umL79u3o1auX3tonouatXk/PNSccaSJ9u3TpEsaPH69+EuyFF17AypUr0a9fPwNHZjhVVVWYOXMmFi1aBAD4y1/+gm3btultawdqXjjS1HToe6RJ6+eOVSoVFi5ciF69eqF79+6YMWMGSktLGyQIIvqTt7c3Dh48iC1btsDV1RVXrlxBeHg4Xn/9ddy4ccPQ4endnTt30K9fP3XCNGXKFBw8eJAJExHpndZJ07x58/DBBx9ALpfjueeeQ2JiIsaPH9+YsRE1WyKRCMOHD8elS5cwadIkSCQS9ZNhCQkJqKysNHSIenHixAkEBgbihx9+QIsWLfDNN98gISEBUqlp7MlHRE2L1knThg0b8Nlnn+HAgQPYvXs3vv/+e2zatAkqVQ3LExNRg7CxscHSpUuRkZGBkJAQPHjwANOmTUNAQACOHTtm6PAa1ZdffonQ0FDcuHED7du3x4kTJ/D6668bOiwiasa0TpquX7+usfdMWFgYRCIRbt261SiBEdGfunTpgiNHjuDLL79Ey5Yt8fPPP+PFF19EZGQkFAqFocNrUOXl5XjnnXcQHR2NiooKDB48GCdOnICvr6+hQyMyen369MGkSZOe6Rrbt2+Ht7c3LCws4Ofnh3379tVa/vbt2xg5ciTat28PsVj8zO0bM62TpqqqqiduspJKpc1mmoDI0MRiMf7+978jKysL0dHRAID169ejffv2+PTTT03id/HGjRv4y1/+gtWrV0MkEmHevHnYuXMnbG1tDR0aUbNw/PhxjBgxAlFRUThz5gyGDBmCIUOG4Oeff35qnfLycjg6OuLDDz9Ely5d9Bit/mn99JxYLMZf//pXjUefv//+e7z88ssaazVxnSYi/Thx4gRiYmJw8uRJAICPjw9WrlyJl19+2cCR1c/hw4fxxhtv4M6dO7C3t8eWLVsQHh5u6LCoGWqqT89FRkZi/fr1GudycnLg4eGh9TWGDRuGBw8eYM+ePepzPXv2hL+/P5KSkuqs36dPH/j7+2PZsmVat/ksjHadpjFjxjxxbvTo0Q0SBBHprkePHvjpp5/w9ddfIy4uDhcvXkTfvn0xfPhwJCQk4LnnnjN0iFp5uB3K1KlToVQq0aVLF+zcuRNt27Y1dGhEaoIAlJQYpm0rK0CbtVsTExNx+fJldOrUCfHx8QAAR0dHyOXyWuuNHj1anRClpaUhNjZW4/Xw8HDs3r27XrGbGq2Tpq+//rox4yCiehCLxYiKikJERAQ++ugjfPbZZ9i6dSv27NmDOXPmYOLEiUb9pFl+fj7Gjh2LHTt2AKj+4/3FF1/AyqrxN/ol0kVJCVBH7tFoiosBbXYIsrW1hUwmg5WVlcaSHJmZmbXWe3QURqFQwNnZWeN1Z2dnk7t3sr60vqeJiIyXnZ0dVqxYgVOnTqFnz54oLi7G1KlT4e/vj9TUVEOHV6OffvoJ/v7+2LFjB6RSKZYvX44NGzYwYSJqYF5eXrUeTk5Ohg6xyTD9HXeJmpGuXbvi2LFjWLduHd5//31cuHABL730EiIiIrBw4UK0a9fO0CFCpVIhISEBM2fORFVVFdq2bYutW7eie/fuhg6N6KmsrKpHfAzV9rPQZXrOxcUFeXl5Gq/n5eVxMdk/MGkiMjEPn7IbMmQIZs6cidWrV+Pbb7/Fd999hwkTJuDDDz+Evb29QWK7c+cO3nrrLRw4cABA9U2nX3zxBZ+OI6MnEmk3RWZoMpkMSqVS45wu03PBwcFISUnRWDYgOTkZwcHBDRlmk8XpOSIT5eDggM8//xyZmZno168fKisr8emnn8LLywuffvopysvL9RrPoUOH0KVLFxw4cACWlpZYs2YNtmzZwoSJqAF5eHggPT0dubm5uHv3LlQqlU7Tc++99x7279+PJUuW4NKlS5gzZw5OnTqFmJgYdZm4uDi89dZbGu1mZmYiMzMTxcXF+O2335CZmYkLFy7o7X3rjUC1KigoEAAIBQUFhg6F6Jn85z//ETp27CgAEAAIbdq0ETZu3CgolcpGbbeyslL46KOPBJFIJAAQfH19hZ9//rlR2yR6FqWlpcKFCxeE0tJSQ4eis6ysLKFnz56CpaWlAEDIycnR+RrffPON0L59e0EmkwkdO3YU9u7dq/H6mDFjhN69e2uce/h35dGjTZs29X8jWqqtrxrj81vrdZqaK67TRKakqqoK69evx6xZs9Sr+fv7+2PRokX4v//7vwZv78aNGxg5ciSOHDkCAIiOjkZiYiJv9iaj1lTXaWqO9L1OE6fniJoRMzMzREVF4cqVK5g/fz5sbGzU03f9+vXDmTNnGqytvXv3wt/fH0eOHIFcLsfmzZuxZs0aJkxE1GQxaSJqhqysrBAXF4fs7GxMmjQJUqkUycnJCAgIwOjRo5Gbm1vva5eXlyM2NhZ/+9vf8PvvvyMgIABnzpzBiBEjGu4NEBEZAJMmomasVatWWLp0KbKysjBy5EgAwKZNm9ChQwfExsbi999/1+l6V69eRa9evbB06VIAwMSJE3H8+HF4eXk1eOxERPrGpImI4OnpiU2bNiEjIwN9+/ZFRUUFli5dinbt2mHBggUoLS39s7BSCaSmAlu2VP/7x+PNmzdvRteuXZGRkQEHBwf8+9//RmJiosZ+lURETVmTSZru3buHUaNGwcbGBnZ2doiKikJxLSuN3bt3DxMmTECHDh1gaWmJ1q1bY+LEiSgoKNBj1ERNS0BAAJKTk3HgwAF06dIFBQUFiIuLwwsvvICvvvoKyu3bAQ8P4KWXgJEjgZdewu/u7hgZGopRo0ahuLgYoaGhOHv2LAYNGmTot0NE1KCaTNI0atQonD9/HsnJydizZw9+/PFHjBs37qnlb926hVu3biEhIQE///wz1q1bh/379yMqKkqPURM1PSKRCP369cPp06exceNGtGnTBjdv3kRUVBS6vPEG9ty4gYeP3P4bQMfbt7Hl6FGIxWLMmjULhw4dwvPPP2/It0BE1CiaxJIDFy9ehK+vL06ePIlu3boBAPbv348BAwbgxo0bcHNz0+o627dvx+jRo/HgwQOYmWm3GDqXHKDmrqysDKtWrMC899/H/T/+XASgejuBE3+U8QGw3skJ3W/dAiQSA0VK1DC45EDTwSUHapCWlgY7Ozt1wgQAYWFhEIvFSE9P1/o6D39wtSVM5eXlKCws1DiImjMLCwtM6d4d2YKA6QDMAZxGdcIkBjD9j++737kD/LEeExGRKWoSSZNCoXhiF2YzMzM4ODhAoVBodY27d+9i7ty5tU7pAcAnn3wCW1tb9eHu7l7vuIlMxu3bsAewEMBlAG8CCAFw9I9zFo+UIyIyVQZNmmbMmAGRSFTrcenSpWdup7CwEAMHDoSvry/mzJlTa9m4uDgUFBSoj19//fWZ2ydq8lxd1V+2BrABwDEAT2zh+Ug5IiJTY9CkacqUKbh48WKtR9u2beHi4oI7d+5o1K2qqsK9e/fg4uJSaxtFRUXo378/rK2tsWvXLkil0lrLm5ubw8bGRuMgavZCQ4Hnn6/e6r0mIhHg7l5djogMpk+fPpg0adIzXWP79u3w9vaGhYUF/Pz8sG/fvlrLp6am1jjooe1MUFOi3d3QjcTR0RGOjo51lgsODkZ+fj4yMjIQGBgIoHrHdJVKhaCgoKfWKywsRHh4OMzNzfHdd9/xhj6i+pJIgMRE4LXXqhOkR58feZhILVvGm8CJmrjjx49jxIgR+OSTT/C3v/0NmzdvxpAhQ3D69Gl06tSp1rpZWVkaAw2P31ZjCprEPU0+Pj7o378/xo4dixMnTuDYsWOIiYnB8OHD1U/O3bx5E97e3jhxovp5nsLCQvTr1w8PHjzAl19+icLCQigUCigUCij/WIyPiHQwdCiwYwfw3HOa559/vvr80KGGiYuIAACRkZE4fPgwEhMT1aM9um6JlJiYiP79+2PatGnw8fHB3LlzERAQgJUrV9ZZ18nJCS4uLupDLG4SKYZODDrSpItNmzYhJiYGffv2hVgsRkREBJYvX65+vbKyEllZWSgpKQEAnD59Wv1k3eNbOOTk5MDDw0NvsROZjKFDgcGDq5+Su327+h6m0FCOMJHJEwQBJZUlBmnbSmoF0dOmxh+RmJiIy5cvo1OnToiPjwdQPaMjl8trrTd69GgkJSUBqH5aPTY2VuP18PBw7N69u872/f39UV5ejk6dOmHOnDno1atXnXWamiaTNDk4OGDz5s1Pfd3DwwOPLjnVp08fNIElqIiaHokE6NPH0FEQ6VVJZQnkn9SefDSW4rhitJC1qLOcra0tZDIZrKysNO73zczMrLXeo1NqCoUCzs7OGq87OzvXen+Sq6srkpKS0K1bN5SXl2Pt2rXo06cP0tPTERAQUGfcTUmTSZqIiIhId429YXaHDh3QoUMH9fchISHIzs7G0qVLsXHjxkZtW9+YNBEREdXBSmqF4rin73fa2G0/C12m51xcXJCXl6fxel5eXp1Pqj+uR48eOHr0qG6BNgFMmoiIiOogEom0miIzNJlM9sTDTrpMzwUHByMlJUVj2YLk5GQEBz+xKlutMjMz4WqC67YxaSIiIjIRHh4eSE9PR25uLuRyORwcHHSannvvvffQu3dvLFmyBAMHDsTWrVtx6tQprF69Wl0mLi4ON2/exIYNGwAAy5Ytg6enJzp27IiysjKsXbsWhw4dwn//+98Gf3+GZnrPAxIRETVTU6dOhUQiga+vLxwdHXH9+nWd6oeEhGDz5s1YvXo1unTpgh07dmD37t0aazTdvn1b47oVFRWYMmUK/Pz80Lt3b5w9exYHDx5E3759G+x9GQuRwEfMatUYuyQTEZHxKisrQ05ODjw9PbkospGrra8a4/ObI01EREREWmDSRERERKQFJk1EREREWmDSRERERKQFJk1EREREWmDSRERERKQFJk1EREREWmDSRERERKQFJk1EREREWmDSRERERKQFJk1EREQmok+fPpg0aVK9658/fx4RERHw8PCASCTCsmXL6qyTm5sLkUj0xPHTTz/VOw5jZWboAIiIiMg4lJSUoG3btnj99dcxefJkneoePHgQHTt2VH/fsmXLhg7P4DjSREREZAIiIyNx+PBhJCYmqkd7cnNzdbpG9+7dsXjxYgwfPhzm5uY61W3ZsiVcXFzUh1Qq1al+U8CRJiIiojoIgoASlcogbVuJxRCJRHWWS0xMxOXLl9GpUyfEx8cDABwdHSGXy2utN3r0aCQlJT1znIMGDUJZWRnat2+P6dOnY9CgQc98TWPDpImIiKgOJSoV5EeOGKTt4tBQtJBI6ixna2sLmUwGKysruLi4qM9nZmbWWs/GxuaZ4pPL5ViyZAl69eoFsViMb7/9FkOGDMHu3btNLnFi0kRERGTCvLy8GvX6rVq1QmxsrPr77t2749atW1i8eDGTJiIioubGSixGcWiowdp+FvqanntUUFAQkpOTG/SaxoBJExERUR1EIpFWU2SGJpPJoFQqNc419vRcTTIzM+Hq6trg1zU0Jk1EREQmwsPDA+np6cjNzYVcLoeDg4NO03MVFRW4cOGC+uubN28iMzMTcrlcfZ2VK1di165dSElJAQCsX78eMpkMXbt2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\n" + }, + "metadata": {} + } + ], + "source": [ + "# Get predictions at time 0\n", + "f_0_x = shallow_network_param_vector(x_vals, phi_0).T\n", + "# Get predictions at six different time points\n", + "f_0_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 0.0, f_0)\n", + "f_1_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 0.1, f_0)\n", + "f_2_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 0.5, f_0)\n", + "f_3_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 1.5, f_0)\n", + "f_4_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 5.0, f_0)\n", + "f_5_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 25.0, f_0)\n", + "f_6_test = f_0_x - kernel_predict_analytical(X, x_vals, y, 500.0, f_0)\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(X[0:1,:],y.T,'ro')\n", + "ax.plot(x_vals[0:1,:].T, f_0_test,'r-',label='t=0')\n", + "ax.plot(x_vals[0:1,:].T, f_1_test,'b-',label='t=0.1')\n", + "ax.plot(x_vals[0:1,:].T, f_2_test,'g-',label='t=0.5')\n", + "ax.plot(x_vals[0:1,:].T, f_3_test,'c-',label='t=1.5')\n", + "ax.plot(x_vals[0:1,:].T, f_4_test,'y-',label='t=5.0')\n", + "ax.plot(x_vals[0:1,:].T, f_5_test,'m-',label='t=25.0')\n", + "ax.plot(x_vals[0:1,:].T, f_6_test,'k-',label='t=500.0')\n", + "ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('Predicted output')\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Compute the mean prediction and uncertainty at a given time" + ], + "metadata": { + "id": "r6D-N-7ph6uZ" + } + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "id": "R7zkbyAleeiy" + }, + "outputs": [], + "source": [ + "# Compute initial covariance\n", + "def compute_cov_init(X1, X2, sigma_sq_p=2.0):\n", + " I1 = X1.shape[1]\n", + " I2 = X2.shape[1]\n", + " K = np.zeros((I1,I2))\n", + "\n", + " for i in range(I1):\n", + " for j in range(I2):\n", + " x1 = X1[:,i]\n", + " x2 = X2[:,j]\n", + " norm1 = np.sqrt(x1.T@x1)\n", + " norm2 = np.sqrt(x2.T@x2)\n", + " if norm1 < 1e-10 or norm2 < 1e-10:\n", + " theta = 0\n", + " else:\n", + " if np.array_equal(x1,x2):\n", + " theta = 0\n", + " else:\n", + " theta = np.arccos(x1.T@x2/(norm1*norm2))\n", + " K[i,j] = sigma_sq_p * norm1 * norm2 * ((np.pi-theta)*np.cos(theta)+np.sin(theta))/(2*np.pi) + 1\n", + " return K\n", + "\n", + "# Equations 14 and 15 from Lee et al. (2019)\n", + "def kernel_predict_uncertainty(X,x,y,t, sigma_sq_n=0.001):\n", + " NTKXX = compute_analytical_ntk(X, X)\n", + " NTKxX = compute_analytical_ntk(x, X)\n", + "\n", + " f_0_xx_cov = compute_cov_init(x,x)\n", + " f_0_XX_cov = compute_cov_init(X,X)\n", + " f_0_Xx_cov = compute_cov_init(X,x)\n", + " Z = NTKxX @ np.linalg.inv(NTKXX) @ (np.identity(3)-expm(-K * t))\n", + "\n", + " mean =Z @ y\n", + " cov = f_0_xx_cov + Z @ f_0_XX_cov @ Z.T -2 * Z @ f_0_Xx_cov\n", + " return mean, np.sqrt(np.diag(cov+np.identity(cov.shape[0])*sigma_sq_n))[:,None]" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Draw function with uncertainty at a number of different time points" + ], + "metadata": { + "id": "zz9AtywWid-4" + } + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "BMHCOgNScoI1", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "7e951f0d-9c3f-4c31-9445-24922c64e83f" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=0.000\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk0AAAGwCAYAAAC0HlECAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAhF0lEQVR4nO3df3RX9X348Vd+kESFBD1AAi5KsVW0WjmA0Ng6jyOnWJzVc7qVKkW0VLf5Y5vpOkPtxOkm1GMpZ8r06GztenRYXfV4LIeNYDlOTYslskMV7ak/JpV+AtSZQOhISO73j37JFgV8J4R88uPxOOfzBzf33s8reZ+Yp/fzyU1BlmVZAABwWIX5HgAAYCgQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAguJ8DzDYdXV1xfbt22PMmDFRUFCQ73EAgARZlsXu3btj0qRJUVjYP9eIRNOH2L59e1RXV+d7DACgD7Zt2xa/93u/1y/nEk0fYsyYMRER0dDQEMcdd1yepwEAUrS1tUVtbW33z/H+IJo+xIGX5I477rgYPXp0nqcBAHqjP99a443gAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAECCIRdNq1atismTJ0dZWVnMnj07Nm7cmHTc6tWro6CgIC699NKjOyAAMCwNqWh69NFHo66uLpYuXRpNTU1x9tlnx9y5c2PHjh2HPe6tt96Kv/qrv4rzzjtvgCYFAIabIRVNK1asiKuvvjquuuqqOOOMM+K+++6LY489Nr7zne8c8pjOzs5YsGBB/O3f/m1MmTJlAKcFAIaTIRNN7e3tsWnTpqitre3eVlhYGLW1tdHY2HjI42677baYMGFCLF68OOl59u3bF62trT0eAABDJpp27doVnZ2dUVlZ2WN7ZWVl5HK5gx7z3HPPxYMPPhgPPPBA8vMsW7YsKioquh/V1dVHNDcAMDwMmWjqrd27d8fChQvjgQceiHHjxiUft2TJkmhpael+bNu27ShOCQAMFcX5HiDVuHHjoqioKJqbm3tsb25ujqqqqg/s//rrr8dbb70VF198cfe2rq6uiIgoLi6O1157LU455ZQPHFdaWhqlpaX9PD0AMNQNmStNJSUlMWPGjFi/fn33tq6urli/fn3U1NR8YP+pU6fGli1bYvPmzd2Pz33uc3HBBRfE5s2bvewGAPTKkLnSFBFRV1cXixYtipkzZ8asWbNi5cqV0dbWFldddVVERFxxxRVx4oknxrJly6KsrCzOPPPMHsePHTs2IuID2wEAPsyQiqb58+fHzp0745ZbbolcLhfTpk2LtWvXdr85/O23347CwiFz8QwAGEIKsizL8j3EYNba2hoVFRXR2NgYo0ePzvc4AECCPXv2RE1NTbS0tER5eXm/nNNlGQCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABMX5HgAAhoXOzjiuqSmKd+6M/ePHR9v06RFFRfmein4kmgDgCJU3NETV8uVR0tzcva29sjJy9fXRWlubx8noT16eA4AjUN7QENV1dTHq/wRTRMSoHTuiuq4uyhsa8jQZ/U00AUBfdXZG1fLlEVkWBe/7UEGWRURE1Te/GdHZOfCz0e9EEwD00XFNTVHS3PyBYDqgIMuiJJeL45qaBnQujg7RBAB9VLxzZ7/ux+AmmgCgj/aPH9+v+zG4iSYA6KO26dOjvbIysoKDv0CXFRREe1XV724/wJAnmgCgr4qKIldfHxHxgXA68O/cTTe5X9MwIZoA4Ai01tbGthUromPChB7bOyorY9uKFe7TNIy4uSUAHKHW2tpoveACdwQf5kQTAPSHoqJoO+ecfE/BUeTlOQCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACDBkIumVatWxeTJk6OsrCxmz54dGzduPOS+DzzwQJx33nlx/PHHx/HHHx+1tbWH3R8A4FCGVDQ9+uijUVdXF0uXLo2mpqY4++yzY+7cubFjx46D7r9hw4a47LLL4sc//nE0NjZGdXV1fOYzn4l33nlngCcHAIa6gizLsnwPkWr27NlxzjnnxD333BMREV1dXVFdXR033HBD1NfXf+jxnZ2dcfzxx8c999wTV1xxRdJztra2RkVFRTQ2Nsbo0aOPaH4AYGDs2bMnampqoqWlJcrLy/vlnEPmSlN7e3ts2rQpamtru7cVFhZGbW1tNDY2Jp1j79690dHRESeccMIh99m3b1+0trb2eAAADJlo2rVrV3R2dkZlZWWP7ZWVlZHL5ZLOcdNNN8WkSZN6hNf7LVu2LCoqKrof1dXVRzQ3ADA8DJloOlLLly+P1atXxxNPPBFlZWWH3G/JkiXR0tLS/di2bdsATgkADFbF+R4g1bhx46KoqCiam5t7bG9ubo6qqqrDHnvXXXfF8uXLo6GhIT7xiU8cdt/S0tIoLS094nkBgOFlyFxpKikpiRkzZsT69eu7t3V1dcX69eujpqbmkMfdeeedcfvtt8fatWtj5syZAzEqADAMDZkrTRERdXV1sWjRopg5c2bMmjUrVq5cGW1tbXHVVVdFRMQVV1wRJ554YixbtiwiIr75zW/GLbfcEo888khMnjy5+71Po0eP9ptwAECvDKlomj9/fuzcuTNuueWWyOVyMW3atFi7dm33m8PffvvtKCz834tn9957b7S3t8cf/dEf9TjP0qVL49Zbbx3I0QGAIW5I3acpH9ynCQCGnhF9nyYAgHwSTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAECCIRdNq1atismTJ0dZWVnMnj07Nm7ceNj9H3vssZg6dWqUlZXFWWedFWvWrBmgSQGA4WRIRdOjjz4adXV1sXTp0mhqaoqzzz475s6dGzt27Djo/i+88EJcdtllsXjx4njppZfi0ksvjUsvvTR+/vOfD/DkAMBQV5BlWdabAxYtWhSLFy+O3//93z9aMx3S7Nmz45xzzol77rknIiK6urqiuro6brjhhqivr//A/vPnz4+2trZ4+umnu7d98pOfjGnTpsV9992X9Jytra1RUVERP1m/PkaPHt0/nwgAcFTt2bMnPjlnTrS0tER5eXm/nLO4twe0tLREbW1tnHzyyXHVVVfFokWL4sQTT+yXYQ6nvb09Nm3aFEuWLOneVlhYGLW1tdHY2HjQYxobG6Ourq7Htrlz58aTTz55yOfZt29f7Nu3r/vfra2tERFx+pw50T9fcgDgaGs9Cufs9ctzTz75ZLzzzjvxZ3/2Z/Hoo4/G5MmT47Of/Ww8/vjj0dHRcRRG/J1du3ZFZ2dnVFZW9theWVkZuVzuoMfkcrle7R8RsWzZsqioqOh+VFdXH/nwAMCQ1+srTRER48ePj7q6uqirq4umpqb47ne/GwsXLozRo0fHl770pbj22mvjYx/7WH/POiCWLFnS4+pUa2trVFdXx1YvzwHAkLFnz56IOXP69Zx9iqYDfv3rX8e6deti3bp1UVRUFPPmzYstW7bEGWecEXfeeWfceOON/TVnjBs3LoqKiqK5ubnH9ubm5qiqqjroMVVVVb3aPyKitLQ0SktLP7A9O/bYyI49tg+TAwADLevq6vdz9vrluY6OjvjXf/3X+MM//MM4+eST47HHHou//Mu/jO3bt8f3vve9aGhoiB/84Adx22239eugJSUlMWPGjFi/fn33tq6urli/fn3U1NQc9Jiampoe+0dErFu37pD7AwAcSq+vNE2cODG6urrisssui40bN8a0adM+sM8FF1wQY8eO7Yfxeqqrq4tFixbFzJkzY9asWbFy5cpoa2uLq666KiIirrjiijjxxBNj2bJlERHxF3/xF3H++efHt771rbjoooti9erV8bOf/Szuv//+fp8NABjeeh1N3/72t+OP//iPo6ys7JD7jB07Nt58880jGuxg5s+fHzt37oxbbrklcrlcTJs2LdauXdv9Zu+33347Cgv/9+LZueeeG4888kh84xvfiK9//evxsY99LJ588sk488wz+302AGB46/V9mkaaA/dpamxs9EZwABgi9uzZEzU1Nf16n6YhdUdwAIB8EU0AAAlEEwBAAtEEAJBANAEAJBBNAAAJjujPqMCA6eyM45qaonjnztg/fny0TZ8eUVSU76kAGEFEE4NeeUNDVC1fHiX/5+8ItldWRq6+Plpra/M4GQAjiZfnGNTKGxqiuq4uRr3vDy+P2rEjquvqoryhIU+TATDSiCYGr87OqFq+PCLLouB9Hyr4/zeyr/rmNyM6Owd+NgBGHNHEoHVcU1OUNDd/IJgOKMiyKMnl4rimpgGdC4CRSTQxaBXv3Nmv+wHAkRBNDFr7x4/v1/0A4EiIJgattunTo72yMrKCg79AlxUURHtV1e9uPwAAR5loYvAqKopcfX1ExAfC6cC/czfd5H5NAAwI0cSg1lpbG9tWrIiOCRN6bO+orIxtK1a4TxMAA8bNLRn0Wmtro/WCC9wRHIC8Ek0MDUVF0XbOOfmeAoARzMtzAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkKM73AMAQ09kZxzU1RfHOnbF//Phomz49oqgo31MBHHVD5krTu+++GwsWLIjy8vIYO3ZsLF68OPbs2XPY/W+44YY47bTT4phjjomTTjop/vzP/zxaWloGcGoYXsobGuLUuXPjI1/+clTfdFN85MtfjlPnzo3yhoZ8jwZw1A2ZaFqwYEG8/PLLsW7dunj66afj2WefjWuuueaQ+2/fvj22b98ed911V/z85z+Phx56KNauXRuLFy8ewKlh+ChvaIjquroY1dzcY/uoHTuiuq5OOAHDXkGWZVm+h/gwW7dujTPOOCNefPHFmDlzZkRErF27NubNmxe/+tWvYtKkSUnneeyxx+JLX/pStLW1RXFx2iuTra2tUVFREY2NjTF69Og+fw4wpHV2xqlz58ao5uYoOMiHs4KC6KisjF+sXeulOmBQ2LNnT9TU1ERLS0uUl5f3yzmHxJWmxsbGGDt2bHcwRUTU1tZGYWFh/PSnP00+z4Ev3OGCad++fdHa2trjASPdcU1NUXKIYIqIKMiyKMnl4rimpgGdC2AgDYloyuVyMWHChB7biouL44QTTohcLpd0jl27dsXtt99+2Jf0IiKWLVsWFRUV3Y/q6uo+zw3DRfHOnf26H8BQlNdoqq+vj4KCgsM+Xn311SN+ntbW1rjooovijDPOiFtvvfWw+y5ZsiRaWlq6H9u2bTvi54ehbv/48f26H8BQlNdbDnz1q1+NK6+88rD7TJkyJaqqqmLHjh09tu/fvz/efffdqKqqOuzxu3fvjgsvvDDGjBkTTzzxRIwaNeqw+5eWlkZpaWnS/DBStE2fHu2VlTFqx44oOMjbIA+8p6lt+vQ8TAcwMPIaTePHj4/xCf9nWlNTE++9915s2rQpZsyYERERzzzzTHR1dcXs2bMPeVxra2vMnTs3SktL46mnnoqysrJ+mx1GlKKiyNXXR3VdXWQFBT3CKSv43Tudcjfd5E3gwLA2JN7TdPrpp8eFF14YV199dWzcuDGef/75uP766+OLX/xi92/OvfPOOzF16tTYuHFjRPwumD7zmc9EW1tbPPjgg9Ha2hq5XC5yuVx0dnbm89OBIam1tja2rVgRHe97f2FHZWVsW7EiWmtr8zQZwMAYMncEf/jhh+P666+POXPmRGFhYXz+85+Pf/iHf+j+eEdHR7z22muxd+/eiIhoamrq/s26j370oz3O9eabb8bkyZMHbHYYLlpra6P1ggvcERwYkYbEfZryyX2aAGDoGbH3aQIAyDfRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQQTQAACUQTAEAC0QQAkEA0AQAkEE0AAAlEEwBAAtEEAJBANAEAJBBNAAAJRBMAQALRBACQQDQBACQYMtH07rvvxoIFC6K8vDzGjh0bixcvjj179iQdm2VZfPazn42CgoJ48sknj+6gAMCwNGSiacGCBfHyyy/HunXr4umnn45nn302rrnmmqRjV65cGQUFBUd5QgBgOCvO9wAptm7dGmvXro0XX3wxZs6cGRERd999d8ybNy/uuuuumDRp0iGP3bx5c3zrW9+Kn/3sZzFx4sSBGhkAGGaGxJWmxsbGGDt2bHcwRUTU1tZGYWFh/PSnPz3kcXv37o3LL788Vq1aFVVVVUnPtW/fvmhtbe3xAAAYEtGUy+ViwoQJPbYVFxfHCSecELlc7pDH3XjjjXHuuefGJZdckvxcy5Yti4qKiu5HdXV1n+cGAIaPvEZTfX19FBQUHPbx6quv9uncTz31VDzzzDOxcuXKXh23ZMmSaGlp6X5s27atT88PAAwveX1P01e/+tW48sorD7vPlClToqqqKnbs2NFj+/79++Pdd9895MtuzzzzTLz++usxduzYHts///nPx3nnnRcbNmw46HGlpaVRWlqa+ikAACNEXqNp/PjxMX78+A/dr6amJt57773YtGlTzJgxIyJ+F0VdXV0xe/bsgx5TX18fX/nKV3psO+uss+Lb3/52XHzxxUc+PAAwogyJ3547/fTT48ILL4yrr7467rvvvujo6Ijrr78+vvjFL3b/5tw777wTc+bMiX/+53+OWbNmRVVV1UGvQp100knxkY98ZKA/BQBgiBsSbwSPiHj44Ydj6tSpMWfOnJg3b158+tOfjvvvv7/74x0dHfHaa6/F3r178zglADBcDYkrTRERJ5xwQjzyyCOH/PjkyZMjy7LDnuPDPg4AcChD5koTAEA+iSYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEhTne4DBLsuyiIhoa2vL8yQAQKoDP7cP/BzvD6LpQ/zmN7+JiIja2to8TwIA9NZvfvObqKio6JdziaYPccIJJ0RExNtvv91vX3T6prW1Naqrq2Pbtm1RXl6e73FGNGsxeFiLwcV6DB4tLS1x0kkndf8c7w+i6UMUFv7ubV8VFRW+AQaJ8vJyazFIWIvBw1oMLtZj8Djwc7xfztVvZwIAGMZEEwBAAtH0IUpLS2Pp0qVRWlqa71FGPGsxeFiLwcNaDC7WY/A4GmtRkPXn7+IBAAxTrjQBACQQTQAACUQTAEAC0QQAkEA0RcSqVati8uTJUVZWFrNnz46NGzcedv/HHnsspk6dGmVlZXHWWWfFmjVrBmjS4a83a/HAAw/EeeedF8cff3wcf/zxUVtb+6FrR7refl8csHr16igoKIhLL7306A44gvR2Ld5777247rrrYuLEiVFaWhqnnnqq/071k96uxcqVK+O0006LY445Jqqrq+PGG2+M//mf/xmgaYevZ599Ni6++OKYNGlSFBQUxJNPPvmhx2zYsCGmT58epaWl8dGPfjQeeuih3j9xNsKtXr06Kykpyb7zne9kL7/8cnb11VdnY8eOzZqbmw+6//PPP58VFRVld955Z/bKK69k3/jGN7JRo0ZlW7ZsGeDJh5/ersXll1+erVq1KnvppZeyrVu3ZldeeWVWUVGR/epXvxrgyYef3q7FAW+++WZ24oknZuedd152ySWXDMyww1xv12Lfvn3ZzJkzs3nz5mXPPfdc9uabb2YbNmzINm/ePMCTDz+9XYuHH344Ky0tzR5++OHszTffzP7t3/4tmzhxYnbjjTcO8OTDz5o1a7Kbb745++EPf5hFRPbEE08cdv833ngjO/bYY7O6urrslVdeye6+++6sqKgoW7t2ba+ed8RH06xZs7Lrrruu+9+dnZ3ZpEmTsmXLlh10/y984QvZRRdd1GPb7Nmzsz/5kz85qnOOBL1di/fbv39/NmbMmOx73/ve0RpxxOjLWuzfvz8799xzs3/6p3/KFi1aJJr6SW/X4t57782mTJmStbe3D9SII0Zv1+K6667L/uAP/qDHtrq6uuxTn/rUUZ1zpEmJpr/+67/OPv7xj/fYNn/+/Gzu3Lm9eq4R/fJce3t7bNq0KWpra7u3FRYWRm1tbTQ2Nh70mMbGxh77R0TMnTv3kPuTpi9r8X579+6Njo6Ofv3jjCNRX9fitttuiwkTJsTixYsHYswRoS9r8dRTT0VNTU1cd911UVlZGWeeeWbccccd0dnZOVBjD0t9WYtzzz03Nm3a1P0S3htvvBFr1qyJefPmDcjM/K/++tk9ov9g765du6KzszMqKyt7bK+srIxXX331oMfkcrmD7p/L5Y7anCNBX9bi/W666aaYNGnSB74x6J2+rMVzzz0XDz74YGzevHkAJhw5+rIWb7zxRjzzzDOxYMGCWLNmTfzyl7+Ma6+9Njo6OmLp0qUDMfaw1Je1uPzyy2PXrl3x6U9/OrIsi/3798ef/umfxte//vWBGJn/41A/u1tbW+O3v/1tHHPMMUnnGdFXmhg+li9fHqtXr44nnngiysrK8j3OiLJ79+5YuHBhPPDAAzFu3Lh8jzPidXV1xYQJE+L++++PGTNmxPz58+Pmm2+O++67L9+jjTgbNmyIO+64I/7xH/8xmpqa4oc//GH86Ec/ittvvz3fo9FHI/pK07hx46KoqCiam5t7bG9ubo6qqqqDHlNVVdWr/UnTl7U44K677orly5dHQ0NDfOITnziaY44IvV2L119/Pd566624+OKLu7d1dXVFRERxcXG89tprccoppxzdoYepvnxfTJw4MUaNGhVFRUXd204//fTI5XLR3t4eJSUlR3Xm4aova/E3f/M3sXDhwvjKV74SERFnnXVWtLW1xTXXXBM333xzFBa6bjFQDvWzu7y8PPkqU8QIv9JUUlISM2bMiPXr13dv6+rqivXr10dNTc1Bj6mpqemxf0TEunXrDrk/afqyFhERd955Z9x+++2xdu3amDlz5kCMOuz1di2mTp0aW7Zsic2bN3c/Pve5z8UFF1wQmzdvjurq6oEcf1jpy/fFpz71qfjlL3/ZHa4REb/4xS9i4sSJgukI9GUt9u7d+4EwOhCzmT/7OqD67Wd3796jPvysXr06Ky0tzR566KHslVdeya655pps7NixWS6Xy7IsyxYuXJjV19d37//8889nxcXF2V133ZVt3bo1W7p0qVsO9JPersXy5cuzkpKS7PHHH89+/etfdz92796dr09h2OjtWryf357rP71di7fffjsbM2ZMdv3112evvfZa9vTTT2cTJkzI/u7v/i5fn8Kw0du1WLp0aTZmzJjsX/7lX7I33ngj+/d///fslFNOyb7whS/k61MYNnbv3p299NJL2UsvvZRFRLZixYrspZdeyv7rv/4ry7Isq6+vzxYuXNi9/4FbDnzta1/Ltm7dmq1atcotB/rq7rvvzk466aSspKQkmzVrVvaTn/yk+2Pnn39+tmjRoh77/+AHP8hOPfXUrKSkJPv4xz+e/ehHPxrgiYev3qzFySefnEXEBx5Lly4d+MGHod5+X/xfoql/9XYtXnjhhWz27NlZaWlpNmXKlOzv//7vs/379w/w1MNTb9aio6Mju/XWW7NTTjklKysry6qrq7Nrr702++///u+BH3yY+fGPf3zQ//4f+PovWrQoO//88z9wzLRp07KSkpJsypQp2Xe/+91eP29BlrlGCADwYUb0e5oAAFKJJgCABKIJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAkaUnTt3RlVVVdxxxx3d21544YUoKSmJ9evX53EyYLDzB3uBEWfNmjVx6aWXxgsvvBCnnXZaTJs2LS655JJYsWJFvkcDBjHRBIxI1113XTQ0NMTMmTNjy5Yt8eKLL0ZpaWm+xwIGMdEEjEi//e1v48wzz4xt27bFpk2b4qyzzsr3SMAg5z1NwIj0+uuvx/bt26OrqyveeuutfI8DDAGuNAEjTnt7e8yaNSumTZsWp512WqxcuTK2bNkSEyZMyPdowCAmmoAR52tf+1o8/vjj8Z//+Z8xevToOP/886OioiKefvrpfI8GDGJengNGlA0bNsTKlSvj+9//fpSXl0dhYWF8//vfj//4j/+Ie++9N9/jAYOYK00AAAlcaQIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABP8Pm4O98x/HzSgAAAAASUVORK5CYII=\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=0.100\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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8cWsqKgou+uuu7LXX389+/a3v50NHTo027RpUy9PPvB09VhcccUV2bJly7JXX301e+ONN7KrrroqKysry37xi1/08uQDT1ePxX7vvPNOdvzxx2fnnXdedumll/bOsANcV4/Fnj17sqlTp2YzZ87MXnjhheydd97J1q5dm23cuLGXJx94unosHn300aykpCR79NFHs3feeSf713/912zcuHHZjTfe2MuTDzzPPvtsdvPNN2c/+tGPsojInnrqqU7Xv/3229nHPvaxrKamJnv99deze++9NysqKspWrlzZpccd9NE0bdq07Lrrrmv9vLm5ORs/fny2aNGidtd/+ctfzi6++OI226ZPn5790R/90VGdczDo6rE42L59+7IRI0Zk3//+94/WiINGd47Fvn37snPPPTf7h3/4h2zu3LmiqYd09Vjcf//92cSJE7O9e/f21oiDRlePxXXXXZf9/u//fpttNTU12ac//emjOudgkxJNf/mXf5l98pOfbLNt1qxZ2YwZM7r0WIP65bm9e/fG+vXro7q6unVbYWFhVFdXR21tbbv71NbWtlkfETFjxowO15OmO8fiYLt3746mpqYe/eWMg1F3j8Vtt90WY8eOjXnz5vXGmINCd47FM888E1VVVXHddddFeXl5nHnmmXHHHXdEc3Nzb409IHXnWJx77rmxfv361pfw3n777Xj22Wdj5syZvTIz/6ennrsH9S/s3bFjRzQ3N0d5eXmb7eXl5fHmm2+2u08ul2t3fS6XO2pzDgbdORYHu+mmm2L8+PGH/MOga7pzLF544YV4+OGHY+PGjb0w4eDRnWPx9ttvx3PPPRezZ8+OZ599Nn7+85/H17/+9WhqaoqFCxf2xtgDUneOxRVXXBE7duyIz3zmM5FlWezbty/++I//OL71rW/1xsgcoKPn7oaGhvj1r38dxxxzTNL9DOozTQwcixcvjuXLl8dTTz0Vw4YNy/c4g8rOnTtjzpw58dBDD8Xo0aPzPc6g19LSEmPHjo0HH3wwpkyZErNmzYqbb745HnjggXyPNuisXbs27rjjjvj7v//72LBhQ/zoRz+KH//4x3H77bfnezS6aVCfaRo9enQUFRVFXV1dm+11dXVRUVHR7j4VFRVdWk+a7hyL/e6+++5YvHhxrF69Oj71qU8dzTEHha4ei7feeivefffduOSSS1q3tbS0RETEkCFDYvPmzXHSSScd3aEHqO78uxg3blwMHTo0ioqKWredfvrpkcvlYu/evVFcXHxUZx6ounMsvvOd78ScOXPia1/7WkREnHXWWdHY2BjXXntt3HzzzVFY6LxFb+noubu0tDT5LFPEID/TVFxcHFOmTIk1a9a0bmtpaYk1a9ZEVVVVu/tUVVW1WR8RsWrVqg7Xk6Y7xyIi4q677orbb789Vq5cGVOnTu2NUQe8rh6L0047LTZt2hQbN25svX3hC1+ICy64IDZu3BiVlZW9Of6A0p1/F5/+9Kfj5z//eWu4RkT813/9V4wbN04wHYHuHIvdu3cfEkb7Yzbza197VY89d3ftGvWBZ/ny5VlJSUn2yCOPZK+//np27bXXZiNHjsxyuVyWZVk2Z86cbP78+a3rX3zxxWzIkCHZ3Xffnb3xxhvZwoULveVAD+nqsVi8eHFWXFycPfnkk9kvf/nL1tvOnTvz9S0MGF09Fgfz03M9p6vH4r333stGjBiRXX/99dnmzZuzFStWZGPHjs3++q//Ol/fwoDR1WOxcOHCbMSIEdk///M/Z2+//Xb2b//2b9lJJ52UffnLX87XtzBg7Ny5M3v11VezV199NYuIbMmSJdmrr76a/c///E+WZVk2f/78bM6cOa3r97/lwDe/+c3sjTfeyJYtW+YtB7rr3nvvzU444YSsuLg4mzZtWvYf//EfrV87//zzs7lz57ZZ/8Mf/jA75ZRTsuLi4uyTn/xk9uMf/7iXJx64unIsTjzxxCwiDrktXLiw9wcfgLr67+JAoqlndfVYvPTSS9n06dOzkpKSbOLEidnf/M3fZPv27evlqQemrhyLpqam7NZbb81OOumkbNiwYVllZWX29a9/Pfvf//3f3h98gPnJT37S7n//9//9z507Nzv//PMP2WfSpElZcXFxNnHixOwf//Efu/y4BVnmHCEAwOEM6muaAABSiSYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABKIJgCABKIJACCBaAIGle3bt0dFRUXccccdrdteeumlKC4ujjVr1uRxMqCv8wt7gUHn2WefjcsuuyxeeumlOPXUU2PSpElx6aWXxpIlS/I9GtCHiSZgULruuuti9erVMXXq1Ni0aVO88sorUVJSku+xgD5MNAGD0q9//es488wzY8uWLbF+/fo466yz8j0S0Me5pgkYlN56663YunVrtLS0xLvvvpvvcYB+wJkmYNDZu3dvTJs2LSZNmhSnnnpqLF26NDZt2hRjx47N92hAHyaagEHnm9/8Zjz55JPxs5/9LIYPHx7nn39+lJWVxYoVK/I9GtCHeXkOGFTWrl0bS5cujR/84AdRWloahYWF8YMf/CD+/d//Pe6///58jwf0Yc40AQAkcKYJACCBaAIASCCaAAASiCYAgASiCQAggWgCAEggmgAAEogmAIAEogkAIIFoAgBIIJoAABL8f50jvdzg5kzLAAAAAElFTkSuQmCC\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=0.500\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=1.500\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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jpcCoekEbLaZZV8+n4//ACqE1+vlWlQIrkXl4FpUFq5H5ch/jpfktUr2SgAAADWM0AQAAFAEQtMJuN1ubdmyRW632+pS6h7XonJwLSoH16KycD0qx0pcC8Ms5b14AAAANYqRJgAAgCIQmgAAAIpAaAIAACgCoQkAAKAIhCZJ9913n1avXq2GhgZt2LBBzz333HHP/8lPfqJ169apoaFBZ511lp544okyVVr7FnMtHnjgAZ1//vlqbW1Va2ururu7T3jtULzF/neR99BDD8kwDF122WUrW2AdWey1GBkZ0Y033qiOjg653W6tWbOG31MlsthrsW3bNq1du1aNjY1atWqVbr75Zk1NTZWp2tr1y1/+Updccok6OztlGIYeffTREz7nmWee0Tve8Q653W6ddtpp+v73v7/4Nzbr3EMPPWS6XC7zu9/9rvmHP/zBvP76602/32/29/cveP5vfvMb0263m3fddZf5xz/+0fziF79oOp1O88UXXyxz5bVnsdfiiiuuMO+77z7z+eefN1966SXzE5/4hOnz+cxDhw6VufLas9hrkbdv3z6zq6vLPP/8881LL720PMXWuMVei1QqZa5fv968+OKLzV//+tfmvn37zGeeecZ84YUXylx57VnstXjwwQdNt9ttPvjgg+a+ffvM//qv/zI7OjrMm2++ucyV154nnnjC/MIXvmA+/PDDpiTzkUceOe75r7/+utnU1GRu2rTJ/OMf/2jee++9pt1uN7dv376o96370HTuueeaN954Y+HP2WzW7OzsNLdu3brg+R/5yEfM97///XOObdiwwfyrv/qrFa2zHiz2Whwtk8mYLS0t5g9+8IOVKrFuLOVaZDIZ87zzzjP/7d/+zbzmmmsITSWy2GvxrW99yzzllFPM6enpcpVYNxZ7LW688UbzT//0T+cc27Rpk/mud71rReusN8WEpr//+7833/rWt845dvnll5sXXXTRot6rrqfnpqentWvXLnV3dxeO2Ww2dXd3a+fOnQs+Z+fOnXPOl6SLLrromOejOEu5FkebmJhQOp0u6eaM9Wip1+IrX/mKwuGwrrvuunKUWReWci0ee+wxbdy4UTfeeKPa29t15pln6qtf/aqy2Wy5yq5JS7kW5513nnbt2lWYwnv99df1xBNP6OKLLy5LzTiiVJ/ddb1hbzweVzabVXt7+5zj7e3tevnllxd8TjQaXfD8aDS6YnXWg6Vci6Pdcsst6uzsnPcfBhZnKdfi17/+tb7zne/ohRdeKEOF9WMp1+L111/X008/rSuvvFJPPPGEXn31VX3qU59SOp3Wli1bylF2TVrKtbjiiisUj8f17ne/W6ZpKpPJ6K//+q/1+c9/vhwlY5ZjfXYnk0lNTk6qsbGxqNep65Em1I4777xTDz30kB555BE1NDRYXU5dGR0d1VVXXaUHHnhAwWDQ6nLqXi6XUzgc1re//W2dc845uvzyy/WFL3xB999/v9Wl1Z1nnnlGX/3qV/Wv//qv2r17tx5++GH97Gc/0x133GF1aViiuh5pCgaDstvt6u/vn3O8v79fkUhkwedEIpFFnY/iLOVa5N19992688479dRTT+ltb3vbSpZZFxZ7LV577TXt379fl1xySeFYLpeTJDkcDu3Zs0ennnrqyhZdo5by30VHR4ecTqfsdnvh2Fve8hZFo1FNT0/L5XKtaM21ainX4ktf+pKuuuoqffKTn5QknXXWWRofH9cNN9ygL3zhC7LZGLcol2N9dnu93qJHmaQ6H2lyuVw655xztGPHjsKxXC6nHTt2aOPGjQs+Z+PGjXPOl6Qnn3zymOejOEu5FpJ011136Y477tD27du1fv36cpRa8xZ7LdatW6cXX3xRL7zwQuHxgQ98QBdeeKFeeOEFrVq1qpzl15Sl/Hfxrne9S6+++mohuErS3r171dHRQWBahqVci4mJiXnBKB9mTbZ9LauSfXYvbo167XnooYdMt9ttfv/73zf/+Mc/mjfccIPp9/vNaDRqmqZpXnXVVebmzZsL5//mN78xHQ6Heffdd5svvfSSuWXLFloOlMhir8Wdd95pulwu86c//anZ19dXeIyOjlr1I9SMxV6Lo3H3XOks9locOHDAbGlpMW+66SZzz5495uOPP26Gw2HzH/7hH6z6EWrGYq/Fli1bzJaWFvM//uM/zNdff938+c9/bp566qnmRz7yEat+hJoxOjpqPv/88+bzzz9vSjLvuece8/nnnzffeOMN0zRNc/PmzeZVV11VOD/fcuBzn/uc+dJLL5n33XcfLQeW6t577zVPPvlk0+Vymeeee6753//934W/u+CCC8xrrrlmzvn/+Z//aa5Zs8Z0uVzmW9/6VvNnP/tZmSuuXYu5Fm9605tMSfMeW7ZsKX/hNWix/13MRmgqrcVei2effdbcsGGD6Xa7zVNOOcX8x3/8RzOTyZS56tq0mGuRTqfNL3/5y+app55qNjQ0mKtWrTI/9alPmcPDw+UvvMb84he/WPD3f/7f/5prrjEvuOCCec85++yzTZfLZZ5yyinm9773vUW/r2GajBECAACcSF2vaQIAACgWoQkAAKAIhCYAAIAiEJoAAACKQGgCAAAoAqEJAACgCIQmAACAIhCaAAAAikBoAgAAKAKhCQAAoAiEJgAAgCIQmgDUlVgspkgkoq9+9auFY88++6xcLpd27NhhYWUAKh0b9gKoO0888YQuu+wyPfvss1q7dq3OPvtsXXrppbrnnnusLg1ABSM0AahLN954o5566imtX79eL774on73u9/J7XZbXRaACkZoAlCXJicndeaZZ+rgwYPatWuXzjrrLKtLAlDhWNMEoC699tpr6u3tVS6X0/79+60uB0AVYKQJQN2Znp7Wueeeq7PPPltr167Vtm3b9OKLLyocDltdGoAKRmgCUHc+97nP6ac//an+53/+Rx6PRxdccIF8Pp8ef/xxq0sDUMGYngNQV5555hlt27ZNP/zhD+X1emWz2fTDH/5Qv/rVr/Stb33L6vIAVDBGmgAAAIrASBMAAEARCE0AAABFIDQBAAAUgdAEAABQBEITAABAEQhNAAAARSA0AQAAFIHQBAAAUARCEwAAQBEITQAAAEUgNAEAABTh/wPYy7vaRUms7wAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=5.000\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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L72k66+/XlVVVbJYLHr66afP+Jzt27fr0ksvldPp1Hnnnadf/vKXw//GRoHbvHmz4XA4jH/+53829u3bZ3z5y182/H6/0dDQMOT5r776qmGz2Ywf/ehHxttvv238zd/8jVFUVGTs3bt3nCvPP8O9FqtWrTIefvhh44033jD2799vfPGLXzR8Pp/xwQcfjHPl+We416Lf0aNHjerqamPJkiXG8uXLx6fYPDfcaxGNRo0FCxYYy5YtM1555RXj6NGjxvbt243du3ePc+X5Z7jXYuPGjYbT6TQ2btxoHD161Pjtb39rVFZWGt/4xjfGufL889xzzxnf+ta3jKeeesqQZGzZsuW05x85csQoKSkx1q5da7z99tvGQw89ZNhsNmPr1q3D+r4FH5oWLlxo3HXXXen/TiaTRlVVlbFu3bohz//85z9vXHvttQOOLVq0yPiv//W/jmmdhWC41+KjEomE4fF4jH/5l38ZqxILxkiuRSKRMC677DLj//7f/2vcfvvthKZRMtxr8ZOf/MSYPn26EYvFxqvEgjHca3HXXXcZn/70pwccW7t2rfHJT35yTOssNJmEpv/5P/+nceGFFw44tnLlSuPqq68e1vcq6Om5WCymnTt3aunSpeljVqtVS5cu1Y4dO4Z8zo4dOwacL0lXX331Kc9HZkZyLT4qEokoHo+P6uaMhWik1+Lv/u7vNGnSJN15553jUWZBGMm1eOaZZ7R48WLdddddmjx5si666CL94Ac/UDKZHK+y89JIrsVll12mnTt3pqfwjhw5oueee07Lli0bl5rxodH67C7oDXubm5uVTCY1efLkAccnT56sAwcODPmcYDA45PnBYHDM6iwEI7kWH/XNb35TVVVVg34wMDwjuRavvPKKfv7zn2v37t3jUGHhGMm1OHLkiF588UXV1tbqueee07vvvquvfvWrisfjuu+++8aj7Lw0kmuxatUqNTc36/LLL5dhGEokEvpv/+2/6a//+q/Ho2Sc5FSf3eFwWN3d3SouLs7odQp6pAn54/7779fmzZu1ZcsWuVwus8spKB0dHVqzZo1+9rOfacKECWaXU/BSqZQmTZqkn/70p5o/f75Wrlypb33rW3rkkUfMLq3gbN++XT/4wQ/0f/7P/9GuXbv01FNP6Te/+Y2+973vmV0aRqigR5omTJggm82mhoaGAccbGhpUUVEx5HMqKiqGdT4yM5Jr0e+BBx7Q/fffrxdeeEGXXHLJWJZZEIZ7LQ4fPqz33ntP119/ffpYKpWSJNntdh08eFAzZswY26Lz1Eh+LiorK1VUVCSbzZY+NmfOHAWDQcViMTkcjjGtOV+N5Fr87d/+rdasWaMvfelLkqSLL75YXV1d+spXvqJvfetbsloZtxgvp/rs9nq9GY8ySQU+0uRwODR//nxt27YtfSyVSmnbtm1avHjxkM9ZvHjxgPMl6fnnnz/l+cjMSK6FJP3oRz/S9773PW3dulULFiwYj1Lz3nCvxezZs7V3717t3r07/bjhhht05ZVXavfu3aqpqRnP8vPKSH4uPvnJT+rdd99NB1dJeuedd1RZWUlgOgsjuRaRSGRQMOoPswbbvo6rUfvsHt4a9fyzefNmw+l0Gr/85S+Nt99+2/jKV75i+P1+IxgMGoZhGGvWrDHuueee9PmvvvqqYbfbjQceeMDYv3+/cd9999FyYJQM91rcf//9hsPhMJ588kmjvr4+/ejo6DDrj5A3hnstPoq750bPcK/FsWPHDI/HY9x9993GwYMHjWeffdaYNGmS8b/+1/8y64+QN4Z7Le677z7D4/EYjz32mHHkyBHjd7/7nTFjxgzj85//vFl/hLzR0dFhvPHGG8Ybb7xhSDIefPBB44033jDef/99wzAM45577jHWrFmTPr+/5cBf/dVfGfv37zcefvhhWg6M1EMPPWScc845hsPhMBYuXGj853/+Z/r3rrjiCuP2228fcP6vfvUrY+bMmYbD4TAuvPBC4ze/+c04V5y/hnMtzj33XEPSoMd99903/oXnoeH+XJyM0DS6hnstXnvtNWPRokWG0+k0pk+fbnz/+983EonEOFedn4ZzLeLxuPGd73zHmDFjhuFyuYyamhrjq1/9qtHa2jr+heeZ3//+90O+//f//d9+++3GFVdcMeg58+bNMxwOhzF9+nTjF7/4xbC/r8UwGCMEAAA4k4Je0wQAAJApQhMAAEAGCE0AAAAZIDQBAABkgNAEAACQAUITAABABghNAAAAGSA0AQAAZIDQBAAAkAFCEwAAQAYITQAAABkgNAEoKE1NTaqoqNAPfvCD9LHXXntNDodD27ZtM7EyANmODXsBFJznnntOK1as0GuvvaZZs2Zp3rx5Wr58uR588EGzSwOQxQhNAArSXXfdpRdeeEELFizQ3r179cc//lFOp9PssgBkMUITgILU3d2tiy66SMePH9fOnTt18cUXm10SgCzHmiYABenw4cOqq6tTKpXSe++9Z3Y5AHIAI00ACk4sFtPChQs1b948zZo1S+vXr9fevXs1adIks0sDkMUITQAKzl/91V/pySef1J49e+R2u3XFFVfI5/Pp2WefNbs0AFmM6TkABWX79u1av369Hn30UXm9XlmtVj366KN6+eWX9ZOf/MTs8gBkMUaaAAAAMsBIEwAAQAYITQAAABkgNAEAAGSA0AQAAJABQhMAAEAGCE0AAAAZIDQBAABkgNAEAACQAUITAABABghNAAAAGSA0AQAAZOD/A49XN4mmXGFYAAAAAElFTkSuQmCC\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=25.000\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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NIkuIBb79u3Dxo0b8dlnn2H8+PEAgD/84Q+YPn061q5di7KyslO+d/fu3Xjsscfwz3/+E1ardbBKJiIiojSTEj1N27dvR15eXjQwAUBVVRVUKhU+/fTTU76vo6MDN954I9avXw+LxRLTufx+P7xeb4+NiIiIKCVCk9vtRklJSY99Go0GBQUFcLvdp3zfPffcg4suughXX311zOdasWIFcnNzo5vdbu933URERJQ+EhqaFi5cCEmSTrvt37+/X22//fbb2Lp1K9atW9en9y1atAgejye6ORyOfp2fiIiI0ktCxzTde++9uOWWW057zNChQ2GxWFBfX99jfygUQnNz8ylvu23duhWHDh1CXl5ej/3XXnstJk+ejG3btvX6Pr1eD71eH+u3QERERBkioaGpuLgYxcXFZzxu0qRJaGlpwc6dOzFu3DgAkVAkyzImTpzY63sWLlyIX/3qVz32jRkzBk888QSuuuqqgRdPREREGSUlnp4bNWoUrrjiCtx22214+umnEQwGcdddd+EXv/hF9Mk5l8uFqVOn4i9/+QsmTJgAi8XSay9URUUFzjrrrMH+FoiIiCjFpcRAcAB4+eWXMXLkSEydOhXTp0/HJZdcgmeeeSb6ejAYxIEDB9DR0ZHAKomIiChdSUIIkegikpnX60Vubi48Hg/MZnOiyyEiIqIYxOPzO2V6moiIiIgSiaGJiIiIKAYMTUREREQxYGgiIiIiigFDExEREVEMGJqIiIiIYsDQRERERBQDhiYiIiKiGDA0EREREcWAoYmIiIgoBgxNRERERDFgaCIiIiKKAUMTERERUQwYmoiIiIhiwNBEREREFAOGJiIiIqIYMDQRERERxYChiYiIiCgGDE1EREREMWBoIiIiIooBQxMRERFRDBiaiIiIiGLA0EREREQUA4YmIiIiohgwNBERERHFgKGJiIiIKAYMTUREREQxYGgiIiIiigFDExEREVEMNIkuINkJIQAAXq83wZUQERFRrLo+t7s+x5XA0HQGTU1NAAC73Z7gSoiIiKivmpqakJubq0hbDE1nUFBQAACorq5W7C+d+sfr9cJut8PhcMBsNie6nIzGa5E8eC2SC69H8vB4PKioqIh+jiuBoekMVKrIsK/c3Fz+ACQJs9nMa5EkeC2SB69FcuH1SB5dn+OKtKVYS0RERERpjKGJiIiIKAYMTWeg1+uxdOlS6PX6RJeS8XgtkgevRfLgtUguvB7JIx7XQhJKPotHRERElKbY00REREQUA4YmIiIiohgwNBERERHFgKGJiIiIKAYMTQDWr1+PIUOGwGAwYOLEidixY8dpj3/ttdcwcuRIGAwGjBkzBu+9994gVZr++nItnn32WUyePBn5+fnIz89HVVXVGa8dxa6vPxddNmzYAEmSMGPGjPgWmEH6ei1aWlpw5513wmq1Qq/XY/jw4fw9pZC+Xot169ZhxIgRMBqNsNvtuOeee9DZ2TlI1aavDz74AFdddRXKysogSRLeeuutM75n27Zt+MEPfgC9Xo9hw4bhhRde6PuJRYbbsGGD0Ol04vnnnxd79+4Vt912m8jLyxN1dXW9Hv/xxx8LtVotVq9eLb7++mtx//33C61WK/bs2TPIlaefvl6LG2+8Uaxfv158/vnnYt++feKWW24Rubm5wul0DnLl6aev16LLkSNHhM1mE5MnTxZXX3314BSb5vp6Lfx+vxg/fryYPn26+Oijj8SRI0fEtm3bxO7duwe58vTT12vx8ssvC71eL15++WVx5MgR8b//+7/CarWKe+65Z5ArTz/vvfeeWLx4sXjjjTcEAPHmm2+e9vjDhw+LrKwsMWfOHPH111+LP/zhD0KtVouNGzf26bwZH5omTJgg7rzzzuh/h8NhUVZWJlasWNHr8T//+c/FlVde2WPfxIkTxb/927/Ftc5M0NdrcaJQKCRMJpN48cUX41VixujPtQiFQuKiiy4Sf/rTn8TNN9/M0KSQvl6Lp556SgwdOlQEAoHBKjFj9PVa3HnnneKyyy7rsW/OnDni4osvjmudmSaW0DR//nxx7rnn9th3/fXXi2nTpvXpXBl9ey4QCGDnzp2oqqqK7lOpVKiqqsL27dt7fc/27dt7HA8A06ZNO+XxFJv+XIsTdXR0IBgMKro4Yybq77V46KGHUFJSgtmzZw9GmRmhP9fi7bffxqRJk3DnnXeitLQU5513Hh599FGEw+HBKjst9edaXHTRRdi5c2f0Ft7hw4fx3nvvYfr06YNSM31Pqc/ujF6wt7GxEeFwGKWlpT32l5aWYv/+/b2+x+1293q82+2OW52ZoD/X4kQLFixAWVnZST8Y1Df9uRYfffQRnnvuOezevXsQKswc/bkWhw8fxtatWzFz5ky89957OHjwIO644w4Eg0EsXbp0MMpOS/25FjfeeCMaGxtxySWXQAiBUCiEX//617jvvvsGo2Tq5lSf3V6vFz6fD0ajMaZ2MrqnidLHypUrsWHDBrz55pswGAyJLiejtLa2YtasWXj22WdRVFSU6HIynizLKCkpwTPPPINx48bh+uuvx+LFi/H0008nurSMs23bNjz66KP44x//iF27duGNN97Au+++i+XLlye6NOqnjO5pKioqglqtRl1dXY/9dXV1sFgsvb7HYrH06XiKTX+uRZe1a9di5cqV2Lx5M84///x4lpkR+notDh06hKNHj+Kqq66K7pNlGQCg0Whw4MABnH322fEtOk315+fCarVCq9VCrVZH940aNQputxuBQAA6nS6uNaer/lyLBx54ALNmzcKvfvUrAMCYMWPQ3t6O22+/HYsXL4ZKxX6LwXKqz26z2RxzLxOQ4T1NOp0O48aNw5YtW6L7ZFnGli1bMGnSpF7fM2nSpB7HA8CmTZtOeTzFpj/XAgBWr16N5cuXY+PGjRg/fvxglJr2+notRo4ciT179mD37t3R7ac//SmmTJmC3bt3w263D2b5aaU/PxcXX3wxDh48GA2uAPDNN9/AarUyMA1Af65FR0fHScGoK8wKLvs6qBT77O7bGPX0s2HDBqHX68ULL7wgvv76a3H77beLvLw84Xa7hRBCzJo1SyxcuDB6/Mcffyw0Go1Yu3at2Ldvn1i6dCmnHFBIX6/FypUrhU6nE6+//rqora2Nbq2trYn6FtJGX6/Fifj0nHL6ei2qq6uFyWQSd911lzhw4IB45513RElJiXj44YcT9S2kjb5ei6VLlwqTyST+8z//Uxw+fFj87W9/E2effbb4+c9/nqhvIW20traKzz//XHz++ecCgHj88cfF559/Lr777jshhBALFy4Us2bNih7fNeXAvHnzxL59+8T69es55UB//eEPfxAVFRVCp9OJCRMmiH/84x/R1y699FJx88039zj+1VdfFcOHDxc6nU6ce+654t133x3kitNXX65FZWWlAHDStnTp0sEvPA319eeiO4YmZfX1WnzyySdi4sSJQq/Xi6FDh4pHHnlEhEKhQa46PfXlWgSDQbFs2TJx9tlnC4PBIOx2u7jjjjvEsWPHBr/wNPP+++/3+vu/6+//5ptvFpdeeulJ7xk7dqzQ6XRi6NCh4s9//nOfzysJwT5CIiIiojPJ6DFNRERERLFiaCIiIiKKAUMTERERUQwYmoiIiIhiwNBEREREFAOGJiIiIqIYMDQRERERxYChiYiIiCgGDE1EREREMWBoIiIiIooBQxMRERFRDBiaiCijNDQ0wGKx4NFHH43u++STT6DT6bBly5YEVkZEyY4L9hJRxnnvvfcwY8YMfPLJJxgxYgTGjh2Lq6++Go8//niiSyOiJMbQREQZ6c4778TmzZsxfvx47NmzB5999hn0en2iyyKiJMbQREQZyefz4bzzzoPD4cDOnTsxZsyYRJdEREmOY5qIKCMdOnQINTU1kGUZR48eTXQ5RJQC2NNERBknEAhgwoQJGDt2LEaMGIF169Zhz549KCkpSXRpRJTEGJqIKOPMmzcPr7/+Or744gvk5OTg0ksvRW5uLt55551El0ZESYy354goo2zbtg3r1q3DSy+9BLPZDJVKhZdeegkffvghnnrqqUSXR0RJjD1NRERERDFgTxMRERFRDBiaiIiIiGLA0EREREQUA4YmIiIiohgwNBERERHFgKGJiIiIKAYMTUREREQxYGgiIiIiigFDExEREVEMGJqIiIiIYsDQRERERBSD/w+Osbdn1rQ0kAAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Time, t=500.000\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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AUMTERERkQQMTUREREQSMDQBWL16NWw2G7RaLaZNm4YPPvjgoNu/8MILmDRpErRaLY4//ni8/vrrY1Rp/kvkXGzYsAFnnHEGSkpKUFJSgvr6+kOeO5Iu0Z+LIc8++yxkMhkuvfTS0S1wHEn0XPT19WHBggWorKyERqPBkUceyfepNEn0XKxcuRJHHXUUCgoKYLVaceutt2JgYGCMqs1fb7/9Ni666CJUVVVBJpPhlVdeOWSbLVu2YMqUKdBoNDj88MPx1FNPJX5gMc49++yzQq1Wi9/85jfiP//5j5g9e7YoLi4Wbrd7v9u/++67QqFQiOXLl4tPPvlE/PSnPxUqlUrs3LlzjCvPP4meiyuuuEKsXr1afPTRR2LXrl3i2muvFUajUbS0tIxx5fkn0XMxpKmpSVRXV4szzjhDXHLJJWNTbJ5L9FyEQiExdepUccEFF4h33nlHNDU1iS1btogdO3aMceX5J9Fz8fTTTwuNRiOefvpp0dTUJP72t7+JyspKceutt45x5fnn9ddfF3fffbd46aWXBADx8ssvH3T7xsZGodPpRENDg/jkk0/E448/LhQKhXjjjTcSOu64D02nnHKKWLBgwfC/Y7GYqKqqEkuXLt3v9t/73vfEhRdeOOK5adOmiblz545qneNBoudiX9FoVOj1evG73/1utEocN5I5F9FoVJx66qni17/+tbjmmmsYmtIk0XOxZs0aMXHiRBEOh8eqxHEj0XOxYMEC8a1vfWvEcw0NDeK0004b1TrHGymh6c477xTHHnvsiOcuv/xyMWvWrISONa4vz4XDYWzbtg319fXDz8nlctTX12Pr1q37bbN169YR2wPArFmzDrg9SZPMudhXIBBAJBJJ6+KM41Gy5+K+++6DyWTC9ddfPxZljgvJnIs///nPmD59OhYsWACz2YzjjjsODzzwAGKx2FiVnZeSORennnoqtm3bNnwJr7GxEa+//jouuOCCMamZvpKuz+5xvWBvV1cXYrEYzGbziOfNZjM+/fTT/bZxuVz73d7lco1aneNBMudiX3fddReqqqq+9oNBiUnmXLzzzjt48sknsWPHjjGocPxI5lw0NjbirbfewpVXXonXX38dX3zxBebPn49IJIIlS5aMRdl5KZlzccUVV6Crqwunn346hBCIRqOYN28efvKTn4xFybSXA312e71eBINBFBQUSNrPuO5povyxbNkyPPvss3j55Zeh1WozXc644vP5cNVVV2HDhg0oLy/PdDnjXjweh8lkwvr163HSSSfh8ssvx9133421a9dmurRxZ8uWLXjggQfwxBNPYPv27XjppZfwl7/8Bffff3+mS6MkjeuepvLycigUCrjd7hHPu91uWCyW/baxWCwJbU/SJHMuhjz00ENYtmwZNm3ahBNOOGE0yxwXEj0Xe/bsgd1ux0UXXTT8XDweBwAolUp89tlnOOyww0a36DyVzM9FZWUlVCoVFArF8HNHH300XC4XwuEw1Gr1qNacr5I5Fz/72c9w1VVX4YYbbgAAHH/88fD7/ZgzZw7uvvtuyOXstxgrB/rsNhgMknuZgHHe06RWq3HSSSdh8+bNw8/F43Fs3rwZ06dP32+b6dOnj9geADZu3HjA7UmaZM4FACxfvhz3338/3njjDUydOnUsSs17iZ6LSZMmYefOndixY8fw4+KLL8Y555yDHTt2wGq1jmX5eSWZn4vTTjsNX3zxxXBwBYDdu3ejsrKSgSkFyZyLQCDwtWA0FGYFl30dU2n77E5sjHr+efbZZ4VGoxFPPfWU+OSTT8ScOXNEcXGxcLlcQgghrrrqKrFo0aLh7d99912hVCrFQw89JHbt2iWWLFnCKQfSJNFzsWzZMqFWq8WLL74o2tvbhx8+ny9TX0LeSPRc7It3z6VPoufC4XAIvV4vFi5cKD777DPx2muvCZPJJH7xi19k6kvIG4meiyVLlgi9Xi/+53/+RzQ2Noo333xTHHbYYeJ73/tepr6EvOHz+cRHH30kPvroIwFArFixQnz00UeiublZCCHEokWLxFVXXTW8/dCUA3fccYfYtWuXWL16NaccSNbjjz8uamtrhVqtFqeccor45z//OfzaWWedJa655poR2z///PPiyCOPFGq1Whx77LHiL3/5yxhXnL8SORd1dXUCwNceS5YsGfvC81CiPxd7Y2hKr0TPxXvvvSemTZsmNBqNmDhxovjlL38potHoGFednxI5F5FIRNx7773isMMOE1qtVlitVjF//nzR29s79oXnmb///e/7ff8f+v5fc8014qyzzvpam8mTJwu1Wi0mTpwofvvb3yZ8XJkQ7CMkIiIiOpRxPaaJiIiISCqGJiIiIiIJGJqIiIiIJGBoIiIiIpKAoYmIiIhIAoYmIiIiIgkYmoiIiIgkYGgiIiIikoChiYiIiEgChiYiIiIiCRiaiIiIiCRgaCKicaWzsxMWiwUPPPDA8HPvvfce1Go1Nm/enMHKiCjbccFeIhp3Xn/9dVx66aV47733cNRRR2Hy5Mm45JJLsGLFikyXRkRZjKGJiMalBQsWYNOmTZg6dSp27tyJDz/8EBqNJtNlEVEWY2gionEpGAziuOOOg9PpxLZt23D88cdnuiQiynIc00RE49KePXvQ1taGeDwOu92e6XKIKAewp4mIxp1wOIxTTjkFkydPxlFHHYWVK1di586dMJlMmS6NiLIYQxMRjTt33HEHXnzxRXz88ccoKirCWWedBaPRiNdeey3TpRFRFuPlOSIaV7Zs2YKVK1fiD3/4AwwGA+RyOf7whz/gf//3f7FmzZpMl0dEWYw9TUREREQSsKeJiIiISAKGJiIiIiIJGJqIiIiIJGBoIiIiIpKAoYmIiIhIAoYmIiIiIgkYmoiIiIgkYGgiIiIikoChiYiIiEgChiYiIiIiCRiaiIiIiCT4/76xYEXc1oi+AAAAAElFTkSuQmCC\n" + }, + "metadata": {} + } + ], + "source": [ + "def draw_func_uncertain(X, y, x ,predict_mean, predict_std, t):\n", + " fig, ax = plt.subplots()\n", + " ax.plot(X[0:1,:],y.T,'ro')\n", + " ax.plot(x[0:1,:].T, predict_mean,'r-')\n", + " lower = predict_mean-predict_std\n", + " upper = predict_mean+predict_std\n", + " ax.fill_between(np.squeeze(x[0:1,:].T), np.squeeze(lower), np.squeeze(upper), color='lightgray')\n", + " ax.set_xlim([0,1]); ax.set_ylim([-0.5,0.5])\n", + " ax.set_xlabel('x'); ax.set_ylabel('y')\n", + " plt.show()\n", + "\n", + "for t in (0.0, 0.1, 0.5,1.5,5.0,25.0,500.0):\n", + " print('Time, t=%3.3f'%(t))\n", + " f_mean, f_std = kernel_predict_uncertainty(X, x_vals, y, t)\n", + " draw_func_uncertain(X, y, x_vals, f_mean, f_std, t)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Draw the kernel" + ], + "metadata": { + "id": "P6eg1Co5lIcZ" + } + }, + { + "cell_type": "code", + "source": [ + "def draw_kernel(X1):\n", + " # Define pretty colormap\n", + " my_colormap_vals_hex =('2a0902', '2b0a03', '2c0b04', '2d0c05', '2e0c06', '2f0d07', '300d08', '310e09', '320f0a', '330f0b', '34100b', '35110c', '36110d', '37120e', '38120f', '39130f', '3a1410', '3b1411', '3c1511', '3d1612', '3e1613', '3f1713', '401714', '411814', '421915', '431915', '451a16', '461b16', '471b17', '481c17', '491d18', '4a1d18', '4b1e19', '4c1f19', '4d1f1a', '4e201b', '50211b', '51211c', '52221c', '53231d', '54231d', '55241e', '56251e', '57261f', '58261f', '592720', '5b2821', '5c2821', '5d2922', '5e2a22', '5f2b23', '602b23', '612c24', '622d25', '632e25', '652e26', '662f26', '673027', '683027', '693128', '6a3229', '6b3329', '6c342a', '6d342a', '6f352b', '70362c', '71372c', '72372d', '73382e', '74392e', '753a2f', '763a2f', '773b30', '783c31', '7a3d31', '7b3e32', '7c3e33', '7d3f33', '7e4034', '7f4134', '804235', '814236', '824336', '834437', '854538', '864638', '874739', '88473a', '89483a', '8a493b', '8b4a3c', '8c4b3c', '8d4c3d', '8e4c3e', '8f4d3f', '904e3f', '924f40', '935041', '945141', '955242', '965343', '975343', '985444', '995545', '9a5646', '9b5746', '9c5847', '9d5948', '9e5a49', '9f5a49', 'a05b4a', 'a15c4b', 'a35d4b', 'a45e4c', 'a55f4d', 'a6604e', 'a7614e', 'a8624f', 'a96350', 'aa6451', 'ab6552', 'ac6552', 'ad6653', 'ae6754', 'af6855', 'b06955', 'b16a56', 'b26b57', 'b36c58', 'b46d59', 'b56e59', 'b66f5a', 'b7705b', 'b8715c', 'b9725d', 'ba735d', 'bb745e', 'bc755f', 'bd7660', 'be7761', 'bf7862', 'c07962', 'c17a63', 'c27b64', 'c27c65', 'c37d66', 'c47e67', 'c57f68', 'c68068', 'c78169', 'c8826a', 'c9836b', 'ca846c', 'cb856d', 'cc866e', 'cd876f', 'ce886f', 'ce8970', 'cf8a71', 'd08b72', 'd18c73', 'd28d74', 'd38e75', 'd48f76', 'd59077', 'd59178', 'd69279', 'd7937a', 'd8957b', 'd9967b', 'da977c', 'da987d', 'db997e', 'dc9a7f', 'dd9b80', 'de9c81', 'de9d82', 'df9e83', 'e09f84', 'e1a185', 'e2a286', 'e2a387', 'e3a488', 'e4a589', 'e5a68a', 'e5a78b', 'e6a88c', 'e7aa8d', 'e7ab8e', 'e8ac8f', 'e9ad90', 'eaae91', 'eaaf92', 'ebb093', 'ecb295', 'ecb396', 'edb497', 'eeb598', 'eeb699', 'efb79a', 'efb99b', 'f0ba9c', 'f1bb9d', 'f1bc9e', 'f2bd9f', 'f2bfa1', 'f3c0a2', 'f3c1a3', 'f4c2a4', 'f5c3a5', 'f5c5a6', 'f6c6a7', 'f6c7a8', 'f7c8aa', 'f7c9ab', 'f8cbac', 'f8ccad', 'f8cdae', 'f9ceb0', 'f9d0b1', 'fad1b2', 'fad2b3', 'fbd3b4', 'fbd5b6', 'fbd6b7', 'fcd7b8', 'fcd8b9', 'fcdaba', 'fddbbc', 'fddcbd', 'fddebe', 'fddfbf', 'fee0c1', 'fee1c2', 'fee3c3', 'fee4c5', 'ffe5c6', 'ffe7c7', 'ffe8c9', 'ffe9ca', 'ffebcb', 'ffeccd', 'ffedce', 'ffefcf', 'fff0d1', 'fff2d2', 'fff3d3', 'fff4d5', 'fff6d6', 'fff7d8', 'fff8d9', 'fffada', 'fffbdc', 'fffcdd', 'fffedf', 'ffffe0')\n", + " my_colormap_vals_dec = np.array([int(element,base=16) for element in my_colormap_vals_hex])\n", + " r = np.floor(my_colormap_vals_dec/(256*256))\n", + " g = np.floor((my_colormap_vals_dec - r *256 *256)/256)\n", + " b = np.floor(my_colormap_vals_dec - r * 256 *256 - g * 256)\n", + " my_colormap = ListedColormap(np.vstack((r,g,b)).transpose()/255.0)\n", + "\n", + " # Make grid of intercept/slope values to plot\n", + " x_mesh, y_mesh = np.meshgrid(np.arange(-4,4,0.05), np.arange(-4,4,0.05))\n", + " kernel_mesh = np.zeros_like(x_mesh)\n", + "\n", + " for idx, x in np.ndenumerate(x_mesh):\n", + " X2 = np.ones((2,1))\n", + " X2[0,0] = x+0.0001\n", + " X2[1,0] = y_mesh[idx]+0.0001\n", + " kernel_mesh[idx] = compute_analytical_ntk(X1, X2)[0,0]\n", + "\n", + " fig,ax = plt.subplots()\n", + " fig.set_size_inches(8,8)\n", + " ax.contour(x_mesh,y_mesh,kernel_mesh,20,colors=['#80808080'])\n", + " ax.contourf(x_mesh,y_mesh,kernel_mesh,256,cmap=my_colormap)\n", + " ax.set_ylim([-4,4])\n", + " ax.set_xlabel('$x^*[0]$')\n", + " ax.set_ylabel('$x^*[1]$')\n", + "\n", + " plt.show()\n", + "\n", + "# Draw kernel for X1 = 1.0\n", + "X1 = np.ones((2,1))\n", + "X1[0,0] = 1.000000\n", + "draw_kernel(X1)" + ], + "metadata": { + "id": "FcJHyAsl9t47", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 707 + }, + "outputId": "9857d813-9a12-456e-fba1-1e56a33485a5" + }, + "execution_count": 27, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAArcAAAKyCAYAAADPUPbEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9ya8sW5beif22dd53p+9uf+97EZGZwWADFRICVJAyWVQVVYKIKgkFpcQSRajEAgckqAGRQwIEkkD+AUSCnHCWAwIkwAFBcEJymkxGZkZGxOtuf09/3I+35m7t1sDcz/HGOvfjfu69L3w9PFw/ZmuvvfZ2c/PPl31rLSGllKxlLWtZy1rWspa1rGUt3wNRPrYDa1nLWtaylrWsZS1rWcuyZA1u17KWtaxlLWtZy1rW8r2RNbhdy1rWspa1rGUta1nL90bW4HYta1nLWtaylrWsZS3fG1mD27WsZS1rWcta1rKWtXxvZA1u17KWtaxlLWtZy1rW8r2RNbhdy1rWspa1rGUta1nL90bW4HYta1nLWtaylrWsZS3fG1mD27WsZS1rWcta1rKWtXxvZA1u17KWtaxlLWtZy1rW8r2R7x24/Sf/5J8ghODv//2//7FdWcta1rKWtaxlLWtZyz3L9wrc/tEf/RF/8Ad/wI9//OOP7cpa1rKWtaxlLWtZy1o+gnxvwG232+V3fud3+Gf/7J9Rq9U+tjtrWcta1rKWtaxlLWv5CKJ9bAeWJX/37/5d/vpf/+v89m//Nv/4H//jWF3LsrAs6+Zv3/dpNBpsbm4ihFi1q2tZy1rWspa1rGUta5lTpJR0Oh0ODg5QlOj47PcC3P7hH/4h/+W//Bf+6I/+KJX+7/3e7/GP/tE/WrFXa1nLWtaylrWsZS1rWba8f/+eo6OjyPOfPbh9//49f+/v/T3+/b//92Sz2VRjfvd3f5d/8A/+wc3frVaLhw8f8v79e8rl8qpcXcta1rKWtaxlLWtZy4LSbrd58OABpVIpVk9IKeU9+bQS+df/+l/zN/7G30BV1ZtjnuchhEBRFCzLmjgXJu12m0qlQqvV+iTAreu6aNpn/7tjpeJ5XuL7+n0R3/djH7986jK6xXzqlJ9P1U8p5Sfh08f242PPv5a1rOXjS1q89tkjqN/6rd/iZz/72cSxv/W3/hY/+MEP+If/8B/OBYD+1//qJxhqOIhIc1NNpxN/Xs8XyT14hF2/wq5fgfQnzitKvIEkD5J8jDsfN3ecVSXGZux8MeeMR8+Q1gD36hw8b8ze8uYJGxO1BVH2RcjORO1jmAmRK8DmLtTPYNCPtBllN2xtofNMHQwfl3wszLZX2URqOtr1JUL6KGL2MzY9bnr+0PdCideZHjGzxqkfDHa+hKdnyLXrCGaBVNzfSf5OvzUTY6f8GB/qKyrtQo1iv43uObFrGD8T5+usjfBz468l0MqU0H2XojuIHBNnI808UeckcK3m0PGpSHtyTOR8SphK5NxRY/uoNHyNA8VGnVjDmM2JueazH7YWF8GJrbCn++T05HUk7UGSrpSShitwJBzklFD9yGs2ar2jvQoZJ6XkxPQwFMFOXgudQ4x9d4fu44Ru/P73HJ/3rQHPN/Po47rj+CDMh7A5Js7P7oPj+by87PJos0A+Z4TrKiFzje+pEjbX2Hsy9MX1fL47aXK4VaJcGHtyPX6dKuqMrYkbkgi5RkL2xXE9vn13ycP9GsVifsaXcVuT9kPshuzb+Djb8fjmu2OePdknNz4XABukkc83HDSUUqnEr//6r0/8XygU2Nzc5Nd//deXNk+aAPcyguBqpYpQVDLbuxSff4le22T8a8v34+dI8uAuPsbNHWfVj5kzzp+ocSJfQOgGSqmC8fAZSrk6Zm/+eeaRqC2Yx37Sezhht1wDTYPdI6htgxDIxHf57hK29+k+A1N/KypeoYyfzeNsH+BrBv7UD7Y086/6AZMvFOx8GdfIYVZ38OeMlN/FX9+P3g8zU8BVdVqFDWzNiNSblrj50/o2rjdQDUw1Q0sv0FMzC9m7iz+m0OgoBg0lS1fod5pvHvElnPoGPaly5huR95dly6kt6HiCd7aC4yZ/XpJkYo9DFmF68KEvOR9Imnb4Ihd+n0PGNSyfk67Lu45D1/HHVOeYY47r+JvLHtemw6tG/+73koTxry+7XHUHfHXawkv6vk7yJeH8m/MWF80ev3x3het6sbpJtpJ8efX+iotGh1+8PMPzEq7JpO+4hO+Ab755z9VVi1989W7y/igE8C7e9lA+e3C7TIkDYRC8+UkXQJKOlPHX2OD0A70Pb/FsC6FpZPcOKDx7gVau3Prpy0SgGedlnI9J/i86ry9l5P7GzRkKsswe9vvX+IM+qCrazj760WNEJju0F+FfzBxRYC5szDwAVw7/m7ERYiT02rg4RrabwetyFfYegp5JbTN8Xel8TwNww/Zo/E/he2iXx+A6SE3H2T7AyxVmAG6YT0mAcXq9M36E+D6u4/v+zY1TkT655iXC9/A0A7O6i6toM+Nj/Yk5P/3WzK5l/Av+9nih38ZwBkghaOdrDFQjetzkFBNzxPk+vo9RelnPpuiYADSNIl1hhOrFvU4zT9TrvHQpekGFmyuRw5TK+OCI+cL3NJ2vw+tCwL6wEELSkSoXvjamP2bTDwdoSfanj4+M7us+upBYvuCDrdzMFbWOdHsQ/XkuaIKt4W+Gt6aPOQ6ow+4Nfvj5ifWG3Y+G4zYyCrWMgi/hZdPGCQFLcuyJXNy1HOhG778QguebOYQQ1Hs2Zx1rbNwsIIx8/8J8lLP78HirgK4o9GyXl2etcN2w+//4nob84J1Y99CXx7sVMrrKwHb55kPjVmf8s+aHgF5/4uKdPT++L0ObT4+2MDQVc2Dz7ZuzGV8ibU34HeLL+PmhX8+fHaBpKp2OyeuXJ5O6KX+cfPac22XIiMPxP335+IaWEPdIfCTLoCpEnxYYtRqZrV0ULbjreIM+1vkpntmb0LwLVeFzpymolRra1g4oKkiJ12rgjdE55qUpzENRCPTT25+HTjAzfEhPEJoWfLibdWhfR9r91CgKUlFwazvIbPCISe22UNsN1CVQFML3bzGKgq9omJUtpKYjpE+ufYXmWKkfoyf5G0dPGPcjOBf8K4FOvopt5BASSv0mWdeKHhez1lhqRQLVQAJtvUBPzyGAqt2hKJ1Uc80zT9RrCVwpOUzVQEjJvt8jK8Z/Sa2OntCRKqd+ELHeVWxqqj+mP2ZzGfSE4b99H97YGr6ELc3nIBdBiUigHCRRIEbHpZS87El6viCjwBcl5fYRfgr/w3RExONpRVFwfckvGzYDT1LJKHxRy9yOS6AnRK4jhJ4w+vekbfG2OUAIwa/vFihl9bFxs4/uw94zoUatd/J407T5+UkLieTLvQo71fysbhRNZ056Qtu0+NNXl0gpeXG4wcHWGA91RH9QZmkGEz6IiGtkip7QbJv8yTfHAPzw6R6729UJX6ZthdITJmyG7OdwzOVVi5//MojS/savPWFzpwZAu92hUv1xIud2HbmNkLhI40hWG8mV2NcNOt99zeDiDOl5qNkc+UdPyT18gjJWGSJNJHdx/2KiqjHzriqKOz3Oa11jvXmJ12mBEKjVTfRHT1EKpaG9cB+io7KfaBS334OTt8heN7gJ1LYCqoKqrTyKG7YncVGgsDUI30ern6EMAblXrOBu7uMJkRjFTRPBXSSKO2ljGKnzXfLNC1THQgoFs7KNk8nPRHPiIklJEdyJoEmKCK4ASmaTjGUiBXRyVfpaNnpczFrvEsEVQNnpkXf6SKBplOjFUAQWieDGjRfAlt8n47lIIThXCthy/BfU6iK4JeGxKWwALqRO1xdj+mM27xDBnTaYU+BADyJdV65C3ZLTKjP2kqKscdFeIQSP8gINieXDW3PsOk/jf9g9wQ+fz/d9NEXwrKKjCGhZPiddZ0x1PGIaH12d8C00uhqc3y8ZbOR0pJR8c2WGRouj1hlqf0J30lY1b/CgFgDa7y7amAN7dq6Iz4GMuSbC/CrnMzzeDUDey5NruubkD9/A5mwkdsIHGXGNTO19tZzn8X7Aef3mzQVmfxDia3yEejIqHLKfwzHbWxUOh3P9+S/e8Pb1SSLeGpc1uE2QZYLc+PMRQEz6WPULOi+/wmpcgpRohSKFJy/IHjxA6LdfLquiKiT5/zFA7oR4Lu7ZMfbxW6RtIzQdbf8Ibf8IND32ScY8dIgo/WnAkrSGKDAaBXJvlTy4PEFenQWPrbI5OHgE+WIocA6zGQ5UZ/cnDU0hnJIQvQYBaJ1rtHrgv5/J4mwf4uuZhQDuMmgKk+PHKQoXaAMTEPRLm1i5UixonQfgBueT/QjOBf8KoNhvkbV6AcDNVzD1XPS4mLXeFeBWnB55dxAkeRklTLTYMfPMk3QPEsCO30P3PTwhOFPyOHJCKWK+uwPcDeFSFg5SCk59g0EErksDcKPWN22wokq2tcDeiaNM8VMjxsasIWqe0XFdETzJB8+C2o7krJ9MPwgD6JH0hCk/87rCo1LwHXbSc2kN3NRrSgL1YfSEZxtZMpqC5fq8rJs3OjLkMXykrQiAO33swUaeStbA8+UE/zaKnhB6fST8eBhRAo62StSKWXwp+eW7q1tObBQ9IdTvBO7z8Nijgw0qxSye7/OL705v3/8oesINgI4AzWFUhuGYZ0/32dmqIKXk9Zsz/uSn3zLohQDqEFmD25SyDJCbDgRHXHeex+D8lPbLr7Fb1wDolSrFZ1+S2d2/eazyufJx4/yJGjMDIMwe9ruXuPXgR4BSKGE8fIpa3RjairoXfWZR3G4befIWOegHj62292FzD4Sy1ChuKIBMuPFHjRv/UxmY6JfH4NhIVcXZ2sfLl1IB3FXwcCfHD+ksQLZTRzfbAFiFKoNiLRHgTkZplw9wC/02uUFAS+rmyph6LhrExKz1zgDX7pJzLSTQyJTorwjghn12FGDX66H6Hq5QOFfyeDGA7Xa+uwFcIWBXOOSEhycFx76BM7GGMZsxSYLxfs2uY1vzKak+UsI7S8Vyw9cRdnBegAuQ1wRHwwcDpwNJ004GuEnn4/i3WzmV7ZyKlPCq5Uys72b8kvi3mqrwxZB/2zAdTtur498KIfhyrxTwby2XV+etcN0l8G+FEHz5YANDUzAth++OG6H2l8G/FULwo6d76JpK17R49e5iwpdYW1EAN+y8L1EUhR/+4AE/+OIIVVVptbr89E9fzo4LkTW4HZME3Al8AiDXsemfvKfz+hucbgeEwNjYovDsS4zN7RsOyzJA7iL+L0qRWFoUV0q8xiX2u5f4Zg8UBXVrF/3BU0Q2N1KJnCfVHDH69xbFdR04e4+8rgebWizBwUPIZD9pmsJIhOugXx4j+j0QAre6hVvZmgQphH8O7hXg9lpkOteAxMkW6Ze3EpPDVgVwpQx8yg/a5AZdYAhwM4WPAnCrdoesayER1DMl+qixY+aZJ+m1imTXM1GlxBYqF0p+cq9XCHAPhIWOjyMVjv3MXBnxSdHh6eMBmIBD3ScjJK6Ed5aCGwYA515/9Gd2wxBsjhLMej6DJSSYhZ0fjXtY0ijoAseXvGzaN+/lJKAMB7ih80YAXIBiRuNRNeBPv20OaA/G6BCjOeb4sTWpO7kPhqby5V4ZgeCs1eeyZYbrhs01Dz3B8zE0lR88CKornV13OW90b8+HfynFnp+0PwlwM4bODx7vAPDhvMlVoz3hy4zERO+DYxHXlx+A6b3dGn/lLz6jVMyxu1udHR8ia3A7JVGgclqSAG5g624gOM4ffzDAfP+a7ttXuAMToapkdvYoPvsCvVq71bsDyL0LSL9PqkIo2LJtnOO3OOfH4LmITAb98BHq9h4oSvSPhznmiNePBrkzx+aM4k5Iq448e4d0HNB02H0A1c1PlqYwbltIidY4R201QIJXKAVR3CXxcGP9YPIajAOWxqBLtlUHKYelwrbxptK27gPgBueHEdxBh3y/A0AvW6KXKU7Mc18At2Z3yHg2EkHDKDMYq2KQdO9ImifptY7PtttDSElfaFyK3ORaVwRwVQGHioUqJAOpTJQIm7C3xAoKqoCHhocqoO8LTpzFKyiESojuQRbyisST8Lrn4yZEEO/Cv1VEwL/VFEHX8XnfXi3/dq9osJEP+LffXpk4YWW0EvZvHv7tUS0IrHx33qG/CP825Y+HajHLw50g3+Tb40Yo13dhesLU3m9WixztVAH46vU5ljXL9b0z/3ZsXC6X4S/+hac8frA9aydE1uA2QtKA3PtKOhv5Eyae2aX3+jvM43dB+TBdJ7t/ROHpC7TibSbhqpPOouQuIHfe+cLeD7/dChLOWs0g4axSQ3/4DGW4N1HTLCOKG+iH694lijtzbVqDINms0wqQT2UD9h4EfONPnKYgALXbRKufgu8jjcydeLgT56f2LtSPGD/HS4Xpdp9c8wIhfTwtg1ndwROTDWKSAO64v3cFuAB5q0uhH0RMzGwRM1v6KAB3w2pjeA6+ENQzFawIgLvIPEmvM3hseyZI6Ck6dSZr8K5KDCEnSoRd+eNR61u9pQFcwFDgge4hBDRdweWKE8wUIXicF6hI+h68nzfBLGytMRG8jKrwpBzQW85Nl3p/1fzbHNkh//a7sfq3q+DfPtwoUM7quL7PV6ftm+t9FfzbRztlKoUMnu/zy7dXt5+tJP5tBD0hLlr99GiLUj6D63r84uXZre6i9IQ4gDukKaTt1rkGtwnyKYHcOF+cdpPuq2/onx3juy5KJkvuwSPyj56i5G4TTz5VPm7omJh9jY0az6AgD/fiBPvDG3wrqB+s7R2i7T+ITTj7rKK40of6OfLiJLgJZrKw/xAK5bmiuLFzRPi9DJqCYvXRLz4g7LvxcEMB+JJoCpprk7s+R3guvqrTq+7gqovXwk0CuHGgYXQqZ/UomAGXz8wU6N0zwAVCAG55oorBqgFuTrpsesHj3rZi0GSsgkMqEBnuTxIAzQufnWEFhbqv0/TGQf2YzSVWUCiokl0tAAPnrkLbTl5H0hxxwFBXAoArgGtbchmRRRcHgKbPx/FvqxmV/ULwQ+FN26bvhERql8W/VQQvtvIIIbg2HU5Wzb/dLaOrCl3L4fVFO1x3SfzbHzzYRFdVugObVyer498qSsC/VRWFVqfPmw+XE77E208JcENAbhpZg9uU8lmAXCmxr+t0Xn7F4OocfB81X6Dw+Dm5w4coRlB4/WMlna2KqpB2jOybOO9f4dYvgg9moTiTcBY1RxTInc+n9LYXTjYzu8jjN8i+GSSbbe3C1pCKkcLmR6UpeC7a1THC7E7xcGeBXRjIjZtnWQBX9Vzy1+cojo1UVMzKDo6WSQ3gpn2NA7jT5yMBrm1SNJsA9DMFetnyvQHc0WsFyYbVRvddPKFwlamkBrjjsijALUqHqhu0p24oWTrjneVXCHArwmNjCHDPpU7vDiXCwiQMeG6okuowwey9rdKPqKAQdjBtlHj8WFET7A8D4sd9SSciwSzM7jwAeDTusKBRMgSeHzR4uK0yMA4ol8S/NVQeD/m371bMv83oKi+GlIGTpsnVCvm3GV3ly6OAnnhc73DVHKuNv0z+LZDLGnzxKKAKvD1pcN0a4/qO9j4KwKcBuNN6KWUNbsckHfD8DECu72NdntN++RVWswFSopUrFJ5+QWb3YKmVFRbxfdlUhaQo7nSiide4wn47nXD2BJHJxr6/y4riprW9cLKZ58L5B+T1VXCiUIL9R5DJfTI0hSjbQkq064sJHu6oHm6SP/cFcBXpk29doNqDYS3cLeyQWrixtpYMcLN2n2KviZDQz+Tp5iofB+AOWmhDgFvPlHH8cFtxcy4KcMvS/ihdzDaFS0m4SCk48Q2sCOwXBXCT/Zq8fwkRdDAb8WGjWvRGRWTTRonHdbcMqGrBtfPa9LFj+KwzdkPsxfFvhRA8KxvoCpiu5E3bvh0XAXDDfIgCuNO6u0WDzTH+rb1C/u1GIcNhJah/++15h4E12QQFWJieMK27Uc5xuBWA6a8/NELnujP/drSHm2X2NgOq3y9fnmHbIbziJP7tuN2RfhRNIYWswW2IfF9ArnRdBqcfgsoKnfawssImhefLq6yQ7Fv0uY9JVZDOeMKZh8hk0Y8eo27tBiW1ovY0ErRGg9xZ3fRR3DuVDGs1kKfvkY4NmhY0fajMl2wWNkeY39PjkoBmeFQ3+HeahxvUwz3A1fR7STSLHz+spCAludYl2qAHCAYhtXDnBbgT4GARgOv0KZgBwB0YuY8CcFUkm1Z7WKZLpZ6p4C4AcNP4Nv1aABv+gJznIAVcKHmse2jyEJQIs8mOlQhzI0qEzbO+OICrCDgyPLRhi97jO7ToTaMrhOAoR1CxwYfXvbHPeBrgHDZfDMDVVcGzioEQUO97XJrh/NsRwI28lhLWOVrb0zH+7cv6avm3j7YKlDIB//br09ZYZYh4/m0kPSFsrqEvT3YrFHMGrufx1furW38XpCfERatfPNwmn9GxHZevXp3f6qapfxsGnMPGpAFeQ1mD2xj5FEHuIr74loX54Q3dty9x+yZCWbyywiL+ryqKuwyqgt9uYb39Dq/dHHY42xh2OCsObYXPnxZEj3Q/WhTXHsDJu9tks+ow2SxlZ7Nl0xRmfQ0HuDDi4Y7q4WoBDzdXXAnAnfiSSvBxshZuA2OsFq5VqMaC1jiAO31+UYBbNK9vAG5nSQB3wuckgCt9Nq0WqvRxFJV6pjw3wI29DyUA3G3fJOO7+PfY5EEZlgjT8LGlwulYBYUJ35eYYKYLeGAECWZtT3C+4gQzdZRgJqDnSo7N5AjiXRLMSobCYSGgl7zrOPTseCpC0vWbhn+rCMF1f7X8W0UIvtwroykK7YHD24tOuO4S+LeKIvjhw82AE9uzeHPWDLV/A3DHx8/Jv1VVhR8920dRBI1Wjw9nY1zfMP7tzBxTADep0UOCrMFtCvmUQO5dfPHMHr034ZUV1GG7WkiOqH5qIHfuuaaPex7u+Qn2h7dI2xp2OHuAtncYgMCI/Vx1FHfm2J2TzYJIKJnsRGezNPaWRVMIj9hGg2fhTdXDrW3jljdCebjT88ZGRkOrUEwCXDl1LuxLWwCZXotM9xqQ2LkS/dJmLGhdNcDNOIMbgGsZOTq56p0BbtwPhDA9TfpsDFooUmIrGo1MaSqaOR/AnSeyK4Btz0TzPTyhcK4UcGNA2+18iwNcAE3AgWKhCElPqpz7440txuwtMcEsr8DBMMHswlFo2ikAbsIccWA4qwoeDBs8XFqSegQHIy7CN30+LsFsL69SzSj4Er5r2bhh4HGJ/NtH98G/BbK6yvMh//bDdY9Gpx+pOzPXnO15c4bGF4dBEOvdRZvr9u1cy+bfFvMZnh1tAfDq/RXtjsmMTK8v5gdOLE0hQdbgdg75HEFumNxUVjg/QXpBZYX8w8fkHj5ByQZ3rk+Vjxs6JmY/5wGgst/DfvcKd9jmWCmWMR49RSlXh7ai1xPlV3p/0vu+cMkwsxMkm010NttFilmby6YpJOmEf/kG/47q4SrtawC8YgV3Y4/peErYZ2+VNIWJWrj9Ltl2HZC4mTxmZZvp2/C9A9xeAyEllpGlk79/gKtLjw0rALiWonNtlCYaHtwF4Cbd+4ImDz0U38cWyp2bPCTJaFxWSPaGJcKavkZjSRUUQo8NX1c1ycawRe+xrWCuOMGsogt2gtxk3ps+5gobPAgheFLWMVSwXMnrtnMzbjJiOgtwI6PQc/BvV1L/dnhsq5hhvxxUMvrmrI21Cv7t0Jftap69WgGQfPX+Ctt2mZZltec92K6wXS0ipeQXL09xXWfCl2lbwTqm3qtpAL1AFHcNbqckzf3scwK5kX5Iid24ovPd1wyG1QO0QpHC4+dkD44QWlBO51Pj48bNtxSqgpR49Uvsd6/w+yYoKtrOPtrhI4RuRO7nZxPF9dygs1lz1NmsHCSbGZmV0hSWwcPVOteo9XOQEj+bC3i4qvpRebgTtXCtPrnmZVALV8/Sq+zMJMJNg5dJELtkgOtalHrXAcDVPw7ANXyXmtVCIBmoBk2juBKAGxo9RrLjBU0eBkLjarrJwxwyT4S1KHw2Cb7QL6VOdwkVFJIiq3uaT2GYYPb+HhLM9jJQVCS+hNfd1TZ40BTB84qBIuB64HHei+ffRvkQOu/U2qb5t6uuf/tkq0jR0HA8n6/P2mPAfEF6QthcQ1+eHVTJZzRs1+Or9/Vbf5dcHkwIwRePd8jqGgPL4Zs3FzNg+8ZW3Dqn1xLWrjdG1uA2ROIA1ITe9wDkSt/Dujij/fIr7NY1CIFeqVF89gWZ7d0gwsfnx8ede65pYGFbOB/e4A4f5Su5PPrDp6gbWyBE5Hv6qURxZ8dPvf/NOvLsPdJ1QNcDHm6pGplslm49sz4njQsHtOEAF0Ad9NAujsF1kJqOs3WAn8l9MolmmmORu75A+B6+ZmBWdnGV+Zo9RJ+L9iEK4BqfAMDN+C61QRsBmGqGll6YoXwkvV68yYN/0+Shq+g0MMYnjpjr7hUUasKlPKygcJqygkKYpIqsyqCCwpHhoQ8TzD7cQ4LZw7xAQ2L58La32gYPBV3hQTGgebzvOnSs1fNv76P+raIE/FtVEbT6Nu8u4/m3k/s1H/9WVRR++HATRVG47vZ5f9GasT9lIPz80K9J+5MAV9dUfvhsDyEEF/UOZ5fNCV8m55la5zxR3BhZg9sY+VRB7l18iQS5jkP/5D2d19/i9LqgKBhbOxSffYleC/pVw+KAM8n3u4Dc0DExe5k6igt4resg4azbCRLONraDsmHZXPReRoLW+4vipko2s/pBZ7NeUFeWjW3YOQBFXRpNIWwvFqEpjO+14toBD9cK6BXOxh5usZKKhxs3x/Jq4Trkr88RnoOvapiV+Zo9fB8BbtZ3qFoBwO1pWVpKbmL8KgFuTrpsDJs8tJQM7XuogSsE7MxZQWEe8Dx9HCnRhglmioCOJzhbcYLZeIOHliM5X3GDh+2cykY2AO0vWzbOivm391L/loAT+3w74N++b5g0u4NI3Zm55uTfFrIGz/YrALw5b9HuDZiWSHrCnPzbSjHH4/2ghvy3by84u7i+1ff8u0VxU8ga3KaQTw3kpptnMZDrD/qY717Re/8azxogNI3s3kFoO99I20TvV5oIdJQsk6owTxQX18U9fY9z+gHpuggjE5QN295LLBuWyn6MP6uK4o4pwOUJcvi4n1whSDbLpquJG0VTCPM5eVz83+O2he+jXZ2idNsgwCtv4Fa38Yj35d5q4foe+euLqWYPRuzY1QPcxhjArd07wM15NmUriEx19BxtJbpV7rIBbkk6VLzgi/xK5OjJsWj6igDuqIKCPqygcLKCCgrTklNgf5hgdnkPCWYFTXAwfBtPV9zgQQjB45JOVhXYnuRVK7n+bdj5KIA7PWaV/NvpY9ulLLulLBLJ12ftUE7sovzbGxn6slcrsF3JIaXkl++ucEfriqInhF+08b4Mjz3cr7FZKeD7kq9en/PL705wnTFu8bxR3DlkDW7HxEt6RMSvDsh1ux26r77BPP2A7zoomcxtO99sEHVZFR/3LlHcOJA7z1yhZcO6bey33+G1rgFQKzX0R08R+eiyYR8jijszPk2yWaeFPAmqRaCqsHME1eiauGHribUf4e+debitK9TmFUjw80WckIYP077MW0lh+nxqgDvT7GEbW8/GAsR5AO7kfT8NwLXHAG5mJQA3aUzBsyjbQbekll6gI4xQ/bh5FgW4Fd+i4Nkg4ELJMVhxDVyYrKBgLrGCQuix4euqJtm8xwSzzSU1eLg5FMO/VRXBs4qOIqBl+Zz2xiKqEQA3dA0JeynlLf82M6p/u0T+7TQ9AeDpdpG8rmK7Ht8skX87GV0NfiS8ONwgq6sMbJevP6yWf/vrz/d5crAZUBQaHf7oz9/SnO5itmiyWYyswe2UeL7/vQW5SX6EidNs0Hn5NYOrc+Sone+T52QPHiD09Elni/h+F5AbOiZmH+OirBNjfB/34nSibJh+8ABt9wBUNfL9vM8o7sLJZo4Np++QnWaAHCvRNXFXSVMIB7ThABdA7bXRrk7A95FGZtjwQVspD3f6HhAFcG+aPVgmIOiXN7GzhaUA3OB8xLiPBHBj92z4uuj2KTpDmoBRpCf0yPVF2VoE4Apg0++T8VykEJwrhZXUwJ0el5mqoHB9hwoK4T7Ngrbde0wwE0Lw4C4NHkLOx/Fv87rCw1LwI+G469K2whPMQu2GnU/g336xGfBvG6bDaWd1/FtVUfhyrxLU2jUtjuvdcN0w+3PybzVV4QcPA8B51TI5rXfGxod+0cSen7Q/C3AfHWzwF788JGtoWLbLn3z1gdfvL2b8GlsQsTSFFLIGtxHyqYLcu8yzaBQXP2jn23n5FXarAVKiV6oUn35BZmcvVdJZ0l6l/VKbdW3++ZZBVbgtGxa0uFVKFYyHz1BKlaGt8HV8ClHc2bFTf9QvkBcBWLypiZtLVxP3LjSFJJ04gKvYA/SLD2MNHw7wsoV7TTSLBLhAtl1H73cBwaC4gZUrz0SPo+YJizRPriFi3Fglh+Bc8O+nAHBLjkneHSCBa6NEHy1WP0nmAbg7fm9YA1csVAN3Hl/CKihcSJ3enBUUknyaBqrTCWar7mCmTDV4OEnR4CHpfBz/diursnXDv3XCwXsE/1aGbEQs/zZzW//27fWAziCkZFeK6y9cd9LvQkbj6VbwJPBNvTfBib3RjfphNyf/tpzP8GQ3+L56eXJN17SYlkT+bVJ73rFx5WKOv/JrD9ndCPjFb08a/PQXb+n3x+adh6aQIGtwmyCfGsj9qJUVXJf+yQc6b77F6XWCpLPN7aUlna0qihsHcqPmitKfLRt2gf3+Nf6gD6qKtnuAdvAAND16H1MC6JHuPFHcmWMpk81mfDW7AU1hVBN3Zx9q28P9jAeAYWsJ24swgDsvD3fcrvBc9MsTRN8MGj5s7OCWaveaaDb9fk00e+heY/SCDGWrUAntZhbrxwIAd9yH4Fzw7yzArd4rwBVAxe6SdS0k0MiUGEglUj/NHFEyPV6BiRq4l9M1cBPtRdsO9/O2gkJpWEHhZM4KCkm2p48jJxPMVt3BDIIGD0fDBg8XluQ6aoEhducBwCP+7cOSTk4TOJ7k5Rz82yi7cfzbvaLBRi7g335zZd4ks0XRE5IixBFfDADslrNsFTJIGfBvHWd1/NvDrSK1YhZfBvxbzwsB0Ivyb6f3Rko0VeWHT/f40ZM9NFWh3R3wn3/+lvPpagpLiOKuwW1KWTbITdaJP/8xQa4/GGC+ex2RdHb3TmerArmhYyL2ca4orjXAef8a9+ocfB8lX8R4+BSlUhvaSr+Ou0Zxo+wuFMV1naAmbqsR/F2uwv4QuC+RpjDjVwqAGxXFFdJHa5yhdJoAeKUqbm3noyaaTQBcsz3sZgZ2rsSgtPGJANzlV1FIaqErgJrdIePZ+AjqmQrWHQDuPBHf8Rq4faFxJbK3a0wFJAnViQOhQsDuWAWFk6kKCmEyD3iePg6TCWYXjkJr2QlmU8equmBryDJ5Z/r0E+gQy+Dfqgq0bZ+T7mr5t882sjf821fL4N/enJ/cAyEEz3dKZDWVgePx3XlnDLgvyL8N8WXEv/3ywQaGpmBaDt8dN0Ltz8O/jQS4w/UB7GyW+Cs/ekilkMXzfH756oxffnecPtkshazB7ZikAabLArnLiOLCxwW5QdLZt/TPPuC77jDpbNjpLJO+09kifiWB3Ki54kDuPPOElg27rgfNH8weKAra9h56iuYPaf35aFHc6yvk+XFwozIysP8QCqWl0RTC1nUXHq4AtHYD9TroNOfnCpGJZklzxq1tXoA7+iIf72bmZAr0y1szwDQOqC0f4K6uTFhcC90bgGt10D0HXwjqmTK2FKFj7gJww15n8Nm6qYFr0LyHGrijCgoaPpZUOBuroDBhb8EEswkZAc6xDmYfbIX+EhLM4nQPspAf8n1f93y8kAUm2Z1YZwz/NqcpPCoGaPqk59IarJB/qyq82MwhhKDeszm7K/924vwkwNVUhS/3yihCcNUdcHbdC9cNsz8PPcHzMTSVLx8ET17PrrucN8aSvebh38YB3JAfANmMzk9+cMTjgw2EEJzXO/znn7+j1e6NjU2I4sbIGtxOSRpgCp8vyL2LL+F+SOzrBp2XX012OnvynOz+IUILuHT3zcddZL5FE84m9Bwb5/gtzvkJ+B5i1Pyhtjm0E257GVHctHYXiuL2e8iTN8i+GdAUtvZiW/eGrWXadhjIjRsTphMFcAFUs4N2dQq+N0w0O5xJNJv2I00lhdj5E/y97WZmkmsFfG3XyN2pXe/dAe5UHdxceoCbxt84gAugINm02mi+iycUGpkyzsR3/eoAbl661Lw+ANdKhs6Ka+DCZAWFrlS59NUx3TF7S+5gll9CglkaXTHi3yIZePC+59/qJ+1p1B7G8G83cypbuSCZ91XLwV4h/7aU0XhYueXfdq0QysA8P0aiAC5Qyuo82igA8OqyG8qJTeTfpqR+1IpZHu4ET12/PW7QH9izribREwKlyDnCaApCCB4fbPKTLw9vOpr9yVcfePPhcgaEzytrcBsh31eQm26eZD9mJ/aHnc6+vu10Vt2g8OxLjK2doEkAnx4fN3RMDKhMC0L9dhPr7cvb5g+bO0Hzh0w28n28axR35clmngfnH5DXY6179x6CbqyMpnBXHm6QaHaMsG2kqi4l0SysVNiE7qSpSICp2QNyrVG73gxmZQeP+Ha9UT4uFeAaWTq5SiqAG/dezAM+RwBX9T0codLIlKeaHqwO4JalTckLgMOVyNEfo0YsC+BOj8sKyY4IAETD12nNWUEh2adJ8DlKMNOEZOALTpz5EszSzDF+fNTgAaBhS66saN2QRaU+P/LnYUkL+Lf+fPVvI+eN4d/ulwxqOQ1fBvxbd4X824Nqjo28gS8D/u0Ia0TRE0LXlZJ/+2inTDlv4Pk+v3xXv/08JfFvZ7hxk9dImihuZZhstlMrIqXkzXGdP/nFOwaDmGSzBFmD2zEpHByi6FOF1vnVBLmLRXFBOjb9k/d033yHa/YQikJme5fisy/RKtVb/z4CH3feue6ccDbW/AHPRWSyQfOHze3IFr73GcVdmKbQqiPP3yNdFwwjALiF8r3TFBLXN/xTeC7a1fFkolmxutREs+n5UwPcsXa9nmZgVnfwhBI5dtUAt9i7RkiwjBzdewa4qvTZsNooUmIrGtdGGe+eAG7NH5DzHKSAcyU/QY2YF+CGSdi4svDYGALcc6kTUWBgaQlm+jDBTAhouYLLNAlmc84xLkVNsDf8Ov1g+vSceJB1J/6tEDwf498er5x/m8NQFQaOt3L+7YvdMoaqYNouL8/a4bpL4t/+4MEmmqrS6Vu8Pr0OtR8JcKcpCnNGcTVN5UfP9vnhk11UVaHV7fOf//wtF1djbYI9P3QtYbIGt2OSrW2w8eUPKR09RM1Mds9Zg9z5fPD6Jr23LzGP3+LZFkLXyR08IP/4GWouH/h2Rz7uvOc+VsKZ320HUdxOK4ji1rZStfBNYztKd+VR3MGwda/ZA0XA1u6daQpJviaBzbBjNwBXymGiWXCj9Mq1oKNZgh93rYUbPza4T6ieQ655gfBcfFXHrO7gKmrk2FUC3IxrUTQDgDswcnSnSpatGuDq0mPDaiGQDFSdplGMnGeZAFcAW76J4bv4QnCu5HEnJ45c67Sk83H4SF24FISLLwUnfgZnwve72Q6TvAJ7wwSzc1eZ6CgWuqx5QfTUsZ0MlNTgjvC654e3zI3yfQQYx32I4d9mNYVHpYB/e7pi/q2uKrzYCvi3Vz2bi649Ni49/zZsLdMAVx/ybwWC83af8+bq+LdZQ+PLoyAR+sNVm3rLvD0f9V09bmPeKG6Ind3NMn/lRw8p57O4ns8vXp7y1csT3JB9jZM1uB0TuxM8Qs7UNqi9+CGlB49Qh4lRI1mD3Pl8cNotuq++oX9xivQ81Fye/ONnZA/TNYGI26O7RHFDwVvMXHdOOPM83LNjnJP3SNcJWvgePkLd2l0oipteN9zuzLFFAK7vwcUx8jroEHZXmkLYNZQG4MYBq3Gfg0Sz+jDRDPx8EXdzD2+SCbB0gBsHAm8Brku+eYFwHXxFw6zs4CrahO69AVxnMAZw8/Sy9wtwDd+lNmgjAFPN0FRzRMkyAa4C7Hgmqu/jCIULJT/z42dallFBYU/YGHi4Q4Ab+pldMMEsLCpZUyVV1UdKeG+rWCtu8PAwJ9CR2D68M8c+r3PYjQS4U2M2syrbC/JvQ9cQw78tZzSOykEQ7PV1n15Yy9yE9yqKnjANWis5gwe1ICj08qITyoldlJ4wrbtZznGwGdTa/fp9Hcueres7Uz1hGuBGJJrNzBdBU8gNk80e7W8AcHbV5o9/9oZ2xyStrMHtmLTfvub626+xWi0QkKnWqH3xA0oPn6BlJ2+wnzPIvcs8C4FcKbHrl3Refo11XQ9+jZarFJ99uZQmEHcBufPMtYyEM7/XwX77Eq/VDKK41Q30h08RuXzk+5cKPMfqhvygDgOFC9MUGsizxWkKs2uIX9OiPNyRqGYHrX4Kvo+fyeJsHeKq05HSKb/vAHAhHcBVfI988wLFtZGKGkRwVX1C9z4BbsFsIiT0M3l62dJCADfK9yTwmfUdKlbQNamr5WgrmVD9ZYs6LBGmSMlAqNRFbuUlwlQBB4qNKiR9qXDuazd2JuwtKcFMCNjXfbKKxJXw3lJuro8o/+PAUJKupggeFwQCaDmS80E6kDXv+XH+bX7Iv52n/m3kGmKizYdlg0pWw/cl316ZNzSaVfBvH2zkqWR1PF/y1Wn75jOUxL9Nas87IUNfnu5VKWR1HM/jq3fR7Xljk8zuSFNQFMGTw01+8uURGV2jbzn89JfveX9Sn/U7RNbgdkrcvkn77Ssa33yF1WyChEylQvXFl5QfPUUbPlIfyecIcu+rfNjMMc9lcHZM5/WwCYQQt00gqrVb/75nVIUZfd/HvTjBPn6LdGyEbgRR3O09EErE/e0Tj+Jai9MUVsnDnbY5OqRYffTLY3AdpBZ0NHONzNyVFOLWtRDAlX4AcB0LKRTMyjaONpUHcE8AN+v0KZhNAPqZAma2NLGGNAA37j1JArh5z6JsB49gW3qBrjBi9ee1H/XamCgRptNk7AfGCgAugDHWorfla1z7q00wUwQ80D1UAaYvOBlMnI4cNy1p+bd5VXAw/H1y2pcTdIgku2F7Hse/VcRt/duO7XPcWS3/9vlmDl0VmLbH68ZtZHEV/Nsv9sroqkLXcnh9sTr+raIIfvhwE1VRaPYGvDsf471O3+emAe7kTXPakYk500Rxq6Ug2Wx7mGx2cjHmS4yswW2EeIM+7XevaXzzSwbXDZBglMtUn39B+fEztHxhQv/7DHIXPR81v2+FNIHYP6Lw5DnqcF8/9SguxFMV0uhLM2jh6zUbAKiV2jCKW4jcu2VEccP07hLFvVWIoClENH0IW0ek7Yg13SnRzHXQL48R1gAUBWdjDy9fmquSwrT9pXQzk5J88xLVHgQAt7yNrU/lANwjwC2awZeJmSnQMwrRY1L6Nw8ALbp9Ck5QqqtpFDFTtOldBsDNTZQIy9JlLLJ/B4AbJqNxBeGzNWzReyl1uila9CatJ44bayhwqAcJZg1XUF92gtnUsU0DqlpwnbwxfewF+LcTumn5t+Zq+beGqvB8Mw9CcNG1uewuVv82bC3TADejqbwYluw6aZrU2/1w3bC55uHfAvmMzvODKgBvzluz/NuoJLMpu8tINtM1lR893ePLRzt88Whndh0hsga3CeJZAzrv39L4+hf0G8EjdaNUovrsBZUnz9ELxQn97yPIXUYUN+z0bROIY6TnomRz5B89JXf0CMUIojT3CXKXWRt3riju5Rn2hzfDKK6OfvgQdXsflNVEcZedbDbz/rYak9UU9h9Cvvhp8nB9H+3qFMXsgAC3uoVb3rhTJYXldDOT5FqXaFZQ4aFf3sI2cpHjVgpwbZPCCOBmi/SMfPSYlP5Njo8HmmWnR84dIBm26UWN1Z9+vYwSYZcif6cSYck+BuOqwqU8bNF7GtOid571xHFjS6pkWw3AxKmjTFQ0CH3LFphjpCuE4CgHGSFxfHjT+/7wb6tZjcNS8J31qtGnPwf/Nsx+JMAFNgoZDivBZ/Db8zYDa5YTu6zyYLu1AjvVPCD58zcXvDxp4I/7mURTmAa54zJnspkQgv3tCrVyNAd/XNbgdkziIKJnW3Q/vKP+1S/o14Pi63qxSOXpcypPX6CPtZ0d2VqD3DTzS+zresDHbQT7qpXKFJ5+sTQ+bpy/YbIoVWGuOaYBT98MuLjXAZ9IrVSDKG7+/qO4M8fuUk1h1PRhex82dsJ/ICxIU0gekxLgIlGvL1Ha1wB4xcqdW/bepRbueLvebLuONugBgn5pA2sKWK4C4E7aD/7N2Sb5fvAYtJctYeqTXzDzAty0n0spg0oGVbtLxrORCBpG6d66mNX8AdlhibALJY89ubhU60nvY5BgtjPVotcL+6wtMcFsS5OUVB9fBglmoSAwZNw8c4yOq8MGD4qAris57d+df3sDcEM+Q+P823nq30auISba/KCSoZxR8fyg/u3o85fEv5VR9mP24NFWgWJGw/F8vj5rj9lakJ4Qtu6hLy8Oa+wPm0l8uGzz05dnmP2xhLY4msL0OpaQbJZW1uB2ShIBoGPTPX5P/auf07+6RPoSvVCg8uQZ1WdfYJTKk/b4NEFunHwMkCs9j8H5CZ1X3+B021N83I1b3xbg4y4SxY2bK+p9uHMUV0rcq3Ps92+QtoXQdPSDh2g7y4vizuqF/KAOsbkwTeH8A7I5TAAoVWDvCKmpS6EphEelFwW4oHWuURtBl71VtOxdGOB2Guj9LiAYlDawMoVYQDNhZwGAOx0tG53KWz3y/WGSV66MqU9WkrkLwI2tOCFHbXrb6J6DJxTq99TFTADbvonue3hCzFZQCPtM3THBTBGwL2zUUYteqd/YmbC3xASzQ93HEEFFg2N7dQ0eALKq4GjIsjkbSFp35N9OyMxe3vJv27bPyYrr3z7fzKOpCj3b4+31GGVgyfxbRQh+sFdBUxTafZu3l51w3Zuks/EfA/Pxb1VF4cXhBj96uImuqnT7Nn/83RmnV51b3RCawiqTzdLIGtxGSDLIdeiefKDx1Z9jXl4gfR8tn6f8+CnV519ilCuT9vi0QG6aa+Q+QO7MnLaF+f4NvXfjfNzDe+Hjhsmyo7hpgKgcmNjvXuEOK0so5eVFcaN9SGdzIZpCs448Pw5uUpks7D+CXGFhmkKSn3eqpNDvDlv2+kHL3q2DpVZSmN7/tAA3071GN4MvsEGxhpUrxQKaVQHcnNUlNwh6z/eyFfra6gDu5PxBqa6NYRcz96aL2eJzpAW4QYmwHorvYwuVSyUf+tmP2r95AS6ALiQHio0Qko6vUZ+zRW+yT5PATR02eFAEdDzB+Yr5tzVDsDHM03vb87HuiX97suL6txlN4flG8Jk4bVvUeyuqfwtkdZVn2wEt8kPDpNkdROrOzDVn/VuArUqev/Ril2ohg+/7fHNc5xdvLnGcMQrGfSWbpZA1uE2QRJDruvROj6l/9XPMi3Ok56PlcpQfPVmD3LHz887v9iL4uIcPl1Ifd951zFsbd96yYWFRXO/qHPvD24ko7jK5uLN66WwuRFPo95Anb5GDIHmLnQOobi5ULizsmlkE4E5+sdzaHLXsxRmrpKAbM5UU5plv0WYPvu8Hj6uBTK+J0Qu4r1ahyiBfiQWuqwC4AsgPOmQHPaSAbq7CQJtMdpsYE+HPvOBzJCqSTas11sWstJIuZtOiIdnxTIQEU2jUGVtz5DzzAdzpcTnh37TorUuNzooTzLIK7A8bPFy6ykRENXRrUswRp3uYDdoQuzLg395co3PYnQRs0Xt5n/zbWk5nf8i/fdnoM3BCQNkcADoU4A6PbZey7JaySCRfn7axw7i+C/JvZwCu55PRVX7jyTZP9ipBA4u2yR9/e8Z1pz9mT85EcScXJyN154riJsga3KaUJBAoXZfe2Qn1r/4c8/wM6Xk3ILf24gcYY61n4fMFuUlzLHf+ED5uuRLUx93eneDjRtpdwJ8kkDvPPItQFSb0pqK4N1zcJVRUCPMhbbLZQjQFz4Wzd8ght5XKBuweIRVlaeXCpsdMn08bxRWeg341Vklhcw8vV0wsFRbrz4IANxg7BLhmG6PbBMDOl7EK1Y8CcAuDNhnLRAro5KpYqhE9JsKfRcGnJv3JLmZ6MdW9dB4JmzeDx6YXZIy3FYP2WOWGuwDcuHEV4VERDlIKzu4hwayqSWrDBg8fbJWBEw8oE0FajK4igvq3qoCeKzmJ6D+cHNEMAbgh631Q0sjNwb9NXENMtPlhNUvBUHE9n2+vzNu5FqUnxOzB0+0SeV3F9jy+WSL/dtof4KZN74PtMj95tkPO0LAclz97dcGrk+vJe9yiNIVgwIQPYZHkJFmD2zFJAm+QAuR6Hr3zU+pf/Zze+bArVzZL+eFjai9+QKZSm9Tn/kFu/Pn49X1UPu7rb27r427tUHz2BfrwR8OnQFWIm2fpUdzDh0utizurl87XhWgKjUvkRfDon2wuqKaQyS6NhzutvzAP96aSQheEwK1t4xarsZUU7lILNw3ABcj0O2Q61wDYuRKDYu2jANxiv0XG7iMFtPNVLEWPHhPhz6IAd6KLmZahpeRi9ee1H/W6IB0qbvD490rkMOesoBAmSSB0RzjkxhLM3BUnmO3pPjlF4kl4b8/X4GHa9yTdjCI4GjJbLizJdQJ6vwv/Vp2Tfxu5d0mgdAjcv9jMoSqCjuXyrjlGGQgBuJHvWQr+raoIvtyroAjBtWlxXF+wPW/M3oaBy1LO4C8932WvVgAk7y9b/Ml3Z5iDlMlm018M8ySbpZA1uJ2SNLVfIR3INc/PqP/y5/TObkFu6eEjal/8kEx1cZCb6FuCrSSAGeh8fJA7M6dl3dbHHYK87MED8o+foeSCL7f7pirMM8+yoriTdXGfLNTdLI0Pd002m51j7A+zE9AUbAs0DXaPoFRdCg83fC0LAlwk6vUFSqcJgFeu4Va35ioVtgqAawy6ZDoNQOJkiwyKGx8H4JpNDHuAFIJ2oYY91jI4DtQtA4COdzHr6Dk699TkoSIt8p4NNxUUxpIOE8EkoefjAK4QsC8stGGC2blv3NiZsLekBDNFwNGwwUN/zgYP0VHraEBY1QVbw99F70yfQUK1hrvwb3OawsPiLf+2ba2GfwsBJ/ZpLUDux22L6/4YmF4y/7aQ0Xi6FfBv39S7tHsWMxJ1vafsYDYDcD0fVVX44miDHz7cRFNVOn2L//LtGaf11SWbpQW5a3AbIfOC3ChV6XuYFyOQe4LvuqiZDKUHi4PcNFHcka143z9tkBs1d1Af9xv6o8h4Lk/h8XOyB0cILfhyvS+qwqrLhoVWVJioizvsbra1C0JEAtw0Ec1oH9L5OjdNwXXg9B1yWB2DjW3Y2kdOVSgY2Zr2f9puGMiNH5MW4ILWbqBeX4IEP1/C3dxj+uspCeBGAavpuafvAdEAt0e2PQK4BQaljwNwS+Y1umMNAe4GjlBDx8QB90UBaN6zKDkBVaB1T00eBLDp9zF8F18IzpU8bgjQG5e7VlDQBOyPEsykutoEM4IGD0eravAQss79LDfR4lXzb7dyKltD/u3LloMTFh29I/929O9WwWCnaICUfHdlYrnL499OH9stZ9kqZJBS8vVZC3eY6JXUnndGpgFunH9D37Yref7S8x0qhQye7/PNhzq/fHu1kmSztLIGtwmSFuRCGpB7TuOrn9M9DQG5tY3gC36kz3JAbho7nwrInWtuKbEblwEft9kAKdErNQrPvsDY3AYhPmmqwp2juP2pKG51I+DiZnOR79U8UdxZvXT25qYpSAlXZ8h6UIKLQhH2HyD15K5my+Lhxv99+1o1O2j1gE7hZ3I4W3crFbaMdr26ZZJt1QGJkynQL21+FIBb7l2jOza+ELQKGzhCCR0Td5dZFIAWHZP8PTd5UIBtz0TxfRyhrKSCwrSsOsFs2ljxHhs8KMP6t6oA05Mcr5h/+7A45N96q+ffPq5myesKjufzXb1/O9cK2vM+3ymRUVUGjsd3F52xdcUDXOn78SXCpvY4LIqbNTR+/GSbx7tBstllq8cff3tGc5nJZnPIGtymlOWBXJ/+5Tn1r35O9/T4FuQePaT2xQ/J1jY/eZAbJ2lA7qLzh+2r9FwGpx/ovPkO1+whFJXMzh6Fp1+gFcuBT58IVSFUfw4QHdnd7Pgt0nFuo7ibO7FR3ES7hK9xpTSFThN59h7pOqAbsPcgsqtZmP+RdkkHcKe//Cf/vrWpWH20qxPwXKRu4Gwf4KralL0k/5YMcO0+udYVIHEzefrlrXsFuBDQN0q9Bprr4CsK7cIGLskAN+0P3jgAKoDKPTd5gFEFhR5CSvpLrKAQN24VCWahx4avtzRJUblt8OCsqMEDgKEIHgz5t5er5t8qgqcVHUVAy/I56y1IT0ihqyqCF1t5FEXQ6jsctyL4twlz3QDcifOTe6CpCl/ulQNw2Rlw3jTDdaPmmwa4c0ZxhRA83CnzF55ukx0mm/3pqwteny4p2WyKphAna3A7JknADm6BwJ15ub5P//IiALknx/iOg2oYFI8efPIgN3ZdQ7l3Pu6gT+/tS8zjd/iOjWIY5B48IvfgMYoRfOksQiFIiuKGgsX7juKaPex3L/FaTRACtbaJ/uAJIpON/ML7GFHcRJqCNYCTd5NdzWpbK+Hh3iXRTHFs9MsTcGykquFs7d+pVNgyAK5mD8g1g4oirpG7V4B7sy9Iyr0GqufiKSqtwgYeInxMhC9xn/skgFuzOui+u/QmD2EyOp/BX1oFhWT/ho+AhbOUDmbh/kwCNyHg0PDRV9zgYXSsogu274l/m9cUHpaC9+tD16FjhXQqi6AnhN7vYvi3eV3lcTVA7u9bFu1BCP92jh8ikQAXKOd0Hg07ir286NAb7yY2kjha1DSGmDeKC5TzGf7S8112h6173120+NOXZ/TH1n2nZLMUsga3U5ImejmSpYHcqxHI/fC9Arkfg4/rtJt0Xn7D4Oo8+CVbLFF4+oLMsMsXxEdXFwW5YXLvUdyLE5yTd0jXQRgZ9KPHqBtbkXs1D8BNG8WdGTsvTeGmq1lAt6Bcm6tcWKTdCB8X5uF6LvrlCcLqx5YKSzvXPO16IwGuMyDXukRIfwhwtyPB6cz8ywK40qfcraN4Lp46ArizvsatKS3YnV6Lgpxo8nCdSVcDN43tuNcF6U5UUOgvWEEhHQAPOpgdCGvhDmZJ/kyDT23Y4EEIaHuCyxU3eNjLQn7Iv33d81fLv82qbGYDwP6qZS+Vfzs9Zqegs5XXkVLy7ZWJs0L+7WE1Ry1n4EvJ16etm89BXHmwaYCbGMWNGDuiKWiqwpcPNvnBgw00VaFtWvzxt6ecN7qTPtylZFiMrMFthNw7yJWS/tVlAHKP1yB3+vxcc0sf6/KczsuvcTqtYSvfraCV77AU231RFe47iuv3uthvX+EN161ubKMfPUboRsS9cLnJZmH2FqIpNK+QFyfBDXVULsxILhd2nzxcIX20q7OpUmGViUoK09fnPLVwFwO4FtnW1RDgZjErW/cOcFXpU+k1UHwPV9Vo5zcmxi+ri1nY9ahKnw2rjSIllqJzbSTXwE1jP+n1eAWFcyWPPbmwhPnDfYkD45pgooNZI0WCWZLdOPCZU2Bv2ODh3FXorLDBgyIEj/ICTUDfgw9L4N+GnQ8qUQgelXSyqsDyJG9azs24iX1agH87vc9CCJ5s5MhqCpbr87KxWv7ti90yuqLQs11enbfCdafB5dT9OzaKO3Vzm9nvoZ871QJ/6fku5byB5/t89f6KX769xB0H93dJNouQNbhNkI8CcutrkLuMuX3Hxvzwlt67V7etfA+O5iodtoifYbJMkJuo63u4Z8c4px/A8xDZHPqDJyiVWuR7NE8Ud1Yvnb25aQpmd7Jc2N4RFCv3xsON/zv4d7ZU2AZeZTOxFm6sL8sAuM0gguvpWczKNn7MuJUAXN+j3G0ECVeaTjtfnbC9CoA7eq1Lj5oV1MDtqxma6upr4I4qKOjDCgoXSgEv4fOzjA5m2wSPnK+kRjciwWyetcSBz5oqqQwbPLy3VawV8W+llBP82ytL0rgj/zaKnjDi3z4b8m+vLY/zFfJvNUXwYjOPEIKG6XDWuS3ZtdTyYFJiaEP+LYKzVp/L1iT/9k5R3EgfwmkKWUPjLzzd4dFOwAe+aPb4429PaffG6szNk2yWQtbgNqWsQe64a/EaywC5ceeSQO60uL1u0Mr3/GSydNj+EUKNLx0Wtx9RvsT5uAyqQuoobreN9fYlfq8DioK2vYd2+BA0PXSf0kZxw/WWS1O4EdeB0/fIYfMONndgc3fGyqI83Hj9tAB3WCqsWQfAK5Rxazt4RM+/coDr2uRuAG4Gs3z/AFfzXUq9BkJKbD1D5x4BbmasBm5Xu58auAqwM6ygYE9XUEgBJqMAbty4ivAoDxPMTn0DOwybLqnBgxBwoPtkhi1zP6yIfzuSsi7YGb5t71fNv9UVHhRv+bc9OwRoLol/W8yoPKwEeSBvrwd0rZCWuQnvU2J73qFU8waH1eDH3TdnbU7q3Sl78VHcCZfuSFMQQvBot8KPn2yT0VUGtsufvDzn7VlzUj+JppASh63B7Zik2bM1yB25tdryYckgdl4+rsRuXNF5+TX2kM+pV4elwza2gLuVDpvHx3uN4nouzsl7nPPgEb+SK2A8fIJSqkS+P8uM4obtQRqawoRv0ofLU2QjqDNLsQx7R0hVXYiHG+ff9P5Nn5/9+9aW2muhNgKut58r4G7E18INmytqLYsAXHVFADdyTAhQ0z3nBuBaepZurjzh+yoBbt6zKNlBt6b7qIELowoKJkKCKTSuuQXV8wLcZP+CBg87wiHDbYJZSAWspTZ4eGB4KAJ6nuBs1fzbzP3xb7dzKrVM0JHtu5aNG0YvWBL/dr9kUMtp+DLg395wYiPoCUkAOuLCAeDRZoGNfAZfSl5edvjFh2tse7w72zT1IOZ+NydNISyKWylk+Msv9tiu5JFS8ua8yZ++PGdgpUw2SylCpkVq32Npt9tUKhX+T48O0IdJRyF15CNFpFRWUurFqglBbmOL/M4uih6klXq2Tf/inMGw3uuEeor5VCX5N06SnaQ9SFp60t4k248+H3ZKzeXI7h6i5fIA+NaAwdkJnnnbulBRwm3Gvz0RYyKOzztH1D6F2Z/R1XX03QOUXJBJ63c7uJenAXUhxGwqm5F66eyJqZWG7cfEsGwesb0PqgqeB1enMOgn2gn3O96/6THT52f/Dv71jSzu5h4oCsKx0etnqNOfy6m5x+ea8UOJPje9qvHzyvBz7Wk6/eoOUiiojkW+fTkR1YhbV5Rf029T2LzB8eBfS8vSLdSQAvJWj6LVnRg/MSbCbtTrqP0RQiAZAlsti4Jka9AiI/xI/XntRx3rCp26Ftxbtv0+Jcaic5HzzH73pPNPwZGCdzKLJwUVxWVPcW/sTNibeG+i/R/3Z+L48N+WJ/hgBzzfRxmfijFuY9ZW8pqjdW1f8m0PXAlbGcHDghqpO+132HmhhM+lKAquL/l5w8L2YCOr8qxqhO+Tqs4eC1mDUEP2cPja8Xz+7KyH7flsFw1ebBVm7E/YiroWRnNMnJ/cAyklp60+b+o9fCkxVIUXe2U2SreUnZlxUx/ymfvENG6I2PewsagKUkoumibfnTTx/CAB7YujTbarhUnd8c+fotLu9Kj+xn9Hq9WiXC4TJWtwSzi4HcknDXI3t8hvT4Jc8+IMq3n9Kwly5wW4EERvs9v7KMPOZk67iXV+FtRbJRp8QvReLOLjMkBupO2p42ptE21UC9d1cS9Pkb3u0EY6nxcFuWkALszux8QwVYOdA0QmG1zn11fQaaYCyrOANd6/hQGuZgQAV9MQnotWP0Ob4tQtCnCnz88NcF2LfOv+Ae5Az9EtVAEo9DsUHDNUf3pNywC4jUwZSzVQpc+21UIXMlI/zn4a3dHrhpKlo2YQUrLv98iOzZkEyuYBuKNxPalwIjNIKdhVbGrqOIgfsxcCKJMAbhhwO3UUGq6CKuBZxiOrx4Pz5DVH67YdyethL4DHBYWNzCyQirr+QsFhDMDtOj5fXdtICY/LOjsFfcbHcfAZundh4DNEtzVw+cWlCVLyfCvPTjEzNk4N3YtZX6LA/OzxnuXy9Vkbc9g57KCa58lOeerzMw1aY+49cQA3xncAhn73LYdfvm/QHZYs29so8vxgA1UNB9rtTo/aX/jvE8HtmpaQIHNQPFJTFpZeXWGshFjp6CG1Fz8gU92YVOfToCvchaqQZH9+qgI4zWu6L7/GagQ1QvVy9c5dzpJ8DJP75OJ613Xsd6/wh0l2+v4D1O294S/8dD4vm6YwMy6OpuC5cPYe2Rlr27u5hxSzNj4WD1dxbfSr8Vq4B7i6HqobNlccRWH6/PTuhT2mVV2HXPMioChomaUkmcVxrMMetWedPvl+G4BerkRfy4bqT8tdKQSCoAauNqqBa5RwJ56mxj/+ndeX0euaPyDrOUghuFDyOOOmE+kA6f0bjSsIn02CH+UXUieiyMBcawk9Nny9q/k3LXPf20o4HSJkXJjvSbrL4N9G0hOm5irqCkeFINjxruNgLsK/jaAnTO9tJatxVA4W9rrRx7TT82/D7E/qzh4vZDR+8qDGfiWI2J40Tf7k7dVELdz7TjbLZXR+8nSHB9slQHDW6PLH357SMW+T7Rapc7uO3BIfuZ2WTzaSqygBXWF75zaSa1m3kdxpWynmS4rkprGxykjusqkKSiZLbu8ALV8EwLctBmeneL3Orc5nQlVIFcUVAnVzG60a8LalY+OenyAH/cj3ZdEo7spoCqUqYiP4IYJtwUXQPWxemsKqIrhSUXA39pDDKLPeuECxTBQRHqWbnutjRnDj9uAuEdxetkQ/W0RIKJnXZD07XD+lX2kjuK5QqGereEIh69lsud2bOZZBTwh77QOnahFXUclKjz1p3u53QrR0SuU2UhczTko4lQZdqaELn4eKhX4TdR6zFRExDZsjLrpq+/DK1vAkbGqSw9zE6dlxqdYcriul5LuexPQFORW+LKu312SS3aj3SJkdH+yj5NumQ8v2yWmCH21mUcOi9yER3MgItBoeMZdS8osLk7blUjBUfmO/dLOuMHpC1FypIrhj5xo9i+8uOtiejyIET7aL7NcKU/5FR3GXTVMAuO4O+Pp9A9v1EELwZK/K0XZ5Qr/dM9eR21XIJxvJHTWD+PoXk219Hzyi9sUPyQzru97Y4u6R3DQ2VhnJTZN0Ns+8vjWg9/bVWJezDPmHj8kdPUIMfzAsO+EsTO4tiisl3tXFsH2vfdu+d2M78n1ZNIq7aDWFxHJhnSbyLCh5hpEJ6uFmcktJNIvXTxfBFb6PVj9F9HsgBM7G7lzNHmYS3pYdwY1JMovbg7gI7sSYkGhkftAhY5lIAZ18FUvRw/VT+pVWNOkPS4RJBqrBtZpPtH+XBDMpxyooSMlAqNTJLFxBIdm/IMFsV9jo+DhS4dS/rW898dFfRoMHwFDgUA+imHVXcB2RYBZ2MCkRbFpXiPutf/ukoqMr0Hclb9t26Ph56t+Gjh+u6/lmDk1V6Nkeb6/74faTbKWsoDA6t1HI8JMHtZtmDy8vRslmbvTYFSeb1YpZ/vKLXTbLOaSUvDq95mevLiZ8ShvBXUduuY3c/vVH++iKEsoBjJJPOpK7uR1Ecod8Um8wCCK5reasrRTz3TWSm2b9cSr3ysdVFDJbO2RHUUHfx6pfYtcvbz6k36so7rBUmFquAiAH/aDCgmOH7s8yebhhenfn4V5Cp7XyRLPUEVzAq27jF0qBu+1r1G4TNWUEd9r2UiO4CUlmi0RwZyPOk+uUQCdfwzayKFJS6dbRpReun8KveSKsfdXgOhNEfCpOj7JvxerPa3/89ehfU2hcqgUQsOkPqDCWGZ4QdQyNgMb6p2BJwXuZxZeCDcVhR/XGdMfsLYl/e+4oXLkKigj4t7l74t8+KSjUVsi/bdse3zQdpISnlaDD2LSPy+LfXvcdvroMeOhfbhfYLBhj49Lxb6fnmI2YzkZxpZScNPu8bYySzVS+2CtR+8jJZmfXPV6etvB9H11T+fJok81KPuDc/sX/8zqhLI1Mg9txWQXQvU+QKxSF3NY2+a1dhBZ8QLzBgN75KXa7NaufMNevWtKZYmTI7h2gD0GJb9tY5ye43cWpCov4F/p4PsLGXSoqKMUS+s5BUI3A93GvzvHbzeH4xWyG6a2EpiAEbO4iisMbXrcN9YuZfVp1olkswC1v4JeqAKjdFmq78SsBcGcSxoYAt13YwNEzKL5PtVdHG4sUrRLgdrUcbaOAADasNvmxagaL2k8a1xIZmloWJOz7PXJjVRuSwV769Y/GdaTKqR8kKB2qFiVFjukO/02gJ8yuOxzgSglvbZWeL8gqkuf522shCeCmpUCMHzsZSC5tUAV8WVLIavH0g0UA7mjMcdfhpOehKvBrGxmyekilhAXoCWG6b677nHZsNFXhx3vF27nmoCdMzzE7Jvxc13L45qyN6QQ/hA5reR5vf9xks97A4av3dXqD4Mfg4WaJrZLB5l/+v6zBbRqJA7cj+fxBrhqA3O2dmw+K2+9jXpx9L0Fusu35QK5erpDd2UfRg1/TbqfN4PwE6Sy/qsJHj+JqGvrOAUphyD3udXAv7qdk2J0BLkC5iqjtBBtjDeDyBBFSc/I+ebjjp7xCBa+6Gdgwu2jNywmAO61/rwC3dRkJUFcBcH0E7eImrqajeh7VXh11jJDwOZQIS6M7mvNKyWGqBqqU7PtdjMlFhcyRHuCGjbv0da6ljiokDxWLkCDnXAA3Dny6El5aKq4U1DTJgxXyb30peTnk3+ZVwRdlZaX826+bNh1bktcVfrSZueXE3hHgTu+xLyV/ft6jZ3uUsxq/tlu8tZUAcGf9iQaTwZ+zF4PnS95cdTltB6HxYkbny/0y+awRPg7mi+LGANyZsUP/fV/y+qzJcT2o6CN9j9/6v/4va87tsiSs8Hykbkpe7n1ycqXvYV6cUf/lz+mdnyI9Dy2Xo/zoCdVnX6CXJi+SJD7tp15Z4a583Glx2i06r75hUL8AKdFKZYpPv8DYCkpqLbONbyRfNqb5Q5gszMV1XZyTd7iXZyAlSqGE/uApIl9cKg830Ev2b24ebruJPB/ycDNZ2HuINIyPysMdv5aDZg8XIMHPF3E3dhfuZrYcDu5Yo4fKVmQXskU4uEm8SgVJuddA9Vw8VaVVqOGNr31FTR4EULG7ZDwbH0E9U8ZZcQUFwahFr4cnggoKy2jRGzduSzjkxG2DBy/s/rGkBg+agCM94P1eu4L6Cvm3igj4t6oA05Mcr5h/+7RsoCsC0/F533ZCxy+Df6sIwRebOVRF0B64vG/etqcNsx9m41bfj230MFNNQcqgFfFOiR/uVdBVha7l8CdvG5xd925sh1ZTWGFnM0URPDuo8euPttA19SaanSTryC3pIrfT8tlHclWV/NYOua2dm194rtmjd36GM/bIHZIjsPDxI7kfl6pgBQ0gereF6ZdFVbjvKO5MlNDIoO0domSCsk1e6xrvKujCtcwo7rJoChNDND3g4RqZ4CZaP4de55OppOBn8ribuyAEwh6g18+Zvm3fXwTXoF/dHkZwB+RbV/cSwR0d9hSVVnELX1EwXJtyrzFhd1URXB/BVbaCq2gYvsum1UKbIyK7SAUFF8GZVsITgoLvsMPgdk2popnzrF3BlfDWz+KhUFZc9lfc4OHSEVy4KoqApxmP/Ar4tzdUD0fy5p74t03L49tmAGxfVIMOY9M+3pV/O/r3qmfzbb0PQvCjnQLV3BjXN4R/GzlfyFwzfkTQFCzX49vzDs1hmbCtYpbnuyV0XYseu2Kagu14dHo9dv83/+M6cjuPzFNK7bOP5HoevfNT6l/9HPPiHOn7aPkClSfPqDx9gT58JA3JEVj4+JHc+6yP69sW5rvXmMdvx6oqPCF3+BChLVZV4VOJ4s60hLUtnPevca/rAKiVGvqDJwgjs9Qo7l2qKUyOGXu/XAdO3wcNKoSArT2obX0ylRQUy0S7CtoiSyOLs7WPN3VTv78I7nir3iz98lZkZDbtE5E0EdybaLbvUe7VEVJiawadXPVe2vQqSDasNoqU2IpG0yjd2F9FBQUIWvRueT2Q0FN0WozVP54jmpnOPx9NwL5iI4Sk7Wtc+8qY7pi9OeaIi65uaZKi4uPLoP6t4/rjp2dshd1Ikurfjo5VdMHWcPvezVv/NuR8XP3bakZlLx8Ay9dtBytsrgXb88qpdW0VDHYKBkjJd1cmthsStY25H8xUMpimZU3oTkVihzfRjKbyawcVHm8WUYTgqjvgp28bNLuD6LGrrInr+Ri6iq6li9yuwW2I/GqBXJfe2UkAci8vkL5ELxSoPH1O5clztPxtK7xlgtx4f5NBbpSkAbmLzBt2eIaqUK7cNoBgcarCPMejAG6YdtTeJAJSKfGuzoclwxyEkUF/8ASluhF6bUWB5nTzJttKAqdDl4cvfLg8QTYDcE65BjuHyCkQGQZwJ8Hd7JfzJJBbEODaFtrlCbguUjdwtg7wpiIa9wlws0OA6xrpAW6sT3MAXM1zKfUaCCmxjCzdTDHlnfVuokmfDauFIKik0FJuyaLLArjTx7LSo+YFIceGyGJKZVwpwcasvaS588Jna1ih4XLFDR6EgEPDRxcSyxecOsrNHJEAN+RYXAmy8WP7WW6aSbw1xz63ScA8ao0h95PRmMOiRkEXuL7kZcu+mWtResIM6BzTfVzLktMVbM/nu3r/FgBPlweLeX8SaQpTIHdqMEIIjmp5fnxYJaepWK7Hn39o8uaiPXVvWCJNIe56C9mvKFmD2xj5lQK5rkvv9JjGVz+nfxWUu9KLRarPXlB+/BQtN3bD5+4gN42NRaO4sBo+buicvo91cUbn9be4ZhehKGR29ig8fY46/GHwuURxw/QmbmBmD/vdK7xu0BlM29pFO3gIqpb4BRlmL2pNYduVBuDG8nCbdeTFSWA8l4f9B0hNm7Bz145ms4A4JcAddTNzHaQ27GamaqG64T4tD+Bqrk22FXTrc40c/dLmvQJcw7Upmk0A+pkCpp4P149a44IA1PBdKlZAx+roObrCiNVPaz9uXEnaFDwbBFwoeezJRc3YuGsHs6pwKQoXKQWnfgZn1fxbI0hAbbqCuj1ua8ZUMhCN0R3n3/ZcyUl/dfxbRQieVXRUBbq2z0knnn8buYcprhFVEbzYzKMIQbPvcNK+LVk3A6Cnxi41igsUszo/eVhjt5RFInnf6PFnb+v0B5OdzSYkoSbuXTubJcka3KaQXyWQ67sO3ZMP1L/6Bf168CVnlMpUn39J+dET1Oz9gtw0UdxVgNykKO70qZsGECfv8V0HJZMl/+gp2YMjhKp9klHcMLuJUVzfwz39ENTA9X2UfAHj4RNEYbnJZmloCmGftViAa3aRZ++QrgO6ETR8yOZXSlMI+6IJsyU8F/3yBGFbSFXF2drH1aLb9a4U4DoWuVbwA9fN5BksCHDHZR6Am3EGFMzkNr3LBrh5z6LoBHVGm0aR/hgDep5I5rjEjRslmBm+i38PCWZCBA0eDHwcKThbcYOHvAI7WgDCzhyFnjP7PRAZ0Uy6R0ydzyiCo+FlcjGQNO340HRYe96JuWLoCRlV4XEp+Gyemi6twXjTg2TQOnM+pj1vwVB5VA3Kub1rDrjqjYFJz4tt8jB3FHdCNyzZTOHFbpkf7JbRVYXOwOGn7xqcf4xksxSyBrdzyOh9SgN05dh/ibpzgtykN3kpINex6R6/p/71Lxg0GiDBKFeovfiS0oPHqJnMrR0+D5C7iO0kkDstTuua7stvsK7rICV6pUbh2RfotaD0U1yUNWyWVUZx56UpjOv67Sb2u1f4gz6oGvr+A9StXSQiFPyljeLOzpvs21w8XNuCk3fIQT9IaNg5gFLlXnm4kQDX99CuThHWABQFZ3MPVzdCdZPmWArAbV8BEieTZ1DamBvgxkXkkwBbzu6RGwQJmt1cBUtdvIvZPAC35JhkXQsJNIwythSx+hPrW6CDmQC2PRNVSmyhciVyK+1gpgrYVywUIelJlSt/HMCP2VgS/3ZTlZTUgH/7YcX826ou2Bzxb3s+Vswj/yi/J6OLs3ONxmxkVbZzKlLCq7Zzs64JWwvyb6fH7BYNNvI6Ukq+uezx3VUPdxwQJ9AUYu89c9IUALZKWX5yVKOS1fF8yTfnbb4+aeI6H6GzWYyswe2Y+NNvSKzu8qO5aUFuoHtPINe26Xx4S+ObXzC4vgYgU61Se/FDSkcPb+q+wqcPcu/Kx007n/Q9BmfHdN98h9s3EapKdu+A/ONnKMPI932UDQuzHQVyU9sdv9E4Ns6HN7jXVwCo1Q30o7slm4UD4WTf5uLh+h6cfUB2AnoFGzuwsfNpAFw5bNc7BN/O5h5OJhuqO5ojsiTXXQGuPSDbqhMA3AKDYu3OADdpzuB48G9+0CFj95EC2vkajlDD9aPWuADAFUDV7qAPo6kNo0wIbolZx3wAF4YJZu79JJgBZIRkRwQRwLqv0/HHAXz8+hKjkFPgUwg40O+Pf3uQhayQQYWI3th9IumajFpjDP/2QUkjpwkcT/Kqbd+Mm4yQLqc974vNHAflDAjBRdfmZ2ddOtYYmJwjijsDLhdJNtNVfv2wyqONAkIILjsDfvquQau3+mSztLIGt1PiS38NckPEsyw679/Q+OaXQfteAZnaBhtf/pDi4QMU/faGnBbkxvqSYCMNyI2S+6IqeIM+vTff0T87Rnoeai5P4fEzMrsHoChzR3FHPqQ9vsoo7pgC3tVFkGzmOohMBv3oMUq5Fg78UwDcML3l83Al1M+QjctgQ0oV2D1CKsmJZuH2ovye40vmBuBKtPoZot8DIXBruzjZ/JSdyXlXBXB1u0+23QAkTraIVaimApNpauBGzRkcD0p+Fc0mumMhhaBV2MAd+8paXQWFoGuZKn0cReXauE1sW0Z0eFxGx7KsNsHs1rdgz8rCoyICvuiZb2CH3I4/Z/6tIqDrSk4T+LdR9IQkABxEwQP+rSKgZfmc9RakJ4xAcQQ94WZd1Sw/2s5jqAp9x+PPz7octwbRYHrqBjz7g3oS4C6SbPZgo8BvHFTJaioDx+Nn75u8vWxP+b8amkKSrMFthIxAblqg+ysDcgcD2m9fc/3t19jtIPKV3dhk48sfUdg/RGi3iTBJAHVZlRWiz30ckDst9nWdzsuvsVvXIATGxibFZ1+glSuBH/eQcJbW9sIlw0bJZr0OKArazh7a3hEoaigATAKBI71JnRXwcNvXyIvj4CaazQUNHxISzcIqKcT7Hf2lMv33DcBFojXOUXodEODWtnHyxYn70b0BXMscAlywcyUGufJSAe7EGkIAbql3jeo6+IpCu1DDi9JP4VMaEAqgSp+a1UYgGagGTXU5FRTixq0iwSzct2DctnDIjjV4GLk8Yesz5N9mVcHRkDV3NpC0V8i/zWkKD0vBd96HrkPHConURtATQtcVA3ABKlmNH+8V2MgFNIW3131+cd7FcsbmmDPZLGr+2bHhyWblnM5PHtTYKQbJZu/qPf7sXYOB5UyMnZA70RRIJZ89uP2n//Sf8uMf/5hyuUy5XOY3f/M3+bf/9t8udY5PBeSmAbr3BXLdvknrzUuaL7/B7gZ1RHNb22x8+SPyu/sTxazvCnKTxqeJ4iaB3Djb854Lm096Lv2T93TfvsKzBghNJ3f4kNyDxwjdWHnC2b1EcT0P9+T9bWezYgn94RNELh+6/0mAOXrOZL/mArj9HvL0XdBKWdcXSjSbfs+XA3BBbV6idFsAuJVN3GJlYYAbGVGcNBEJcDOdawDsfBkrV4rxfz6Am3S/UpBUeg0Uz8NVNdr5SXrEvAA3SUa6hu9SHVZQ6Gp3q6CQZpwANoYdzEYJZmF3xbhod9r5gsx/2Bc2qpAMpMKFPxaYiAC4aeyGKAMr5t9OHasZgtpwOW9NH3uZ/NupMVtZlY1sQLd41bJv+LBREdWkqHAcwJVSoqsKX2zleLqRQ1EErYHLn551qS+YbDYDLhdINtNUhS/2ynyxU0ZTFNp9m5++bXDZMifG3YmmkBAIm5bPvkPZv/k3/wZVVXnx4gVSSv7Fv/gX/P7v/z4//elP+bVf+7VUNkYdyv7ag91UHcqU6a4csbqpVT9a17NldDzTiyUKu/vohaD8lfQ8+lcX9K8uZ26OSbMldTtLGr+qTmdL63ImBJnNbbKbO0FSk+9j1S+x65c3N5JVdjibx3bazmbTukFnsyOUTNAdzLuu4zUuh+NT+LikrmZJ3cgm/FHUoKNZNhe8D41L6LaW2tFsnm5mo5cS8Eo1/HINALXTRO1co47dh6bnjOoaNu3/vJ3M7FwRqxj4keldkx30YvwPX/eiXcxcRaNd2sIXgowzoNxv3fi8qg5mAB09T0fPB9UNrBa5sdhxkv1FO5idaiV8ISj6DttzdDCL6gIW7lswpicVjv2A172v2FRUf0x3+G9Ex7A4u9PnEQJPwktLxZGCqiZ5kB2bI8z3hPXG6XpS8m1XYklBWRc8KyqxdsO6l82sUZkdrygKni/5ecPG8iQbWZVnVSO8y9sw6BPZTSyhg9n0333H49t6n54dXJO7pQyPa0H73uk5w+aI9WXKhxn/IjqbDRyPr8/adIaR291yjmd75Ynv9bt0NmubAzb/q+QOZZ89uA2TjY0Nfv/3f5+//bf/dir9ecHtSNYgd1aMUpnC3sFNXVzfdelfXtAfA26QDFBhtSA3aanLBrlhhxXDILt3eNvG17IYnB3jmQFg+BgtfKNsL9S+Vwi07T3USgCG/L6Jex7Ucw1zKamtbfSc8Tphn6fotr0CNncRpeFNs92E68uPBnDHbXnFCl4lqLqhdtuo7fpHAbhWvoxdqACQ7TbIWGao/sz4JQBcRzVoFzeQQpCzepSsbrh+hA+LAFwJXBslBloGVfpsWS0MIWf0l9Gi9wa0CJULtRhcjv6ACrePeJOAWRLADdvjK1+jIQ0UIXmoWGSVEFsJADcRfA4Nmj68sYPa2AeGz1Zm3Fb4mDBbt4A+WrfvSb4NcvU4yAn2cuqMblJ73ok1xrTn7To+X1/b+BIelXV2C/rs+KT2vNPzToHLsDG+lLxvWpx0gjq4OV3lxVaeYmayVvYEyJ3jHhQHcIM/Z/fMl0Et3A/XfSSSnK7x5X6ZUj4TPTYG4MLt9dfummz+5v/tV6v9rud5/OEf/iG9Xo/f/M3fjNSzLIt2uz3xP8z3+B8WoyvMU0YsjXxqdAW70+b6269ov32NOxigaBqF/QM2vvwR2Y2tm4s/iWoAq6Ur3JWqMA8lIGo+37aHbXzfDWvjZoLauPtHCFW9l7JhaW0vmmzmXpzinH4A30PJ5TEePEEplO6VpjAfD1cGiWbDChCUq7BzkKqjWbi9WZ8WbfagdluozSuQ4BXLeJUtvAUoCtP+z0tRMMw2+rAO7aBYwzbC+agz4+ekKIQ9cte96SYPuXD9CB/m5ciO6AKjCgqeUGgYJdw5KAeLJJjlpEd1LMGsH5FgdjtHMv929DpsjzeFS154+FJw6ht4vpy19Rnyb3Oq4HBYbOS0L+k4s4/bI+kJYXPF8G+LusJhIQCU7zsOpr0g/zaCohA2Rsphslktyw+3CxiqoO94/GzVyWYTurM0BUUIHm0W+fWDyjABzuXP3l/z4ao7tYYFk81SyPcC3P7sZz+jWCySyWT4O3/n7/Cv/tW/4kc/+lGk/u/93u9RqVRu/n/w4MGMzqpAbqD//Qe5VqvJ9Te/pPP+LZ5to+g6xcMjal/8kEy1dmuD+wG50eei17Bo6bB5QbXTbk7Wxq3WKDz9Ar1SDfz4hLm4YWudqYnbbWO9fYXfN0FV0faPYmvihs2bPGeynbl4uK1G0NFMSsgVYO8IOfV4b9nNHuJ0bwBur416fREA3EIJt7q9MMCNmi/us+T7PgLI9Fro/S4g6Jc2sPXbcmWrBrgZZ0C+P2zykC0zUDPh+lHrWwCETlZQ0GgapaVUUIgbV5Y2ec9GiiDBzAl5Y9Lwb9MAUSFgT1ho+FhS4VzqNzaiAG6c79P+TDt2n/zbDR0qWnA9vO35OCvk3+7mVSqGgi/hZcse+5EQDjIjP5Mx4HKGIzt8Xc1p/HivSC2nIWWQbPbLix6Wu4JksxlwHJ5sVskb/MWHG2wWMvhS8vqqw8/fN7DtxZPN0oLc7wUtwbZt3r17R6vV4l/+y3/JP//n/5z/+B//YyTAtSwLy7ptZddut3nw4AH/zVE0LSHt4/+RfGzKwidFVxBBRYXCzt5NyTBvMKB3fordbk2qJszxfeLjhh1Wczmye0dow3q4Xq/L4OwE3w6u18+Nizutp27uoG1sASCtAe7ZMdKxl0ZTWAYPd0LdyAY8XE0Dz4OLY7CtCRt3oShM66emKGQLeBu7IEDp99CuL1En7EzOGUkJiOO6xfmsKEhgUNrAzRYASb51ie7aoWPSrjktRUECvVyZQaaAkEHCmeG74fpR65uDRjD611Y06tlqUD3OMan6g1AbSbbT8m994FQt4ioqWemxL83U/NtxlXS+KZhS4VhmkFKwq9jUVsi/dSW8WiL/No6e4EnJ1x2Jg6CiC57ekX8bR09wfMnP6xaOD9s5lSfVzMx4mJ+iEIyJpimM/pZSct61edu08GWQgPZsM8dGfrIhzKI0hRk/4mgKw/NSSs7bA15fdfGkxFAVXuyV2SjlosdG3JvaXZOt/+3/9KvJuf3t3/5tnj17xh/8wR+k0h9xbuPA7UjWIPcOcyoKuc1tCtu7CC34YLmmSe/8FKfbmbSRMMfnxsedbz6BsbFFdns3+CKREuvqYuGEs1VxcaP2IQnkKvki+t4BqBr4Pu7FKX63nQrghs27DB5ubKKZqsHOISKTCaIK9TMwu3PxcOcBuNPnowCun8njbu6CECiDPtr1OSrRc64M4JY3cTN5hPTJtS7RPSd0TFre8TwAt5OvYRtZFN+n2qujjUWBFgW4SRxZU83QzAQ8+Q27Q0Emrzet7bDXDgpnWhFfCMq+zRa3gZlkwDfPuoMxDV/jShqIIf82F4JjVsG/PTR8NlfIvzVdyXdmcN0c5QU72fn5txNrjQG4bdvjm6aDlPCsYrCZ18ZUh7amngTFfebjQG4UEDXtINnMHJYJ2ytleLyRm7wP3HOymWm5fH3epmcHP0QPq3ke75SnPhfRyWZCiNTg9ntBS5gW3/cnIrPLlHnoCvDplBFL1rsHuoLv0788p/7Vz+mdnyE9Hy2fp/LkGZUnz9HyhVsbxD8e/ZT5uHefT2I3Lum8+ganG9QSzmzvUnjyAjUXFPOfh6qwKi7uoiXDfLMb0BTMLigK2t4h2s7+nWgKszrxduZq+OC5cPYeafaCG+32PpRrc5cKi/NnkW5mimWi1YOya342h7uxi0f0nHetgzvL2w0oCtl2HdUeIIVCv7KNq2ihY6LoCdOSlqIggJLZRHNtfEWhlZ+/Bm7o/Akc2bxnUXACPuy1UcQa48MmcWoX6WCm47PpBUl7bcWgw1iiUMJ8UY/5w30L9qsmXArCRQ7r34byi1fAvz11FMwV8m/zmmBvGEQ9NmUi1zeMfxtJT5iaq2yo7OcD4PimYzNw4vm3M7an780xFIEoOkHeUPmNvQL7pSBie9ax+LPTDr2P1dkMyGc0/sJRjYNKELE9bpr86ds6Zt+eGDshMTSFOPnswe3v/u7v8p/+03/izZs3/OxnP+N3f/d3+Q//4T/wO7/zO3PbmmfjRoAkLdD9VQW5ocd9D/P8lPpXP8e8vAAp0YtFqs9eUH70BDU7xt/j0wS599EAQjo25vs3mMdvbxPOHj8ju38IymIJZ1E+Tcu8XNxUNsePeS7O8TvcevD+K+Uq+oPw1r1RvN5knXif5ko0kz5cHCPbzeDv2tbcLXunr6flANw+2tUp+D5+Joe7sfdRAG6udYXiWEihYFa2cRU1dEwa/u20xANcSbl3jeK5eAk1cJNsp+XfApSdHhnPRiJoZMqE4KSYNaQDtePH8tKl7AUUiCuRxZJiXGlm3N35tzY6Po5UOPeNGxsTtpbIvy0qAf/2va3ghc0VA/Sm7cetcduAkhp8at+YPl7IwpbFvz0oaJR0gefDy5Zzc11O82/jOLgz644Bl2FAVBGCx7UcP9jOo6sKph0km522P2KymSJ4ul3iR/sVdFWhazn8ybsGZ9e9G9uhNXHTgqKhfPbg9uLigr/5N/8mX375Jb/1W7/FH/3RH/Hv/t2/46/+1b+6sM15QG6gvwa5i8wnPZfe6TH1r35Ov1EHCUa5Qu35DygdPULRx4qms3qQu8ga7gJy087ltFu3CWeAXt1I3eEsrU/zRnFn9EL2IQqUjut5jaugda/jIIxh695SJXS/k2yF68zaSBPFnRwz9kfjAlkPErooVWDn8E6VFJYCcO3BGMDN4mzuT0QwVw1wIQCZ+dYlimsjFZV+eRtPJEc0F+liNi2K9AOAKyWOZtDJVcOv/Yg1LAJwBVCzOmi+hysUrjOrTzCr+hYZz0WKoMGDmwKo3h6fUY0FoqqAfcVCCElHqlz74z9Wxmz4IQ0LUgL2kTEhAkqCJiSWLzgZTJxObStNe14hBA9zAg2J5cH7XjgwC70/z3E++JEgeFIx0BRBz/H50HEix08D3Ng9jAGXUUC0ltP58V6BalYLErsafb667GHfU7JZmN2NQoafPKhRzRlBTeLzNl+fNHEdN3rsHDeG7yXndl4ZcW7/6uFOKOc2DR91Uj+97q8aJzdORc1kyO/ukx1VU5CSQaOOeXGG77oTunfh5K6Kj3s/CWd5cvtHqJkguu12OwzOjoPuWqyOi7vyZDNVRd89RCkUAfDbLdzL05svv7lsRerE25kr0SxXQGwfBEZtCy5OEFNfDquqhRvJwdUN3K0DUBSEbaPXT1FD9MLmuCsHd8RP9IWCWd1BajqK55BvXqCOwco0HNxF+LcAtmbQKWwiBeQHXYp2L1w/am0p9mOGDytU6rkqPoKCO2DDC6/5u6wEMw/BqVrEUxTy0mFXrrbBQ9PXuBjybx8oFvkV8m97nuCtE7TrXpR/G2d//HjXlbwcvlWP8gqb2Xh+7V34t9eWx3fN4P78ompQy03Vn43hwMYmdiVwYKOSzc6GyWZSBoldz7by1HL6pO591MQdnpdSctzs87YRRG4zmsqX+2UqhWzo2HbXZPt/93//1eTcLiqZYin0+H1EctNEc7/vkVzPsui8e8P1t19htwOuaXZzi1pES984+T5QFcLm8vom3dffMhi2uNWKJQpPX6DXguL+q4rirp6m4OGcvMO9Og8eXZUrH4WmMKEfEsG9GdLvIc/eIV0XjAzsPUDqRuz4eWvhRp2LjOA6NtplALKlYeBs7ePFPL1eZgR3FDVTpE++dYnwXHxVp1/Zmmghe5cIblJU0nBtCsMauGa2SF/Lhuun8CdtlFWXHlWrgwB6WpbOnC1659GVUqIi2fZMhART6DTRx40kzJE830hG+1URLqUh//Z0xfzbgirZVm/5t/0F+LeR9qfmKmqC3eFb9b7v03eXWB5saq5aRmVnyL/9rmVz3LEj9+yuNIWkKK4Qgv1Sht/YLZDTFWzP55fnXd40zMnP4DJpCglRXCEER7U8Pz6sktVULNfjZ++bvLvsTF2nv2Ltd5cho8jt//zf/jWE59K9OMNsNCJRzCojubCaaO7nGMnVC0UKe/vow2ie9DzMy3P6V/N1O/tYlRVWXVVBMTLk9g/R8sH+eH2TwekxvhU81/tco7gil0ffPUToelBN4fIMv9MK3eukqgPhOsn+pI7iqhrsHiKMDPg+XJ7CwFxaqbCFIriajrd1gFRVhDOM4MpZvbA5lhXB9VSNfnUHqaioziCgLKSJZC4hgtvLFulnSwgJ5V6DjO+E60etLTQiGH++o+XoGIXULXrTRoajxnWEQUPLgYQ9v0dejH3xJ0ZMZ9cdHVkOOLDv/CwOCkXhcajedhicsBVSsSDO7vSxIIoHb22Fnq+QVSTP87fvfVTkOXm9swZGUcyXPUnPF+RU+LKs3l5/CX5HnY9qz+tLyeu2Q2MQvE8lQ+FpRSejhZcDg9VFcUevPV/ytjngvBskcxWMoLNZ3hir7DBHNYWZeRbobOZ6Pq8uu1x0g++wSs7gi70y2cztj7h212Tnv/5//GqWAptXRuD2//nXfpvs8HGv5zr0Li/oXV3OPBIfl3mA7hrkLjbfTEtfx8E8P2PQbNwbyE1a5yIgd1lUBb26QW5nGNmWErt+iXU1TNRaQl3cKF/uUjJsfppCE3cYrY4Dg1FzJgHcMJ3UAFcosLOPyBWC67FxAd127PhVtesdvZSajrO5D5qGcJwhwJUzemFzLA3ganoAcIWCZpnkOvV7AbgS6OarWEYORUoq3Sv0BUuEpQWhkskWvdtWC32JLXrD5qsrOXqqgSolB34X/eZ6TABmYyppgehACj7ILL4UbCsOm6o3YwvSA9yk+rcvLRVXCjY0yVFu4vTsuDkB9Liu40u+6YErYSsjeFgIfxwf5nfY+Th6AkC97/G26+D5oCmCR2WdzRiaAhBZDzfs7wmfUtAUABqmw8vrAa7noypBAtpO0ZgCqtEgN8mneWviAly0B7y86uD5QZ3e5zsltipBpaA1uJ1Dbji3D/epbu9Q3NlFGz5ilNLHrNfpXpzjWoNIG6uM5q5BbiCZ6gaF3T3UTFDPxbOsoBFEqzlpI2GOVYHcRQBuss10IFdoGtndQ4xRkpllMTj9gNcPiGX3GcWNWk26qOrk32ptC21zG4RAWhbu2YfQpg+LANxAJ97OXDzczT1EaXizbTWgWf+4AFfVcbY+LsB19Qz96jYg0Addcr1mqojpMgBuq7iJqxmovke1W5/g/oYB3HRAL1rHB+rZKo6iYfguO077zrbjxvnAmVrEUVQy0uNgjgYPoSAx4vVoTEuqnPsZAv6tTV6ZvZaWxb/teoJ3Q/7tA8OntkL+bduRvA4qu/GkoFDLrI5/C2B5Pi9bDr1hy7mtnMqjsoEacW3BLLiMes+m5wzGJtfEtVyf7xp92oMgkLdZMHi6kUMfH3vPNXH7tsvXZ226w5q4+5UcT3Yr9Mz+GtymlRG4/e1RQpkQ5Ko1iju7ZMZqrw5aTToX59hTDQfGZQ1yVwxyhSC3sUV+Z/em25lrmvTOTnB63UnVhDk+l6SzeaK4WqlMbvfgptKEc11ncHEGvv/ZRnFFLo++d4jQhjSFixP8bid0/UlgeeUAt7qJqAb8Z7ptqJ+vrNlDOoCr4WwdfFSA6xg5BpVNQGCYbXLD1rlJa7grwPWFQqu4iadq6K5Npde4sbmqBDNXKFxla/hCkHctNrzeQgA3ja4Q8zd4SKInjL+e3lsp4UwadKSGLiQPlQH6jb9jtkJAZVxUeOb48N8LR+HSVVAFPM145PR4YJ4ERON0j/uSKwdUAT8oK2RGYCzJ76j3JgHgSik56bmcmh5SQlYTPC0bFDMxIPYeks1OOjbvW9YwsUvh+WaeysdINhue86Xkbb3HcTMI0hQMjf2yzpO/9v9eg9s0MgNux8QoFinu7JKrVG++pGyzR/finH7z+qPwctcgN7iB5rZ2yG/v3nxonG6H3tkJbr8/qZswx6cEcpcRxUVRyO7skxkmmUnHYXB2jDv8Ufaxo7iL0RQ09L1DlOGPTa/ZwLs6XwjghuvEn58L4BbLiGHnMPomXJ4ipu4THw3gug761d0B7uz+hPsw+jK3swWs0gYA2e41GasXqp82Wp0EcEeHXEWjXdrCF4Ks3ac0uI2mrqpFr6XoNLIVJFBxepR9K9RGeJQ0Hagd/9cUGpda8LnY8U2K44XgEgHf7LrjgKg/5N/aKBSEx9GK+bdvbBXTF+QUybMV8m99KfmuJ+n7goIm+KJ0t/a8wR5Eg83R+I7t86ptY3uBymFBY7+oR+4VsDBNIRibHMXtWi7f1vsMXB+E4Kic4UE1Gwu0o/Yg3P/5aQrXPZtvzts4vs9gMOC//9v/vzW4TSNx4HYkWiZDcWeX/MbWLafMsekOebkzNeLGZB6guwa5880nVI38zi75re0bJavZxDw/xbPHvlQS7H8uVIV55lLzhaBsmBHQOJxWE+v85OZanYdS8LGiuDM0hc1ttI1tAOSgj3P2AVw3ERCG2borwIVpMDJ2IptH7ARluYJSYceIqaLr9w9w90HTPxrAtfIl7EIVgFynjmH3Q/WXGb2FyRJhhUGXwpJLhIWd72pZ2kZxJQlmYceulQxtNYuQkgO/R2bE900AlOMqaYGoJQXvh/zbLcVha4X8W0fCS0vDk7Cp+Rzmwj8jcUB0fI6o6KYQAsuXfNsDT8JuVnCYvxv/NtiDaLB5Q93xJW8708lmBhktBoiuONnM9SVvrvtc9oJkzFJG4/lWnpw+BqxXRFMI/pzdW9v1+Pa8g5Auf/l/+F/X4DaNpAG3I1FUjcLWFoXtXbThY3Hf9zDrV3QvzvFsO3LsGuTGy11ArmIYFHb2ydY2gm8pGdTI7V2cBeWaRuMT7H/uIHfmsBBktnbJjnirnsvg/BR3yFP+HKO4Sr6IvncIqhp0Ojs/QZq9lQDcMJ3UUVwjAzuHCE0D1w0AruPEjv0+A1wJWIUqTr4ESPKtK3Q3Oaq5DIA7MHJ081UAymaT7Ni8q0owaxol+sMEsy2rhTEEnHeNDEfNd64WsBQNXfoc+F3U1IAvfs3jr8P4t0eKTWGF/NuOJ3hnB0DqYcanasxe23GgNcn++LFrW/JumFrzvKhQNubn386sNwbgjmxIKakPPN513Ztks8dlnY1l1cSd9i9lstlVz+bV9QDPl6iK4OlGju1iZlJ3QZrCjB9xAHd4XkpJu2ey91v/rzW4TSMjcPtb+9sYmpo8AEAI8rUNiju7GLkgi08iGTSbdM7PcMxezNDVgFxID3S/ryBXzWYp7B2QGSZWSd+nf3lB/+piorbgXUBu0thlg9x4e+lArpLNktt/gJYNUo/dbofB6THSjW7+EDVr2ijuSmkKmo6+f4SSzYGUeNdXeI2r0P1NigaHzxVvIzXA1fQA4BoGeB5cniAsK3ZsXKLZpw5wp3cyDOAOShu42QJiWBNX85xQ/WUD3F62RD9bREhJpdfA8N1w/RD/5wGho9cSuFpCglkaXSGCBg8nahFfUSj6Dtssr8HDzPso4VwatKWGJiSPVsy/PXMU6kP+7bOMR3aF/Nv3pqThgqbAD0oKxgL825k5IBVNYeD6vGrfJptt51QefuRks4Hr8+2VSdcOIvQ7RYMnG/lJn+4x2azdNdn9rf95DW7TyDi41cY+AFFRrWnJlMoBL3cIqACsXpfu+RmDqUz+cZkH5Ab66XWXDXIhHdC9T5Abd1ovFCjsHaIXAi6a77qYF2cMGvWllQ+LG/tJRnERGJtb5LZ2QVGQnod1cYbTbARzfwZR3AkdIdC2dlGrAZfT73Vxz0/A92bWngRww3Xiz6cGuIoSANwhEOfyDPrdhWvhLgfgLjfJbF6A269s4xlZhO+Rb12g+fGP7WP9SAlwJdDJ17CNLIrvU+1eoa24gsJdEszm4d+OXg9QOdeKIGDTH1Bh7ElB6ByfD//2ta3S9wV5VfIsR/hcIQfTAujRMV9KvulKLCko64JnxXj+7bTdKJ1gL6LB5k2Xv2Gy2dlYstmzikHBuP9ks9FrX0o+tCyOOzZISVYPauKWMlOR5XtINmv3THbXkdt0EgVuR5IW5GrZHKXdXfK1jZs3w7UGdC8uMBtXE5HDcVmD3Hi5C8g1ypWgRm52WL/YtjHPTrFa15M2Yux/SlSFpURxjQy5/SO0UXJWr0v/9BjpBJSazy2Kq5Qq6Dv7AWB3bNyzY6Q1SAS4YfOtDOAKAVv7iEIxQFmNC+i2PguAG5vYlQLgzviqKEghMCs7+LqB4rnkW+dT868G4PqIoIKCpqN5DtVu42bsfSSYVe0eJRlPxUgLnKPGtYRBU8shJOz7XbJj9XYJnWM5/NtV17+1fXhlB/zbbd1nPzt7XU+MmxNAj+v2vYB/K4GDnGAvNwvawq7rUIem15qCpgDQtj1etxxsP7i+D4s6ewUtcg+BhZPN0tIUWgOX7+p9bM9HCMHDapaDciYWaMeC/TigHQFw1+B2DkkCtyNJC3IVXae4tU1hewdVDX7Z+J5L7/KS7tUF/hTvbiRrkBsvC4NcIcjWNijs7t+WD+v36Z0ez1U+7HMAuemjuGDUNsnu7CMUBen7QRT3uh7Me8cobpQfi4LcJGAqjAz6/tFNpzD36hy/3Qxdd1IUd2UAF2BzB1GqBq+bDWjVPyGAexLZyWwVANcXCmZtB6nqqK5NvnUx0Q9+VQDXEyqt0ha+opBxBpT7raVWUAg739VytBM6mC0SGQ47JoFLJU9f1dGkz4HfQxM3ChFzzA9w77X+7QhceYIPtooQ8MjwJjixYX6HrTctPaFuSz4MguvgRUmhqMfTE6ZtxwFciAe548lmb9oO11YQGCtnFJ6WDYwFk83iAG4wNjmK63g+rxoDGv0Ax1RzOs82c5Pd1lZIU1iD2zkkLbgdSVqQKxSF/MYmxZ1d9GHnMyl9zEaD7sUZ7mA5TSFWAXID3ZTzfy4gV1HIb20Py4cFHz6706Z3doo3GMvcTpj/vvm4q6QqCN0gt3+IXigB4Jm9oIXvsNLEpx7FndBRFLTdA9RicMMbdTUTzN7iPirArWwihmXa6LSgcbFws4flAtz4Vr3LBLg3j2AVFbO2i1RUNGdAbgVtesOAm6PqtIubSCHID7oUl1BBYZ4Es+1Bk1uslB44jx+PG+cDJ2oRT1HJS5dd2V8p/3a8/u0jZYC2Qv7tia1w7SloAp5lvZuqApGfizkB9OiYlJK3fWi5YCjwZUm5bWqQFuBOOza95pTJZlcDj3cdF1+CPkw2q33EZDMpJeddh7fNAb4cdhHbzFHLG5O6K6AptHsme7+9rnObSuYFt+OSFuhmK1VKu3tkhu1EAQbtFt2LM6zOcppC/CqB3LuWDyvs7pHb3AqUJFjNBr3z04mo+qpA7seO4obNM9HC1/exLs+xG1fBvCuI4q6SpqDWNtE2d0CIYbmwY3CdmTXPC3ADnXgbcSB1QrVYGdbCBcwuXJ0hpu7E9wdwxzuZ2UGSWcRcqwC44216dcsk122E8lLH/15KBQU9R3dYmqxkNsmtuIKCT5Bg5ioaGd9h2+msNMHMRuFMKyEF1PwBte8J/9aX8MpSsaSgqEqerJB/60nJ1x2Jg6BqCJ4Uwvm3cbaTdIFUyWZ91+dVy8F0gxvFTl7jQVm/rYoRZnfFyWam7fFt3cR0gsjyQTnDw1pu8vO5ZJrCGtzOISNw+3/Y30JTlNQVAsYlLcg1CgWKO3vkqtXbphB9k+752dKaQqxBbrq5FMOgsHtAtlYDQPqSQf0S8+IcOZ7gkmD/PkHuSqO4mh5EcYeRT69vMjj5MHcUdx4/VkZTyBcw9g5B1YJyYWfHyL6ZCHDTzLW0KG6+iNjeDw4M+nBxEtvsYaUAV9Nxtw6QqoqwhxHciLlWAXDH2/Qa/TY5sx3hb/h+LApw562gsGiUdfR6PMGs4A7Y8MxEe2kiw9OvR/92hE5Dy4OEPb9HXozlfYSC89Xyb5PoCZPrjaYPWEP+rS9hV/fZDeHfhkVvo9Ybp9tzJS/NgH/7IK+wnU1PPYgDubEAd0p3PNnsuBskmwHkhslm+Y+YbOb5knfNAWfdIGejkNF4sZkjb2hjdpZHU2ib/TW4TSvT4HYkqwS5qhE0hShsTjWFuDgPmkLcc/LZpwxy06z5LiBXy+Up7B9gFINH89L1MC/P6NevUldWuG8+7ioTzvRKjdzuQXBDkjKI4tYvg3k/8ShubLmw+iVes/5pAdxMDrF7CCmbPdwfwLWGAHdWL8n2ogDXyeQZlAO6xiJdzBYBuGkrKET5Pg/AHf07GCaYAdTsLkVph9qYNzIcdkwCdSVHTzVQpeTA76LfIvUI3z8P/u21KzhxAv7tE8OjuEL+7YUlObWC6+BBXmHDSM+vXTZNAaBlebxuOzjDZLMHJZ2d/MdNNmuYDi+vB7iej6oIntRy7JSWXxO33TPZ+6t/ew1u00gUuB3JKkGuUNVh8tlYUwjPo1e/pHtxfu/JZ7/KINcolSnsH66sssKyAS4sj6owc2/TNHJ7R+il5Udxo3yYAYBhOmkB89gXoba9h1qpAeB327jnJ58WD1c3YPcoaPbgOAHAHWs8Mj02DuBO+zEvwPU1A3c76KymWAO0xtm9AlwrV8IuVgFJrl3HcAah+ssEuLMVFOo3NleVYNbR83T0PALJ9qBFZiyiGgVUp+2m0RUioEOcqkVcRSUrXfbvjX/r80ixlsa/nQafUsKxo9DyFHQlqH9rrJB/+8aUtL3geNUQPMiJWw7u9KTT807NkwjsUkRxHV/yuu3QGiabVTMKTyrGhE9xAHf6fBzADcYm0xQs1+e7ep+2Fdy/tgoGTzZykz7dMYq7BrdzSBK4HZeVAV0hyG9sUtrZRR8W2pdS0r+u0704x+n3Y4am92keTPwxGkLcF8iNO52tbZLf3Uc1hpUVTJPe2clEZYUkD74vVAW9UiW3e5g6ihvlyaqjuEnRV6VcDcqFCYG0rKBtr2PHAsM08yy12cPuIUIfNnu4OEZMdTtctJvZ3ABXN3C3RgC3j9Y4vzeAKwGrWMPJFUFK8q0L9Hto8jBRQcEeUB7cvYJCUoJZI1PGUg006bE9aDFKgL8rcA57HfBvi0ghqPoWG4xdW6G+L86/9Yb8WweFovA4XCH/1hvyb20pKKuSR3fk38ZFeqWUXFhwbgcRf0OBR3mFkjF1r4/9TCyHpjCyJaXkou/xoTtMNlMFT8s6leySks1iAG7UWCklx22LD20bOaqJu5mjlNWnbC0WxW33TPb/j/+fNbhNI/OA25GsMpqbKVco7e6RHT4mBxh0WnTPz7E67chxa5A7K3evrLB384G22y16Zyd4Yx2m7hvkxi1npVHc/aNQLu7nRFMQ2Rz63hFC18Hzhm17u58OwFXUAOBmsuD7AQfXGsSOXR3AzeBuBbWDlcEQ4EbMlabJw8w8UX4OAe6gvImbyQddzJrnK23yMDrkqMawggIUBh0KtjmjG+d7eDQzGrj5CC6zVTxFJevZbLnd1NzeRfi3XaFTvyf+7WDIv5VSsKPYbKj+rK0l8W/7Pry2NaSEA8NnKzN7ncaB1iT708d7ruRdX2LL4O/drGA/p0zeJ2I+Y6tINjOdoLNZf5hstlfQOCrp8Z/7BWkKwdjkKG7bcvnuqo81rIn7oJrlcAk1cdfgdg5ZBNyOZJUgV8/nKe3skavWbt5Yp2/SuTinf934ZJPPvk8gV2gahZ3xygqSQaNO7+IMOfboOM76onzcRaK4sDqQO8HFTVFRYZ51pQG5ywC4qFrAw83lAx5u4xLvevU83PTNHhTYOUAM/ePyFNE3Y8euDOAa2QDgCoHSN9Guz1FFeERv3i5mkARwBWZ1G1/PBE0emueoyFD9eQBuEngbGDm6+SoA5d41Wc8O1w/xPSnKGqbjCJWrXBWJoOSYVP14GkZau1HH6kqWrppBkZLDFfNvm77GhTQQQvJQscjNVtFaGv+27grOHBVFwJOMRyFle94wv9PoelJy3Ifr4VdAQRM8yguyY/Vnk0DrspPNPCn50HG56Ac/BAu6wrOKTlaPAbErTjZzPZ+X1wMa5vJq4q7B7RwyArf/+71htYT58SowP9BNn3xmUNzepbC1haIEF8Kyk8/WIDd+HjWTobB3SKYSJIJIz8e8PKd/dbGUpLO4cYuA3NVFcfVhFPe2Lm7/5APSsT+pKG4SONW2927b9n4kHm5sN7PtfUQ+eDRP/Rwx1Wzk3gBuJoe7uRcAXLOL1rxcGsCdfoemgcxkkweLfPMyMgobtsZ5orfja+lmywyyBYSUVLt1dOmF6yf4kbQHo39NNUMzE3yeNq02edxI3Xnshr2WBPxbR1HJSo99aa6Uf3sqDbr3xL997yh0PIWMInmeB3US/4aOi7IfpTt97tqWHFvgyeAae5BT2MiIVGOn50vSTZtsdj3weNtxcXyJIuBRWWcr9/GSzaSUXPQc3jQH+P7da+K2eyYH/+3/sga3aWQa3I7LIkB3VdHcyOSzq0u6l8tJPluD3Ph59EKRwv4hej4PgO849M5OsJq3SWdJs38fqAp6dYPc7j5CUVN1N/sUAe4sD/c9OHevh7u0Wrhbe4ghFYTGBXTSt+tdLsDNDwEuqL0OautqJQA37EvfVzXM6k7Q5MHuk+/UE0HlMiootAsbOHoG1feodq9uyqKtKsGspRfo6TkUKdm2mhjDosd3tRv22hnyb30hqPgWm/fEvy0pLgeKe2MjDOCmjQpPn0cI3CH/1pGCmiZ5kAtd1u24BAAdNse4jM7ZvuStKTH94O+aITi6r2SzCDu2J3nVdujYQeBrI6vyuKyjfcRkM9Px+Pbq7jVx1+B2DokDtyP5lEAuIjr5rHN+jjsITz5bg9xZWRTkZqo1CnsHqEbw6zOsne8qQO4yo7hR9lJHcfVhFHfY3cztdRmcfEC6zr1EcdMA3DBbMzzc/SOENuThnh0j+71PB+BubCPKteB1sw6txkcBuF62gLcRNJ1Qu230zvUUuIvy4e4A19MMzGrQlMPod8iarZUDXF8IWsUtPFXDcG0q5u16V5VgdpWp4Kg6hu+y47RXyr/tCY0rrQDArmdSELfRaaZ0Z9Z8gw3TAG+FvlT4IDNIKdhVbGoL8G/Tgs+eB2+dgH97ZPhsLMC/jZ1jaszovJSScwsuxpPNCgolPToyGwtwE3TTJpudmR7HPRcpIaMKnlYMSpmPWxP3bXPA+bAmbjGj8WIrT05PT1PomP01uE0racDtSD4pkAtkyxWK08ln7Rad8zPsbnjnszXInfZnwXmEILe1TWFn77adb7tN7+w4ddLZ94GqYNQ2ye7sIxQF6XlY56c4w/JpHyOKe1cernt1jt+6/nQAbnUTUR22621dQ/Pq4wDcXBFvYwcAtdPE6LamxkT5cHeA6xg5BpVNQJDpXZMdrL4GrqtotEpbSCHIWT1KVjdcN8L3cGAWDQg9oXC5ogYPYcfuk3/b8DWupIEy5N+O+iBMYKUl8W8vHcGFG/Bvn2U8cin5t3FgMw3AhSDZ7K0ZdDQD2Bsmm6WJAE/PmaQLpIridp2gs5nlSYSAg4LGQVGPfO+AldfErZsOLxt9PF+iKoKnGzm2i+lq4rZ7fQ7/uzW4TSXzgNtxuQ+gmz75rEBpd6rzmdm77XwW5c8KgO73FeRGnZ5t5yvpN+qY56dIL12ns8+NqjB9SDEMcvsP0PJBNMjttBmcHiM9d+nJZiuhKQiBtr2PWqkC4LebuJdnMzzc+wS4Q7cCKVcRQ2BJpwWNi48DcAtlvOoWAFqrgW52psZE+XB3gGvniljFGquqgRsG3iwtS6dYA6Bktsi5t3MuM8Fs9K81bPAguZ8GD6dqAUfRyEiPgxXzb0+kQU9qGMLnsWqPJfmN2VoS//atrdLzBTlF8ixP+FxzAtyw82H75EnJhz40P6VkM1/ytuNQHwRR85Kh8LRikNGiAfx91MT9tm7SsYLvyJ2iwZONPOr4dRwSxV2D2zlkUXA7kk8J5KpGhtLuLvmN285nrm3RPT/HrF8h5f0ln/2qgdzZpDMP8+Kcfv1ypUlnn1QUd3Ob3HaQgCRdl8HZMe6wfN2qo7hpAG6YrXEdtbqBtrUb+D/o45x+QPjutIk7gdyFAW6xjBhyX+l14Ors4wDcYgWvEkSSteYVer83o5Nk+641cIX0ybcu0ZZQAzcpOmlmipi50kpa9Iad72g5OkaB+2jw4CA400r3wr91h/xbF4WK4rKvuuG2lsC/dSS8sjRcCZuaz2Eu/LMQFVFdRhS3YUtOhslmqhh2Nsukj8yuItms3vd423XwfNAUweOyzkbu49bEfd+yOO7YICU5XeXFVp5iJrp1b7vX5/Cv/3/X4DaNjMDtf727eQNu0zyqnpb7ALmQDugqmkZha4fi9g6qFlwonuvSu7qgd3mB785+YcMa5E76sxjI1QtFigeHaLkg6cyzbXpnJ9it5u3YGLuffRQ3kyV38ABtyAd3WtcMzk7A9z8LmoLIFTD2j0BVka6De/qB/z97fxbkyrqm52HPnxPmqQagxrXW3qcPmzJb7GZLLdoa6GBIthlhi9Fy0DLDcpgM2yFZNClLlMMyqcGkZanlKWyHTYcdHqQr3VK80i3J4L1barJFdp9z9l5DzagqzMj590UmUBgyEwkUhlp749+xYwGZ/5RZqMKDD+/3ftIyEwExap1loripATdfRBwHSXAMevBwOzVyW4Drlg/wS1WQoLXu0Sd0/psG3GH5CC+TQ/gehdYdqpyHv7jrWxS9Ha0zeS1JJXo3pb99zpQxN1zgYfTvNvW3A6lwFepvTxWbygb1t11P8MkOwOhdxqdqzL+O00Rio9aKWi/qnOVLPk0kmx0YgsuCMuUZnQStc+su6JtGpmC6gSdu3wlew/W8ymXZmPGxngXVzUZx26bLzx4H2J5EEYL3tSwnpWhP3D3cLtGi4HbUvnbIFUIhf3hEsdFANwJNi+/7DB6b9O5v8WaqIL2M+3FAbprrXDnprHZAoXE2rnTm9Pv0b65wJ3xL3wLkbiaKK8gc18keBolAvmNjXn/BG/TXnmy2LpnC1HldRz+9RAkLKrj3N/i9ztsA3FwBUT8LDgwH8HCNkPHjNgG4EvAqh/jFCkjQn27RbGuqT9S8c2uuArhCMKjW8TUDxXMotO5QYvqPYTIWeuPXmbyWyRK9umtTXTHBLNW1i80WeIg6tqr+VsTcv6RI66Ov8Rjqb98rFpkxuE/MtYI8Yep4+O+to/DoKqgCfinrjb+Gj9v33MmEtRaNHZ2TUnIbJpsBZMJks+IOks3GLiRSct13uR14SAk5TfCTikHe2F2ymeMFpXtbZhB4O8jr/OQghz7jibuH2yVaEtyO2iqQC9sB3bSShVy1RrFxQibURUokw+dneve3OINB5Jg95E7uZwXIVRTyR3Xy9cb4D7b1/ET/9gbfnfhKNWHer0mqMHtIzeXJnV2ihh+s7Mcm1sMtSPkmZAqR84yOKQrayTlq6AbhPTXxnh7eBuBmc4j6OSgKmMOgmtnEn/J1A+78G1kIuLVj/HwJpER/vEVz7Kk+i+ZdtYqZr6gMqg2kqqLZJvluc+MOCp6i0i4d4wtBzhpQsrrRfSP2vSjKGtVnssBD2RlQ2WCBh23rb69khoFUyQqfdxvW335nqwx9QUGVfBtTnjdqbOw5Zl8b6eC4FyabueFv+UlOcJLdTLJZWplCx/b4RdvB8YPfg8uSTj2/W0/cm67Np7aFlJKMpvDTozzlidK9nf6Qiz/55/Zwm6algdtR+yFAbqZYotg4IVeujI+Z3Q69u9vY8r57yJ3czwrgqOkUTs7IHhwAIH2f4cM9g+Z9UGqVZMCFeMhNGvcmorhCIds4JVMLdJq+ZTK8+oxvmV+FTEE9rKMdBElUcQUf1gm4wZ6TADB8kMkiGhcB4Fom3F8h/O0DrnvQQOYK4PvojzdobrSWcv0WYTrDah0pFHSzR67f2hjgjg7ZWoZu4QAp0iWYLYpmxl3/6N++mqGdKSGAQ6tNjvkyxKvMG/V46/pbmcOVgqricrJB/a3tw89tDV9CXfc5yab7PYi77snrWHasJyWfh9AOL7eoCd4XBJlteOLO9B87kfiS7zoObSt4H6plVD5U9Cmf3iTAnT2/EPZTyBR6lsvvPQ6x3LB0byXDeSWLEGIPt8u0ZeB2sr1VyUJqh4VcjmL9hHztYPyicoYDune3QXnfqL3sITfcS/L5uNNaLkfx9AK9WASWLwLxNUkVZg9pxRK50wsUTQcpse5vly7fmwZyNwG4SqmC3gikANIycW4+Izw39fjo88nrpwJcIxMArqqCbcHdFWKiYuFWAFcI3IMTZDaH8Dy0xxu0SZeQDQKua2QZVo5gQxZh0QlmBQa5cmKCWdy+F4FoVES1ZRQZallU6XNsthh9m/2aeWcfj2F6i/rbvlS48rMAnKkWZWWyvHL475rswdqe4IutIgRcGj5lVaKoyXAeeTLi/CqeuE8OXFvgh8lm7/IKtYRks0VgnbTHtJ64d0OPq56LL8FQBd9WdMqZ7SebjR67vuQXT0Mew9K9lZzOLx3msCx7D7dp26pwO2rbiuZuSpcbVd7XtS1696HDwivL+75VyE2zr01BrlGuUjw9Q80EX9e7gwG9myvcwcSbc8K865QqJF1CGghcZn6hqmRPLzBKwbcGQfnez0gnuvDDqoAL65EpzBd8uERoGtJ1w0Sz4cLoT5KWdS2AqxuIk8sQcG24/4LwdgC4R2dII4PwXPSHa1Q5DytJ867HIqyJ4ViR/Rdd23IJZlVsI7e1BLNmthpIBnyHY6e7Nv3t5OPRv9vU3z74Os9SRw31t8YG9bdXtkLLC84faT51XaJp0YA7O+9sh6WiuDF/Y0xP8mkoGYbJZkcZwUVemf6btARYL+qbJtmsH3rimm/EEzeqdG8jL/iVf/5/tofbNG0Et/9U/QBNUVaG1a9dsiBUleLxyGEh0Lh4rkv/IXRY8F7nsLALyH3TzgpCkDuqh0UgQj1u65n+7fVUKeVVIDdpzFuI4uqVGrmTs6B8r+dh3l7jdlrBeikgd5uAO9VH09HP1ptothbA1XQ4CSutOQ7cfUFMRE83Cbijh1JRcI7OAth2HPTHa9SJd5dNAe6cRVjrHs13o+eJuLZF0dvROpPXse0EMzfU3/oISu6QqjeM7bvMvFHHJvW3WelxumH97WeZwZQqOeHxTn0pfx0FuGmjwrPHEAJfwp2r8OQG57OK5MLwyeurAW7cumnGjs75UnJrwkP45z6rwvu8QmGHyWaeL/nUc2kOg78fgSeuTkZLgNhNl+61PX7/MSjdO7Qs/rk/95f2cJumzcLtZNsm6L4ZyBUK+cNDio2TGYeFB3r3d692WFjmOtOA7tcOuULTKDROyR0cgZjQ4z7cjf1xVwHcpHFJ17EM5L4miqvoRmAZFiY4Ou0W5u3V2i3D1i5TUBS0xhlqMfjD6j094D013wbgNi4Q+usAN23kORJwVRXn6Bw0DWFb6I83qESvs3aLsMoxnpFF+G5oESaj5wkffy0JZqN/h6rBcyZ4zR1aHfLMA/wq80Y9dlC41Ypb0d86UvBJZvGk4FBxOFajJS3r0N8CdD3BtaPiyuBnfaL7HBqCiK6J80SeS1o/YWw3TDbzwt/085zgeMfJZo+mx8fu7j1xR489X/J9y0S6Nv/Iv/AX93CbpiXB7aj9GCEXIFerUaqfYIwcFqRk+PxE9+4Wd8Lbcmove8hdKelMy+YonF1gjPS4tk3/9garvTk97luI4maO6mTDwgmLLMNWBVxYHMVdOtHsqI5WCxPNum3c+5u1JpolAS7MAstoU1oQwdUNcF24+4xwtwy4mo5zHDg5KOYQ7ekWVUTDz1oBVwgG1Qa+pqO6FvnWw0QWfhzIrga4o0O2lqFTDJJE151gFnW+rRfo6zkUKTm2WhihB9xr5518PPq3L3SaWuDVvSn97WhMV6rc+BmEkJwrNsVN6G8nJnMkXNsKPT/oV1YlZ4aPsQ2ZQsxYx5d8Hkq6XvC8rAve5QXGNpLNYuaxPJ+ft1f3xE0E3Jl105bu7fSHXP7mn9/DbZqWBm5H7a1LFjbmsFAqUWqcki29vJjMTpvu3Q12rxc5Ji3kBn3T9XtLkJvm+laB3Fk9buCP+wV3OPFVZMKau5IqvAZw1VyO3Nm7wDJMSuzHB6yHe2B1y7BVABeW0+Eq5Sp6PSiqIIcDnNsvCN9LPT76fPy51IDbuEAYI8D9gnDdyDGz+1kX4Pp6Bvc4SMBTBj2M9uMMmC6edxXA9RWNQa2OVFR0a0Cu97RWB4XFFcweMfzJDxPLJ5gt0t8+ZirYqo7hu9Sdzlb8b1UpOduw/vbO12lLHU1I3ism+hjGJ+Z6rf725QBSwpMnuHNVpARdwLnhUTZmISv6WuZORpxfJdmsacONFWi7NSWQKVRm9rQMWCf1XcYT96YfvK7zmuDbqkFe341MYQ+3S7Rl4Hay/RijuXo+T6l+Qq5WG89v93t0724xJypwTe3jRw65q+px88d18vWT4A+6BPP5if7dNTIElVUAN2ncJqO4qeZWFLKNMzLVIBLmDQeY15/xbXvnMoVE0MvlMU6DhC7p2LjXn8G1U4+PPh9/Lh3gqiHgZnYHuJkc7uEpCFB7bfRuawLEouecnSvy6/TYvqGDgp5hWD0GBJlBm+ywG9l/GcBNilBOVjBTfY9qr4ka1Tdm39GRx/j77AmFh2wNXwiKrknNG8T2XWbeqGOB/raIo6hkpcupHCbqbxfJE+L3peBL+ORnsFEpCI+LNepvZ49PTjr04cpWsWTw/Ej3OckIEgKb03MtAbhpxw69QKYw2lM9IzhbItlsG56470o6x+vyxE0A3Nm+nf6Qd//cX9jDbZq2KtyO2o8RclUjQ6nRoHB4hAhB0zGH9O5vGTw9jbWiU/vYQ+7S8yuaTuH0jGwt9Mf1PAb3dwwfH16lx00as+sorlYqkz+9QKga0vewbq9x2q03B7iTfYRuoJ+9C6Klnodz+wU5HCS+KW6q2MO4m6IGEgUjA54Ht5+3Drheroh3UAdA7Txh9LtzfZLmXNlBIVvAKgW/M4GDQnIBhLg9LJVgVjrCUzUM16ayRIJZPJjFA6Gp6DxlA8eRA7tLQTqxfZeZN+qxg8KNVkQKQdW3ONig/taSgs8yiy8Fx4rDYYT+dpE8IWreyRYFVb4Mqpk9h24KuTDZLLfjZLNrEx7DH21OhQ8FhdyEdGJZsI5aZ/w8jSeuF3ri2oEby0FW5UNZR9uAJ24c4O7hdok2gtt/8jiA2xVZ9UcpWVA0jeJxg+LxMYoaiM09x6Z3f0e/+RBpI7aH3OUhV8sXKJ6eoxcC7bNnWfRurnAmim6sE3J3HcUVmkbu7B16IdAfL5tslnbdtepwVTUo2ZvLg5SBk0K3vXvAbVwgMiHg3n1BTDhxbAVwCxW8alDAQ3t+QDcHc32S5lwVcM1CBSdfBikptO/QvGQHhdcmmLmKRrt0hBSCvNmjaPej+ybsIc21j9/k9Tw9Pb8V/W1P6DxqeZBw4vfJi4m/6xHQ+hr9bVuq3IX620vFJr+C/jZpP7PnJifuhMlmXphsdqr7HOw42aztSD6bjPd0kVM4zIjU627EE3fg8aXvIiVk1KB0bzGz+dK9Qog93C7TZuF21FaFXHjb0dyNOCwoCoWjOsV6HU03APA9l97DPf37aBuxPeTGn487lakdUDw5Q9EDqza726F/fYVnT3h7xsy5K6nCa6K4xuExueMTEALftjGvP+MNB29XhysEWv0UtVwFVivZu37AVaBxuVbATbofUYDrlg/wS1WQoD/dok2+XjcEuBIYlo/wMjmE71Fo3UY6KCyK3gbH49eZvAZLz9It1AAo95/JevZc38l9vwZEJ/W3eqi/VRbM9QKS6aB28nFTydFXDdTQ/1Z7uYiYfa9uD3YrDbpSQxc+7xULbQX9bdTzNHDpyMATtx8mm1VUyem2ks1i9m/7kk8DST/0xK0Zgsu8mP6meYlrX9Q3TbJZL/TEtUJP3Iuizklh86V7O/0h7//b/8oebtO0OLidbKuC7luGXFgOdFMlnwlB/uCQUuMEPRNUn/F9n0EztBFztmMj9kOGXKEo5Osn5I/rQQcpGTzcM3y4G0fKk1b82qK4s8lmVvMeu3kfrJUCTNOsu24drnpwjHZ4DKzmpLAZwL1AZLI7AVwJeNVj/EIJpERv3qC5zlSf6LVfCbhisw4KURHKfrbMMFtAkTIo8CAnC2qsN8HMEwrNbBVPKBRck4MN6m99Av2tq6jkpMvJBvW3noRPfhYHhZLwOFugv42bd/bx7L6iziOCZLNHT3A/SjZT4EL3KK0p2WwZmcLovJSSewvu7OD3yVACmUJxh564ri/52HV4MoPXeCWj8G3ZQNfiP0S8NtlsD7dLtDRwO2qrQi6sBqxvEXIhHejmqjVKjWkbscHzI727W1zTjBzztUJumv0kXdsqUgU1k6Fwek6mHGjvlinl+9VFcRWF3MkZRiVMNhv0GV59Qrru2mQK6wZcpVxBrweOAf5wgHvzGSH91ONnz791wE2KxIwA1z08QWbz4HsYD9eoE7KlTQGur2gMDhpIoaBbfXK954WR09cmmHUKBzh6Bs1zqfYex+M2kWBmhfpbCdTsLsUN6m/t0P9WCkHNN6nxshaR+15df2uG+lspBQ3FpqbOv1ZEAiSuI4o79OGLrWLLQJpwpPk0dpxs1g89cZ3wt/4kJzjZoSeulJKm6fGpG5Tu1VXBt2WdSnYznrhd09rDbdq2DNyO2rYhd9Vxyw7ZBORG2YgN2890b29xJsrNTu3jBwq5r4nixs1vlMoUzy6mrcOuv0z5EC8LuUm7WAZyXxvFnT2kV6rkTs7DymYu5vUVbq+zVZnCck4KBYyzC1BUpG3hXH9GeE7q8bPn1w64a0gyWwpwxUSZXtdFb66/TG/UG/mUg0K/RdbsRc+x4LpSJ5gJhVbpCF9RydgmZbO90QSzrp6nq+dRkByZbTKhJjZNNHNZ/W1X6DyF+ttTv09ug/rbZ1/jQRooQvJOscgq0/PA+gB37nz42Jdw47yU7s2HyWbZHSabeVLyeQjt8Fe3qAk+FHbriTtwA5nC0A1kCqd5jfPS+kv3dgZDPvypf3UPt2naKnA72VYF3R8b5Or5AqXGCblqdTy/1e3QvbvB6nYjx+whN+XcYqaUrwTzqUn/7gYZVqlKWnEXUoVVo7iKbpA7f4eWCwzm7acm1v0tyHlP3DSAG3VsnYlmwsign10idAPpurg3n8E2U42NOr9WwF2TTViaBLPReKmoOMdnoOlrrWIWBYpB35GDQhGrVANk6KBgRfaPuq64+58EcY6q0ykeIQUUhx3yzjC674I9pAFRCTxlyliqge571J32xvS3kkB/O1ANNOlz5vc3qr+9lgZ9qZERPu9VeyJ6PjHXAkBMep4WLtue4CZMNlNFmGyWmX99x861BGymgWMpJU8OXFsBgGsC3hUUqjv0xPWk5HPX5WGqdK9BZo0yhT3cLtFGcPtPHNfQFXXxgJi2KuTC25UsbAJytWyWUuOEfO1w/OK1B326tzev9sr9sUPunHWY69G/u8Z8enwZFzPfpqUK643iCjL1BtnDwGbKM4eYV59Se+KuA3BhiSiupqGfvUPJZMH3cW6vkINe7Jv9ornXmmS2RcAdPZSqjlM/A0VFMQcYzw8zcJo858oOCsUaTq6IkD751h2a7831T3NNaRPMhkaefr6CkIQFHtz5vjF7XhZEPQQPuRr+mvS3SXvxgWu1hKco5KVDQ5qv0t/Gw7yCG+pvXRQqisup6kbOBcmQu0wUNw4ubR+uHJVBmNhV1SSnuj+jMZ0dGg+Fq0SSZ8+ZoSeuGXriHmcE5zv2xJ0t3ftNWae2ptK9ncGQD/+df20Pt2naJNxOuSUsCXaTbVXQfauQC8vdj1ReubpBsdGgcHj84qNnDund3TJ4fp1X7jYhd9NJZ6tIFfRCkeLZBVouB4A7GNC7/oI7DN7wkmZ8K1HcNPNqhRL5s0uEFnjimrfXuK/wxF0EuFHzpAZcRUE/uUApFAOrsIdb/E5rh4A74YO7oFTv/D7i9pQecCermKn9LnpnsprYxN7XCLgSGFbqeEYGxXMotO5RSLbQek2CmQR6+SqWkUPxfWq9Jmq43ub1tz2K0k6c6zWAa6FypxWRAg59k8oK+tt00WqFgVS4khmkFJwqNhV1Vrs+8XiJKO5ScBkuJCU0XcGDFySbGQpcGN5cYlfS7/UysJkGjn0puTGhuS5P3AV9Vynd28hrXJb1ZBlTCpnCHm6XaHFwO2pfC+SuOm7ZIeuG3MArt07xuD72ynVtOygI0Wwi5epeuT8WyI07lTs8pnByOv6jYT490b+9RnqrVzlbB+SuM4obeOJeohdKADitZ8zba5DznrirAC4sL1NIglStfoZaqQLgPT3gPTUToz3bA1wHbr8gvC0CbjaPe3ACAtTOM0a/M9cnac6VEsyEwqDWQKoamm2S7zY3mmDmI2gXD/E0fSsFHkb6W4HkeMP6244weNZyCAmnfo9s6LUbBWBR9ybNWqMxTV/jSRoIITkWLlXhRr+mR88TIrFJz9PC5SBMNnPCZLO65lPP7N4T94sJbkpP3EVwn9Q3beneLz2Xu0HwN6WgK/ykopN9RenePdwu0RbB7ajtAnLh7UZz1y1ZePHKbaCFPq6e67wUhJh40x2P+QFC7qJrWto6TNMonpyRPQiM9KXn0b+9wXxqvvSJme8tR3FnD2WO6mSPGiAEvmUyvPqEb1lbkymsahXmtVt4DzcrA25wPvpc+lK9l0F1NccJJApbBFyvUMarHgHbK/LgqTrDWh0pFIxhh9ygEz1HxDUtit6O1pi8hk0WeJg9v2397YOSZ6jq6NLnXPbHay0C3LjXTnS0OtDf3kiDngwCIAXhcaLY6CkBN+n6o56nkQh4YbJZO0w2K6hBsllmhzIFxw9kCm/JE7dleXzfcXF8iarAh7LB4Yoyhc5gyDf//F/cw22alhZuJ9vXEs39GiEXISgcHlFqnKAZgQOA73n0H+7pPdzhu6sXhHhLkLtoL+uGXC1foHR+MU7EcofDQKoQOlYkrbbtKG78+GTIVfMF8meXKLoBvo95d43Ten6TgKuUq+j10wDG+13c26tEL9xVATfYZxwMhg9UDU4uEboeAO7tZ4TvR47ZBOC+FHmQ6I+3aI491ydpzlUcFJxMDrMcQHWu+4hhD6PnGIFfLPQSfTyhwEOl/0wmosBDHJAvC6Lb1N96CK7VIr6iUPQd6kwkS0bue3X9rZRBBbMmBr4UaELSUGxKyuzvzcTjDSebSRkmm7kqfphsdm74VI10vydzJyPOr5JsNumJm1Hg/Y49cW1P8ou2TTeUKdTzKpdlAzVp3giZwh5ul2irwO2ofS2Qu8q4nUMukKsdUD45Rc8G2lHf9xk8PtC7iy4IsU7I/RqSzlbR42YPjiiens1IFa4Wuip8LVFcoaqBTKEY/OFz2s+YN+uTKbw20WwKcAsl9JNzUBSkOQyswqSXamzk3tYFuLYdaHB9GTkmLsEsab9JgCsBr1bHzxfB99Gb12ieN9Vn0ZyrOChYhQr2ghK9aa4nbYGHXraMOSrw0G2i4c/3jdlzWhAdPV6H/jZNBFkIgRnqbxFw7A8pMRGAiNz36vpbAEsKbn0Di+BvWFVxqStusv/shpPNrDDZbBhGTA80yVl29rUxOzQeCtcRxZ31xD3NCRo79sS96rvcDjykhHwoU8gtIVPoDs093KZtr4HbybYq6L51yIXNgm4ayM1WqpROTslMFoR4eqR3d4NrWXP995CbPK9QNQqnZ+RGUoU1uCqsA3LXKVOYKt2bIFNYBXBhfVFckc1hnL0DdTUv3LUCrqYHgKtpYFuBBlcuB7hp9zoPuAL36BSZya7kgfvaEr2K75J/vhsnfMUC1gLATYI4CbSLh7iageY51PovSXRfu/9tS2Roa1mElJz5fTIp9bdxr51FgOtLaEqdlgwkbBnhc6rYYy/cl7ETjzeVbBY+lhLuXYWmG/TNKJJLwye/w2QzT0o+DyRtL3he1gXv8rv1xG1bHr/oOLh+8HvzoaxzlNdj550E3O5gyDf/3X99D7dp2ghu//GjF7hdFThhdch9zbo/BMnCKgUhJJLh8zO9uxuc4XCu/x5yk+edkyoMBvSuP+OG9zJpK8tA7msBN26ORZCr5grkzwOZgvR9rNsrnJRuCmnWWxvgGgb62bvQC9fBvf4MjpVqbPS5+HFpAFecBrCNZcLd1asAd6kyvYqCc3QOerIH7rpL9ParDaSmozomhc5qCWZp9beeUGiXjvEVhZw1oGR1o/su2EMaEJXAY6aCrepb0d/eKQUsVcOQHmdysDb97ezjybF9qXDrG3goKEJyJBxqij8z59TQjSeb9TzBlaPgyqCaWUP3OTJ2l2w28sS9MoMPWJoCH/IK5R164jqe5Bcdh44dfOA6zqm8KxuoMa87CCB3D7dLtCi4HbU95Ea3XUOuUShQapySC7POAcx2i87tTWTVsx8a5C66nmUhd8pVQcLwqcng9gbpb16qELfVjckUWk+hm8Liog/bBNwpL1zPw7n5DNYw3djIc/HjFgKubiBOLgPANYdwf4WYeKd4DeAmwS2MPHADqYYy7GO0JmFz8vrWB7ieqjGsNcIEsy65QXvhfldJMBsdsrUM3cIBUkBp0CLnWvN9Y/a7LIh6QqGZreJtQX/rIrjVSnhCUPZtjpj4gBa572T9bdLjyfGuhLuw2ANAUXg0dpxs5kq4dhS6YbJZWZWcGT7GDpPNhqEnrhV64jaygrPcbmUKN32P64GLlJDTBD+pGuQTZAo9y97DbdqWBLej9hrIhdVBd5uQu8q4XUOunssFkFurjec2ux26tzfYvfmqZ28Nct9SFFfRNAqn5+MCEL7j0r+9wmo9h3uNb28xijvbZdJNIanoQ5o9bwxwFQX97BIlVwiKPdxdwaCXbmzkuYRrWAS4RiYAXEWBYR/ur2PHrBtwfSODexR64PbaGN1W5PzrANxxJMnIYVa2l2A2yBQZ5EoIKan2HtFDrfUm9LdmqL8FOLC7FKQz13fZqHDc44HQeNAC+VjdG1AUExryyH0vB7hRz0fJZi2p8Yg+TjY7UWyKO042e/IEd27giasLODe8uYhp3HXPnVxhD7PnfCm5GsJTKIsuhKV7MzuUKXRsj1+0HZxQpvC+rHMcI1PoDoZ8+9/7X+zhNk1LA7eT7TWg+0ON5m4ScmEx6GqZDKXGKfmDl6pnVr9H9/YGq9OeX38PubHz6sVSUAAimwXA6fXoXX/GC7XNcbN9DVFcNV+kcP4uKPrgeZg3X3C7nZVkChsDXCHQTs5Ri0Gik3t/g99tJ74BrgK4qWzCMllE4zKYpN+D5s3WANfLFfAOGgBorSb6sD/XJ2nOVRwUrHwZu1DZSoKZBDqFAxw9g+a5VHuP43Gb0N929Dw9PY8iJcdWC0Mka4vTRIXj1npSsnTVDIqUnPs99JebHrPvaDlg0u9cHHBZUnDjG9hhsllNcTnecbKZGXriWqEn7pHm08iI9Mlma9jD7PlnW3JlMS4n/C6vUMvsUKbgS37RfpEpHOVU3kfIFPZwu0RbFm5H7TWQC6uD7luGXFhuf+uGXNUwKNZPKB4dIULotAd9une3mGEEcnqve8iNnFcI8sd18vWT4A+/lAwe7hnc344rx60Dcl8bxV0FcIWmkT9/h5YvAmA/NrHub4na9rKAC8tBbhKkThZ7cJt3+K2n3QBuNo9onAcHeh14vNse4JaqeOUDkKA/3qxsEbYoehv03X6CmS8UWsUjfFUlYw8pm53EBLM00dM0+lvDd6k7ndTzrqK/vVUL2IpGVnqcysHLfV8AuDNdFv7ORc0xm2yWFT4nM8lmywBu1DVOtjQSAV/CraPwHMoU8krgiZvVo687ap1lYDMNHFuhJ+7I4WHXpXullNwMPK778TKF7mDIT/6Ff2MPt2naqnA72V4DunvIDfuvUbKgaFoAucfHKErwi+GYQ7q3NwyfnyL2+sOB3HVGcRXDoHh2QaYcfKXp2Ta9q884oeRjHYAbrJ0MpFN7WhFyp58KMvUG2cM6AN6gz/DqE9J1F8JpmrVeE8WdKvZwVEerBV+Ve09NvKeH3QBuvog4Djx56bTguTk1alOAG1iEHePnSytZhH0NCWaOqtMpHoX62zY515zrG7ffZUHUEwoP2Rq+EBTdITUvWXqRNioc9dgJ9be+EFR9iwMmrBuXBNyktaKej+bpSYU7mcGTAkVIjoVDdcfJZh1PcO2o44jpme5Ty8T/rUobiV1mD5Pn3mLp3q7t8/O2HSlT2MPtEm0Et/+Voxr6K6zAYDeQ+5p1v3bJwkLIVTWK9ZnSvpZJ9+6WwdPjOAr5stc95EadMsoVimcXqIYBgNV6pndzhXSTy/i+9SiuViqTP71EqCrSdRlefcIb9Heuw50C3Noh2lHw9bzXfsZ7uN0N4BZKAeACtJ4Q7afYMesF3FmLsCvUiV/bUfevsYLZ6NAgU2CQK8/pb6f6xuw3LYiOHk/qbw+tDnmSpRdposJx4/tCp6nlQcKJ3ycvJkqpR6w1eb0TXSLXStrH5DyuhFtpMAiTzUphspm2hWSzOLi0Q0/cwaiKWOiJqyZBdwpQjdrD3PmY/c+W7r3MKxy+QZnCwDT3cJu2TcLt6AX/GtCE10Hua9bfQ27MXKpK8eiYYv0EVQsh17bp3d3Qf2zOQW6w38XrrwNyX+ussGgP64JcoSjkG6fkj+og5sv4rgNw4/a7ScBVDIPc+Xu0bA6kxLq/xX5qvikd7lQ1s24b9+56N4BbqiAOA9Dm6QHRbUf2n99D9JqpAXfCIkyxTLTH23Flo6mf5RoAN7KCWaeJ4ZjRc4zGxUJv/Brj6wO6+Rq2kUX1PKq95hh0NqG/besF+npuK/rbppKjrxqoof5WE+OOkeNnr3mm68Lfuai5pITnMNlMSoEeJpsV1pRsthRchgtJCQ+uQtML9pcJZQqFHXri2r7k00Tp3gNDcFlQpqqILbNmUt9VZQoNw+dX/uxf2sNtmhYFt5Ntl6C77WjuDx5yFYXC0THFegNND6KQnmPTu7+j33xATpQcfdnv24DcXehxow5r2RzFi3fo+ZE3bp/u1Wc80wz3Gd3eWhR36qlQyJ2eY1RqALidNsObLyhEfOhZOO+GALdYDqqZCYHf7+HefmGyXO/WALdygAilEjRvEf1eZP91lekdHZKajnMcWoQNehjtx7VahEW9SZuFCk6+jJA++dYdmu/NzZHmWtLpb0Wov9XIOCblYXuj+ttmpoKj6mR8h2Onmzhv2qhw1DEfuFGLuIpKTrqcyGGk/jbp/kR0XQk2TSm49TPYKAghORAuR4o389qcWWdFmcLsNcTBZT/0xHXCZLOTN+CJexeW7gXIhjKF/A5lCpNuCqZl8qf+tb+yh9s0bRHcjtoectc/Zpkha7URE4LC4RGlxila+FW75zoB5D7c/2Ahd11RXJj1xn1dwllc321HcY3aIblGYEHlWxbDLx/x7cVVzbYFuCJfwDgN7Ln8YR/3+gsCf+G46HPR66UC3NoxolILftYPN4jhILL/2i3CMjncw1MQoHaeMPrduT5Jcy5bolcCw8oxnpFF8RwKrbuFRRBer789RApBcdgh7wzn+sbtd9lIqysUmqH+tuQMqfqb09/aKNxqJaSAA9+kykQFvmVAifjX0aLnk8lmD1KnPZFsdqrYZOJ5bOPJZm/RE7frBlFcN/yLcJFXOMqI2LGL1kzqu0zRBzybP/Yv/Vt7uE3T0sLtZPsaQXfVNd9aNHfdkJs/OKR0copuZADwPZfe/R29h3vkRPLKy5A95I77anqQcFatAptJOEsLuJAOchfNp+by5M/fBVXNPA/z+gtub94ubBHgRh2bgoIFe48F3GwO4/wdKCrSHOJcf0LIHQDuYQNRCmyzuLtCWGZk/7U7KBTKeNUgcqw93aFb5lyfuDlX0d/6QmFQayBVDc0ekO++lMxdBLhR0duoNSb3PjTy9PMVhJRU+o8Y/vr1t6N/h6rBc6aMINDf5jaov+0KnadQf1uXAwrSTQVZk9cd0zURLuOgqytV7qUxTjZrCIeK6s+MnVlng8lmUsJz6Inrh564F4ZHaYeeuI4v+TSU9MLSvTVDcJkX04n3S6yZ1DetTKE7MPnp/2CxLOF12VM/sHb4/gOZQjFVXxn+t2qTMlLmudG1R2suu64vJf6Sg5Yds8y+5MR/C/fhS3w/oZ+UDB6b3P293+Hp43c4lomiapRPzzn5Q/8wpdOzqbrWwRDJos+Eaa7Hlz6+nI8Qv5wP/o9dY8E9SFo/6RqSfnazh33XofPpO9rf/RzPtlENg8o3P6F0+R6hakiI3KHn+3gR0fGovlF7jbu/UfueHxs933hvwwG9736GO+gF1c0u32McN+ZeR7MrRc87/Xxyjtl7M7v3ubHhc2kOsb98BM9FZHPo5++Rijo1bnLs5Lzzc0avl+p19XiH7PeCN6H6GTL8BmT2OqfXj14vbo8yYqza76D02gC4tTpumCg6O3/Ua2Hq/svpn0XkvnwfRfrkOo+AxDXyWNli9BwLXntx93p271l7gGGbSCHo5mt4ET+KuP1GX8P8Hkf/5jybvDNEAs9GESfiz9Ey15h0vigd8p4NAu6VPE2RxZt+QSRcg48/8fdidpnZPSTtaTRPSXi8EyY54eGH3rjXnoY7db9m1pnaQ/I6yfufuwCEgANN8o3hkhESR8L3tsqtKYm7TXN/c165h9l5dUXwbV5wYgQfqJ5tyT/o+PQnXyhLrJnUV/oS6cdfi+/7CCHmoTym7SO3vERu//R//Z/B0HXsQZ/O/T29x8dx+dE07ccSzX1rkVxYbzQ3V6tROjnDyOYA8D2P/sM9vfs7/AlT95e9vj6Su2lnhW1EcVEUCpMJZ65H7+YKq/UU7i+6bSKKux6ZgiDbOCFzcAyA2+syvPqMQoRkZcG8r5EpxEZwjQz6+TuEpiNtK4jgzrw+00RHg3PRY+L8bIN+4c4b54hcHjwPbj8jXDdyzLotwtzDE2Q2j/Bc9Idr1Im3slH3dSaY2dkCVukAkOTbD+iuPdc3zbWk0t8iaJeO8Lakv33IVnEVjazncOS+Tn+btBcJtJQMHSULAnTpc+wPyIoZDEl6rW4g2exJajyNk80CmUI+Iei4DU/cG0ehFcoUCqrkXN+tJ27PDTxxRzKF87zgOBNfundTMoXuwOQP/Jm/vJclpGkjuP1v/vqvcdBojF+4vufRf3yk83CHPRgsmOWl/VggF5aH1q8Kcqs1SienGLkgccr3PfoPD/Tub/HdeIhI3N+GIXfbUoWow1ouR+niHVp435xel+7VZ3zbDvcY3XalxV00l16ukju9QCgKvh3qcK3t6nBjpQa6jnH+HqEbSMfGufqE8JypvhsHXKHAyQUikwXHgbvPCM+PHLNWwBVKkGCm6wjbJPN4P06wm5x7XQlmEjBLB7jZAsL3KLTuUMNvXhbJEyaPp9XfuqpOe0v6W0eoNHNVJIKyM6DizztDLILmNH1Hj02h8qDk8RUFJNRkoMOdenUl/P5sItlsKBVufQMnTDY7FC6HG0o2SysRaHuCmwlP3HPDp2pE/A4umOc1e5g854YyhW4oU6gagsucQE9ZuncdMoU93C7RRnD7Rw+qGLpG6fiY8nEdI8wGB7B6PToP9/SfHiOTjaLa1wi5q6771qK564TcbKVK6eSUTD6ol+77PoPmPd273UHuW9Pjzh0WgtzRMYXGGUIRSN9ncHfLsHkf7i+6vaUo7hQgZbLkL96jGhmkH+pwI8r27gRwNS0AXCODdB3cq08wEVWcHbtOwB13UVQ4fYfQdbAtuP2CmHhr2RjgqjpOfeSg0MVoT+phJ69rCTB7GRYBuIJBrY6vGaiuRaH9sEX97ROG7873jdnvspHWgZqhlSmF+ts2OZKdIdJEhZMeewgelRxDNUzski7H/vClVO/kjYiYZ/IeRHRdCTY9CffSoBt64uaFx4liY+zYE/eLo46riB1qktPs7Gtodmj8yVX2MHleSsmDDbdW8A1KRgncFGYtzKLgOGrNRfubdVNIC7dfveb2t37rt/iN3/gNSqUS9Xqd3/zN3+Qf/IN/sPJ8vufRvr3l8+/851z97t+j22wifZ9MscjxN9/y7lf/CIfv3qOHX1kntWW0oZHjV9TIvnbtH5IuN9U+FuhyzXaLh3/wX/Dw89/HGvRRFIVi/YSTX/nDVM4vUXR9Yo+L9bhBv+Rrect63Lj5pk5JyfDhnqff+13sbjewYDs9o/pLv4yWza1Nixu1jzR7XqQdnJ3Lt0z63/8Mp99FKCq5i/Q63KTni8Yn62XD566L/eUjvmUiNB3t/D3omdh1X6vB9aM0ib4Hd18CaYKRgfrptJ54TRrc2SY8B+3pDiT4+RJuvhQ5d9r5IFl/K5Dk2k2E9PG0DGa+Etl3M/rb6lr1t7Pnc55FzrVC/W0Jd4362yhNrIrk2B9w4A4QUmIKjSulSE+qkxPOaUEn26wON0mPmkYTqwo4ETYNxUIRkoFU+ehn6fpiYtzMOjN/r1bR/0b1HS1iKPCN4XGoBX0fXcHPBzB00mmQl7uHizW8QgjqGcFP8qAjsXz4va7PvenFjk1ac9H+5nS4KSHgq4/c/ok/8Sf403/6T/Mbv/EbuK7LX/7Lf5m/+3f/Lr/7u79LoVBINcdk5DbKLUHRNMrHdUrHdYxcdnzc7Hbo3N8zeH5KBTTwdUZz95Hc6ZYplSmfno2TD6X06TcfgkiuE/+VcOzeUmxtk5HcjUdxgUztgNLpBUKbtw1bJoob13ebMoVs/ZTMYajD7XYYXn+e88NNE2mOi6hFjU9VzUxV0c/eoWRz4Lk4V5/AsRaPi9jbyhFcI4M4CazK6HeheTd1LctEcFdyUJCgP92i2dZcn8k5l5EnTO1pVPXKyDKsBK+BXPcRw5630Upzr9+a/tZH0MxWA09az+bQ7a3N/3b28eRzB4UHNYejhFXEfJtDrOno24aiuHHz2GGSmUUA21XFpa64yRHTDcsUumHp3lEVsTPd52CHpXtdX/J5KOlsUabQHZj8gT/7b/74ZAkPDw/U63X+1t/6W/yxP/bHUo1ZBLeTLVepUK43KNZq4x+E5zj0Hpt07u9xJ2xpFrVdge6PWZe7dsg9OSVTDKJFAeQ26d7d7CE3Yj6haRTPLshWawB4lhXYhoVFAF4LudsEXL1SJX9yAYqCb5kMPn9EOvZaZQorAa6iBIAbJng515/ANhePi9rLqoCbzSMaQbEJOi14bk7AWHq4TdrfnDwB8KpH+IUy+D7GwxXqRHRofHsWwN78tUb1DV6PVqGCHVHgYZE8YfL4W/S/tRWNx2wVCVScPmXfmuu7CJqT+sSdk8CzkqWrBt867DLZbNIT91HqPIeeuJkw2Sy7Q09cR8KVrY6riC1dunepDwmL4VhKSdOGmy3JFHqm9eOE25/97Gf89Kc/5Xd+53f4lV/5lcg+lmVhWS+/sJ1Oh8vLy1RwO2qqblA+PqZUr6NnXr4CHHbadO7vGLRa6cPn+2juWsbsDnJLlE7OyE5C7mOT7u3bhNxN6HGXieIapTLF83eoRvCGYT426d9eI31/a1Hcdehw1WyO/MX7sR/u8OoTXr/3BgH3M0xEFmPHzR2P3/dCwC2UEMenwePnJqLTiuy/XsAVuEenyEwW4TjozWvUifMLr/e1BR6e7yIjsVHXEnefowBrdGhSf1vtPaJLb6pf0n7TRlpH//a0LB2jiEBybLbJiOTEudcC7uTzoVBphslmQgbJZpUNJZst/l0M5uqHyWYeCoqQHAuHquLPvGZn1tmwJ27TFTx4KlIGpXsvDZ/8Dt0U+q7k+6miD4KjDbgpdAcmv/w//JEVcfB9nz/5J/8krVaLv/N3/k5sv7/yV/4Kf/Wv/tW548vA7WTLV6uU6w0K1er4B+LZNt2HBzrNezzbTp5gom07Eey1675FyIXNgO5CyC2WKJ3OQO4bjuTuNIqrqBROz8gdBmb8vm3TXVD8YRvJZssCrtA08hfv0XIFkBLz7gbn+fFtAO7pJUq+AH4IuNaWAbdcRRzUg8cpy/S+GnAVNXBQ0DQUc4DxPJnw9TL3IsCNit7O9x0VeDhBqiq6NSDXSy7wkOY+v0RXp0FFAt18DdvIonoe1V5zHK1bBLiLQHT2/Eh3a2oZdOlRt9sLK7NFRYVn+yx6Pno8m2yWky5HO042cyXcSoNBmGxWEh4NxZ5ihiTAjbvWdPuPBtO+J/jiKLhSoIigdO9hQuneNJHYqPUXjR2dm3VT2ETRhx8l3P7L//K/zH/6n/6n/J2/83e4uLiI7RcXuf3HDiroMW+gaZqWyYTa3ONxSVekZNBq0Xm4Y9hup55rL1lYT/9dQK5RLFHeIuS+NanCMt64eqFI6eIdavjth/X8RO/mCul5X49MQQhyp+cYlQMAnOcnzNtr5v5OL7lGEiCnAlwhgghuvgC+H0gUtg24tSNE5SD4Fuv+CmFuvoqZrxu4x4EsQu22MHrtqfNJ861SwczVDIa1OiDI9p7JWP3Efb5KfysEreIxvqqSsU3K5uv0t0lRVh/BQ7aKp6jkXYtDL/m65veeHuSinkugKwxaag4pQJWSI39IQcx4zycA47qjuFLCs9R4nPLEdcgrM5r7ydfwFkr3XtkKPT/oW9EkZ7qPnrZ07xoge/J8lJvCN0WFvJYOcGfXnO3bG1o/Lrj983/+z/M3/sbf4G//7b/NN998s9TYkeb2HzuoTH8KWxUwhaBQq1GuN8hXXrJpXcui+3BP9+EBz3USJpiZbh/NfXX/PeS+HcidOzxT/MF3XHrXn7E77XBf823dUdx1yBSMgyNy9VMQAm/QZ/jl41RZ3Kj9bQVwTy9RCsW1Ae7cnhcB7tEpolgC3w+KPEy89tcBuLNwC+Dlinhh1Fh7uke3hnN9JudL9bX65DWP4TBMPsoVsYo1QFJo3aNNeA1H7fP1+tsjpIDSoE3ONef6xsF45F4SANdSNJ5C/W3N7lGUyYUrkuZe1DfunI1CU83jhFX4yr7NwY6TzUypcPOGPHGlhEdPcO8GMgVDgUvDm9O9xv1ezZ5cBbJnz83LFBSOMiJ27KI1R327A5M/+D/6t3/4cCul5C/8hb/AX//rf52/+Tf/Jj/96U+XniMObkftNXCpZ7OU63VKR8eoI8soKek/P9G5v8fsdlLPtYfc1/ffBeRGyxU2567wtUoVtHwhKP6QDRxJrNYzvesvO43iLgu4WrFE/uwdQlXxbZvh5+/x7eSCDz98wBUvVcxcNwBcz4vsvwzgJkVvAdzyAX6pClKiP1yjTVRvG/VZa4GH8iFuJo/iu4H+dlxQIu5+RkFvzDXP6G8HmQKDXHkr+tuulqNrFFCQHJstDJF8XVHPV43ijh7PJpsZ0uPYH5LZYbLZW/TEHfjwxVZxZCBNONF9jhJkCnNzvRKyZ8/NyhQODMFlQUFdcU2E+PHA7Z/7c3+O//g//o/5G3/jb/DLv/zL4+OVSoVcbrEXLSyG28m2MugpCoXaAeV6g1z5xYvRGQ7pPNzTaz7ge+lK/X5tCWjbgNxlx+wKcsunZ9PuCg+rF4P4miB3meIPhcYp+eMGCPBdl97V8lHcuC0mgWnSXhe/+U2MNzLkLz8EBR9WTDTbNuDOrbck4M6+XuYAV1Hg5BJhZMC2A8CdeOtZBLhp4HsWcCUTJXpdF/3harMJZkLQrzWQqo5mD8l3HxfKA9ICbpT+tlM4wNEzaJ5Lrf/EqDrbJvS3j5kKtqpj+C51pxN5XUlzT86fpm/c84HQeFLzeEIgJBxIk/KOk806UuVeGvhSoArJiWJT2qFMwZNw7Sh0wtK9ZVVyZvgYO5Qp3FtwGwb9syp8U1DIrShT6A5M/uD/+N/54cNt3Jvpf/gf/of82T/7Z1PNsQzcjtd9BWAa+TzleoPS0RGKGvy5lb5P7+mR7v091kTixSb3sW3IXXXNTUZzdwK5pRLl0/OxT67v+/Sb9/R2ALmbkCqsJYqby4clfIMPqFarFUZx3a1EcV+rwxWqGiSa5YsrJ5p9zYAbKU9QtaCKmabBcBBocBFz/ddeord+DpqOYg4xnu83mmDmqTqDWgOEINNvkTV7kX3H0LrgHseBmRDgC4VW8QhfVcnaQ8pmJ7pvwvpTe0mQJ3hC4SFbwxeCojuk5sW/bpKjnun7xp3zEDSVHGaYbJaXDke+iTb9g0lcZ9OeuDXF5XiHnrhSwrMnuJ2QKVwYHsUdyhR6ruRjKFNQBFzmFQ4zy9uF/Wjgdh1tFbidbKtHc1VKR4eUjxtkii8FJ+xBn879Pb3HR6T/tqO5e8hNWH/JYhC+79F/uKd3d4fvLQe5afa/CchNWncdUdx8/YRCPYCFdUZx0wBu1F6jx832eXmQOznHqAaJZvbTI9bd9aucFNYLuPMuChsHXCODOHkXTNDrwOMLbG4swUwzcOthglmvjdFtRc792gSzMehkC1ilA0CSbz2ge8k61dfpb43Q/3bz+ltT0XnKBjkkB3aXnGcn9p9sSR/UlgG70XMJdIRBeyLZ7NgfkBczZdWWArTl9jA7jy+hKXVaoSduNvTEzcQHKDcuUxiGMgU7lCk0NJ/jzO5kCo4fAO7Io/coI7jIK9N/uxasuYfbJdpr4XbUXgOYmUIx1OYejV/wvufRe2zSvb/DHg4XzLCefawKuauu+9YgF9LvaW2QW64EkJsPPuD4vkfv/o7e/R1yRqryWsj9GqUKWi5H6eL9RBR3c1rctQMuYBwck6ufgBC4vS7Dq08LK5qtCriz+40F3LGLghdUMpso9LBxwM0VEPXzYOOtR0T7ObL/OgB3dMjLFvAOG8D6E8xm33wlYJYOcLMFhO9ReL5F3aj+tsggV0JISa3XRAuTGF8rT4jq29YL9PUcAig6A0ruEDUlqC78JmKJsaPnVphs5ioqSKhIiwPsncoUelLhTmbwpEARkoZwqKgziaWTP9sfoUzh1oL78DNfLpQpZFPKFLoDk//Sv/hX9nCbpo3g9jdq5emyca9oqwKmoqqUjo4p1+sY+fz4uNnr0r2/p//0uJVSv3vI3T7kZisVyqfnGLng5+577gvk+rN/HL8uyE3ab7QEYP5AoX5Cvn7C2FHh6hN2mJAZNfuuZQqTT7VSOUg0UxR8c8jg80eEPxOdX2L+tQJuRCWzjQNuqYIIYZOHW8Tg9R64SdFbmEgw83305jXaxAfHUZ/1FXgQDGoNfE1Hs03y3WYkDK8CuMn6WyfU3zLfN2K/iwB39rwEWkaRoRYkfRq+S83ujpPMZsekef7aZDMfeFJy9NXAfjMjPY79Acb0BS/Yw3plCo4U3EqDoQxkChXFpfEGZAp3roovQVfgUvcoGruTKXQcyWczsDJTBbzPK1RTyBT2cLtEm4RbLeKX+jXtNYCZLZWDaO7h4fiH7Lsu3ebDUqV+95KF1/XfPuRWKZ+dY2SDSKXvuXRvb+k3778KyE1a8/VR3Dyly/djRwXz6Yn+zZfY6mbblikkAa6azZG//ICi6UjXYfD543xp3AX7Wjvgnr9DyYWAe/URnPlSq7NzzZ+LPr6UB+7dF8SE9/gygLtcgtkpMptDuA76w2oVzKKit/N9A/3tsFZHCoXMoE122E3c56v1t6VjfEUhZw0oWd3ovgnrT+1lgdxgqGZoG0V8IVCkpOL0KMpk55dVo7hpQa8fJpuN9nQoTUpMf4BcDtBmh6bf08gT90lqPIWeuEYoU8gl1CnYtEzB9OHzG5Ip2H5gFzYMZQr1rOA8F1/VDAKf2z3cpmxRcDvZdg26qq5TOj6mfNxAz06X+u3e39NvPW+l1O9rbsMPIZq7bcjN1WqUT87QQ8j1XIfu7Q395sPcz3uTkPvmpApixlHBtul++YQTJmKuE3LXAbiT8whNJ3/5AS2bQ/o+5tUn3F53GiYW7ikeDJYG3IlSvdJ1ca8+gjuvEZ2da/5c9PGFgHt8iiiUwPMCB4WJhMqNOCgoCs7xxUoVzFbR3zqZPGb5EJDk2w/oEfd20XWk1d/aWoZOMdB3l/vPZCe0vuvW3wK4QqFllLBHiV2eRcXuM/3tcvrflXXIFFwED2oeWwnsuYq+wxHmTj1xB2HpXncDpXtXiaB6Em4chfaOZQrjyLuU3JjQDD8bFTXBh4LAUJXIcd2hyR/6F//qHm7TtEVwO2q7hlyIKfXrhKV+H9KX+v2aorlfK+RCuutdBLn5g0NKp2foRvDBxnPsAHIfm1OQm+b1+ZYg97VRXL1QoHTxflzdbNh8oH97DVJuXaYQPSYGlBWF/Pk79GI5tZPCxgH3/D1KNod0HZyrjwh3vghB0lzBuej9JQKuEIFFWCYLTmgR5s9bhG2ugtkzRq8zdX52vlTAF7Wf8PU2LNZwc8Wt6G/72RLDbBFFSqrdJhrr199OPpZAT8/T0/NIQJMeNbtHlvhcgaVey0t+kBQikE60lQxtJQsCdOlz7A/I7tgT91Ya9Fcs3bvKmnF9EfMyhbfgpvBsS75YQWKepsCHvEJ5RjaBEHu4XaalhdvJtmvQ1QyD0nGdcr2+01K/24TcVdb7wUCuEOQPDimfnI1/3q5t0bm5Zvj0ONP1dZD7VUkVFIXi6Tm5wyMAPMui+/kj7nCQOtlsXYAbNS4+EizInp6RqR4CYD82se5vdgi4KvrFe5RMFumEgBtRZStpruBc9P4SAVdV4eQdQtfBHMDd9cYcFEaHxhXMJOhPt2j2pBwjea7V9Ld1fM1AdUwKnc3qb9vFQ1zNQHdtqoPnRP1t/IeAxYA7+dxWNJ6NEp6iIoCSM6Dsm6lfv0mv5WXHjp6bqDTVPJ6iICTUpEllh564UkJLajSnSvfa5HcoU5h1U1hU9CEJcGfPryJTML1ApmDJ4C/GaU7QyE7LFLqmtYfbtG0VuB21XUMuYn2lfveQu1r/bUNu4eiYUuMULax455hDujfXDFvPM12T11q0768qilssBVFcQw8+5N3fMXi4W3sUN2o7r9HhGofHQclewO20GV5/nru3s0umhYKlAVdV0c8/oGQySMfG+TKd9JYGIleWJ+gZxOklKAp02/D0sFbAnY3eAriVI/xiGXwf4+EKNdSzT867Pv2txrDW2Ir+1lNU2qVjfCHImz2Kdj+6b8L6cdeb1M9H0DaKDLXgm5SM71C1eztNNvMQPCo5hqF0Iiddjvwh+vQPa8Ee1itTmC3deyRcDtZUuneVCGqUm8K54aPvSKbgScmXIbTCPz0VXfAuL8bJ/t2hyR/6l/7Xe7hN014Dt5Nt16CrZ3MTpX6Drz+k7zN4fqZzf4fZ6y6Y4fV7gO2C7iprLQOubxVyhaJQOKpTPjlBUYOftT3o07m5xgp9YF/29eOAXKGqFM8uydZqALiDAd0vH/Es600Drl6ukD97B0LgDfoMPn9EYSZxMGFPawVcTcM4/4AwDKRlBRFc6SWPmTses89FgDtpEfb0gOi2I/uvL8FM4B6dIjNZhG2TebxFjCUDL/O+FnC3qb8dHbL0LN1CDSGhPHgiMxGFT6u/jbveqHOj55Ig2ayTKeITJHZVnR6FhGSzZQB32bGjPfWEzrOafzOeuLOle4th6d60MoXZedOsGdcXEcgUnkKZwqjow6XhUdDTg/1y9y8ZjqWUPDlwZQbfRmQU+FBQKOjKHm6XaeuC21HbNeQKRaFwcECl3iBbein1aw8GdB/u6T02t1Lq94cEucv03yrkqirF4walemNc7c7q9+hcX2HPfJh5a5C7CcAFyFSqlC7eIVQV6fv0b64xn5rhXuZbGsiN2tPsoVc5KeQLFC4+IFQV37IYfP4OMVvII2FP6wVcHePiA0LXkeYQ5+oTYgK2Nwq4pSriMJAL8HCNGA4i+68twUxVceoXoKgogy6Z9tP8nmLmW0V/axZrOFvS3/ZyZcxMAcX3qfWa47WW0d9GPU8TTZ1LNnMtal5/KrFrOShM3zfunB164jpKaM/l79YTV0poS5UmQelePSzdW1ixdG+aNePOjRYZhm4KTihTONV9DrchU4gZN3ADmYIT/uW4zCsYvsWv/E/+3T3cpmkjuP1Ha2U0IeZetK9p6wDddZT6LR8fIcJfat/z6D8+0nm4wx4MFszw+j1sE3JXWe8tSBZeC7mKqlFsnFCq1xEhhJqdNp2bK5yZn/FrIHdVPe6mo7hzoKnplC7fYZSCP352t0P3yyekG12+d1OAGzUuDnKVTIb85TeouhFahX0PE1rQRXtaJ+AKw8C4+ACqhj8c4F5/Gkc148bMH4/Z5yLAPawjQj9abj8jHCey/wv4Ra+TVn/rZ3K4h6cgQGs10Yf9ib4vc6dNMIsCxqDvjP+tY5JfoL9d5t5G6W9bxSM8TcdwLCrDVqL+Nm4Ps49nrzuurwS6ep7+ZLKZ1SUr4u0M1wHWSfP6wLOSpaeG0ok34IlrScGNn8EOZQqHwuVwxzKFK0ehG8oUqprkVN+dTMH1JZ+Gkq4XPM/6Fn/iL/57e7hN02bhdtTeGuTC6sCnqCrFwyPKjQaZieIQVq9H5/6O/vPTnIfquvcA2wXdHyXk6jrlk1MKh8fj19yw9Uzn5grXnPFU3RDkbiPhLG0UN3d4TOH0HKGE5Xu/BIUfVgXcqP1EbWXVKK7QNPKX3wRWYZ7H8MtHpDnz4SRhP2sF3EwW4/w9qCp+v4d783lpkFwZcBsXiFweXAduPiMm/ja91kFhNnoL4BUreJVDkDIo8OC6c33WlWA2pb/tt8mam9PfuopGu3SEFIKC2aVgD+b6LvN6WiWaaik6LaO4lWSztMA7EBqPG/LEXS4iHczjhzKFTihTKIQyBX2HMoVHT3AfyhQyiuTS8MlvQKaQJvorpeTOgjsbXMvkT/0b//4ebtO0OLidbG8NdF9XHKJEud6geHDwUurXdek2m3Qf7nDMzReH2EPugn6vhFzVMCifnpE/OEQgkEgGj490b67xnGm7uKTX46L9vkWpwuwhNZOl/O49Wlj5zXxs0ru5Sp1stm3ARVHIX3xALxRBSobXn3E77dReuGsF3GwuAFxFwe+2ce+utwO4igKn7xC6AeYQ7q5enWAWH5UMCzwcNJC5AsJ10R+uNlLgYRf6W1PP0StUERIq/UcM353vy3RbNZoaN9ZH0DKKmKNkM8+hZneZdJ5aDgrT94075yJoqnmssSeuzRFWak/cTcgUOqg8yECmoAnJ6Y5lCoNQpuBKgSLgTPc5yMT/7UsDqlHrz42NGddxJJZl8o/9K3u4TdXSwO2ovTXIhdUhU9E0ysd1Ssd1jFx2fHybxSHeMuTCcuD6FiFXy2Ypn52Tr9QAkNKn//BA9+4G343OhF9lv6tA7rqkCksVfqgHJV89y6L76Xtcc/g2dbhCkDu7xChXATBvr+e8cLcGuPkCxijhrf2M37yNXXetgKvpiLMArF/joJBafysUnPo5aPraCzxEvakPSwe42cLa9bdR8oRevopl5FB9j2qvOQb3OHnC7DqLnqdNNhuEyWYyTDar2V3yMxHTVcF6mf1O7mnWE7fuD8is6ImbBLizz+PmCWQKBjYqb0Gm4Eq4shV6ftD3QJOcZWdfezP7SQGqC9efGTs61x2a/OH/6V6WkKotA7eT7a2B7quKQ1SqlBszxSHsieIQzuaLQ7xl0P3aIdfIFyifX5AtBgmGvu/Ru7ujd387JUd5DeR+DVHcWcuw/u0Nw+Z9uI/pti6ZwmsSzbKNMzIHgYev3bzHerjbCeAqxRL6yUUAuE9N/OeH+HVWBNx1Oyikge5ZwJ0q8NB5xui/rsDD5J2ZfVOf0t/aQ/Ldx43pb30E7dIRnqqRcUzKw3ak/nZ2z3F7iXueLtlM5TlTwgkjpgXXpOYNYu/Voj2sxRNXqDwoefzQE/dAmpTX5Im73IeESZmCTkcGCXlvQabw4Co0vSDCnAtlCtktyxSEEHu4XaatCrej9tYgF1aHTM0wKNcblI6PZ4pDPNO5v2c4YzO17vVhD7mJ/V4JuZlSmcrZOUa+AIDnunRvr+dK+n6tkJvWMqx08Y5MpQqA3e3S/fIxdbLZtgF30gvXeX7CvL3aDeCWq+iNMwDc5h1yyllgMUiurL8t1xAHx8Hr8/4KMSGb2kSCmZcv4dWOgwIPjzdozqRkYME1Lq2/1RnUGiAEmX6LrNmL2Ff6exsHLUKAq+q0i4dIISgO2+TsYSQMz+55dt7Z58vA5uixBDp6gb4elBbXfY+a3SUj4j9obyqKO3rsIWgqOcyRw4N0OPJNtOkf4II9pIO9xdcSzNOWb0um0PMEV46KK0EVcG74VI3ZeePXSAu4c+cnHneHJr/65/eyhFTttXA72d4a6L6uOMQB5Xp9pjiESef+nm7zYepr7U3sYQ+5Cf1eCbm5ao3y2Tl6JpCjrFrtbN2Qu80obvbgkOLZBUJR1pJstghwo/aV/Kb7clyvHpA/CSKKUcUe1gG4SXsbnVNrh2hHgbTDvb1CTkU2Nwi4hyeIUhk8L3BQcN25/mst8FA9xi+UEJ4X6G/l5vxv7WwBq3QASAqte7SIynCLriGt/nZoFOjnywgpKQ47ZJzh1HxJkLtcBDJdX1PRaWdKeEJBIKnYfYrSTr3uKmCd9FwCHWHQVnNIAZr0OfaH5LbgiRs3z1uTKTgy0OEO/eD5se5zkom3C4ubJ+pcmvX3cLtEWyfcjtpbg1xYHTLjikP0nx7p3N9j9XsLZnjd+rA90N0k5C7Tf1uQmz88onx6hqYHUXpnOKB9fbVUIYh1Ay6sB3LTRHFnk82GzQf6t9eRyWa71uFqpTKF8/cgBF6/x+DLRxRmojgx86wVcI8aaLXAWcC5+QxT1lmbAlwBJxeIbA5sOwBcKef6ri3BTAjcozOkkUGxTIynu43pbyVglg5xs3kUz6XQuhv/XOP2+Br9bTdfxTaCiGnGMSkO22MN7uyYyX1HXtOC126aaKqHoJUpYanB36CcZ1O1e0w4T20ErJPOWag8qDk8RYWwdG/1K5YprLJmZN/wsZRw6yo8uUHfYljVLLMFu7Cuae3hNm0bwe0/Ui2iCrHQy3PZ9tZA9zXFIYoHh5QbDbLF4vi4PejTub+j9/i4cTuxbUHuKmttIpq7DcgVQqFQr1NuvFQ7s3pd2ldfcAbR4LLsXt90FFcICidn5I/rALjDId1P3+PZ6SqbRfVZFMVdFXAniz14wwGDT98nVjPbFOBqjTPUchV8H+fqE9jDxP7zx2P2mAS4qgqn7xGaBoMePNxuNsFM1YMEM0VB7bYweu3IedeivxWCfu0EqWpo1oB87+lV+ts4WBkB7jBTYJgtBxW7fI/ioE3Gn64itmqy2TLR1NFzCfS1LF2jiARU6VOzu+TwYseuA6yT5vWBRyXHYATd0uXYH74ZmYIeyhTyO5QptD3BtaPiS9AFXBgeJSM92JP4uolevzs0+dW/8Ft7uE3TZuF21H7okAurQ2amUAi0uUdHL3ZinkevGSSgOcPhghletz6sdj/3kJsAuapK+eSU4vFLIYhh65nO9Rdc66WYwNcIuWlkCkapTOnyPYqmIT2f3vVnrNbzmwNcJZujePkNQtPwLZPBp+8Q/gwExMyzTsDVzy5RCiXwPJwv30OEndXsXKsC7vi0kUWcXgYHWo+I9nPktbw2wWx0yMsW8A4DGYb+eItmT/4eLLi+ZfW3Wqi/RZDtPZOx5j9YLrqGRfKEyX27qk43X8VTNYSEnNWjYPenXwdrkikEcy0GK0eoPGfKuKEnbtEZUNmhJ+4uS/fGzTNb9OFIuBwkyBSSADftmlHnRotYoV2YFVY1a2g+xwkyhSTAnT0fFUXew+0SLQ5uJ9sPHXRfUxyidHxMud7AyOXGx81uJywOkc5ObA+5bwdyVT30yD0MPXKlpP/4QPfmem32YXG/T7uO4iqaTunde4zQVcJ8fqJ3/QV8fy0yhbUBrpGh8O4bFN3At20Gn36RWK73tYA7N0YIEAL9/D1KLo90bJwvHxF+9OtjrQ4KhTLi+CR4fL+4RG/cG2tq/W3lEL9YAd/HeLhCDb+dmnrdLADc6Wub389Yf5srYhVrgKTwfIcW3s+4n99rAVci6OfKmJlAlqO7DqVhC036keNm9z+7RtJeg7kW9/WBjlFkoAX5ABnfoWr3MCbsuZb7mj1937hzNgoPah43lClUpUVtB6V7J2UKd9KgGxZ9KIYyBW1HMgVfwrWj0A6rmlU0ydmaqprNrt8zrT3cpm1p4HayrRN03xrkwuqgmStXKNfrFA8OxhfmORN2YvZm7cRWvfy3pMt9S5CrZbNUzi7Iha4Cq9iHrQK4wbmY+bYUxc3XTyg0gpKsnmnS+fQ9nmVGrr4oirspwBW6QeHdN6hGBuk4DD59NxU9nd3LRgBXVTEuPiCMDNIyA8Al+rWxzFfpCxPMDo4R5Vpiid61Fng4OkNmsgjbIvP4IodYBLir6G+H5SO8TA7Fcyg830XfnwXXkAZwJ/dv6Vn6uUpohRUkm2Xd6df7tpPNhmqGtlEcVxGrOj0K0okdu47IcdK8PvCk5OiHMoVsKFPQp2/Egj2sT6YgZSBTaDKSKfihTGF23onHG7YLe/YEtxuuatYdmvzav/If7OE2TVsWbkdtH82NbqpuUK7XKdfrX5Wd2KajuV8r5BrFEpXzCzIj+zDHebEPm9rLeiF3XQlnaQF3drxeKFK6/IBq6Ehf0r/+gvn8uBbAjdprEuTGAq6mBYCbySFdNwBcx5rum3LOZQF3fFzXMS5CmcSgj3v9aSmYfHWJXseBm08rJZil199qOPWLQH/ba2N0W5HzrkN/6wuFQa2BVDV0q0++9xzZd9E1LAu4nlDo5as4elhFzA6TzSavb+ueuAoto4Qd2nMVXJOqN5iqIrbuyPGi5z2h86TmkEK8CZmCGcoUnFCmcCwcaoo/M+/E4w3LFAY+fLFVnLCq2bnuU1uxqlnU+nu4XaKtCreTbR/NjVycQrVGudGYshNzTJPuQ3o7sT3krm/9Rde2jH2YYw7pXF9htlsT+0ief52Qu40orlA1ypfvMcI/otbzE92UMoWobbwmihsLuKpK/vIbtFwe6XkMPn8H1nQJ7U0DrshkMS4+QFim17u/Tuw/fzxmf0mAq6hhiV4dBn14uEmdYJZmT2MQDQ/52TzuYSCH0J7u0Cfu8ajPa+UJQV8FV88wrB4Dglz3ESMiYe8193W0zmQTYpRsVmSYLY2TzUqD1lTJ3tmxSYA7d80rwKYEunqevp5H8npP3HXIFJxQpuCEMoWKtDhYk0xhuWsJ5vFCmUIvlCmUFJeGcHYmU3AlfLEV+mFVs0PN5zQrZl6PM/uJo/GZc92hxa//q//bPdymaeuA21HbR3Oj267txFa99E1KFr5KyBWCwtEx5ZMzVG01Z4VVADc4FzPfBqK4s4dyxw2KJ6cgRKJMYds63PFDRaFw+Q1avoD0PYafPyLNwfS42DnWBLiTZXoTqpitFXCNDOI0WHMbCWZu+QC/VN2K/tbKl7ELFYT0ybfu0MKkwbifXVTUODg+v8bLnqIhy1F1eltKNksLm5ai85wp4W/AE3eZ/U5C95OSpacGke6s9Dj2BzuVKbSkRhMdKQWG8DlTbLJTlmoza2xYpnDvKjRDu7CCKrlYg13YHm6XaOuE28m2j+ZGjFEUioeHlOszdmL90E7sKZ2d2FuP5i67Rlp4fSuQK1SVUv2EUqPByFlh8PxI5/pqSlu9bsjdFOAGcydDrl4oULr8JpQp+PSuVndT2AjgCoX85Xv0Qgnp+ww/f791wFXKFfTGOQDu/Q1y6uv79QLu+PQWE8zm9bd3iLEnLYlzraS/rRzjGVlU16bQvo/suyzgRp6PgCw/TDazxslmNqVBG43Vks0WA9pioNymJ27aefqhTGGkDT72hxTEtHsJCfOuW6YwlAo3voGLgiIkDeFQUWfsAifX2LBMoRPahXlrsgvbw+0SbQS3v14toK058gr7aG5cyxQKlBsnlA4PX+zEXJdus0n34Q7HNBfM8Lr195Ab9nmts8LZGfmDkbOCT+/+ju7dLdJ7+QO/CuS+xSiuUDXK795jlII/qubTI73rL2O952TbDeAK8hfv0Ytl8H0GXz4iJ4oszO5jE4CrHhyjHR6vtcjD4gSzOiL03eXm06srmMXdFyFAqipO/TLU33Ywus9T55PmWlp/qygMaidIRcUYdskN2jH7Wnxfg3PRa43Wm2yj05aepZ+vjuGtOGyTda3YsYtf56vB5uh54Imbo2sUkARVxGp2l+wWPHHjzk3JFICKv1uZgivhVhoMQplCVXGpK26yLGCDVc1m7cJOdJ8jYzW7sN7Q4tf/tf/dHm7TtEm4nYzcviY6GNd+yNHcle3ENI3S0chOLDs+Puy06d7f039+Shj9+vW3AbnLrvO1Qa6ey1M5vyAbQp/nunRvrug/NsdWcF9zFHe226Sbgjsc0vn4Hb5jz628K8DNnb/DKFVASoZfPuIPpmU/aQB3DjRi9hUFVlNFHr58P5XktgzgLorehpcbtJPLiQpmnxg5R60zwWx0yM/kcY+2pL81sgwrxwDkOk0Mx5zrOw+x6QA3ar3pc8G/nqLSzVdxtdApwB5SMrvjqHXk2Oll1g6btqLxbJTwQk/ckjOgvANP3NHjtyhTeJQaz6FMIRvKFIypKPfMGpuQKYSPZ+3CqprkdAW7sD3cLtHi4HbU3jrkwg8HdHOVCpV6g0KtNr4o17aDBLT7ezzXWTDDdiF3lfV+yJCbLVeonF+gZwPPY8cc0rn6gjnhkLFLyI2bf5Uorl4sUX73ISz64NH9/BG721m7DnclwEWQO7/EKFcDwL36hN/vxu5hE4Crn79DyReRroPz+fulPHBfXcGs34XmS8nct6S/XSRPmO4bZsQXKjj5MkL6FJ5vUaU/Pz4BcOevkdhzk+tOXs9cspnnUhq2MGYKiGwz2cxH0DaKDLUQKD2Hqt1FV6LHLXq+jmSzSZnCa90UEmFvwX5G8/Slwq3M4EmBGlY1K+6oqpmU8OQJ7kK7sGxoF5ZLaxcmxB5ul2mL4HayvXXQ/aFArmYYQQW04+MpO7H+0xOdhzvMbjd5gleuv8qlvwXITdt3o5ArBIXDY8qnL0lnZrdD+8tnXDO6TGva/S0rVdi0TEHRdcrvvkEvBDZpg7tbBve3kauuM4qbDnAhd3aJUamtDXBn95wIuIqCfvEBJZMNPXC/n4r0LYqWrgS4mSziJKxg9vSA6LYj+25Gf7tZ/9tBtY6vZ1Adi0LnIbJv0nVE9V0t2cygm6/iqypCSvJmj7wz2FmymST0xM0UkYiwdG+PHG7s2HVEjpPOzboprLPow3L3L5jHkYIbaWBKFSEkB8LlKKGqGbAWmUKcvKDvwRdHxZUCVcCF4VMx4v/+Tc7TG1r8+l/83+/hNk1bBm4n27pB961Gc9cBubDa/RJCUDg4oFw/IVcujY87wyGd+zu6zSZyJnKwrrWD9VcY8yOD3MSks8YppXpQzlciGTSbdG6uUlU6S9rbrqO4U0+FoHh6Tu4o+OrY7nbofv4I3vzr8ocGuAvL9Go6xqhUcL+Ld/slvm/k8Zi9EQWJ4YNSFXFYD+Qwd18QE6Wj16+/3aL/raIyODhBCoXMoE1m0IkE76jnq8oURmvPXpMvBL1cFdsIZGSGY1EcttF2KFMISveWcBUNARSdIRV/+IZkCssVfdhEVbMHqdOWoWew8DjdYVUzRwY63KEfaG+PNZ9GirK9e7hdoq0Kt6P21qO58LZAd9X7ZeTzlOsNysdHiFC473sevccm3fs77OFwwQx7yH3N2qtCrmoYVM4vyVdrQPAz697e0Hu426oed9NR3Ey1RuniHUJR8Gyb7sfvcM3h3Ko/ZMCNhMNsDuP8PSgKXusJ//Eusf/88fm9LdTfHp0iiiVw3SDBLJQMbER/O+F/qz/eodnr19+OI3CZPGb5EJDkOo/o9jABvuMBN/p8wrkYT1zLyNHPVZBCoPg+pWGbjGfHjl38Wn8dbEqg/cZK966z6EMS4C7az2iejlS5l/FVzZIAd9EaywKulHDrKjyFdmGl0C4sSYfbN+093KZtr4XbybaP5i45zwr3S1FVikdHVOoNjHx+fNzsdujc39F/fh5D07rXhs2D7g8Vco1CkcrF5bjSmWtbtL98Tl0EIu7UpqK4qwCums1Ref8NaiaD9CW9q0+RdmHbAtzJsbsEXKVYQj+9BMB9uEV2oqturS3BTIigwIORAXMId1cb1t8e4pcqof72C6q/Hnuw6b6h/rZYw8kFNorGsEum31rq9bDuZDNX0ejlq7haEBHMWX2KVm9nMgWAoWrQNkpjh4ea3SW/Y5nCvZrHDWUKNWlSxdm4TCEOcC0puJ6oalYXDtUVq5otvneLZQrPblC2109Rtrc3tPhH/vX/wx5u07R1wu2o7aO5S86x4v3KlspUGg2KBwfjC/Icm+79A52HezzHXjDD24XcZddYZ/LZJiE3f3BI+ewcTQ+01FavS/vLJ5zhYj1u0r52GcWdeiNQVUqX78mUg6p8w+YD/ZurjQLubP9UgLsGF4VlAFetHaIdNQKLsOvPYKa3CFtJf6vpiLMgYkz7CdF6iuy7Hv2twD0+QxoZFMvEeHpJZosC3Nj7GQG4s5AjAatYxckFMi3Ftcl1H8dFHiLnSgDc+esl9txoDy/ngn8l0M+WMbPBB1fNcygNWuhy8564cX1dofCcKeMoge6/6A6peruTKfjAk5KjP/LoDWUK2vSGYudZt0xhtqpZRXFpbMEuLA5wh6Fd2Lhsr+FTi9Dh7uF2ibYJuJ1s+2jukvOscL9U3aBcr1Ou16cT0J6f6dzfYXY7G1kX9pC7CuQKRaHUOKHUOCFOj/u1R3HzjVMKjeDraqfXo/Ppe/Dmy00vA7nrBtzB54/I4QvgpgWOVQF3bBHmeYFFmBtd8CMSApcA3PHpfBFRPwsexxR42Ij+ttvC6LUj512H/hbANbKYpQOkooKUZPstDKufGt42kWxmaxl6+Sq+oiCkpDjskHWn7bm2LVPo6AX6euDeYvguNbu7EZlCmnkkgUzhWc0jReDRW/eHZDcgU0gTUZUSnqXG44Rd2Klik0kpU1ju3i1ftvdY9zmZ0eH2zT3cpm4juP0jlTyqEGuDtNm2j+YuOccq90sICrUalcYJuYkX/igBrffYxI9I9FnL2ix//37skKsaBpWzC/K1AwB8z6Vzc02/+fAqPe62oriLANcoVyhffkCogQ638/E7vFfqcNcCuOfvApuwiEIPGwVcIQKLsFwB6diBRZicL/ax1gSz2jGiUpsr8LAJ/a2XLeAdNkCC/nSLZk/6+y64P0v63wL4QsEsH+AZAbxp9pBs9wk1wpUi7vm6ZQq+UOjmqzh6kEiVsU2KwzbqJOBvOYprqgatCZlC1e5RwInsu641k87ZoUzBU1SEhANpUk6QKaT9cLHsfkbzDEK7MDe0CztRbEobsAtLW7b3zlV4nNDhnhs+RqjD7Q0t/tH/+R5uU7VZuJ1sP1bQfUuQC6vdLz2XoxLaiSnqdAJa5/5u6mvwda4LP17IXVmPWyxSPb/ECPW4jjmk/eUz1kTEfVmpwi6juJNP1UyWyodvQx2uT/fLJ+x2a8eAK8hdhIUefJ/BTKnejQKuqgYOCrqBP+zjXX+K7xt5fH5f6Qs8WHDzhZEl2Ub0t5Uj/GIZ4XnoD1eocv3625drDWQKTq6IVawGd8L3yHUf0d1pSdY2ZArB+ZEnboFhthx44voepUELw3djxya95hbuP6VMoWWUsNVAG/wWZApNJc8w3E/BdziSw2kGWQoU011H3DyzdmGHwuUwwS5s02V722HZXl+CocA7wyOvK3u4XaYlwe2o/VghF94W6K5kJ6aolI6OKDcaZCYT0DphAlprcwloq1zyrpPPdgm5+cMjKmcXY3/cYfuZ9pfPeLYdrhs/7zogd1OAK1SV8rsP47K9g/s7Bnc3a9XhLg24QpA/f49eKiN9j8Gn72Cy0lbiuqsB7vgreSODcfkNKApe+xm/eRs99wLAjYrezu1JAKoW6G9VFbptxNNDZN+16G+FCPxvjQyKNcR4ul+b/nb2eDAm1FCqOmb5ED9M7DKGHbKDTvqf4wIgWiWK66h66ImrISTkze5OPHFHjyXQ1fP09OB94C3IFDrCoKXmQIAufer+gMzEfpIAN9jD62UKcXZhReFxsia7sFUA1/Th04wOV/fsPdymbWngdrL9WEH3a4dc2F0C2h5yY9aI0uOqKuWTM4rH9eANQPp0727p3d4iIyozpdnPtqK4i2QKhZMz8vUGAHanTefzx7FN1ahtA3DHD4Ugf/kBvVBCeh6Dj7+YLpWbYq6VHRTyRfSzoOCCe3+L7KZ3UFhJf5vNIxoXwSabt4h+b67v2vS3mh7ob4VA7Txj9DtT5+Oua3Iv89c23aLgRCLCZLPATUF1bbIzyWYLv3JPBOD4PUzuIzgX/Osj6OUr2KF0wnAsSsP2lHTixy5TMFF5UPNjrfKRNCnNuDuQMM+67cLaUuUhtAszwrK92R3Zhc3qcPPekP/Wv/l/3MNtmrYs3I7ajxVy4esH3eQEtNtUFdDeomThhwS5WjZL9eId2TDa6do2navPDFvREJRmP28hipupHlC+fBdA3XBI5+MvkM70G+t2AVeh8O4btHwB6boB4E4meqWYaz0OCp9gUhqxAChXAtzqIaJ6GISobj8hwvu+Ef1tvoRXOw70t4/XaBM/400AbjAu/IrZyGGVD5BCQUifTL+FYQ1if5Zz6y8E4MV7eDkf44k7aJHxndixi1/zSZC2uO8mZQrLRH9Hjz0ED0oeSw2+tSr7NodYsTrc2XnWrcM1peAmtAtThKQhHCqqPzPPxOMt6XBty+K//7/a+9ymaqvC7WT7sYLu1w65CEGhdkCl0ZhKQLMHg3ECmpyJrK1r7U1C7jLzvxXIjZMqZCtVqheXaEaQoBKU8v2Ea5rhmvFzRp16C4Cr5QtUPnyLomn4jkvn03e4g/7caupSb/ZJay8AXEWh8P5btGwe6Tj0P/4cMeHssEnAfXFQcLE/f4/wnLn+a00wa5wjcgWwbbj9jJDr0d/ORW8Br1bHzxcRnot+f4U6u5eYuRb6uSacG3/FrKiYpQO8sIqYbg3I9p5Rdphs5ioa3XwVT9MREnJWj4I9/brftkzhrbkptJQMHTUsQiE96v5gZ1XNPAk30mAQ2oXVFJe64s6A88waG5QptD2BZZn88b/0f9rDbZq2DrgdtR8r5MLXD7pGLk+5EVEBrfkQJKCZ5oIZ9pCbdr1lIVcIhdLJhHWYlPTu7+jeXo8/fLzFKG4S4Cq6TuXDt2i5PEhJ98vyBR/WCbhCVSm8/xY1k8O3bQYff46Y/Do7xVwrOyhcfEDJ5pCWifPl+3HC1yKgDI7P7ytRf6uocPYeoWnQ68DjiyZ2E/pb5/gCdB1lOMBoPSTqb+fWSIoGMt2iYEECdq6EXawAAsV3yXae0L3tJ5uNTkmgn6tgZgLdq+7alAatnZbunZUpvKbowzqqmg2ExqOaxxebrWq2+N4FdmGPUuNJBt9w5sOyvfqOdLg90+KP/ht7uE3V1gm3k+3HCrpfO+Qqqkrp6Jhyo4GRy42PDzttOnd3DCa+Fl/nuqtc7iYkC9uC3NWswzJULy7JVapAoJduf1m/VGGTgDs1TlEoX74nE17P4O6Wwf3t7gBX0yi8/wmqkcG3TPrf/wKFlzfVjQGupgUOCpqO3+vg3V3F9408HrGnJMDN5BAnl8EGm3eIiWpt69bf+rqBe3wOQqC1H9EnCmeMuiYC5BqiuJ5mMCwfIFUdkGQGHTLD7s5kCgCWnqWfrwZA6fsUh22yOyzd6wqFZ6OEE8oUSs6Qir87mYKD4EEt4KSsapb2vi9/HcE8XalyNy7bKzlTLHI70OHu4XaJtim4HbUfK+TC1w+6uXKFSqNBoVYbX4xrWXTu7+g2H8YFB9a97rKX+2OD3Gy5QuXyHfpYqtCm/fkzrpUsVXgt4EbtNw3gBvPFj5tMNLNaz3S/fBp/XT5qWwNc3aD4/lsU3cAbDhh8/A5l8mvaFHOt5KCQzWFcfAAh8B7v8VuP0XNHzhGzpyT9beUAUTsKnFJuNqy/LZTxqsFa+sM1mudOnZ+da3a+2X0tE8UdJ5sJgVms4YZVxFTHItd9RJ2oIrYwkpcEQbNwkwgswb+eotLNV3G1sGqXNaBoTUP3LmUKGd+hZnXRlehxcfMss2bSudmqZnnpcOQP0WaAL26edduFTZbtVUZle7esw+2ZFn/0f/l/3sNtmjaC218rj4o4bG6tHyvofu2QqxkG5XqD0nEdzQg+2Uvfp/f0SOfuDnvQXzDDDxtyd6HHFUKh2DihfDKSKrzOVWHdMoVlATdbO6R0EbgHOP0+nY+/gJmCI9sCXCWTofj+JwhVw+11GX7+yOTS6wDcKGBVylX0xlmQYHbzGYbJJXrjviKPAtxI/W39HJEvgGMHgCvn974u/a170EDmCgjHIfN4M/7wsirgzl8nseeCsWGyWSaPVaqNk82y3ScMx4wdu+ibiLifQdIegnPBvxIYZEsMs4HDg+46lIYttB2W7h2qBu1QpqBKn5rdI7cjmcJsVbNd24V5Em6lQT/U4VbDsr0JvL1WmcIebpdos3A7apuE3GD+rwN0f6jR3NVgU1A4PKTSOCFbLI6PW71e4Jn79MiiX6k95C44vyTkqkaG6uU7cuUKAK5t0f78CbPTDtdLD7iwfZnC5FO9WKLy/huEquJZFu3vf460p7+q3Rbgqrk8hXffIhQFp93Cvv2Sat2oN/YouJ3rGz7Wjk9QqwfgedhfvkO4r0swS6+/7cLj3av0t0n3VCpKoL/VNJRBl0z7aXovE23TMgVfURmWD/HDKmK62SPXb4+1zpHzJryO1xHFnSzdq0gZyBRca6rvtos+PGfKOIqGAErOgLJvpnrdr7pm0jkrtAvzNmwXtvg6Ah3uk9R4DHW4OeFxtiUd7h5ul2hxcDvZNgm6Xwvkwj6aO9kyhWLgmXt4OP7F9RyH7sN94JlrJ3vm7iF3wfklITdbqVK9fIemB39wh62wAISTXAAi6vBrorirAO7kODWTofLhJ6iZDL7rBiV7Z74Z2BrgFooUL78BIbCfmjgPE8UWUsyzqoOCfvEBJZdHWlaYYDYfif8q9bdGFvfoDARozw+ow97Uay3tz2r+OuIBd26fY09csPNl7EIZECieQ67ziOanj1CuO4rrCYVevoajvx2ZQtsoMtAC94KsZ1O1ezuTKbw1u7CeVLiTGbxQh3uqWOQ3rMPtmRb/5b/0f9nDbZqWBm5HbZOQG8z/dYDuPpr70lRdp3R8TLneQM8EkRCkpN96pnO3Oc/cZS71a4XcZfW4QlEonZxRqjcQQuD7Ht2ba3r3d+Fay314XWcUN2rtuCiu0DQqH36Cns8jfUn38/fYnfbUKquW610WcPVylfz5OwCs+1vc52bkmmsFXDVMMNOXTzB7lf52G/63pSpe+QCkROs8o/TbqDGAmzTv7P7mr5fYc8HYYE1Xz2CWDpGqCkiyvRaG1U8NjZvwxB1kS5iZIlKA5jmUB7uVKQzUDO1MEYlAkz41q0NWzGpN04LaaoA7ej5rF5aVHsdrsgtb7sNBMI8d6nDtLelw93C7RFsGbifbJkH3a4Fc2EdzJ1uhVqPcOCFfqYyPLeOZ+5aiuduE3EVTLBvF1bJZau8+kCkE0hF70Kf1+RNOGAF9bRR3KzIFRaF8+YFMpQISejdXmI8POwFco3ZI7uQcAPP6C163FbnmOgA3KsHMbd4hp77Gn4erRfKEYG0xv5/Rw5H+dov+twCKOURrPaBKOdVvsq1LpjA/NpQpCCXwxM0EiVSaPSTbfZqqIrZ9mYJBL18bV+0q7Vim4AiV50wZV1ERQMXuUZT2zmQKs3ZhdX9Abst2YXE63E364Q5sZw+3aduqcDtqm4TcYP6vA3T30dyXpudyVBon0565rks39Mx1LStxY6feTQABAABJREFU/B5yY84vCbn5wyOq5xcoqoZE0n+4p3N9leiNG7eHVSH3VYALFM8uyB0dAzB8uKd/ez13F9IWe3gN4GbqJ2QP6yAlg88fkcMJS6sU86yUYFapoddPEyuYbcr/VjzeR/Zdi/4W8POlwEFBCPA99Ocmmj2b2PXyeNPJZhJwskWsYhWEQPgeue4jurs7T1xfKHTzVZxQG7xrmYKPoGUUMbVgP3nPomL30FYE1dfbhSncq/kAuCUcyCFl3FiZwqqAu/g65nW4m/LD7ZkW//i/+X/dw22a9lq4nWybBN2vBXJhH80dNUVVx5KFSc/cQatF5/6WYbu99jX3kDvzh1fTqJxfUjg4BAJv3Nbnj5jhvd9VFHcZwM0dNyiengFgPT/TvUq2CtsU4ObOLjAqB0jfY/DxO5iAsVUBN20FM+m6OF++G1dOWxQxDY5H7Ce1/vYW0e/N9X2tPGFynNR03FodGVraqf0Oeqc1k9jFVNu4J66qY5YP8bW34YkrgWGmyDBb2rhMIY2zgQT6Wo6uUUACuu9xYHe2XtXsBbihqeQZjsoI+zZHWCjTAxPWX78O91ZmQj9cnzPFTu2Hm+a+7eF2ibZOuB21TUJuMP/XAbr7aO5Ly1eqlEeeuWFzzCGd+3t6zQf8Gdunday5zGV+bZC7bBQ3UypTffd+7I07bD3T+vIJP9RXrjuKu27AzVQPKF++AyFwel06H7+DGZnLawE3+c0smDX/7gN6oYR0Hfrfr16md7Jv6gpm5hD3+mPgTRvVd2aO1fS3h4jaYXBvbz4hQi/r18oT5h8H/0oEXrmGX6oGxx0b7flh7IU72392/tl5Z/e6ikxBIrCKVZxcIJ14C564kzKFt+CmYCk6z5kSvgj2U3V6FKQT2XfR+uuwC+uIDC01C2K9ZXuXA/VoP9yGcKisSYfbt+w93KZtm4DbybZJ0P1aIBd+mNHclTxzMxkqjQbl4zqKFmiUfM+j99ikc3eHYw7XvuYmIDftvG8JcoVQKJ2eUqqfIITA91zaV18YPDbD89FzRR1el0whas04yA2swr5FqAruYED7+1/ADARtHHAVhcL7n6Blc/iWRf/7ny+sYraMPGGuvxCg6WTefQuqitd+xm/exvedOxZzLUn628YFIpcH24KbL+NI6roBd3Ksn8nh1o5B1cJksye0QW/mfk4N3Xiy2VvzxN2kTGGp+xc+9sKqZvYoauoOqXqbr2oWd24oNJo7Lts7qcO9kQaDUId7qDgcKd4MOE88Tgm4PdPin/i3/m97uE3TNg23o7ZJyA3m/zpAdx/NDfsrCqWjI8qNEzL5/Ph4UOb3lkGrtdb14OuG3EXDl4FcLZuj9v4DmXxQrcnqdWl9+n6shU4bxd2FDlfL5al88xMUTQu8cL/7GdKZjhitE3CjYExoGoUPv4SqG3iDPoNP371IAGLXWg1wx/rbfBE9dG1wb6+Q/U5s37n1IgA3UZ6gqoizD6Cq0GkhJhwiVtHfzh6PA1ypKLjVY2QueF0q5iBMNpvvG7XG3Pob8MQ1hl2yg3ZqgNuUm8JU0YdBC43dyRQ2VdVsmajp6PFs2d4DaVJZsWzvqoA7mkdKaEqdZxnCv/A4UewZjfLMGgtkCnu4XaKN4PZXy7mgQtkGopazbZOg+7VALuyjuaOWK5cpN04oTpX5NYMyvw/rlyy8ZcjdplShWG9QPj0P/xD7dK6v6d3fhutEz7Uq5K5TpqBmMlS++SVUw8B3HNrf/Qx/JklxU4A7ehhUMfslhKrOFXlYB+BGAZJ6cIx2eAy+j/Ple3Berjkt4C6SJ4yvMZtHnFwEB+5vEBPV0lbxv509Hv08TDYrlPEqhyAEwvPQWg9otjXXN2qNqHnX4YlrFSo4+QAmVNcm231E873IcZF7SAKqhN+D1EUfBi2y3nTyW1qZwmJQW9x3qBq0MyV8gqpmB3aXLF5k30VrrkOH+6jkGIRle4u+w6EcTgfvEtdfrw63I1XupYEvBYbwOVdsMivqcPuWvYfbtG0WbifbpkF3k5AbzL8H3dXneP0ky94nzTAoN04oHx+j6qMyvx7dZpPO/R3OcL2ShT3kgmoY1N69J1sK7NvsQZ/nj9/jhvKQbUdx0wKuoutUvvkltGwW6Xq0v/8Z3szrY9OAq+aLFN99A0JgPdzhPj1ErrcM4C4s8HD2DqVQRNoWzufvSVvgYSX9be0IUTkI9LfXHxHhh8xl5AmzfebWj/n5+pqOV2sgjQBQ1F4bvTtbRWxq6MZlCq6RxSwdIBU1kCn0njHsYezYTcsUPKHQLdRwtTBD3+pTsKalHNuUKQR2YSXcsKpZxe5TlFaq34XZ5+vR4Rq01Bzb1OHG/dzMUIfroqAKyaliU1TkzDwTj2NkCj3T4p/8t//aHm7TtCS4HbV9NDdm3h8B5AbzvG6iVSQLxbDMb6ZQGB/flGRh2ctbZ/LZLiA32jbskOr5ZWAbJiXd2xu6dzcg5ZsFXKGqQbGHQgHpebS//0ViNbNNAK5eqZE/uwRgeP0Zv9uOXG8R4E4BSRLgqirG5bdBgYduB+8+ucDDInlCsLaY2svk9XFyicjmwDLh9ssLhC9R4GG2z+y5uf2ED6UQeOUD/GLwwUvYNlrrHs3z5vqmXee1UVxfUQNPXCMoIrBs6d51yRTG9wgYZMsMs8HfSd21Q5mCjBw3e53LfPW/kl2Ya1Hz+lPuBZuQKcRGlIVKUy28CT9cV8K1zGBKFSEkx8KhpvgzvzMTjyMAdw+3S7Q0cDvZ9tHcmHl/BKC7C8lCtlSi0jiheHAwvoivTbKwachdBXBh/s1K0XWql+/IV2oAOMMBzx+/xxkOwnXWB7lrA1xFofzhW4xiCelLOp++w+12pvrGAW5c1HB2vUWAmzk+IXsUeuB++g456Ucbs944orpCgtlUgYeHW2TnObbv/LH5/STKEzQdcfYeFAXaT4jWU2TfNICbdF3Rz4N//Ww+SDZT1CDZrP2INpytIjY1dKNR3OjSvc2dyhQsPUs/X8UXAsX3KQ1aZPxpLfo6ZAqr2IUZvkvN7qa2C1slapx0zkVwP6HDPZQm5S3rcMcfjiTcS51OqMOtKC514aCm1OH2LXsPt2nbsnA7avtobsy8PwLIDebZLujGSRZ6zUfa97dfhWTha4HcXLVG9fI9qhZGce9u6N6uP4q7rA431ipMCMrvvyFTroCUdD59j9NpT/XdNODmzt9hlKtIz2Xw/c/BfQGLqPUWyRPi1h/rb6sHaMcnQYGHL99Pe+7O9J1bT8wfS5Qn5IuIeuAzzN0VYsLRJEp/OzWW+Xu8ikxBKmrgiZsNEpeUYR+t1USNWXPROutINnP1DGb5cCxTyPRaZOzBVN9NyBTiANdTVDr5Gp6mIyTkrS55exArU1gE8q+NqAZ2YeUAuKWkZnfJM2vx9nqoTrPvWR1uybc53JEfrpTQkhpNdKQU5ITHWcqCDz3T4p/6d/7ve7hN01aF28m2j+bGzPsjAN23JFlo394ybLfWu94OIHeTzgpppQqKplG9fE++WgMCT+Ln77/DGQ5if+ZpIHfdMoVJwC1dvCdbq4GE7ueP2O3nqXEbBVwhKLz/Fi1XCC3CfoYSfjUct9YygBsF+drJOWqpgnRsnM/fIeQG9bcHdUS5Cp4X6G9Dj+G46O3U2KjrTQCC6Odhslmxglc+BAHCddGe79HcWX/Vl8cblykIBbN8+CJTsPpku8+J8oJNyxR6uQpWJnCgyTgWxUELVUSPm73OdUdUPaHwZJRwVB0BlJwBZd9cSYc7u+ayMoW3psPthwUfvCUKPuzhdom2DrgdtX00N2HuNd+btwa5wTzbff1ESRYc06Rzd0u32UT68ZKFHwLkrqrHXT6K+w5V00Mt7jXdu9tXRXE3BrhA8eIduYPDAHCvPmE/P02NSwO4SRHAJMAVqkbhm8AizO11sa4+plgrGXAT9beKgnH5DcLI4Pe7eJOODREAtUieEKwr5vcSwjun7xBGBoYDuH8pgzz3wSjhXq4jiuvrGdyDOmg6SFC7z+j9zo5lCiXsQgXGMoVHNN+NHbdJmYIELCNHP1dBCoHqe5T7z+jSix+XcJ2vjahKoG0UGWjBB4CcZ1HdQtneuHPTfrg+DX9IdlKHuxCw1ydTsMNEMzss+HCi2JQTEs16psUf+yv/jz3cpmnrhNvJto/mxsy7j+YuHr+iZKFSnykM0XygfXeHa5mJ49fthLDMvGnm27ZUYVEUN3BU+A7XNFcG3OBY8n5WBtzzS3KHRwD0rj5jPT1OjVsWcNMA2OiQks0GFmGKgv3UxHmYKLiwYA6YiJjGXuc0tIpMFuPyGxACt3mHbD/N9V2b/61uIE7fBwOfm9B5joTh2TXH42Ouf+Vks+oxfj7we1UsE+35HlXKub5p1lmbTKF0iFTfhkzBVXU6+Sq+qiGkpDjskHOn/xZuyy5MAgMtS8corlS2d5WocdI5B4V7NY+rqAgJR3JIaUYyQeL6myv4cKQ4HMYUfNjD7RJtU3A7al97NDeY/+sA3bcGucE8q0+0rsIQg9Yz7btbzE4nYfQecufmm43i1g6oXb4LHRV8OtdX9O7vwvkXQ+5WAffsgtzRMQC96y9Yj82pca8B3ER5AqCVyhQuPgBg3nzB67RSrDUPiYsAd1zgoVxFb5wF+turj2ANY/vOrru0/rZYRhwFWl+atzDoxQLx/LpTp5aKXsbKFHJFvOoRKAr4Hvrzbj1xo2QKuV6LXbkp+ELQy1ex9WA/WXtAydx8VbO4cbai8ZQpj8v27lqH21TyDMMKaxXf4gB77Ylmi/Y20uE+SJ1WmGhWUlxOIhLN9nC7RNs03E62rx10vxbIhbcHutuO5ubKFSonJxSq1fEF2IMBnftbeo+PSN+PHbspycJbhtzUUVxdp/buA7lyYM9kdTs8f/wez7FXjuJuykmhcHJGvt4Atg+4mcM62XoAgYOPv0BOAmfEWovkCZPrR8HQi/7WCfW3XmzfyeMr2YMdnSCK4RtrrwNPD4iJt9JlorjrkClIVcc9qCONwH5q15640TKFzbgpJAFXcD74EDDMFBlmS0gxqmr2vDO7sMmyvYLX6XDX4YfbUjJ01FAyIV2O/QHa9Is0Yf316nDbYcEHKQVZ4XOuWFOJZj3T4r/6V/dwm6qN4PYfLmbQVXXxgDW0rx1yg/m/DtB9a5AbzLP6RMveHz2bpVxvUK7XUcLXt++6dB7u6dzd4Tl27NivGXI3HcUtHB1TOb9EURR8z6P1+SPDUN8aByHT+3udDnclwL36gvW0PcDNnV1iVGpI16X/3c8QkxrMBXOsor/VL79B2Yb+FqB6iKgEiV04DjRvEPZshaxosJ6aJ2GPUefm9jgCXAReuYZfqgbHbRv9+Q514kNsEuDO7WEDbgrbKvoQX9XMoJevBVXNdmQXNnosgbZeYBCW7c15NlW7uzMdbl/oPKo5pBDo0qfuD8hMSCa2CbgDqXATJpppQnKuWONEsz3cLtEm4XYUuZ39YW2y7bW5MfPuo7mLxy9xjxRVpXR8TKVxgp4NPqUjJf2nJ9r3t1i93lrWga8fctMCrmpkOPjwDZlCoHscPD/R+vwR6XmporivlSm8ecAVCoUPP0HL5vDMIYPvf/4iA4hdZx4SJvsm6m+NTKC/VZTN628BMrkgiqvrgUyh9Qid1sxX3vE/oyTATdpr9PPgXz+Txz0IPXF9H639iG7O6l6j14jcw7plCmaPXL+VCMdpQX+1qmYq3UIVVzPehF1YX83QyZTWrsNdJto8emyh8KAW8MKSxsf+kIKYSUpOAacz3RbuO+p140jBlW9gowaJZsKhrPp7uF2mRcHtZNsW6O6juQnz/sCjuduWLOSrNSonJ+QrlfExq9ejfXdD//k5eKNew1rbhNxdShVKJ6eUT84QQuDaNs8fv8PudVMBbrC39ckU0gHuepPMkgBX6DqlDz9FaBpOu4U9GVGNXScE0VX0t5Uaev009L/9CPb69bejawsPwkEDUSwFz80hNG/HpXpnx82uPzUX838L1uKJO+hidJ6npBPzH7TSQdPcHqaniQSe2aIPqmuT6zRRpR87bhMyhfH9Afq5CubYLsykOGhv3C4sbpytaDxnynhvQIfrIbhX89iKBhIOpEllRwUfPAm30qA/kWhmWH3++L/7/1wIt9sLT26w/e2//bf5Z//Zf5azs+DN5T/5T/6Ttc7v+z5+gj5xXU2G/210Dfny/2bml2zi89K6740v/fH/r23ruKej+7bqvVv2/gxaz9z8/f+Cz7/zn9O5v0f6PplikfpPfsrlH/41KienYwnDa9ZKe1/SzLloLl9K/IQOSefjhsXty/enj3Vvb3j4vb+PY5lohsHRT/8A5bNzJMz9TKPWmn0dzkw/t4fZOSbXmL3G0dP+7TWDMPmteH6JUT2Y38h4vei5J6f2p45HPwaQjkP/y0eQEr1SRaseLlxnvMbEjZg8G/VzHB3z28943TYIgXZyhoz4IBu398jrmVh5aj+j16PvQ/MG2bwNHmdzcPoOmStMjZscG/czGq09+/NMutezPx8pQfge2uMNaucJJPj5EtbhKa6qRa4ZdU+m9uDP7nf655L0c/R9HwFkBh1yrSbC9/A0g37tBFvPJFzLzDyJ56bXn967P3EuvD9AcdimOGghpMTSs7SLhzhCjRw3us40e026d3HjDN/lyGxheA6+EDxlynSUTMLvYfzPI/FnlTBu9FhFcuL1KXg2CHhSsjyQxZt+kSZc7/z9jlsvbm8j5lIFnAmbmgikI01f5z5MOFvUfhBw2+/3+dVf/VX+2l/7axtdZ3TDNw26cuK/ja6zBchdN+hu4t6sC3JhPfd0HZCb9v7YgwEP3/2Cj7/9/+Pp82dc20YzDA4u3/Hu1/4Ih+8/vEgYYtZKta83BrnLzhsHuJNvJPagz/3f/116jw8IBKXGKcd/4A+iGplIwJ2Hi+0A7rD5AEDp4h1GpTru4y14M49adzEkhnMP+wzvrgHI1E8Q2Rcnj6hbHgsHi/qGj937G6RtI3QDrX6a2HeyzULSy7pJ8BA+6HWQ1x+RlgmqCvVT5MExciIiNQu4/sx9jQOB2f0uAsERwKndFlrzGlwXqes4x2c4ucL4ambXnH/dTF/3LKhN9Z0ZFwU8mmOSf75DcSykUBiWjxnmyokQF/czmz83tZ1Y4ArOBf9m7SHl3iOK5+GqGq3iIWZYwWs0bgrWppdYK3Cq0ufQapN3zbEe90kr4Mbc82Q4jP9ZpQFzARz6Q2ruECT0FJ1bpYA7/YNKuN7o+z3bL+5eTM4jBBwrDg3FQgjJUKbD1h+cLEEIwV//63+d3/zN30w9ZpEsIantJQvLzP91SBbghyVbWE5GICgcHlI9OZ2qfjZotejc3TKcKem6+jop+21YrrAuqUJU4Yfau/coqjaVbLaKDncTEoWxD66cL9W70QSz0wuM6kGQYPb9zxCeu2Cd+a9bF8kTRsen/G8fbpGd57m+y+hvg7WTvnKeOFE7QpQPgs06NjzcIpwdJpspCm61jswFHyqWLd27LpnC6P1SAlahipMPpByqY5LrPKLuzC5MoZuv4oSR5LzZo2D3d6LDlUz74Rq+y4HdRd+wDjfu3GTBBy1MNMvuMNHMNE3+G/+bH4ksYdlmWRadTmfq/1XbtiULm4zmjj7F76O5P8xobtp1es0mX/7u73D1u79L/+kJpCRfrXLyy3+Q8z/0D1M8Oo6EtK8xkruqVGFunplIybD1zN1/8buYvS6KqnLw4Vuq7z+AEJFRtuk9zUdwpyKKa4jg9q4+Yz49gRCU331AG+lFmY7gviZ6G9V/eHuFOxwgNI3cxfvxu11S5G68TngTJvsmRY6lZeI2AxmGdtSAia/AF41PE8Gd3NPoGsddn5vIuy9I1wXdgNNLZKkyvfcFUdypa5FJfZMiYWEU1/fRnm5R248gwc8VcI7PcDVtru/kOpNzrkOmMHq/FEC23yLbaSKkj6dn6ddOcCaipomRyQX3IO7nN9rD7DUr0qfcfyJnBkm1g2yRdq6KFzcu4Rpnn8+vn/yzE0DBNTkw2yhSYisaD5kK5sRHkXXLIpLO5aTLidtD8z1coXCjFOjJiY9FMy+cqJ/3ZNfVriGYIy98jJSBkR8l3P7Wb/0WlUpl/P/l5eWr59yWZAGWg4iV19gg5Abz77W5q82x+geEZT8EmN0Ot7//e3z8z36b1s0Nvudh5PMcf/Mtl7/6R6ienY+roa26zrYhd9lzcXOm0eJ6jk3z9/8B7ZsrJJLCwRHHv/wPoWVzqQA3SaYwu/4qgNv98hGz9RwA7vtvUPMvkfqNAa6UDL58RLouajaHMSkZiF1n/j7HAe7sMa/1hNfrhPrbc2QYc0v6qjuqzQLurExhFnIBMAdw/T2y3wsg/uA4kCpMRLNmIXHjMoVeG+3hKpApaDrO0bRMYWr/RL12kq57pu/MuChY0a0huec7FNdBKiqD6jFmdnY/SRCbAEQJIBX1tbkACmaXUj9IvLP1DK3i0c50uBnf4ch8RvddPKHQzFToiRf4j1oj7txrdbg6Piden4znIoXgXsnzjD79FzAR6KMBd7lrWO49+EcpS7AsC8t6qeDS6XS4vLxcSZaQ1H5IdmKwly2M2o9VshBYidWpnJygZ4IomPR9eo9N2ne3OMNh7Ni066xLrrAJqcIyMgWY/jrQKJY4+PANmm4gpU/r8ycGj821yxSWligIQeX9txjlMtLzaP3i9/HNl/Kk65YojA6p+SLFd4FkIE0Fs7hs8NGjZP9bFePdtwhdx++08R6u4/tGHmeqpZUpTF4vpQrioB4c8LzATcEcxo7dfOleBbd2PE56271MQWCWarjZYD+6NSDbe5qKvm3CLiy2bK+i0SnUxmV7S8M2WXe66tu2/HB9oGWUMLXgb27RHVL1hqmkPMusl2YeSZBg1lPDvfgOh3I4zU0blin0TJt/+t/7f+1lCVEtk8lQLpen/gcQa4bRfTR32fn30dzV5thOAprvebRvb/j0n/02dz/7fcxeLyj3e1zn4lf+MCd/4A+Oq3bFrbNwP2uK5KaJ4i4rVXhNFNfudbn/+7/LsNNGCIXauw/UXiFTmF0/buzCCK6UtD/+AqfXQ6gqlQ+/hDBeokPriuDO9vUGPYYPtwBkT87BeElajPqpJEWhktb1pQTfw7n9AlKilCuIYiWyb+x6SZGmiCjudN/wQbcdJJvZVpBs1jhHVg93J1OQPtrTHWorWaYw2TYrU5Bku09kus+AxMnk6VcbuIoaOW6ZezAn64lYf/aaNd+l2muiOxZSCDr5Kr1QAzs5dvIaY68/IaKbJvFLAWp2l5ITeBX3tBxNrYQ78WdhHetFzTN7TgCHvjmVaHa3g0SzNO1HCbdx7dtf+3WO371HM4zFnZdse23uMvN/fdrcdYLu6uNfd99S3xsp6T0+cvX3/i5Xv/v36D0+gpTkKpUXXe7h0at0uduE3GXPxQ1ZBLi+6/L489+ndf0FKSX5kUwhk90Z4I4GtL//Be5wgKJrVL75JcQE5LwGcJP62o8P2KFlV+7iXaRlV9Kb9Ox+EgHPHOI+Bi4R2vEJaPN/4xO/gk8ApGAfSQARPnBsuPmEHEWpKzU4uUBO3OutyxT6yTKF2TXXKVOY2nuowzXMHvnne4Tn4as6g2oDW89OjVtGpjB9Lnn9l3PB/4qUMzrcwk51uCVnQM3qIJCYqs5DtoI14RywzvUWnStLm7rXQ5ESU6hcKwUsKSY7xs65LcD9QcBtr9fjt3/7t/nt3/5tAL777jt++7d/m0+fPi01j6rpHJ5f8pNf/w3OfvrL5EqlxYOWbNuCXFgCVl6zxgYhN5h/s9Hct5iEto4PD1uBXMDsdrn72e/P63K//QmXf/jXqJ6eRfrlviXI3XQUd/ZNv3d3y8PPfg/XcdCzOY7/4D9ErlbbCeCOHkrfo/Xdz/EsC9UwKH/4SVDhKmzLAm70+fm+w+vPeLaFohtkz15yH+LXiPhZTDxO1N8+N/EHPVAUtJPzl2S2mXuzqp9q1M/9pW94zVLC0z3y/jqQJ2SygSduvjg17jWeuNN9k4A3+FdxLPT7L4hhH4TArR5hVw7xYl5PC+9Rkp50Zm9R0KO6NvnnW1TbDO3Cjhjm128XFrf+5DVH6nALy/nhEvM8KfodB/E5z+Zo2EL1PVyh0sxUGKAtHLfqeol7kR4nbi/cS5Bo1t9ColnaN8YfhOb2b/7Nv8kf/+N/fO74n/kzf4b/6D/6jxaOH1mB/dHLBvXzSwrl6vjcsNfl+faGbvNhI5AFe23u8vN/HdpcWJ8+92vR5iqqSrneoNJooI11uR7dhwfad7e4lhU57i1pcuM0t+vQ4k7pKjWNgw/fki0Fsqje/R3t6y+RO0/S4a5Dgzt6qBgGtZ/8ARRdx+n1aH//86mqVlEa3NdahCmZLKUPvwSKgnV/i/v8Uhp47fpbVQv0t5oWJJs178Z7XqYy2KKyr3FVzUbXDICqBaV7Q3sueh14epi639ss3SsBv1jBKx+CAOE4aM93aBOV1pJ0uLPzrqOqmVWo4OSD3w/NMcmuyS5sJR2uqtHJH+CrKoqUFActst6svdt2dLgegudMGVvVEUDZ6VPyrbXrcNNWNHtQ81hbqmjWN23+6X///70vv5umjeD2V4oGqhBk8gVqp6dUjhrjG+86Nq27O1q3N7gzfoXranvIXXb+zS3wQ05C20oCmhAUZ/1ypaTfeqZ9c4PV771q/jSXsKmks2UgN40nbvn0nPJJ4Bpg9bo8ffdzfNeNBJDpfWwGcLVsjupPfopQVazWM73PH8d9NpVgpldq5M8uQUoGn75DmoO5ddbmf5svYJy/B8C9+YLf78YmtrzGTzV1sln1EFEJgPK1nrjLAHrc68s3Mri1BmgaSInWaqJP/Dxm11x4j5J8VhPHBa81J5PDKh0ghYLiu+Q6TTTPjR23DOS/xg9XSMhbXfL2YCU/3NcCpwTaRpGBFsg2Cq5JzRsk3tN1++FO7uVRydEPrdxKvs0R1kYAdw+3S7RZuB01VdOoNk6onZyihwkPUvp0mk2eb64xY96g19F+SMUh4OsF3X00N2bcEvclVy5TOTmlUKuNj5ndLu3bGwat51fNv2nIXdZVIa77IsjNVqocvP8GRVXxHJun736O3e/vDHD1YonqNz8BIRg27xncvDgMrANwo/pmT8/JVA+DAg/f/T7C9xasETyOit7GrTs6ph7W0Q6CIhbe8yPe00NqSEwCpKjzqaK4mRwcnwZaZynh6QF6nRloStpT/B5WLvpQqyPDSnJqv4PeaSGmoqbTa6Z1U0gC3Lm9h681T9UZlg+Rmg5Sku09kbGHseM2AbjB+QDk+tkyZujskLFNSsP21Dxz42L2uXDfKQo+9LUs3TDZLeM71KwuukLiuFXXW7SXjjBoqTkQgT/usT9Am/7Fip0zrZNC37T5Z37r/7OH2zQtDm7HTQhKB4ccnJ6RL1XGhwfdDs/XV3SfHje2t300d9n5N7fAPpobMzblfdFzOaonp5SOjsbOJM5wSPvuhl6zGSv7WUeVsjTzrAK564ziapksh9/+BD2bI8kuLAlwg+fRay4LuJlqjfK7DwD0rq+wwoQsWB1wk+QJCEHhwy+hZXN4/R7ml+9TrJEOcKOuVaufoYblh6U5xLm9QnhO5DqT4+LPx59LVdlMUQKZwkh/2+/B491OZQpeqYZfqoEAYVvoz/eoE1rJJMCdnffVdmFCMCwd4mVyABjDLtlBOzU4rlumYBo5+rkKUgg0z6Hcf0ZDxo9Luc9VgNNUdFqZclhFzOPA6pIR/sJxq66XdG4QVjSTQqBLn4bfny688ErA3cPtEm0h3E60bLHIwckZ5aP6+GY7lsXz7TWt+zt8100cv2r7oUEufL2g+0OO5m4DclVdp9I4odJojItAeI5D5+6WzsN97O/Q1wa5cfMkgo6iUHv/DflqDYDewz3tq88Rb/6z628GcHPHdYqn5yCh8+m7lcv0ptbfGgbFb36KUFSs5j3u433iGnHwNObFmLVGx5ViGb1+Gthz+R7u/S2yP12xcl1R3PSeuFXEwXFwwHUCmYI967GaBG3p9j63v5h5/EwO96ARwLfvoz/fo83sJ+qDTNS869Dh2vkydiEIMqmORa7T3JkO11F1uoUDfEVB8X3Kg2cMf/rv17ZkCo5QecqU8ZRAE1yzu+RxF45bdb2kcxYK92oBX1FQpaTuD8iJmWTruN/NBYC7h9sl2jJwO2qablA9OaV2coIW2sr4vkfn4YGnmyvsBEP717YfGuh+rZAL678/bwVygzlWmyS1pEBRKR8fUzk5Rc/OJJ/d3uDa0dr2bUDuugA3bq5FUdzSySmV03Mg1OH+4udI35vqvy3ALZ5fkjs8Qvo+7V/8DG/4or9cBLhx0BP1hjg6pJcr5ENN7ODTd8hhf26NuDfbZfW3AGg6+skZSljQwO+2ce9vEcRHvjaebGZk4PgMoQdfw9N6hE5rdzIFVcWtNZCZQJ6ndlvovdmoafReotZ4rQ7XNbKY5UOkUBC+S77ziJYQdd+ETGF0yhMK3cIBrqYjpKQ47JBzzfhxTLd1AqeP4OmNJJq5CO7VAo6iIiQcySGlGdiOA9xg/Wgdbt+0+a/9B//fPdymaavA7agJRaF8dEzt5Ixc4cXOpff8xNPNNYN2a827fWk/NMiFrxd099HciHHLJJ8dHFA5OSVbDH+HpKT39Ej75gZ7OIge9hVB7iqAm61UOPjwLYqi4toWjz//fTwrPmIWrL0ZwK18+AlGuYzvuLR+/nvIiYSn1zooRPXNnpyRqR1tVH87e1w9OEILI6bSsXHvrsGK13VuXKYgFDhsIIqhJeWgD4+3CH+7MoUx4CLwKgf4YREMxRyite5RJXN906zxeh2uhlk+wt+hDvfl3kAvX8UyAslEzhpQtLpfRaLZJgHXB5pKnqGqA1DzTaqvdFLYw+0S7TVwO9lypTIHZ+eUDg7Hf7ysQZ+nm2s6zQfkhvxttwm5sB3Q3TTkBmt8HaD7ViA3mGOzoJsrl6menpGvVsfHhu0WrZsbzG4ncsw6IHdVqcImorhTOtxslsNvfwk9k8X3PJ6+/wVWpx3xxjK59voBVyj/f/b+PMaZfb3vAz+1cV+b7L373c5275Fk+VpABBlxEgRwosSzGJkk9mA8kBwgCoQECCInQfKPBGWBgbEnngX2eOKBbc3uceyBHQTJP46RTYYzkXQjXZ171nfpfeO+s5bf/FHsfskiiyySVSS73/oeHLxks34Li9XNDx9+n+eRyX30KWo8jtntUv3ua7ivSxqY//Yj1FgCs92ie/pm6hqz7Anjz2ky6EixONreIZIWsZPNyndY1buRY1duU0hlkQqD1r2GAbeXa7UpmPEUZt7+ECAZhl0uzDDGjvOyhh8+3G56CyNqJ76t04crgE40RTtufxiJ6D3SnepIS+PVJprFaUTshhwxUyffb6CuKdGsIsdoDLXsLYrO6LmfA3BDuJ1DfsHtvbRYjK29A3I7ew8F7A1Dp3p9ZZcSc/m61Q+F0dxF5n8ckAubA7pBQ24kkSC3f0C6UHjYbK/ZpHZ1SatSXnjuZSB32tggo7iyorL16iNiqTQCQe3slNbtje+AOx3aQNY0ch99hhLR6NfrNN69fng8EP+tNvDfKv74b51rj4152KCMur2HMqh3bnVaGFcXSJZ7+anAbQpaFHb2H6B7lk1hGuCO729+wLXUiO3DHdgm1FoJbcg+4lxzUcCF6QA42YfbJb7Gerg9LUYzkUNIEoppkG1XUIcasKw00UyJUImmEUholslWv05E8nZe/ARcsCspVAaVFGLCYGfBSgqtXp9/KoRbb/Ibbu8lK8qglNgBkeh9KTFBo3RH+eL8SZQSg6cDufYajwN0PxTIVaNRcnv7ZHZ23ldY6HaoXV7SLE2usLBpkOuLTUGSyB8/J1koAoNEs7OTQAF3Yg3ceILcR58iyRKd2xvaV4uVCJvbf7tE/VvnfmbbCQYfKtJZO9lMlsE0MW4uEe2G69gPzqYgyRj5bcTAq6y0Gmj1CkGXC3OL7OmROL3MoB6uOaiHO+UDiV+v3aSvzg1ZpZ583/Ah3aoQtXT3cYzKT9uAM9Fsq18njtO/P/33cdJ6iwCuH5UUQridQ0HB7bDSWwXy+wcj3c/a9Rrli3OaLpEoP/QULQsQPOg+FsiFDwN0ZVV9qLCgaLZ/y+z3qV1fUr+5mWj5WRfk+h3FHX5DSe3skT08REKiU6tSeft6rB1l0IAbzebIPH8JQOP0hH71/d+vZRPMJkFUbO+QaL6AMHRar79FEvP7b53Hu60/9pimoe0dIcdsL6VZq2CVrkfO+XptCvrApuB/04dp8HI/j93VLIeZ2QIJu1xY+RpFBAu4zsdH6uFmCwhFQxIWsUaZiN51Hbfoa+cFcC1Jpp7MY6gRJAHJbp2E3nEfN+X5LQu4piRTjmbQZRUJyPUbpIQ+c9yi6017rI/M9VAlhV2rTWy4ksIMwA3hdg6tAm7vFU0mKewfjpQS63c7lC8vqN1cB+bLhTCau/gajwN0PwTIlWSZzM6OXWFh0N7XMgzq19fUbq4mlhELEnKnjfMzijv8hhLP5dl68RJJkum3W5S++wZhuldSCAJwE7t7JHf3QQiqr7/FbL//Str3BDNJIvXyY5RoHKPZoHf+bmz+8XGT34ynAe7YuKHbD00fANHrYVyfg96bOG72vLg+Zu9xGkgMbjirKcxo+hC4TWGoXJhkmqiVG1RHlzW3131s/aV9uDKdTAFz0Hgp2q4R7TQ8XSvOvS0LuAJoxnP0outPNLOAaiRNV7X/bmb0Nhmru5ZEs9FKCoJtq0NKGv0bhsucrV6fn//f/PUQbr1olXB7LzUSIb93QH5vH0UZ1Po0DarXV1QuLzEcCQN+KozmLjr/44Bc2AzQDdSyIEmkC0VyBwdE4vYbh7BM6jc31K6uMCe0yF4WclcdxZ0GuJFkksKrT1BU1a6k8O03mFNrj/oPuJnnL4lmc3YFhW+/QhjvI0H3gOv+xjm8l0lQO3qsHIkO6t/K9G6uMCrvk7wmAfTY/qdEcb3aFKREEm33AEnVwLIw7q4RjaqnsZMfcx/n2aZQ3EO6r9LTakDpxpemD4uVC1MxtnYRkSgIUOsl1HbTcQ1M3svY+j7Uw+0lc+gJ28Kh9trEG+Xp59zj818s0SxJO26DWETvkW5XUYbPxQoTzRpagqZmJ+AlzB65fhNlAbuBH5UUbuUEXUUDAVvCrqTgGDg2LoTbOXQPtz+R1FAkKTCImSRJlsnt7JLfPyQ6+OrrKfpy4elArr3G4wDdTYBce/z8E3g9F8n8FrmDg4cyYsKyaJbuqF5eYPTGPyQu08Rh1vh5IHcRwIX3bypqNErh40/RIlFMw6D03TcYjrJpgQKuLJMfVFAw2m1qr795+Lo+EP9tNk/i4Nj23757jRgq07Us4Dr3MTb2/raioO0eICdtaLKadYybSyThf01czzaFTA5pUL0AvW/bFHTddVwQNoUHwJUkzNw21qDLmtxuotbuUFyur1lrLO3DjSboZrYACdnok6jfoUx5rYICXICeGqOZzA06mhmDjmbrSTRrKVHq0fRGtOwtyzGag0oKGatPgdG6vE7ADeF2Djnh9l6rhFyAVH6LrYPDMV9u6eKMVqUS6NpP0bIAwYNukNfIUwTdIKO58UyW3MEBieygRfagVm718gJ9QlOVoCDXb8CdtNZDJQVVpfDRJ0QTSSzLpPz6W/rN0Q/EQQKuHImw9fH3kFSFbrlM6/zk4fEg/Lfxg2Mi2TyW3qf1+lvkARx4BQHwJ4qr5LZQi7sgDWriXl3AlBqrgdsUojHY3n+IKlO6QWqPXgerKhcmACuZxcwWePDhVq5RrPUkmplqhE62iJAVJMskXr9DM737Tf20KRiKSj0xSDTzsaPZIsDZkzUqQy17C731VFIQ2JUUqqod3EsInW2rM/ot+tDtVq/PP/PnfiOEWy9yg9t7rRpyo4kkhYNRX26v06Z8cR5ovVwIo7nLrRHMIk8Rcu3x80/g5VzEUmlyBwck8/mHn7UqZaoXF/TbrbHjl4HcdUZxH7pxyTKFVx8TS2cQwqL89g09R/MYN8AdA6s5APchoppKk3v5MUjQPD+jV35vGfDdfyvLpF5+ghKJYjTqdM7eTexK5hw79hx8SDaTojG0vSOkyKAmbukGqzaaHLxSm4Ks2IAbt79ypl6Fyp2rD3d8PyMPeYbzSYALYEViGIVdkJW1+3AtWaGTKWJpEUAQa1SI9p3fcqwGcEcTzQSpTo244axb/OFVUmhJGiUlgZAgKkx2rTbq6KcX+7gQbr1rFtwOa5Wgq0aibO0fkNvde/DlGoZO9eqSytUlpq7PmGFxPVXIheBBN4zmzjs2GMiNJBLkDw5JbW09bLBdrVK9PKfXHLf7BAG5qwJcJImtF69I5PIIBNWTd3TKJde55gXcqfYEIL69Q2r/cGqC2ej71HTAdX9DBTkWI/3iE5AkulcX6JXSQoALjjdkx1jPNXF39lHS9rcFVquJcXPx0FFt4ppT53Xfv2ebQq6AlCvYt3td26YwlHC40nJhTh9u7Q6101qpD/ch0QyJbsZ7w4cgAVcg0Ujk6A+S3hLdJsl+y/FBZEWVFLBb9uqKhoQg32+SXFMlhS4Kt2oSS7ovFdYeiSYjSSHczqN54PZeq4RcWVHI7eyR3x+ul2tRu7mhfHlOf8JXrr6u/0RBdxUvYRjNnWdsMJCrxeLkDw5IF4sPG+zUa1TPz+k2G2PHrwpyfQdcIHf8jFRxB4Dq2clYswcvgLtogln62QtiuTyWblD59ku7mxbB+G8j+QLxPRumu1fn6NXKVFD1GnFyjvVcEzeTQ9veA1lGGLrdurfrHhkM3KYQTyJtv6/Ry+0lUm+0JFbQ5cIeQE4a9eGusx6us+GD2u8Qb5SQp4zz43VzSzRrx9J0YvZ5ifa7pDvVkTW8+nCXBc5NqqSgD0qFmbKMPCgVFh8qFdbq9fln/vz/NYRbL1oEbu+1astCulBk6+CQRMp+UQWCZrlM+eKcjkt7Ur/0VCEXggfdDy2au+zTnfd8eTkHajRK/uCQzPb2wwa79TqVizO6jfkg1y/ABW+QOw/gZg6OyOzuAVC7OKN5fbUawB1KMNNbTeqvv314PBD/7eEzIoP8BKNeo3t1PprYxagCtylEoqh7h8jRmO+texeyKaiabVMY7GedXc3serhZzIztw5V7XdTKTeD1cN2iqHo0Tjdtdz+UTZ1E7XZtiWZdLU4rkUNIoBl9Mu3qSHe1VVZSqGtJWprtfU0aXbJ6y7WSQpCAayJxoyToyyqSgG2r/VAqLITbObQM3N5r1ZAbT2coHB6RzhceftZp1CldnNN0fB3pt0LIXXaNYBbZRMiF5c5pENFcNRIhN4Dc+65n3Uadyvk5XccHxMcUxR1+Q0nvHZDdPwCgfnVB4/JiJYCrRKPkP/4MSVE8dTBbxp4AENkqEt/ZB0lC6Dqdi9ORLmbDaznnmHR/aZuCJNmte7N5AKx2C+P63LNNYRrgOh/3Vi5Mgq1dpPQAAloNKF0z/E3vSn24I/VwDdTyNaphjB03eS/uz3ds/dFpJkKmqUboZIoIxd9Es0UAt69GaCa3sCQJxTLJtMpoa2rZ21Jj1CMpBBAz++T7TVSfKyl4mcNZKqwgumTRQ7idR37A7b1WDbmReJytg0Ny27tIgzepVTWFgKcLuo8ZcmEzQXcjIXf/YKS176og1+14JzAsY1NI7eyROzwCoHF9Rf3iLFDAfQDOTI7si5cA1N+9Qa/XHo71238Ltgc3cfAMZRCh7Jdu0Uu3MPy1N6MK3KYw1Lp3I2wK6RzS1uAbi34fbi+QhqBypT5cVUPf2gXNTsRTK7doPWelicnzO+f0O9Es3igTmVL1wq/Iu1vL3kYyj6moyJZFul31pWXvIoDbVSJUomkEEhHLYKtXX1upsJIcp6VEAMhaPSLdBn/sf/t/C+HWi/yE23utGnIVTXtoCqGqdntSw9CpXl5SubrAnNC5yU89VciFxw26mwi5sPg5DQJyFS1C/mAS5I7bFRaFXL+juF4BN7m9Q/7oGQCN60salxej43wA3EkglNw/JLG9gzBNKt9+hRi0h/XTfzuyH0kmtrdPdJBIZXbadM5PkYYicdNgwHnfH5tCBHXvaMimcItVdSb5+QNL3suFHSCpql0u7O4KyVEXeXU+XBljawcRs5O7lEYVrelM7po8v3NOvxPN1tnRbLySQp244fRKrybRrC+rVKIZTElGERaFXp2o5M264Tfg1qQoNdXON5I6LX7hz//HIdx6URBwe69VQ+59U4it/UMig6YQlmVSvb6mcnmOPqGovZ9aNeTC6kD3MUMubCborjKauwjkduo1KudnY9UV/PTjBg64xR3yxzbg1q8uaF5dus4zD+BOsycgSeRefoyWSmF0OtS++9pzgwc3qPHytbeazpDYP0JSVIRl0r26wGrURo8Fx1iPb8qOcZ5tCjv7KANvsNVqYFxfeG764LtNQVFswI3F7cB2rQS1ykI+3Gn7HtvbhHkEYGa2sNI5e3ynhVq9XUvDBwH0k1n6CRuWtF6bWAAdzbwArgCaiRy9yMD72m2SWFMlBUOSKUczGLK69lJhzUGpsH6vwy/9ub8cwq0XBQm391o15IKdfFY4PCY+aM8ohKB+d0v54pzehHqffuopQy48btDdRMiFxc/pSiC3VqV8djZWJ3cRyF0mirso4Ka2d8gNIrj1ywua1/MB7kINHlSN/KffQ1ZVuqU7WhdnD48vW//WeXt4jKRqJA6PUQfZ+XqtQvfqAtmjTWHsefldTUHvY1ydQ7/rOjaIcmEjU27tIN03C2o34e468La9bq+XGU9hDjqsSXofrXy1toYPeixJN50HJBSjR7x2N5Lc5Qfgjj3moZJCrN8h1am5VlIIEnAt7FJhfUVDAnL9BqmAS4W5zdGRVLrdLv/cXwg9t560Cri91zogN5nNsXV4RGqQ5ADQqlYoXZzRrtUCXz+0LCy7RnCLbCLobgrkqpGIXV1hZ+dhU61Kmcr52VjHM78gN1DA3dkld3gM2FUUWjfXE+fw03+rpdLkXn0MQOPkLf2h5hKL+G+dx0y+b/8bLe4QG3QRs/p9Oucn40A5dZ4p4MSovFZT0PaPkCJREALj9hrRGO086RWW7Men7N2LTSGVRSoMrm0ffbiLNXyIYm7t2cldpjlINNPHjpu8F38B19CidLNFhCQjmwbx+h2qZbiOCwpwAbqRBK14FiFBxOiTblVQhn8vAk40u78tgMqGlApr9fr8T/7C/z2EWy9aJdwOa9WgG0um2Do4JFPcfvjj12k2KJ2f0iyXZ4xeXmE01481glnkKUGuPdb74JmQG42SPzwic18nd9DWt3J+hjFk8wkyijuvTcFLkln19B3t0t3E8X4CbnJ3n8TuHsK0qH77FVbfPmfz2BOG5520phs0KfEE8YNjlAFQ9m6uMJy+19FlPEOAc6z3pg8HKIPqBVajhnFziTQlOrgyH65p2j7c7ugHt5X5cEcaPgjU6i1ad02JZopKO1tEKBqSsOxKCoazu9rsDzRj8y8AuH01SiOZR0gSqmmQaZVRN6RUWN5srxxwQ7idQ+uC23utGnK1aMyusLCz9/CL0eu0KZ2fUb+7ffDGBaUQcv1YI7hFnhLo+hnN1WJxto6OSBUG5feEoH57Q/XifKRb4KZEcd0AN7N/QGbvAIGg8vY13Wp14ng/E8yyrz4hsqT/dvLznQ1NyDLx/aP3NXGbDboXZ0hiqDzX6DLzvTHPsb/7x5XcFuogqix6XfSrc6QheJoGS2P7mQJMC/lwK7fQGE3uWmXDByO/g4gn7a2tMdHMkmS6mSJmJMq6W/Yasko9uYWlKMiWRbZVRhPmxDHO5+cn4AI01RiNQamwuNkn12+gLuCnXRRwW70+/9P/3f8jhFsvWjfc3mvVkKtoGlv7B+T3Dh7a++q9LuWLc6pPsIwYPD3Itdd5HKD7VCA3mkySPzwimc8DICyT2tUVtatLLHMYmCbPsQmAe9/JTAiL0nff0h/q1LYo4Lp9PStJo/7bTumO9gz/rXO+aZDr1aag5bZI7B5wX56rc76amriuNoV4Am3vaFC9wMS4vkC0HYmLLud0/DFcH/Pmw5WgsIM0aCNMsw6lG1fAHX+O7us/xkSz95UUoJvewojZsB1p14l16p6jlX4CrinJ1JNbmKqGJASZdoWouZ5SYR0lQjWaQQBRS2er11hZLdwQbufQPdx+nlRRJGmlADRJq4ZcWVHI7+2ztX+Iqtn15AxDp3J5QeXqEivgMmIQgq4/azwOyIX1ga6fkBtLpykcPyOWTgNg6jrVywsaN9cM/1kNAnL9ANytF69I5LewLIvSt1+ht9sTx88CXLfInRN+IukM2ZcfAd7q3zrnmyeK6wa4cjRK4vAZSjQ+VBP3ZvTYqXtYDHCdYx8eU1S0/SPkuF2GyizfYVVuZ49z288UYPJeD3fHfjK9ru3DNS3XcYEmmiXSmDnbCiT1e2jl67V0NHO27LUrKZQ8f8DytVQYEo1kHl2LIglIdWprKxXWkzUq0QyWJKFZJlv9OhHJW/LdIkB9fzuE2znkhNt7fWiQK8ky2e1dCgfvy4iZpkHl6pLKxQWmoc+YYXmFkOvXOo8DdB9LNHfac07k8mwdHxNN2IBi9LqUz85oDXUKnNeqsBLAlSQKrz4mnsliGga3X/0YS+9PHL9sBYX7HyX3Dkjs7Nr1b7/5CqFPr3/rnG98X9NhbyIcSxKx3QOig+6OZrtF5/xktIvYzD1MAYGh254AF1CLuyiD/Vitpt3VzIdyYQsBbiyBtL1v2xUMwwbcft91XLCJZjGMgl1lQjIN1NI1qrl8R7N5ARdAjyboZrYACUXvEa+vtpLC/Y8F0Izn6EXt9+hEt0lyTaXCdEmhHM1gysrKauG2en3+Z//7/2cIt17kBrf3+tAgF+wyYsWjY2KDcjqWZVK9uqJ8cY6h92eMXl5PHXJhNaD7WCAXlgfddUNuenuHrcND1KidUdxrNSmfnow0gpgnirsKwJVkmeInnxFNJDF6XW6/+hIx0ir2fl6f/LeSRO7VJ2jJJEa7Re31txP9t/bc4/NNWmt8nVnAa/+rZbLE94+QZAVhGHbr3o6z1Nu0ebwB7qz9ve9qlkHbGdgm9D7G5RnovZnjJu5nCjB5simoGuwcIkUiYAkoXSE5yuCtMtFML+yDpoFloVVuUPs9x7jJ8zvn9OrDdQPc0UoKOonaLcqUDyF+A6792KRSYW1SnfpaSoWZkkxphbVwQ7idQ7Pg9l4fIuSmtrYoHj4jnrK/ehXConZzQ+n8NPCGEBBCrr/rPA7QfQyWBVdIlWWye3vkDw6RFQWAdqVM+ewUvdudPd4D5E46Rp76Juo+lyxLyKrKzmffR41E6bWalL75mvvWtbOit84574+fZk+QtQhbn34PSVFo31zTvr58mGEa4DrnnQX6nmwKkQjxw+eog2+q+nc3K7EpuAGfFImiHRwjaRGwLIybC0TL0SXPB2DyBLiSDNv7SAnbb0o1mIYPngBXku1KCoOkN7V2h+b8IOIz4I6Ps69NU9HoZIsIRUWyTBL1O9ThTngrAlyATiRB+75UmN4j066OzOM10WxZwHXWws33GyR9qIU76bgQbueQV7i914cIuclsjsLRMclBxrFAUL+9pXR+St9R8zMIrQNy4WmC7mOBXFhPNNcPyFU0jfzhEdn7GrlCULu+pnpx9pB0FmQU1yvg3r+RqLEYO59+D1lR6VQrVN6+njh2Wf/t/Y8imRzZFy8B23/br49mxK/eprBPNF8E5rcpTANc51hv5cIUtL1D5EHzHbNyh1VezIc7DZjsvU2DmMGN/DbSfY30VgNK1wxZKwO3KTwALmDmtrGSdqBFadbQGlUHsE3ex9jay1ZSkGU6mW0sLYIkLGKNMhHdvSmHV7hfBHB7apTmoFSYZuhk2pURu8Q6auFKQEZvkbGcEfblgbrd10O49ap54fZeHyLkxtMZCofHpPNbgA25jbs77s5OVgK5EEZz/V3ncYDuOqK5fkCuFotTePbsobKCqetUzs9o3N7MHDsGBkvaFGYBbiSVZvvjT5AkmcbVJY2ri4lj/fLfpg6PiRdsoOzc3dK6uhjpkrXqKO6oTWG5agq+lAsr7KBu2edn7T7cVAapYJcuo9eFmwska/WJZgKwUjnMrP3+E1QlBS+AK5DoZAqY0TggiDWrRHvOaPL8gGs/NnmO4fXtx+x/dUWjkdzCkmUU0yTbLqMKa+IY5/Pz0xfrrIWb1jtkrY6vEeNWr8///P/w/wrh1osWhVtYP+DCeiA3mkxSPHpGZvDH9z3kntLvtGeM9kch5Pq5zuOAXNjsaK7bc41nshSeP39IOuu3W5TevaM7KMHlp01hGcCN57covHgFQPnta7rVysSx96/Bsv7b5N4Bie0dAIxOh8bpO6zeaAQsiCiuJ5uCEPRurzEqd6PHTl1/Cgw49u7Jh5vKoN2XL+v3bB+ux3q4vgNuNI60c/A+0ezmHGmovvNqW/YmMfP2tyJ2JYUrFDF+3OS9zAFsLvuyx9mVFHqpPHrcjrKvtVSYrFBLbmEpKrJlkWmXiVirr4UrgKYapxGx7SxJo0tWb6HMWfLLudb9YyHczqFl4PZeHyzkJpIUj99DLkCjfMfd6Sk9RwJCUAotC36v8zhA99FBriSR2dmhcHSMrNp1pZulO8qnJw9NILzWug0ScDMHR2R29xDC4vbrLzGGvpF5gECf/LdglwhLHz9HVlWEJWhdntMrjwLlKpLNHm5KEvG9QyI5OzpoNOp0Ls6QGYqaji7hHQYc4zz5cKMxu22vFgHLRL86hzG/qTdY9DfRzILby8A7mrm9viOVFAwDtXyFao4nQ86af/y5zg+4o6XCWsQaZc/Px9dSYYNauMYG1MJtKVHq0TQCiJl98j41e2j39RBuvcoPuL3XuiF3HYALEE0kKB49I10oPpyDRqXE3clJCLl+rxdC7phWDbpezo3bc5RVla2j4wc/rmWaVC/OqF1fgxAL2xT8BNzCq4+JZ3OYep+bL79A3PuEh8b5Vf8WQFJV0kfPiGZsQOjXazTOTuyWsAP5ZVOYFW29v6vl8iR2D0GWsfp9OmfvRqsXTFnfeX9pH66iDOrhJkEIzNINVq08e9zEx9z37QlwZdnuaBZPPHQ0kxo113GBJpqpGnphz4Zuy0IrX6Pqzja53ub3s1SYqneJ1++Qp4xb5PXyBLg4a+FWiRs993GMapGoqttxXSVCJZpGIPnW7KHV6/PH/4//7xBuvchPuL3Xhwq5kXiC4tExmeL2wzmol+64O333pD25sJ7XPATdUT0myI0mkxSfv3hoAtFvt7l794Zes+k6bt4o7qKAK8kyO599Hy0WtysofPu+Ze4swJ3Hf+s8Ll7YJnVwaEO/rtM4fYfRGu3atVKbQixG4vA5SiQKlkXn6hzLAXLTwMdXwAXUnX2UQXKXVa9i3F4hTam1GqhNobD7vqNZvQqVu9HntCrAlWWMrT1ENAZCoFZu0Xodx7jJ8zvn9LNUmGL0iddvHY0nlgfc8T271MJN5OhFbO9rqlMnoTsj7Ktq9qBSiWYfmj0UejW0JQA3hNs5FATc3uvDhdy47ckdQO6HkngGIeQuPPcGRXNXCbnp4jaFZ89QNA2EoH57Q+XsFMs01wq4ajTKzmffR1ZUmrc31M9PXeaf3387aV8PQcpYnMyzF6ixGAho31zRubkaOXaVNgVJVogfHqOl7DfSfvkO/fYahqFydAnvX+k6xnny4WbzaNt79geAThvj6my0ssMqATeTR9ratm+3W3B36XslBU+AK0kY+R1E3PZ5qrUSarvpuC4m72Ns7WVLhakanew2QlaQTYN4/RZ1yuvjN+Daj93Xws3QGbQOTvRaJHtNxweQFTZ7iGUxJRlVWBR6tYW7mXV0PYRbrwoSbu/14UJugu1nz0cSz+q3t9ydnYzU/QxS64JcWP3rvsqX+bGA7mOAXFlVKRw/I7NjJ1eZep+7d29pVyquY8bgwCPgeikTdv+GFctkKX70CeCeYLZog4dJ+3m4Kcuk9g8fqinorRaN07eIoQSmVdsUosVdYtu7wKBc2NkJkli+XNgigCslkkT2jkBR5m744DvgJlJ2RzNJgn7PTjRbQ8teAZjZAlbKjiYrzTpao7IWwLVkhXZ2G6FqSMIiXrtFM73VffUbcDvRJO24DYGxfodUpzb692BFgGtIMuVoFmPQzWyrVye2QDezVq/PP/cX/0YIt160CriF9QMurA9yo8kk28fPSQ9aTAoEtZsb7k5PMPrBN4OADwtyIYzmTtKqQHdRyI2l02y/eElkUFWhVS5RevcO09ADA9xp0VuAzP4Bmb0DLMvi9qsvMAfNWyZFb+3bk+fzCrjDx0azOdJHz5AUBWGYNM5P0Ou1kWNXaVNQU2kSB4P96Drt83d2aSzP608BgqHbXmwKkhaxGz4MLBN2ollz5rjJj7nv25MPNxJD2j1ceyUFu1RYFjNrv88sUypsacCVZDrZIpYWHdTCLRHRvdd99bMWbleL00rkhpo9VFwB1/n8/ARcE4lyLIv+0M2sQRxj5rjh2yHczqFVwe29PmTIjSVTFI+fPUCuZVlUry4pnZ9iGsaM0f4ptCwEtdbjAN1NhlxJksgfHpE/OABJwjIMSidvaZZKLsfPmu/97UUBt/jxJ8TSWfRuh9uvfryQ/3biXj1ElOVIhMzxC7Sk/fVq5+6W9tXFwx5gcZvCIk0f5EiUxNFzlIHHs3t5hrkuH64s24lmiRQIgXF3jahXZo+b+Biujy1WSeECyfHt3CI+3GVLhcm9Lmr5GsVlLecaU6PscwLuWC3cRoVov+06zo+Iuxvg9tUojYdmD/1Bswfcx7nscdqevXYzq0TT9JQIEpDvNUjivZtZu6+HcOtVq4bbe33IkBtPp9l+9uKh45lpGlQuLihfnj90cFqFQsgNaq1gF9sE0PUTcic9n2gyyfaLV0RTNtS1KmXu3r7BMoyVA66sqOx8/3NULUK7Uqb67o3L3PNFcO37097Q398YqYnbblM/eYsYyoxfhU3h4aYsEz84JjJIqLJ9uKO+YK9wYE/nDk1ebArDiWZmrYJ159jLqgB3pJKCsLuZORIC11IqTNfRypcolhg7btb848/V/QPJZMCFbnoLY+B9jbaqRLtOP7C/gDu8vv2Y/a+uaDRSBSxJQjUNMq0y6gZ0M8v1m6SEs8rF5DlavT7/i7/0/wnh1ovWBbf3WjfkrgtwAZK5PNvPnhMftFQ0DJ3y+RmVq0vEUAecoPUhQS48HdB98pArSeT29ykcHYMkYep9bt+8oVOrzrQp+A24kWSS7U++hyRJVE/f0S7djY1znkM3wB1ba8ob+vCxkXSGzLMXti3ANGmcvkNv1EeO9WpTmAY348dO3s+wD9doNemen4x2EZu6vr+Aq+S2UIt2FzGr1cS4OkdidR3N3h8mQXEPKWX/Tadagtqo93VVlRQsNWIDrqoimQZqaY21cJNZ+gkbxiKdBtFW1TOw+wm4hqxST25hKQqKZZJtra+bWS2Soq3GAMh6bNcbwu0cWjfcwvoBF9YLuelCke3j50TjttdQ7/e4PXlHfahN6SoU+nKDXCvYxR4T6M4LuZFEgp2PPn7ocNa4uaF0+g5hWdOh0SfAvX+jSu3skjs8ths8fPVjjMHXzm7RW/u++3NbJIoraxEyz4ZsCrc3tk1hSEHYFFx9uOkMiYNjJFnB6vfonL4b7SI2+hQDBVw5mUbbs2vzil4P/fIEyTRmjpv82OQ923ubDLj2sYMbuSLSoBEGjRqUb1zHBVoqTFHQC/ugRdZeC7cfT9FL5YHZzR6c933tZiYp1FNbmINuZtlWGU2Y7uOmPLdlAbehJWhq9t81L+16Q7idQ5sAt/f60CE3u7NL8egZkaj9aa7banLz7g3tWm2l+wghN+j1glvwqUDuJC/u1vExuT07M73fbnPz3bfo3U5ggDutwYPR63Lz5Rcz/bf2/VnPbfR5jo6dAMPSqE1Bbzapn761k5kGWqkPNxqzfbiRKMI06ZyfIJxdxDzOuXSiWTSGtn+MpGkIQ7crKfS7E8c45/QdcNNZpK1d+0ksUSpsacCVZIzCcC3cGzRHm2ev14CvzR76HeL10vTzHBDgDnczk4Ug3aoQtbx1M/MTcMFu11v32K631dP55/9PIdx60j3cfi8uoynK7AEr0IcMuZIksXVwSOHwGEUZtCmtVrh994Zeuz1jtL/60CAXwmjuJG0S5MYzGXY++hg1EkFYJndv39Is3fkKuG5jx/y35Tsq794+7N/5NBa1Kdj3J7+pDx9rV1N4jqTIWLpO/eQtpqMjoh82BS8AJSkKiaPnqIPkru71Jaazi5jLHM77SyeaqSrawTPkaGxQSeHMl5a9CwFuPIm0YydH0uvCzQWStbpSYe8Bd6gWrgC1doc2dk4m72Ns7aWbPcToZgt2swe9R6J+hzylGYcfr9XsbmaCdLtKzOy7j2NU7ud8fsBtqTHqkRQCSJg9cv3mRMD1Crfre+feUFmWhbVCr6ebBOv/zLGuzz1CCErnZ3z32/8/ypfnCCFI5fK8+OkfsP/xJ6iRyMr2ss5rQQz+W/m6YiQRPeC1RKDXmV/n0BLWw/9zre/xXE47D87n0KnXOfvR79GuVpFkhe1XH1F88WrsnWd4unnPgdtYyxJYpkH57WsEgsRWkfhW4WHvzufrPF+WY97huZ1Pf/h8WI4H7+/2alUq336F0e0iaxq5Vx8THdTGvZc59DvsPAvDazjXt0Yec64/Pk6YJq2TN/SqZZAkYnsHRHb2GX5hhMsczvuW5XjMZV9j4+5vGwb62VusVhO7osIxUjo3e9zEx0Z/PvLcndeGNeF8dlqIq1O7lXI0BnvHCFUZGTcsa8pr4nXPztdHCJCEQC1fI7fqIIGRK9JPZhyvyeR9jK3tfH1Gzsnoz0fH2deiqneJV2+RhIWpRWnldjCHPghOvTYWfK2G38vufywjyLTKRPpdhCTRSOTpDDywE8cxKvdz7lx79u9S0uiS69XtIL8SpRxJY0wZN0th5JbRyK0y8ulsM9j/Q47iAmixGDvPXpAp2J1wLMukdHZmg+8HkHR2rw8hkmuv93SjuctGcp17z+0fUDi2k826zQY3336DpTvrRk4eP489YXjsfRQmvbdPdv8QISzqF+c0b65nREInV1KY9LzmtinIMunDZ8TyeQB6lTKN81OkgMuFuY2LbBWJ79j2EaPVpHP2bjQyB45xHqNejnHutVDf31Z3DlCyOQDM8h1W5dZ17cBLhe0eIWmaDbo350j9/sQx48/Nfe2Fmj2k81gZ+1pRWnWUWglFGo9szpp/6W5myqCbmbL+bmbNeJZe1Pa+rqJdr9txXVmjEssgkIhaOlu9BurQlts9nX/+L//N0JbgRW5we691Q829PnTIjaXS7L54SWJQfkfvdbl5+4ZGubTSfaz7eggh16f51+zNnfX0vFoV4pkse598gqyqmP0+199+Tb/lrKU5eew8gDvpK+itF69I5O2koW6jRuXdW4RhjI19P2+wNoV4cZvU/qENle029ZM3nrua+Z5olkqTOHxmJ5r1urRP344md40+Pd8Bd/gxZauIWrD9yVa9hnFz4foBIlDAVRTYOUKKRueuhesn4AKYyQxmtggSyO2m3ezBBXDH9+If4I50M7NMErVbVMs9CTBIwB1u15vsNkn0W44qF6vpZtaXVcrRLJYkEbEMtnp1tMHSIdzOoVlwe691Qw1sBuDCeiE3XSiy++IlWsT++qRdr3H95jU9h9cuaK37eljntRCC7mStEnKH96xGo+x9+hnRRAJhWdy+eU2rXHIF2XkA123c/ZtUolAkd/QMWZYxDYPquzf0HOW5Rtfwp5qCG+BqqTSZZy+QVRXLMKi/e7M2H64ci5E8eoGsRRCGQfvsreeOZn4DrpzJog28r1a7iXHpf6kwT4ArybAzVAv37grJ8fqsttmDnfAmdzuoles1djPbxtIiG9CuN0U7bpdxi/daJLuN0b8LKwJcXVIoxXJYkoRmmRT6dTRJhHA7j7zCLawfaO61CZC7TsCVZJnC4RGFg+NBHUFB7fqa25O3K+10Buu/JkLI9XH+Rwa5IyAoK+x+9BHJLTuSWnr3lvrN9cKAO08HMzUWY+vFKyKDUn7N22vqF+cjJsZpUdwgyoVlX7xEHQBU8+KMnuMbnpUlmqkqieOXqLE4WBadi1OsVmN03JTnt0iimSvgJlJo+0fYpcK66BenSFOihIHWwt3eQ0qmbaIq3yA1Rz8QrazZQzRu18KVJKR+D610tZ5uZpJEJ7ONGbHb9cbrJTRjPe16O5EErYT9DWms3yHVqa0FcA1JoRTNYMoKqjAp9OoY/X4It141D9zea91AA5sBuLBeyNWiUbafvSBbtL9yMw2dm3dvqd1cr3wv674mPiTItdd8mqA77Wl5ieIWnj0nt78PQPX8nMrF2VyAu2iLXiSJ7MER6R27qUG/3aL85jXWUE3RaYBr35+8xtj6HgAXWSZ99IxYLg8M2vZeno+MWxXgIsskDp+hpTJrr6QgRWNoB8+QVBWh923AHa7LGzDg2scObmztIA26VK612UMkilHYx+5m1rcBd+oHs/kBF9xfY7d2vfFGmUh/1Pu6KsDtanFaiRxCgqjeJd2uugLutOe2PODKlKNZDFlBERbx+h3/q/9zWC0hMG1KRYUPuaoCgN7rcfHNV7z90f9It91EUTX2P/qEZz/5Bx6iSKvSuittrPN6WGWFhfdrPq5KC57XnXIu3Z7z8D5LJ+8onZ4AkDs8pPD8hWtVgknPzxrJvp497iFLXghq56fcffcNpmEQSSTZ+d7nxHI51+c2q5rCyHOclgk+ITsey6Jx8pbWoMFDvLhN+sUrkN/H5ZyVFNyqGYzv2z0zfOI4y6J9+pZe5Q4ku5KCVtwbfX4uazvvL1tJQfS69M/eIPo9JC2CdvgcIrGRMe7n1lnZYMqembLn+7vlG0RlEFHPFSBfdB3nVjFj8r5mZ+cPzyH3e6i352AYCC2CXjzAHIK3eSppTK0M4LKP+/cNCUG8fofabQESnfTWQ5LX5P17e96WcH+tnO9Z9w/F9A6pVgVJCHpajHoiP/q3wTnO4x49V50Y3FaFRaFXQ7UMTEmmFM3iRSHcLqFNAFyYv8xPIHsIGDRmqdOo8+Z//B2u373GMk0S6Qwvf/oHbD9/gbTiiOq6r4sQcn2ef+i/ZbQI5Lo/Nh1wqxcX3L55DUKQ2dll+9VHU8tuOX82L+DC+zeqbr3GzZe/T7fZQFYUtl58RGbQPnjyWqPnxe9yYe2ba2pvXyMsi0g6Q+6jT5C09+UETY9v0uP7nv3G7BzXvbqgc3MJQKRQJLJ/5Hi+o/O5zbl0qTBdp3/2FqvbQVJVG3AHiURTx03Y19KAWyshSjf2k8jkoLg3FXBdr8dlAdfQ0e4uwNARqopePMAYqnu/CsC1LAsJiDXKaJ0mINFNbdGNpabs3/vznhdwo0aXdKuMJAR9LUotuYU5/DswB+B6vpYnHKcIi2K3hmbqRK3ROrxuWsiW8Hf/7t+ddwh/9I/+UeLx+NzjVqFFbAlOrfsr6XttglVhnTYFADUSZfflKzJbdr1Lvd/j+s13NMvlGSP91yZcFx+aXcFe92lZFua1KtzvL7m1xd7Hn4AkUb+5pvzu3cQ5lykR5hwP779uzOwfktmzLRK2TeE7rKHqBYv6cMf278GmoMbiZF58hBLR5k4087uSgpbJkTiwgd9st2ifvkMeTu4CxziPX4MP/9yDRQFZRts7Qk7ajSeM6wtEy5kMOM0aMPmr74UsCsk0UtH2vtJpwe2aupnJit3NLGJXdNBKV6iGM7nL2/zLdDMTQD+ZpZ+wv3qPtmtEOw3PX//72c1MVzQaqYKd3GXoZNrlEV+yV4vCtD17sShYSHT6ff7kf/y3gvHczvuGLUkS33zzDa9evZp3qZXID7iFzQAZ2AzAhfVDbiq/xe7Ljx5a+dbvbrl+893KE85gM66NEHIDWsOH87os5E4D3FShwO5HH4MkUT0/p3pxPjRu/PjhnzthZqrv0QVwo5ksW89foqiq3QDizWv6TUdC1QgsBOfDlVWNzItXaIkEwhI0z97Rr1VHxvntw3UDXCWRJHn0AkkZlAo7eYM0XON06treAHfavkZq4e4doqSzNuDeXiMaFde1/SgV5gq4sQTSzqE9UbdjdzMbQhQ/auF6Atzhdr2WhVa+RtX7jnFu+/APcAF68TT9VA6ASKdBtFX1fK35CbiGolJPFrBkGdU0yLbKKIiJY2Y9N8/X8oTj2n2dP+EBbhd+x726unoIo8/6P5FYrfdxXVq35/Jem+TFXadVoVkp8/qHv8XdxSkCQaa4zcs/+IdIbxVWvpdNuDY2wa7w1CwL4I9twatlwe0cTnqe9/tplkrcvn0D2B7c9M7OyHzO44d/7vwaeKrv0XEO7r9u7NVr3Hz5Bb12C1lRKXz8CclB0tmkeZbx4Y6Om/B8DJ3q62/o1apIskT62QtixZ2RcX53NBv/SnawTrtF8913WHofORoj8eIjUN/bJaavPeVrcMc4dx/m+9fWuDrHHHRWU3f2kHOjXd4W6ZA1tmcv3cy6bcT1qV0DNxaHvSPEEDT50c3Mi0VBEhZq6RKp2wFZRi/sYURijnFu+5ijO5fLPuxx9nUY7TSIDj5s9ONpuqn81GttZI4FLArDa9uP2f+qpkGmWUI2TQxFpZrcwhhCWK8WhZl7djlf8/4dXwhuf+EXfmEui8Gf+lN/aiphPzWtG2LutQmAC/NflL6ubVncvnvL29/7Id1OC1WLcPjZ9zn49DMUVVv5fjbh2lj3dbGOy+H+DWdVoLuovLb5nQa5zv0A1G9uKJ+eAlB4/oLEoJPX/VzO450/dwLuVKiYALim3uf26y9plm6RsKsq5J6/9N2H6zXRrP7uDe3bGwCS+wckD45GXrVVtey1el2a777D7HWRtQiJ56/sFrVDa7tBgh+AO/yYcXuFUbLPiVLYRi7sun548ANwx/Z8f7PXRVwO2vVGona7XsXfdr2zkgABu11v6Qqp0wJJQt/aRY+Oco/b78jY2ksCbqTbJFYvAQI9lqKbLnj+MOUr4FoG2VYJ2TQwFZVaqoAhyRPHzHpuiwKu17/hYSkw/LMlOLUJX0VDaFMYXr9w9Izi4TGSJGEYOtfffbvyDmf32oTrY93XxjoviadiWZj0NNw8j/dlwoRlcvHFF+idztCY0WMnze+HTSFZ3CZ3dIwkyejdDqXvvvHFh+v1a+nhY+OFbVIHRyBBv16nfvJmoZa9Xi0KbuMkRSFx/AI1nkRYFp2zd4jOqB/Y69e8S3czy+ZRd2yf9Fq7mQ236zUMuD5DGrKUBd2u98GiAJj5bayEXZNXrd2hOV+bKb8jnn2lLj+3x9nXoR6J080WAAm13yFev/N8rflpUTAlmXqqgKmoyJZFtlVGE+bEMbOe27wWhXZf50/+lb8dlgJbpzbhq2gIbQrD69+dvuPN7/0O3XYTVdU4/Oz77L36eOUVFWBzorjrvDbcIpCrWftpWBYmnUO3CG7p5B2tSgVJVtj5+BMkZfy6n/bV/7w2hZHnMYjGtO5uuf3mawxdR4vF2f7s+2hD1jXn83FGcN1sCl6jdsPHdkq31N69RliCSCZD9uXHdovYgbxWUhjf83wRXGGatN69QW/WkWSZxPEL5NToG7fXKNiyEVyzVkG/OgMhkDNZ1L0jxBCeuFkbxh8bXXvuCK6hw9Upot8HVbUjuJo2ccz4c3Nf22uVi/vXVAKUyi1ysw4SGLkiesJZvWDyPsbWnlYZwOXn9jj7OtT6HeK1OxACIxKnk9meXq0ioAiuIiyyzRKKoWPJMrXkFrqkjIyxXL798COC60WBvaOfnp7yL/1L/1JQ0z8qbQLEwPq/jr7Xur8s6LVavPndH3J3bntxc7t7vPgDf5BoIjl7sM/apA9Aa13/iUMuLA+6XiB39P5kwL357lv0bhctFqP48tXQ8eN7dZvbq03BzYfbbzW5/eoL+u0WiqpR/OSzkXq4znm8+nCd19F0ELP/7ddrVF9/gzBMtGSS3KtP7GjhQH6UCvPyNTjCon36jn6tApJE/OAYJfPePjJ7bXfAHT7SC+BajTr6he19lVNp1P1jV8CdNue0+qqeANc0bMDtde0PHbtHiEhkZIxbLVw/APd+HglQanfIjSoARrZAP5kZO87L/PMA7ug4+zpU+13itVskYWFEYrSz21iOca5rT7km5wVcWVhkWyVUo/8AuH1ZcR/ncY+zANfr3+rA4LZcLvMbv/EbQU3/6LQJAAPrh5h7rTuKixDcnrzl5Isfofd7ROMJXvyBnya/f7CW7WzC9bHuKC5sBuSuEnQX0TTInQZ39+tapsn1t98gLItkfov07u7DXsaAYAo4Ot/A5/fh6tx+8xWdWhVJktl68RGpXUdjgwUA1zluOojZ/xrtFpXvvsbs91FiMXIffYo85H0Nuhbu+3Mr6Fycvm/2sH+Imnckd01dewpEDd2eDjkDwG036V+c2ICbSKIdPEMMWUT8SF7yBLiWCddniG7nPeBGY67jAgXcehm5XgHAzOTpp7KYYhz8Zs3vFXDHxw0AV+8Rr9qAa2rRAeC6f/hYxC/tDXAFmWb5AXDryQJ9WXUf57Ku8/40wPWqhT23s2rdvn79mj/zZ/4MpmlOPW4TFJTndpI2wWd5r3X7Le+1bi+uoqrsf/wp6bxdRaFZKXPxzVdYa7p2N+Ua2YTrY82XxkqvzUXPt5sn180neb9OZmeX7ZcvQQhuXn9Lq1z21KbX+Zi9h9n+1knz3HvqsodHpHdssG2X76icvHP49IbXCrBUmKaRffkxaiyGMExqb7/D7LRHxq2qFm50e5dYcdDKuHRL7+bK1U8baLveWJzIwTNQFESvi35xMlqyzIfyU548uJIMOwdI8YRNYbcXdjUDl3Fe2/Uu8tqYqSxm1n6/UJo1lHoZRRr3ps6a36sHd3ycvZapanRyOwhJRjH6xGu3I+W5vHpwxx+b/PPhte3H7H8tJBrJPLoWRRKCTKtC1NLdx015brM8uO2+zv/y//L/DabO7f1GJUmaGuWQJCmEWxeFADOqdQMuQG53n90Xr5BlmX63w9mXX9DvdGYPDEDh9TGqdV8ejxVyZwHuzquPSG9vA9hNHk7ejYRXxhJzpiRwLQu4iUKR/PFzJEmiW69RfvPdSCjMj0QzL4ArKQrZF6/QkimEaVF/9xqj1RwZt0gt3EUgKrJVJL5rf5vUr5ToXV2sB3AjUbTD50iqiuj30M9PkCxj4hjnnPMkL7nVwn0PuBJsHyAlkva1cXuJ5PjwsTLATWYwByXTlFYdpVZaD+AqGp3cNkJWkE2dRPXGd8B1W9v+uf2vAOrJrfeA264QNf0H3K5heILbhd9B9/f3+dt/+2+71rb97d/+7UWn/iC0CV9Dw2bZFNat6vUlb3/0Q/q9LpFYnOc/9dOktrbWspdN8uJuwjWy7stjlTaaRb25k6wKbl/PP/hvX39H5dxu6pDZ2eXg859AiUYnjh8eN+mxZRPN2qU7Sq+/xbIsYpksxU8+Q5KntT+dXCps2j69WBSEaVJ98x39Rh1Jkcm+/Agtkx0Zt0ipsEXa9fbLd7QvT0EIIvkCsYMj14QxPywKY+MGt0W/h372FqHrNugePUco2sQxzjnnSV5ya7v7cJgQcHOOaDUGoLuPcORKuFkURuZxeZ6THnN7bZRWHaVyC8IGXSNXnGpRcPUlL2lRUEydePUGyTSxFI12bgdzin1kEYuC29r2z+1/JSDTKhPpdxGSRD2Rp6dERuZwsyg45/fDorAw3P7Mz/wMv/Vbv+X6+KyobqgQcJ1auw8XO9ns7e/+kFa9iqKoHH32OcWjZ2vbT3iNDO1BfFiQC/N/uJjkx50FuOWzUy6+/DGmrhNJJDn8iZ8cq4PrBqfTfLiLJJp16zXuvv0KyzSIJJIUP/0MWdMmznH/fN/fHn1s0Vq4gw1Re/uaXq0KkkTm2QsiuffnBBYHXK8F+O/v6tUK7QsbcLVsnvjhM4b/LDgB123OpQFX79M/e4vQ+0haBO3wOUJdA+AC3F4imnUbcIt7CEf1gkUBd97XRmk3UCrXIMBKpDFy266A69yLv4BrkKjeIJmGDbjZ7bUBbrpdGQLcHN0AANeLFobbf+vf+rf4w3/4D7s+/vHHH/P3//7fX3T6D0abBC+bADCw/iiuaeicfPEjSpd2RKt4/IyDT7+3NuvEJl0jm6B1A669h/VArtfXYF7A7dRqnP7e79Gp15EVu0xY9uDAfY4pCVzLJpr1Wy1uvv4So9+3S4V9+j2UiHs0eRHAte+7A64Q9o36uzd0yyWQJNLHz4k6uhsG0c1sdA77X71epXX2DoRAzWSJHz1zJNRNW9s/wMXQ6Z+9xer3kDQN7fD5aFe1FQDuw6F3V4hG7T3gJtOj8y8AuNP27Aq4nRZq+R5wUxj5nbUArmw5AXd9Edx0u0K030FIEo1Enq4aHZljFYC7MNz+kT/yR/j5n/9518eTyST/+D/+jy86/dz6i3/xL/LixQtisRg/+7M/y3//3//3K1t7WW0KvMAmAcya9yEEN29fc/HtVwhhkSkUOfr+TyAryuyxASi0KTj2IcbfNNazj9V/2+D1NZgHcAUCU+9z8eMvqFxcAJA/PKLw/IV7BNSxDz8B1+h2uf36x+jdDooWofjpZyjDnbuEcz1/AXf42MbZCZ27WwBSh8dEC9sjx60KcI1mndbpG7As1HSG+NHzhQHXzdrgDXAN9LO3WL0ukqqhHj4HLToyxv2Dw/KAax87uFG6RtSrNlEVdxGp9QCu3G2hlq9ACKx4co2Aa9qAa+hYijqwKCgTx4zN4TPgptpVor02QoJGPEfHJ8D1+vd2Ibj93d/93bneaH//938fY6iziN/6G3/jb/Arv/Ir/Nqv/Rq//du/zU//9E/zT//T/zQ3NzeBrem3NgFc7rUJ8AIbALhA7faGky9+hGWaJLM5nv3ET62lbe+9NuU62ZxrZN07sLWOa9UL5DptCtPe0B9sCqcn3L55DUKQ3tlh9+NPR7JLpsGpn4Br6jq3X3/1UAt3+9PPUOPT2p8GB7jNizPaN9cApA4OiRV3Ro5bGeC2mjRP3yAsCzWVJnH8AksMvTZT13a8HssArmmin73D6naQVBXt8NkI4LqOm7SPZQG3fIMYlOeisItwNL9YHeC2UUtDgLu1i7nAa+8L4NZukA0dS1Zp5bYx5NUCrhADwO3UHgC36RPgetVCcPuDH/yAUsl7y9Kf+7mf4+TkZJGlPOk/+o/+I/7lf/lf5k//6T/N559/zl/+y3+ZRCLBX/2rfzWwNYPQpkTnYJPgZf37aNdrvPv938XQ+8SSKZ7/1B9Ai0ZnDwxI4TUyqg24RID1XateIffheA8wUb+54eqbrxGWRSKfZ+/T7410M5sHcN0SzbwArmUa3H77Nb1WE1lRKX78GZojgWhVgNu6uqB1fQlAcv+A+M7uyFkPAnAnjTPbLVonbxCWiZJMkXj2YrTG6dS1fQRcy0Q/twEXRbUtCpHY7HGT9rE04N4iamX7dmEHkc6Ozr8qwO113gNuLIGxtbMmwLWIV23AFbJKO7szBriukX0fANd+7D3gxkYA11mjOBjAXagUmCzL/NIv/RKJoZaJ0/SX/tJf4osvvuDVq1ezD55T/X6fRCLBf/Kf/Cf88T/+xx9+/gu/8AtUq1X+zt/5O2Njer0evV7v4X69Xuf4+HilpcBmKSwFNapNKBUWicU5/vwniURj6P0eJz/6XfSh62jVCq+RUW3AJfKgdV6v014P2aVUkX1/vFRYLJVm/7PPkFWVfqvF5Vc/RpiW+xwLlAqbNsd9mSRJlil89AmxVBrLMil99w16q+XY/+Tnad/3tsfpZZLsfxPbuyQHzV7a11e0b65GzvgiZcKc600r33R/U4nHSR6/QlIUzHaL9ulb5CE88FpqCXAtL+alTBiyjHbwDDmesCO6FyfQ784eN2kfC5QJs48d3MgVkXKDCjflW6RGbXT+BcqETduzW5kwKxLDKO6DJCF3O6iVaxSPvxtTX5s5y4RZkkwnt42lRpAGEV3VMl3H+V0mzH7MhtZWPEM3mkQSNvDGjdFrxGuZsI5u8Kf+2t8JphTYP/aP/WN89dVX/M7v/I6n/3/u536OuOPrJL90d3eHaZrs7u6O/Hx3d5erq6uJY/7sn/2zZLPZh/+Pj4+BzYgS3iuMzo1qE16bfrfDu9/7H+l12miRKMef/ySKFloUNucaCaO48D6SOymi6xbBte8PR4fs291mg/MvvrArKSST7H7y2UIWBXtt9wjuSPRsQqROWBalb7+h26ghywqFjz7xHMG173vbo5cIbvv2muaFnWya2N0jsbMXaATXbZzZ6dA8eY0wTZRE0rYorCWCa6FfnGB12qAoaAfP1hfBrd4hqoNvlbe2EZnc6PwBRHAnvTZyv4t6dwmWhRWL2xYFj78bU1+beSO4wiJevUU2+ghZGYvgTno+k/Y0/tjstd8/ZsNqslMn1m3ZHtxENvAI7sJNHDZFFxcXHB4e8pu/+Zv83M/93MPP/+1/+9/mv/qv/iv+4T/8h2Nj3CK3n8UkFEnaiCjhvcLo3Kg24bVRIxGe/+RPE4nG6LaanPz+762tmxmE14hTG3CJPGgTrtexpgnSeGTl/e3J0bJIIsHh9z9HVlU6tSpX33yNJCbP4VzT1wiuJFP46GNi6QyWaXL37dcYjiL+q4rgxos7pA4OgfVGcOVYnNSzMIJrHzu4kS0gDTpOUrlDqldH5/c5guu8PxLBLeyBLNuWhfIaI7jZbSztPoJ7i2oZruOCjOC2Yxk6MfuDaapTI6HPF8Ft93X+13/97wbXxGFTVCwWURSF6+vrkZ9fX1+zt7c3cUw0GiWTyYz8P6xN4v0wOjeqTXhtjH6f0y9+9ODBPfr+TyCtETDDa2RUG3CJbJSmRW/Bmwe3325z+dVXCMskns2x8+rj6RHQBSO4bnM8RHCFRem7b+k2G8iKQvHjT1Hjo/a4VUVwO3c3GxHBtbqbFsFtrT+CWyshKnf27XwRkcm5jvMjguu8PxLBLQ0iuNH1RnATtVtk/T6Cu40hq1P2H1wEN9GtE+/aHf+a8SxtbfRbfa8R3Fl69HAbiUT4mZ/5Gf7e3/t7Dz+zLIu/9/f+3kgkd15tAkTdK4SXUW3Ca9Pvdjj54keYpkEinWH/o0/Wup/wGhnVBlwiwGZcq5O0COB2mw0uv7KTzJJbWxSePV8j4H4zBLifoMacEOX+XIME3Ph2sElmbuMmAu46qihYFvrF6YYAbnkEcMnk1wS4vY0AXGmjALcxBLiZQAB3brj9b/6b/waA/+6/++/mHRqYfuVXfoW/8lf+Cr/xG7/Bj3/8Y375l3+ZVqvFn/7Tf3qpeTf1jWmd2hx4Wf8+eu0Wpz/+fYQQZIrb5Pb217qfEHBHtQGXyEZrEcDt1Gtcf/sNAJndPdLbO+sBXMsG3PsqCoWPP0WJjHZCmga4XvfoGXAHDV+Se/vEi9ubAbjP1gi455sSwQ0B1x4zDLg3jx5wvWhuuP3P//P/nH/wD/4B/9l/9p8tsFww+hN/4k/w5//8n+dXf/VX+YN/8A/ywx/+kP/iv/gvxpLMFtEmQBRsDrjAJsHL+vfRadS5efcGgN0XL4mlUjNGhAq1ei3yO+sGE61KhdKgtGPx+Qti6czCgDusRQD37rtv6HfaKKpG4ePPkB01qN0A1+8yYZ3bG1pX92XCDoltFdcGuK2RCO5ijR5gScAVYhDBHUoyW1cdXCfgpnOj839wgCueRAR3luaC21//9V/HMAz+yX/yn8Q0Tf69f+/fm3O54PSv/Wv/Gu/evaPX6/EP/+E/5Gd/9md9m3sTIAo2C3A3RZvw2pQvz6mX75AkmcNPv4+sqrMHBaRNuUY25QNQqOmaFr21709+HauXFzRub0GS2P34E7QptgCnRoFzGjA4xk0C3EFSmd7toEYiFD/5FElxZoMPzx8c4LZvrmhf2xV6UodHxPLBtup1G2d2O7RO39fBXbSTGfjlwR0A7jobPdTKo1UUAq6D67y/eYD7eC0KXt9Z5oLbX/u1X+OTTz7h3//3/30++eQTfvVXf3We4Y9amwBREMLLpury26/pdTto0Si7L16udS+bco1sgtb9a7sJ1RLu5fY7Owtw3ea4ffOabqOBrKpjXcyc8zjX9hNwLcPg7ttvMPp91GiMwkefTC2ZEWijh+tL2rd2Z8zU4TGRbG7kuCAAd9I+zE77odGDmkoTP3zG8J+F9QCuinrwDFSnfWRFgFstOQA32E5mzvuugJtfrJOZc8/+AO56yoSNA657mTCvmtuWYBgG/+a/+W9irrH00boUAu6oNgVwN+F1sUyTi2++AiC7vUs8nZ4x4ulrU66PUMvJDSSEEFx98zVGr4cWj1N88XIqxAYJuKbe5+7brzANnUgiydarj0dWGweGAAH38pxO6Q4kSB8/R3NA1Kpa9ZqdNq3Tt2BZqOkMscMjV1CdNacvgDto1asePkdsBODuIFKjf6eDANxJc9iAe9/JLL5wJzPnnpcH3PXVwR0F3Ol1cL1obrj95V/+ZQD+lX/lX5l3aCgfFQLuqDYBcLvNBpUb23e3+/Kjte5lU66PD1mbFLW916LRWzeQMHWd62+/BSFIFYpjCWZe17f3MBsKJo4bvJMavR53332DZZnE0hnyz1/MgEX/AfdezfNTupUySBLpZy9Rk6Ne/JUBbrtF6+wtCIGWyRE7WBxwR45z2ZNz3FiSWa+LpKpoh88QitMfvULAfWjVu4tIBgu4bq/NQ6MHMdyq173JSpCAG69tRqOHYcCd1ehhlh59KbBVaxMgKtRkbcJrc/vuHaahE0umyO1OrrP8IWlTPvyEml+zAPde3WaDu0GCWeHZcyKJhO8VFJzHjtXuHbyT6u02pdffIYQgkS+QPTwKBHDd9jx8XOPshF6thiRLZJ6/QnHU410UcN2Pm3y+jFaT1tk7G3CzeWJ7hwsB7hgsDt32Brgm+vm7AeBqA8B193kGCriVO0S9Yt8u7CIcHz5WCrgPEdwERn5xwB2dfz7A3aROZjbg2q21l4ngLg23jUZj2SkenTYBomBzonMhwLyXaejcnr4DoHj0bK3tsjbl+vgQtYlR23t5jd7OM0/t6pJmuYwky+y8+nisqckqAbfXqFMeVDBJ7eyR3N7xHXCnQ837G/WTN/QbDSRFJvPiFXJ0NKFqEcCdBhOugNus0744sQE3v0V0Z289gGua6OcniH4PSYugHT5HyO4JuIECbvkWUa/aRFXYQzjaOa8McHud94AbTy4MuOPPc1HA1R88uKbk/D1eFeC+b9U7CXC9aGm4/SN/5I9wdXW17DSPTiHgjmpTAHcTXpfK9RW63kONRMgUiuveTqgVa5PBdl7Nit6OJJi9/u7Bf7t1/Gyqx3bWOssCbqdSpnpxBkD26JhYNus5Gup8M3Zd2yvgvnuN3m4jqyrZFx8hOcqVrQpw9XqN9pV9TiKFbSKF7amA6zb/8oBr0D9/h9D7NuAePENIysQxzjn9B9wbRKNmE1VxD+GIrq8WcK/fA25ue42AezMAXJV2dmcMcF3n8Blwk906sd4w4I5+MJylpeH2Bz/4AT/7sz/Ll19+OfLzH/7wh/yz/+w/u+z0oUI9PglBZVDzMr+/3sYOoULNIy/RW7cPkJZpcvP6OwAyO7skcrmFE8zG9+X+oNsH6+b1Fc27WyQk8i8+Qkss36bXOc4L4ArLovbmO4xuFzkSIfvyI3CUK5sGuO57XgBwqxU61xcARHf20PIFV8Cdlvm/NOAa94CrI0WjaAfHiCGIWgXgPqh0jWjW7W/ZtvcRMWcpqlUBbhu1fA0CrEQKM1tcH+DWbpAMHUsZB9yp14XfgNupE+u1B4Cbo6tGPQewlobbv/bX/hq/+Iu/yD/6j/6j/Lf/7X/L119/zb/4L/6L/MzP/AyK4xf4qWkTooQQRm+d2oTXpXp9hRAW8VSGWGp9lRM25dpYl1YdRH0sUdt5fldn/ToNz9Wp16lc2PBUfPEKRdXmSjCbBm/zVlAAqJ6d0KnXkGWZwqtPPDd5sO9726cnwDUNam++xez3UWIxsi9eIeQpEbGRtbyfIy8Q1S/f0b21v22N7R2gOcqVrQxwdR394h3CMJBicbT9YwTSxDHOOf0A3JHD7q4QrYb9B2PnABF1+jwXA9zR4zwAbreNMgBcM5nGzBbWA7iWXUVBMo0B4G5jSu6vTRCAC/eAWyM6ANxGPEffYwTXl4SyX//1X+dXfuVX+KN/9I/ykz/5kzQaDf7BP/gH/Kf/6X/qx/QbrU0AKdgciNkUwF23TF2nfncLEFoTPhA9FrCdpUWit8O/95WzU3rNFoqmUXzxYsJYx/05KijMDbhCUH7znd3FTNPY+ujjsU88qwJcS9epvfkOYZioiSSZ4xcjM5rO6NXIWv4Cbu/uhl7Z/vsU2z9CTowmVK0KcEW/j37+DkwTKZ5A3T9aH+DeXiLazfeAGxmFqEUAd5HXRum2UCo3A8DNYGa21gS4JonqzQBwNTuCO+W18Rtw738sAalOjWivMwDcLF60NNxeX1/zr//r/zr/wX/wH/D555+jaRq/+Iu/yD/yj/wjy04dKtTC2oQPHY2KXW4mmcutdyMfqFbJmo8RbP2M3o4eK2x7ghAk8lsktwozLQheE8zm2ddwm97Sd9/aNXDjCfIvXs6ARXe4nxqF9rBPs9el+vY7hCWIZDKkDo9XDrj36l5f0q/a5crih8+QYg7bxtS1FwNcJjwm+j36FydgWciJFOru4UJf99uPuY8bOc4NcG8uEZ0WyDLsHiK0iOu4QAG300Sp2h8+zFQWM50fuS6nXfdBAm4nu421NsCtEu13iPfbeNHScPvy5Uv+6//6v+Zv/s2/yW/91m/xt/7W3+KXfumX+HN/7s8tO/Wj0SaAFITR201Tu1ZFIIgmkqiRyOwBoR6lHiPYztIkwBsD0inRsX6nTfnMTl4qPn8x0Z4w/Q3auR+PUOGSYGbqfUqvv7WtQtk8mYPD6fATYJMHo92ifvIGBMS2CiR29gIBXLd9DR/WuTxDb9RAlokfPQdHtNJvwHUDVdHt0L84BSGQU2nUnQPfAdft2rCPG9r5zQWi2xkCXM11XKCA226gVO8AMNM5jFTOFXCngqQfgFu7RbJMTDVCO7uN5TJmbA6/AbddJdb1VqFrabj9q3/1r/I7v/M7/LE/9scA+Pmf/3n+/t//+/yFv/AX+Ff/1X912ekfjTYFcEO917pfE9Mw6DbtX8RkLr/WvXxoeoK8uZGaak+4vKDbbCKrKsVBS+pF/bdOLQK4/VaL8ru3AKR394lvFVyhz14jOMDt12s0zu3awIndPWL5wsKAO7rnadA0ec/t8xOMdhNJUUgcvwSnL3nK2tMgyuu+HgC300K/PLMBN5NFKe4uDLhue/QEuELA9Tmi17UT/3YOEariOs7rh4qFALdVR6nZHdXMTB4zmVkP4JoG8eoQ4Ga2p9tAAgRcr3/al4bbP/kn/+TYz/7QH/pD/OZv/ib/5X/5Xy47fag5FUZvN0vteh2AqCNTO9TT0GOP2s77ezrX50UhuH39GmFZJPJ5kvmtmfMt6r8dm9dlnk6lTP3KTnjLP3uOlkisDXC75RKta7uqSurwCC2Vngq4bvNPi3J7AlwhaJ2+xei2kVSV+PHLkdJcsBjgOl8BL4BrtRro1+cgBEpuC2WruBDgToMmb4BrwfUZot8DVYWdI4Qiu46b6gVfFnCbNeRBwwkjW8BMpCceN2v+ZQFXMXUbcIWFqUVpZ4uBAO6wJgGuVwXWoezFixf85m/+ZlDTb6TWHSkMtXnqd7sAaLH5i1A/BUmeP2f7uOaKlnzsYDtLXps6zLInVC7OASg8f4GsKL7ZE2Yd65ZEVL+8oFOrIkkyhVcfI6vOLlnu+/FaA3d83OQH29dXdMu27zXz7CWKowyV3216XcdZFu2Tt5j9HnIkQvzZixFvpXN9z35W52NeALdRRx9Uc1C2tpGz+amAO7JHPwHXGgCuroOm2YAru//OBwq4jQpyowqAkS2iR+MTj5s1v7+AG6OTKXi+1rwC7th14QBcr5gVaPvdfD78KnYd2pTobSjQezbcRqIfJtw+VT0lsA0iejs8Z/Xigl57UK3g+PnMNWfBr1f/rVPDb+zld2/Qux0ULcLWy48mvLEPrxdcBQWAxvnJQxez7ItXSNryTR7G15sNuMI0aJ+8QRg6SixO4uj5DJifAqrLAm6tglG6AUDd3kNOZVzP7aJfe3sCXNO0AdfQIRKxLQpDv/tOWAwKcCVAqZeRm3WQwMjvYERiY8d5mX8ewB3WA+AafWK1OyRhYUTidNKrBVyvChRuP0SF0dv32gRrwrpfj3u41UK4XYlWwZxPCWxnadHorfOx2zevQQjS29vE0pkJxzjuB+y/FaZJ6fV3WKZJNJUme3TsGjWz1wgQcIWg/u4NRqeDrGlkX3xkJzMNKQjAnbRnS+/TPH2DME2UZIr4wfFCbXphecA1y3cYFdtvqu4eIDnLla0KcA0drs9t0I3G7DJh0uQx48/Nfe15K1xIgFK7Q243QAJ9awfDUc3Bb8B1g0xV7xGr3QECI5qgm97aOMAN4faJKozeboZMwwBAUj68X7VVWxJCsF2d5o3e9ppNatfXgF09AUmaqzyYU8v4b+/f2I1el9Lb1wgEqeIOCUeC2fia/pQIm9zFzKT29jvMvo4Si5F+9mJqaGDqYwtGWx8At9uldfYWhEDNZInu7q8ccO9l3l1j1qsgSWh7hzD2dfyKAFfvI67PbKtCLA7FfVfby/hzc1/bK+De35QApXKL1GmBJKFv7WJMbUwSLODGB4CrR5N0U/mFAXdkfp8A98N7x12B1h0tDLU5egC88JJ49HrKYDsdJJeP3gKUz04x+n20eJzs7t7Mdcfnd+5rDqBwWadXr1G/tBPMcs+eo8WDTzBz6n3UVKf+7juEZRFJZ0gdHAVSIswL4JrtFu0Lu5pDZKtIZKsYCOC6zTG8Z+P6ArPZAFlG2z8GLepp3PhjU/Y89cPJ4Ea/hxgku5FIQmE3EMB13eMQ4KrlG6RuG2QZvbCHobj7xucB3JHjXMbY4waA2+8Sq5cBgR5L0UtmFwLc8Q+As9eepRBuQ4UKUg889GHR7VOL2j5lsF1U80ZvLdOkdGIDU/7wcGLt53ntCX4kmDWuLunUa0iSzNarj5AcbeODAFzXGridDvWTtyAgVigSK2yvDXD1eo3OtQ3+0d191Ex2IVAde2zotqc2vYBxdYbVaYOioB4cIxRntHIxwB3d17So5uBGr4O4ubB/kMpAftt3wPXij5YQqOVrpF4XZBmjsIfpsLIsArjjyaGTx9jj7GtR67WJNioA9OMZ+onMTIvFpH3NA7heFMLtE9YmWBM2wXe7Tq0biuQp/eufikKw9UeriN42S3d06nUkWaHw7PnEdeexJ4zvc/pcI8cOJ5i9fY3e76FGomy9eDUVFMfXdH9sEcDt12s0L+0KE6n9QyLpzMoB91798h29kt0pK35wjJJIzrH2FFgcuu0JcIVAvzjB6nWRVA3t4Hi8XJkPX3t7AtxOC3FnV3Mgk4Ps1sKA636cB8AVArV0hdTvIRQFvbiP6ajmMO31H1l7ScCNdFtEmzbg9hJZevHUFIvFtPPjH+A+/Xe+NSm0JoQCUAaGf0PX17yT1WmVUdsQbNerSX/mpgEDwO3bNyDs1rzxTHbpNf3w3wrTpPSd3cEslsmS3tufAYqLJZg55bbXzt0NndIdSJA+foHiSEj1WgPX63rOccOHdW8u6Q98r/Gj5+BMYpqytq+Aa1noFycIvY8UidqAO+VvzaLQ5AlwWw3EoJoDuQKkslPHTZxj4r7mBVwLtXRpe4IVFX1rH9NxStwAd6p9ZBHA7TSJtGoA9JJ5+rFkMIDrka1CuA315LXODxqRQX1bfVDvNtTj0YcItn5Eb2fNq3c6VK/s5gWF588XSi7zy54wLKPboXL6DoD0/gGRVHoGKAZbIqx5cUa/aZcIy7x4BQ5f5cpq4AKdi9OHLmbx4xcIefkmD85xngDXMNAvTsA0kWJx1L2jhWFxacBtVBGDag5s7YCjmsMibXpn7Xki4FoWWukSDAOhaehbe5gekzF9B9x2Ha1tNy7qpvLoEfcEwEVfK68K4faJaxOsCR+ytKid/KD3eitfex2WhKcStf0QwXZReYneOlU5P7eTy2LuyWXzAu6wZtkT3OClXSrRKt0hIbH18hWyps0AxeAqKCDsEmFmr4cSiZB5/nKkxiqsEHCFoH32DrPXRdYixI9fzNXkwWsS03Q7gf2Y6PfpX5yAZSEnU6g7++sD3FoJUa/auRXFPYSjCcfKANc0bcC1TEQkiuEA3Hle/2UAVwKirRpapwlIdDIFdNU9ATBIwA3hNkCF1oRQkbj9xy6M3PqrEGwfn9ySy3IHhyiOxgWLaJY9YSoMD71zVk9P6HfaKKrG1otXY8dOA1y/KygI06T29jXCNNGSSVIHx3OVCPMTcIVp0jp9izAMlFic+OGzGV+/TwHVJWvgim4H/fIMhEDO5FC2tlcOuA8q3yCaDfuP0vY+wpEouTLANXTUu0uwLKxoDCO/gzl0ba4CcMHm/Gizgtpt8wC4irMeb/CAG8JtqMC17qSydcJKfFCwvtNqrG0Pq9KqorYh2AarRawJi0Rv7eSyBrKikD86nrj2svaEhfy3wqL85jssy27wkN4/mAAXrtP6nmBm9rrU3r0BAbGtrbkqKMxa320vbuOE3qd1+gZhWaipNNG9g7U1ebDaTfQbu5qDslVEzkxv0+u9oYVHKB8+7O4S0W7ZzTd2DhGOls5BAO6kOWS9j1q6AiGwYgmMXDEQwB1de/gDgL2WBMQaJZReByHJdLLFCeXKggXcEG5DhQpIiqYRjSUA6DRWC7ertiSEYLteCSFG/t9UOYGydDLwuBa3iQwy8f20J4ytP2Ouexm9HpX7ve3tB+a/HZ9n8rF6s0Hz8gywKyhoqfTaSoSZ3Y5dA1cIIvlCYDVwPQFuvTbUpncXOZmaCotu+1q6yQPA7SWi1wVFgd1DhKNxz6KA67ovlznkfhe1fA0CrEQaM7PlO+BOe42HATdeL6H0ewhJpp3ZxnB6tRcEXC8K4TZgbfIbTahglRhEbXvtFtagU1moxRWC7bjcYDZIyPUzettrNWnc2qWm7kuDLSu/7AmdSplm6db23754hayqM77m9+6/9RqtG1bn7pZuuQQSZJ69QImMehlXCbhGo07nxk4KjO7soaYzK23yMCyzfIdZq4Akoe4eIsXW1MVMWHB9juj3QdXsCK7j78o0wF1kz66A222jVGzoN1NZzFRu5PqcB3Bd15625wfAFcTrt8h6HyErdLLbmJKzHu/8a3tRCLehQgWkZC4PQLteX+m6TzVqG5QeI9h6hddFATdIK5Fz7vLZKcIyiaXTJPNbE4+ZN3rrhz0BoHZ6it7toGga+ecvx8dOAdxp/tvxeaZFrd7/vHF+it5qISkKmecv7a/BhxR0ibBh9ct39Cp3IEnEDo6RnVDpOuMMiJmyLzfoM24uh7qYHSFUd49noIBrmXB9hjAMiERh52DqefC7Te/wPEqniVK1qzmYmTxmIj0VcF3X9timd3zcAHCFIF67RTZ0LFmlnd3GdCYjujyfac97lkK4/QAUVkxYj9JbBQCa9+VinqAeux3hsYJtkMd7kZ/RW6Pfp3JhRwHzR8eeX+wg7QnD/tvSm++4r3+b2tmdGgV1yu8EM4Sg/u41Zl9HicVIHT0fA4xVlgjrXl2gN+tIskzi6Pn6SoQx3MVMtWvgTvkKPNA2vaYB12dgWRCL21UUpiSmBQq4rRpyvQKAkS1iDmxyk9abp03vvIArC4t47RbJNLAUjU52m2lUMvV5e/zgHcJtqFABKJHJomoRTEOnVautbN2n2JEsBNv3WjgSu8C4VUZvq5cXg9JgMTI7uxOPmfcpzGtPcK9/26V6dgpA5uAQLZ6YEQV19986NR/MDH5uGNTfvQYhiGazxLd311ZBAaB9foLZ6yBpml0iTPhTImxuwBUC/fIU0e8jaRG0/fEmD9PO77CWbtOr9xE35/YPkqlA2vQ6H3O7JpVGBblVBwmM/A6GswnHqgDXMm3AtUxMNUI7U/R8vU17rdz09N4JQ4XaAKULRQAa5fL878qPRKuI2oZga8sPD+06/f8TfcHDUUzLojwAyPzBIbIj2/z9PO5zTHrcL/9t6+6WdrWCJMlsvXyFJMszIDHYBDOj06YxOF/J3f25WvQ65fXraddxluUoEXY8FVT9AlwmPWaao00edg89n99pWflje/YCuN0O4vbSfhKZHGTygQCu23H3NyVAqd4hdVogSehbuxMqF0zex9jacwDusO4BVzENG3CFhanF6KQLgQFuCLehAtc6PZnrgBhJlskUtwFoDPqyr0KrjNqGYLs6rRVKfSoL5kWN21t6rRayqpLbP5i5fhCa5qusnLzF0Puo0RjZQemykbEzAHfaOmIKSLm9qXcrJTp3t4MWvc9RItG1VVAQuk7r7C1YFmo6Q3Rnz5cauGOPTYVRMdjLUJOHVBqluOv5/PoOuO0mojxo05svQjK9MOB63bMb4KqVG6ReB2QZo7CHKTsTuybP75zTK+COJw4OANfQidXuAIERTdBN5QMB3BBuV6CwYsKHpUyhiKpq6L0urWp13dt5lArB1pbffzs2OXoLPDR2yOzsog66+wWdXObVniBMk/LbNwgEycI2sWzON//t2FpTAez9z5uX5+itpi8JZssCrtlp0x6UK4sUttGyubWVCBPdDvr1OQBKbgs5u3gNXF/a9NbK9u3CLjh8r9M/BCy254mAKwRq6Rqp30MoCnphD9Px53DaNeB5zy77sMfZ16Oq94jVSoBAj6XoJbIzrrH5ATeE21ChfFZ+bx+AyvXVytZ8SlHbEGxtBQWifs7rd/S2U6/RrlaRZJn84ZHncauyJ/SbDRqD3+v88xdj7XnHxvrkv3U9Vtgtei3dTjBLH453MPOaYObUIhUU9HqV7u01ALH9I5R4Yn01cJsNjMFe1OLsGrh+N3kYUeUO0ayvv4uZsOwmD4aOUDV0R5vesefj9fUZg/4pex5cj1q/Q7RRAaCfyNCLpzwDrheFcBsqlI+KJVPEUxmEsKhdX697O74rBNvg5Ye/1k/5aQ3wFL09taO3qULRc2MHvzXNnlC/vKDfbiEr6tzlwez77ut4/Sp6+FjLMAYdzATRXJ54cXvqKzYdMN3X9Jpg1ru7pl+vgiQRP3qO5GitPHVv06BygXFmtTRaAzca877eSLTQ/THPTR7urhGd9vsuZoriOi5QwLVMtNIVWCYiEsXI7668Te894Ea6LSKtKgC9ZB49mpgKuPMohNtQT1brAJrCINpUv7vDNPSVrLmqqG0ItsFrVVC7ydHbfrtN4+4OgK0J3la3+YO2Jzy8kQtB+e0bLMsils6Q3N6ZaU8I2n9rtFs0LmxLQHLvADWR9C3BbBHA7VycYnTbSKpK4uj5+iooYNfAtVp2DVx1/xgxpQ1soDVwEXBzgej13ncxk703efAn6mz/Kxk66t19m944Rm57fYDbbqC17Q6enfQWhub+AcT+4O/69EYUwm2oUD4pEk+QKdiJZKXzs5Ws+VTANiiFYOuPVh29tRs7WMSzWWKDTn+L7MFPe8KwjF6X2rldrSB7eIQai63df9st3dGtlEGSyDx7geSoOLFogtms/UwcJwTt07dYho68wgoKbqCqX51j9bpIqjooEebeJSvwLmY35whDBy0C296bPDjlNers9trKes+2KAiwEinMdH7hLmaLAi7YyW7RVhW12wIkOpkChuKI9i/wtzGE2w9A66x9+lihaBEVB1GmRvmOfqe95t08LgXBoCHYrn/NRZcwej3qN3aW+TLR22U1DVhad7d06jUkSbbtCZK0Xv8tdgczo9NB1jQyz16MtX9dZYKZMAzaZ29BCNR0hsj2buAVFJzzPDxmWegXJwhDR4rGUPfGS4R5TVryWgN37LH7h0wDrs953+Rhd+U1cB8At9dBqdoVfcx0DjOZWRhw3dae9tj7Nr0Qa5RR+h2EJNPObmNMacLhRSHchnqSWjXYROLxh/Jfd4P6k0HrqURtQ7Dd3IitV0372n2SvERvKxfnWKZJNJVybcs7ce5V2ROwy4OZhkEkkSQ9SCSdvvZi9gT7voevrC2L+skbhGmiJVMkd/cDSzDzVkGhQ/vS/nsYLe6gprOBJ5i57tsw0C9O7RJhyRTK9t6M6PqUvQzdXaiCgt5H3FzYP0imIVdcG+Aq7QbKoJqDkSlgxpJTAdd17WXb9ALxWglZ7yEkmU52G1Nyj7DPUgi3oUL5oO1nL5CQaFRK9FqtwNcLwXbanCHYBrH+olHRRZ+iqetULwdteYcqJ/iRXOaXPcHSdaqn7wBI7+2jJZK+2hO8wtfwsWavR32QlBff3iGSyQaSYDY2j8tjeq1Kt2RH4WMHR8jR2PpKhPW66Fd25zAlm19vibBuG3E3qKiTzUMqu3LAvZfcrCI3a4MuZttYEafvdfI+xtZeGnAF8dodsqFjySrt7DbWlC5z0xTCbahQSyqezpDZsj953757u+7t+KYQbIPVusHWbwURva1eXmLqOlo8TmrQ9W/yXNPnWfZUT4vedqoVWpUSEhL55y+QJHnqazvLnrCo/3ZY/XqV9q0NlOmjZ8haZK0JZr2bK/RmHUmWiR8/R3JUCpi+/pTz4bjvqURYq4FxZ58btbiLlEiuD3BbDUTFTp5kawdiianjJs4xQQt1MauVHF3MnLYA9/n9BFxZWHYXM9PEUrRBm17Xp+OqEG5DBaZ1+W1XDTg7L+xyQLXra/qdTuDrrSJqG4JtsNoksF1F9HZRCcukcnEB2NHb+9d4Hcll0wC3enqCoffRYnEyB4ce1g7ef9u6uhht8DDDfzs8q+8JZkDn/BSz30PWIsQPn+G0/05ffwo8uW/NdW/DJcK0vUOkSNTTuGUecwXVWhnRsKOmbO+DYy8rKxHGfRez7vsuZpIzajp5fuecy7bplS1zqE1vlE56K2y/GyrUKpUuFEmkMliWyd3gq8Agtc7kQL8Ugu3mgK3f8qMsmBMi6zfXGL0eajRKenvHfdwcEVC/JUyTyoltT0jt7BJJpWcC4jL+29F5XI4VgvrJWyzDQI3HSe0fTvXfju1hyv4XSjCzTNqnbxGmiZJMEd3dX2sFBePmEqvdAllB3T9CTElgCrZEGFC6RnRadg3c7YP11cAVArV8BbqOUFS7i9mUa3EewB05zmWMPW7Qptec3qZ3lh7/O+Uj0DrfeJ8CDM2jVZ5rSZbZHURty+fnGHo/0PWegs82BNvNBNt17cvLusKyqFzYrVRzBwdIg9+DTUsu69VrNO/szPP88xdI8rg9YTqket/7LHvC/V1L16mfvAUBsUKRaDa31gQzq9+jfWEHASJbBbRsfn0VFAD98gzR7yFpEdS9I8QUf2fggHtziej3QFVh52Cs0sXqmjxYaKVLJNNEaJGxJg9OeW3TO0+JMLc2vf14JvTchlqvPoQSYMXjZ2iRGP1ul9LFauraBq0QbIPTpoLtvFpFYtlY9Pb2Fr3bRdEiZHZ2fVnjXn4Cbu38FKPfR41EyRzMbh+8Cv+t3mzQurETl1KHz1Ai0bUmmBnNBt1bez+x/UPkWHx9FRQs066gYJrI8QTq9v7CXlZfauBenyMMw7YmbO9Pff39qIE7/pj9r2QaKKVLEPdNHopra/Jgt+mtAtBLZulHEq77H1YIt6GejFYJOpF4nMK+/eZ1/fY7xJSv9/zQY/fZhmC7+WDr1x79SCybcBDlQWOU7N4+0uArZD+it35KWBaVkzcApLZ3FrInBOG/bV9f0m82kBSZ9LMXc/lvZ+1h2n5cE8zubug3aiBJJI6eIzm7hk2Z1/cKCnqf/tUZCIGcyaLkCgtHQn2pgXtzYU8UT8DWzvpq4Op91NI1CLASacx0buVNHt636W0SadcB6KVzeFEIt6FCLaC9Vx8jSXbpr1alEuhaIdhOmjME23VqHdHb5t0d/U4HRdPI7u0ttUag9oRGg+YgG38Re8LYXv3w3wKNNfhvx+d5f7tzcYrZ6yJpGvGj6Qlms/YzbZwnwG230AfRZKWwjZRM+QK4C1VQ6HcRd5f2E0lnIZ1bH+D22kNNHvKY8VQggOu2r2FFWjXUbgut3XQdO6wQbp+w1uW3XYclYZWwk9vdJ5nJYVkmN29eB7pWCLaT5nwcYCuEeHRgu9HRW6ByH73d3UNWFo/eetFy9oQzjH5vYE8Yr54wvlZw9oSHb+ANw/bfYvtvJ9W/XaX/FsuiffbWTjBLJInu7gWSYOaU2/OwahXMqt2+WNudXUEhUMBtNxEV+wMS+W2IJ9cGuEq7gVy3AzhGbnoNXKe8Quy0a83ZxSw6iODOUgi3oULNITUSZfe5nUR2++4teq+35h0tpxBsg9Fjg9pVaqnobalEr9VGVlWyu+MdweZZY1b0dhnZ9oRB9YTtXSKp1ErtCdP8t+2ba2By/duxdcbWdYeoeTygD8Dd7w8lmBVRsznfEsyG73muoHB7hdVugizbFRQk7y1gfS8RVq8i6lWb6orTS4SNr+f60EJeXaVRQW43QWJQA9dhI/EYyfeji5lXhXAbsB7Lm/Fj1irP8d6rj5EVhU6jTuXqMtC1go7ahmAbjB472Hrdv9+ltuaN3mb2pkdvZ0VaJ8lfe0KdZmlQPeHZ5OYOftoTvNoBWteX7+vf+uy/9ZqZPyw7wcwG7vjeIXLMnw5mTnmvoHCO6PftCgr7RwtHQn2poFC+QbRbIEvrLREGKJVbpF5nUAN3dyU1cCcBrleFcBvKVz3lKgnZ7R3S+S2EsLj87ptA13rMJdxCsA0F81sT3OQEgValTK/VQlYUsnvu0Vsvcy3ycs1tT9D7qNEY6f2DmXPPa0+YJ0L3cFcI6ifvEKaJmkiQ3N33zX87+9jJENe7u0Zv1kGWiR8+B2fN2SnzBlJB4fIELLuCgrK9N+d59hlwb50lwnAdFyzgCjvBTO/bNXC3/KuBOw1wR/Y8B+A+3nfQUFP1mOFoHq0KerRolN2XHwFwd3oSaCeyx+yzDcH2w5LfiWVzR29395BV1XUvftgTlrErCNOkejqwJ+zuoiUSvtoTxtbzuHdL71Mf7Cu+vYOWSi/lv/UKNeP7fX/7oYNZJEL88NgXH+2kcZ4SzPp99MtzEAIlm0fO5DyDolNLV1AQll1BwTRta0JxbyoYB9vkwUIrXdk1cCMRjPyOLzVwnRp+xK2Cwix9GAQUaiV6ylHb/Y8/RVFUOo06pfPHXdM2BFv/9dTAdl2JZW4aj95W6DUH0dvdPdfjvMzlRcvYE7q1Gu1KGQmJ/MAGMC/gTltrUXtCv16jM2g6kT56jqSqC/tvnVq4g9nZO7As1FSaSHFnLQlm93u32k2Mkp3UpW7vIcUTC4Pi0glmho64sWGbRApyhTXXwL0CIbBiCcxsYeU1cL0ohNtQj1arAp+t/UO7OoJpcvHt14Gu9Vh9tiHYhppXy0ZvyxOit/OsM+0YP5PLAKpnJ5iGgRZPkN51L2PmpkDsCUDz8hyj00HWVNJHz8fG+uW/HT928p6sXpf2lf26Ros7KMn0yhPMhmVWSpj1ql1BYe8QVM3z+r4Dbq+LuLPLlZHdgmRmjTVwe6jlGxBgJjNYyczKa+DOUgi3AWpdb87rsCSsOmq7qnMbTSTZef4CgJt3b9C73cDWCsF2eM4QbNctvxLLgoretqvBRm/9TC6zDIPqmV0VIL23jxqNLW1P8KM8mO2/fYuwLCLpNPHizlr8t8PSa1V6lTuQJOKHR0iattYEM+PmEqvbAUVF21+8Ra9TC1VQaDUQ1ZJ9u7AD0fj6ALfbQqnbezEyBcxYYqMAN4TbUKFcJMkyh59+D0mSaVRKVK+vAlsrBNvhOUOw/VC0bPS2cjEUvXVkkntZZ95jZo2ZBridSplOvYYkyeSePR+Mnw9w59qLR1+o2evSHJzH5N4+aiy+dv9t9/oSo9NCUlTih8/G/tBMjyBPASfHsZ4SzIRAvzxFGAZSNIa6M96id6UVFKolRKthn5PtfTvRzGWcU/NE+N32OSy5WUNu1kECI7+DpUU8rxdEWbWRvXk6KtSjURi19U+7L14RjScw+n2uvg2uOsJjBdsgFILtZmldZcG8qlWpvK+cMFT3dlXR23lVPX2HZVlEU2kSheLc4+e1J3iGyXKJXq0KkmS355XltfpvEYL2+QnCNFDiCWK7+wv7b2ft3UuCGYaBfjlo0Zseb9Hr1DwJZgsB7t0VotcFRYHtQ4Tj7+ZKS4TV7pC6bZAkjK09TDn4EmFeFMJtQHosb9KhJitdKJLf3UcguPjmK0zDCGSdxwy2fl/ij+V3Zh1gK4S3/zdVQVkTACrn58Bo3duJY32K3i5jTzD7feqX9n6zh0fImhaoPcGpqe15z04w+32UaJTU/nhXtVX7b4Wu0z4/ASHQ8gW0ORs8+J1gJrpt9Bu7trlS2EZKJBcGxeUrKAi4uUAYBkQisL3GCgqAWr5B6vcRirKWEmGTFMJtqKX0FKO2WizG/kefAFA6P6NdrwW+ZhAKwdZ/rRps54XWICA36Oe8rDVhuO5txgfv7Txg5nXe4Tft5s01vXYLWVHJHT0brDkf4E5de0b01g10hGnSOH0HAmJbhZntecfXnf4cph87+WCj1aR7Zzd4iO4dIkejnv23TvmRYGbVq5i1ykOLXrTpCWaBVlAwDbivoBBPQr64vgoKwkItX4JpILTJJcIWBdyR41wfGVcIt09IT7227SoASJIkDj/9Poqi0m7UuTs9CWytIF+vEGz91yrBdllIXUcUd12JZQCVi0E0dAHvbRClwWapevIWIQTxXJ5YJrvA+qP3l7EnDEtvNWkPuoWlD58hL1kezCvQOO8PP9S7u0FvNpAeGjyM/t2ctofAEsw6bVAUtL1jhAOjVlpBod9D3A5yQTL5tVZQkEzTbvIgBiXCMoWpv/Nea+BOSzCbpqdNQ2vSY3mzXlaPycvpVbsvPyKeTGEYOhdffxkYJTzWDyIh2Aa9jn+X3CbbFJxaOnpbLtNrt5FVlczO7vvxC3qBF4nezmNP0DsdGjc2RGaPnyPJs1vzrqR7GYP2vO02kqqQPn4+NnaWPWFR/61Tww91Lk4w9T5yNEps73A5m8GyCWaAfnmG0HWkaBR1d/EEs1l7ddv3iNrOCgqx9ZcIA8xUBjORDqSCghc9znfYUGN6rLDkVauAoBGf7ddfYfT7gazzWH22IdgGvc7mzrlpiWWT1qleXAB25QRpyu/YotFbv5PLGlcXGP0eaiRCZtCa1097glPzlAdrnL5FWBZaKk28uD3TnjAdLkfvL+S/NU069/7bbA4tX1hvgplpoF8NEsxSGZT8fAlmwVZQOAAlmAoKnkuE1coAGNkiVjS+FsB92kQUKjCtMmq7CgiKxBMcfPwpAKWzM9q1aiDrhGB7P18Itu/XCDbKukkR3Kmdt5aM3jZLd/Q7HRRNI7Oz8368T9HbSVomuUxYFpWB7Sm5vYsWj8+9x2XtCe7lwXoP5cESuwcosdja/bdmp01nkNAV291HjsXXnGDWeZ9gtjVfgplT8ySYeaqgsHOAcPyJ9SPBbGxvLo/JzSpyqwES6PkdrLHmF65TLhzZHtuD5yNDedI63rRXHbV9anYEWVE4+t73kWWFVq3K3aDnuu/rhGA7mO9xXD+rAttVyI91HlP0Nru3v5LorRdNg5NefdCaV5LIDSwAq7QnjO116NhuuUSvXkOSJbt7mSStpDyY8/7wQ/3yHf1GbdDg4dlc/tuxPQSRYDajg5kfCWZODUfcubkA04RIFAq7a62goFRvkXodkGW7RJjjz/7wNItWUJimEG5DbbRWAUL7H39KNJZA7/Vsn20ACsH2fr4QbO35Vx9R3ZQI7iJfrXt9PRqlO/RuD0WLkC5uvx/voSrC5HVnH7N0ctn5KZZpEkmmSA7teZk5p8mzPQG7PJhlGKjxOMmhOsL38tOe4Lkm78UZZr+HHIkQ3z/yzX/rlOcEs9ur9wlmMzqYzdyPR8CdVkFB3FzYP0imIbvlWwWFxUqEXYOhI1QVI7+LOeVaW7SCgptCuPVRYdTW57VWcD4Lh0dktooIYXH+9Y8Dq2cbpEKw9VfrKn21Ci279qadm7E3biGoXr6P3s57EfsVvZ3HnmDpOrVB7dvMwaFdoWDGGstGb71+9SwMwy4PBsSLO2jJlK/2hIX8t9Z7/62aya7Mf+vUSAezqzNfOpiN7WeeyPP93V4HUbKTFckVIJ70JcFsnr09AK5loZWuwLKwojGMXHGsRJjbXsYemxNwHz3c/of/4X/IH/7Df5hEIkEul1v3dkL5pFWAUDKXZ/vZCwCu37ym22wGss5jLPkVgm1Q8wc6/cbsYVVlwSapcXuD0euhRqOkhrqArTJ660XDb9at25uH2rfZw+PBurPAcDX2hH6jTqd0BxKkj54hyYpv5cHG1/UGfma3Q+fa/hCzCf5bZwczOZuf+jyDSDAbUbOOqFfs28U9cLTFXWmJMEO3I7gCrEQKM5X1JcFslh493Pb7ff6Ff+Ff4Jd/+ZfXuo8wavu4pMViHH76PSQkqtdXVK+vAlknBNsQbN/PH+j0T0Zu58nt9RmHOEH1yv59zg2qEMy1/oqit05VT98hECS2CkRS6ZnzL6t57AnNy3PMnm0FSB3M370siPJg/UqJfn1z/Lei28YYNJxQi7tIsbhnH+vYfhYE3JEpy7eITts+L9sHCEdb3JVWUOh1UGp3AJjpLaxoInDAffRw++u//uv8G//Gv8FP/dRPrXsrT1pPyY4gKwpHn32Ooqh0GnWu33wXzDoh2IZgy3r8tbO0zH42LbFskuo31xh9HS0WI7lVmLqnRaO3i5QGm1r7tt2meXsLQO74mZ3AFXD01jNwWRb1QfeyaH7LU/ey6RFQx/QLABNA5/L0wX8b259d/zboBg9mtYw5SHhT947GSnItmmDmlKcEM4DbC4Su253UivuBJJiNrz/5MaVVR27WBhUUtrHUiGPc6PHTzo0XPXq4XUS9Xo96vT7y/2PTU61ru6oEslgiidHvc/7Vl4GATQi2Idjacwc29dJa9978LAs2BnGWRf3a3+jtIvaEec9x/fIcQ9fRYnFSg2YUm2JPMNot2jf2OU0dHiNN6F62av8tlvW+/m0mh5bfWnuDB+P6AqvXRVJV1L3DpXysSyeYWZbdoteyIJ6Yu0WvV8D1Wu1CqZWQuoMKCoXdqRUUnArr3HrQn/2zf5ZsNvvw//Hx8VLzPZY38UX1lOwIxeNnIwlkhu5/o4YQbB/P78SHCrbLalWNLZZR7frKrkKQSJAYysdYFFwnye/SYMI0qZ2fApDeO0CJjEa3gtA89oTWzRVGx+4Elz58NnvuGWvNAzNT/bf39W939pGjsYX9t2PHOu57avAgBMblGVgmcjyBUtxZ2Mc6c+9eAFfvI+6GW/SmPSeYzVp/6t4mAO5DBQVdRyjLVVCYpY2E23/n3/l3kCRp6v9ffrl4yaZ/99/9d6nVag//n56e+rj74LXKqO1TsiOkC0W2j54DcPndt3QaDd/XCME2BFt77sCm9lVB7zOIxDKvr5tlmtQevLfjPtGZ66wwejsMGJ1KmW6zgSzLZI9Wk1zmGXCFGNgTBJFMhmh+a257QiD+2/IdeqMOsmz7b6Vg/Lfje5h83oTeR7+yE96UXAE5lV7YxzrNfzs2j2uL3uZQi95diER9qaCwyOslCWcFhcJcFRS8/v6rsw9Zvf7Mn/kz/OIv/uLUY169erXw/NFolGg0uvD4Ya36jTy0IyymWDL1vgPZxRn12xvf1wjBNgRbe+7Apt4oCSECfb2FmO/6FIix35Pa9RW5/X2iqRSxdIZuo+567Lzr3csSAnnGQOfck9YfVvX0Hbvf+wni2TzRTJZevTZzTktYyENQZwmQp6y56PM1u12aV5ek9g9I7R+iN5tYen/k2ZiWheLx7+H483A/n85rbnhs5/IUJfYJcjRKbO+A7uUZ8tAJEDCyx+G5nPNalhgZOyzn/tx+D6xWA6N8h7pVRN05QO+9Qej9h/2OrTnleY+9lsN7d7yuw3sfObfVEiISRUqk7Ba9lye2XcHDcx67fofWn3Y+3F4vybQrKBiFfaxEGkvXkVq1h+t3nmvCTRsJt9vb22xvTy5mHWp1WlXUNmggUiORhw5kzUqZ23dvA13Pb4Vg66+CAtvHCrWLQo7n+WeA3EJzegRrU9ep39yQ3dsjd3DA1Vfz5VcsCsGLvBkPw4XR7dK8vSa9s0fu+BnXX/xoBR8mpsPWCEjeXhPNZNCSKdJHz6i9+XYMHkfmxh0snXPP2pfbWGGatC9OST17hZbLY7SaGPXqVMCd+vyHIdExbhrQDT9mlm6QY3HkRBJ1/wj99A3DseBp53z8sVHAHdn7lN+xkXN7e4XYf4YUicD2PuL6zBWMp73+Ti3ygeS+goKZK2JktpCMPvQ6vgHuow8Dnpyc8MMf/pCTkxNM0+SHP/whP/zhD2kGVLN0WE85avtUfLaSLHP0vc/RIjF6nTYX33wVyDpBvTYh2PqrEGwna537XySxzPX4CV8iVy/tjk3xTJZIIjn12Enrras0WP3yAkPvo0aipHf3BnNsiD0BqJ++Q1gWWipFbKie8L2CtCe4+m/bLbqDclyx/QPkSGQl/lunhh/Tr84Quo4Uic5s8DBrf0snmImhBLNYHPLbgVRQ8Hpe5VYduVkfVFDYwRprXzx6/Dwe90cPt7/6q7/KD37wA37t136NZrPJD37wA37wgx/wP/wP/8O6txbKg4KGooOPPyWeTGMYOmc//n0s0/R9jRBsQ7D9UPUYEsuMfp/6nV1jM3cwf+WESVrEeztxnmnJZZY1lFy2v3By2SzAXVRWv09z0FktuWeD5Lz+25HHZoCMV/9t7+4Go91EkhViB8c4Y7Wr9t9imuhX5yAGDR4y4w0e/Eowm7r3+7uGjri1E/DI5CCZmauCwrT1F2nRq9TukHqDCgpbuzjfoef5MDCsRw+3f/2v/3WEEGP//xP/xD8R6Lph1NaHdQI+h8Xj52QK2whhcf7lj9F7Pd/XCME2BNunoiCfyzKJZW778loWDKB6YSf3JHN5tFh86rGrjN5OnGckuaxCt9lAkhZPLpt3T/NEb7ulO/qNBpIskx4k685zGQVSHgxon58gTAMlniC6s+dr/dvhews1eNjeRYrGp14LgXcw67QQlfsEsx3fEsyc8pRgxqCCgqEjVA1ja2cswWyRv02PHm4/BIVgO7+y2ztsH9mlauzKCP7XMg7BNgTbUI8jeqt3OzTLZZAksvv7vswZVPTWqerpO4QQdnJZOjNYez7ADdKe0Dg7QZgWWjJJvDieKzOvPWHaKfP6dbcwDNoXdtQ7UiiiJFO+1b91ar4GD/VBg4dDkJXpa061PUzZu9cOZrUSotW03xi2D8b2s9IWvZaFWroeVFCIY2a2lm7RHcLtAnosb+qbqqDPXyKTZf8juzLC3fnpo6qMEIKtvwrBdj6tM3q70JwLRG9TW4WRr/iDjt4uWxrsPrkM3ncu2yRZep/m5RkAid0DlGh0KXvC2PwL2hOMZoNe2bajxA+OkRR17f5b4+YC0e8haRrq7sFK/Lfj8wzdubtC9PugqrC95z3y65zHoYVa9Bp91Ir9Xm2mspjx1NQWvbMUwu2cCu0Im61IPM7R9z5HkiTqd7fcnbzzfY0QbB/HdRKC7eOSn4llk9RrNWnXakiyTHaQoLWsJu0rkOSyq0sMXUeNxkhtr6Zz2Vz2hHKJfqOOJEukBs0dNsGe0L25xOh2kFSV2MHR+NgZc43swQ//rWWhX56BZSEnUyj5QmD+W88JZrcXgwSzyR3MVtmiV+62kesVAIxcEUuLLgy4IdyGAp6GHUFRNY6/9xMoikqnUefy2699X+Ox1RkOwdbPOT8MsF3kOa7TmjBX9PbSjt6mt3eQFWXqsYtGbydp6eQy06R+YUdH0/v7yNpoVrn7uqu2J5gDe8LO2F5WaU94D2/Cbs9rWaipNJGtoq/2hOF7nv23/R76rd1cRNnaRoonAvHfjs3jtYNZIrW2BDMApVFBatt2CWNrFzFm33BdfkSP6516zXqqUdunALaSLHP0/c+JxOL0u13Ovvyx72+4j61JQwi2fs7p+5QfpIJILJtHnVqNXrOFrChkNix6O0vtcoleq4ksK2QPDgdzzG95CEqWrtO8sKsnJHb3V25PcPu9t/o92tf2h5rozh5ybLw97/C9WfP64b+16lXMWtX23+4egqIsHAX1JcGs3URUy/btwh5okZUkmLlVUFCrt0j9HkJR0LfGW/R6UQi3G6rHFiGcpcBLfn3yGYlUBtPQOfvy9zEN3df5Q7ANwfZD0lOO3lYG0dvMzi7SjN/rTYreAlTP7CSpxFaRSDI52OOsr/RXaE+olOjXp9sTnIA7ba1Z9gSv/lu9WqbfqIEkET+wfctr99/eXmL1ukiqagPujD1Mi4L6kmBWvUO0W3aniO2DsRbGq23RK+wKCpaJiEQxcsWpLXon6WkRVIB6LG/u8+op+Gx3Xrwis1VECIuzL39Mv9Pxdf4QbDf/GrkvAej/vL5P+cFr3dHbVrlEv9NF0TTSQ9n9yyS8BRm9HYYKvd2iVbKTpLKDajCLKFB7wvmwPWF2p9Fl7Aljc00D78szLL1vt+fdHa+YMWsfw/LFfysExr3/NpFE2SpuQILZJULXQdOguN4EM8k07AoKAqxECiuZmauCQgi3G6jQjuBd+b19Cvv2p96Lb772veRXCLaPA2yDmTeQaR+NHlv0dh7VruzobXZvf+Yvzbqjt07VLs6wTJNIIkli0BnM79q3y8jS9YfmDondfZTI/PaEqWC5oD3Bbs97BkKg5Quo6cxayoMNPy70PvrAMqHki0jx5MKQOGu/nhLMrEGCmRCQSEJ2ay0JZvd35X4XpWZ/mDMyBaxo3PO1HMKtB63yDT60I3hXeqvA7suPALg9eUtjENHwSyHYhmD7oesxnYd5rAmN21uMfh81GiWZ35p6rPf1x38WRPTWMgzqAzjPHBwiKYrbMMdeVl09wW7ukLpvPuHYzzR7glN+2RPMdpNu+RaA2N4hkrpcebCRr/gdY73u0WrWMWuVgf/2ABQ1EP/t2LFugNvvIUp26TmyBYglVp5gNiy5VUduNR5a9ApFdV1vZJynoz5gPYY3+EW0iqhtkOcunk5z8Mn3kJCoXF9SOj8LbC2/FYKtPwrB9vFq3dYEIQS1aztDPOehqYPX6K0nUPUhetu8vUHvdlBUjfTe/mDtxb/Od93HnIA7rPfNHVLEBhHmqWuNrT0rGj1/JBCgd3ON0W3b5cH25y8PFoz/9gprULJM3RtvEb0K/+2ImnVEo2pndxX3bOBeY4KZUr1D6nVBltHz45U4JimE2w3SU7IjBAlHkXic4+/9BLIs06iUuH79ne9rPKZatiHY+jlvINN+UHosiWX16+uHr/fjmezUY5dRENFbhHhILktt76JGY57mnTd6O6+G17P0Ps0r256Q3D1A1iK+2hPG155lV3i/Suf8FDEoD6blC3O153XKN//t1bntv40nUba21++/Ld0iul1QFNg5AMd71zz+26UTzBgkmJkGwuM3FSHcTtFTtCM8drBVtEEtW1Wj06xz8fVXvq8Rgu1m60MAWzHjv5XuJaDl1h29tUyT+o3dEclLS96go7djQDDj/PQadTq1KpIkkb3/6n+BExOoPaF0h95sIikyqcPV2xOmlQfrDLyusd195Oj08mDj+/AYAfWwx4efj/hvC+v33yJs/61pQiQKW9sL+2/n2btrgpllopau0W4v3CceUgi3G6CnBLZBSlYUjr//E+9r2f74x4g5/jB6WiME243WUwbbeeB1XaDrVY8lelu7ugQhiGeyRBLJqccuIy9teSdp1tfItfNThLCIZbJE0xl7zMyv81eXXAYDe4IliKTTRIf8zW7y054wNvfQoXq1jH5fHuzweKXlwVzr3475b+erf+t7gwfTQNxe2k8onYVkZi7/7aLeYdcEM72HZBqu44YVwq2LHsMb/SYqsPMmSRx++n3iyTSG3uf0xz96NLVsQ7D1R08RbP2A1FVA7ibAv1N+7Mno92nc2Ymoq/beep3fqWEQMXo9mreD6PPRsec/DKtMLjP7PVqDiGRq/xBZVTfEngCdyzMsQ0eOxohujzf1mGcfsyK/c/lvF6x/Oz6v+1jP/ttuG1EdJGsXdiAS9ey/dcqPBDOvCuF2gkI7woJrBHje9j/6hFQuj2WZnH35BXq36+v8Idhutp4a2AYBpJsWyfXymi1jTVhEk1vyXgKQzG+hRqOe9zav/IreOlW/usQ0DLRYnGTBrivrR3KZn4Dbub1Bb7eRFIXkwebYE4Rp0rm0k5EjhSJKIhlYe96ZY4f9t8P1b/MF3/y3Y8dOAdyRaWplxKAlLsV9kP1p8DBr75MSzLwqhNs1KgRbb9p+9oLc9i5CCM6/+pJus+nr/CHYbraeEtiuJMoa0PybGL110zzXTL/TplWxvwrO7j2+6K0wTeqDurKZgwPX0mCz7AnTIMgPNc5OQAii2SyRoQQ+N82Kms4LuG5jjWaDXsWOTMYPjkFWfCsP5tRc/tsb+0OXsrWNFE+sxH87fuzQnbur9w0eCss1eFg2wcyLQrh16DG82c+jxw62+f0DioNEhKvX39KqVnydPwTbzVZQXcdWDWqrjqpuUgR3ltadWAZQHbTkTRe3kdX3dTQfS/S2dXdLv9NGVlQyg1JSm5ZcZnY7tG7s+qmpg2MkRVnanjDPU5zavez6ErPXRdI0YpNKcc2cawqQOe579t82api16nv/rbxm/62zwUMmv9YEs1kK4XZIT9GOELQCbdJQKLL34n2ThtrgD6NfCsF2sxUU2K5a6wLNQKwPc073WBLLuo0G3WYTSZbJ7Ox6mNvbvKuK3oKdXAaQ3N55KA0WRHLZMoDbvrnC6HaRNZXkPYQ75p/HnuDUvPaEh7tC0Lk4BSHQsjnUTDbQ8mDe/beXWL0ekqqhTmoZvGr/bb+HKNkeb3JFiMbXkmDmRU+DsB6ZnpIdISglsjkOP/kMgPLlhe9NGkKw3Ww9BbDdFA/sJuwhSPkXvbW/Bs7s7CIN/X14LNHbXqPxvjTY4XhzAvf9BFv7dnQyYdsTgNhWAS2Zmj1kbAr/7AnDMrsdund2AMXuXqZthv/2auC/TaaRs/n1+2+bNUSjZpe93d63KzpsYIJZCLcr1lMC26AgKZZMcfzZ50iSTL10y83b177OH4LtZuupgO1TVRDR26ASy+aJ3rbKJfRuF0XTSHnoqOV13lVHb4UQxLI5z6XBPO3FR3uC0W7RubNb4KYGJbhmRW/nBdxpmtq97O4Go9NCUhTiB7M/IKzEf9vvoQ+gWy3uIkVj6/fflm8QvZ7d4KE4HlFeRYLZLIVw+wT1mME2Eotz/P2fQFYUWrUql9987ev8Idhuth472G5KtNapTdzTJqp2Zbfkze6NloXyE1ohuOjtSGmwKdHbWfYEP5LLpgFu6+oCs99HiUZJ7Njn2s8rdGF7AtC5sLuXKcnU0t3LnFrUnmDVKpiNuu2/3TsESQ7Mf+upwYMQtv/WsiAWh1xxZQlmXs93CLcr1Cqito8ZbFUtwvHnP4mqRei2mpx/9WNfYScE283WUwDbTZaf+wvivK46sWxiS97bG0xdR4vFSeTz80/qMu+k/S3alncWRNSvLrBMAy2eIDGIQK8juWyahGXRHHiEE9s7KLH42DHLRm8XtSdY/T7dm0H3sp095Eh0/fYEwLi5QOh9JC2CujOhJq9P/tuxY90A19ARd/aHQbJ5iCcX9t/OOnYRhXC7IoUJZNMlqyrHn/8EkWiMfrfD6Re/j2Wa/s0fgu1G6zGD7aZGaydpbcltq/aFLLi2sKz3LXkdZcH8jt5O0qJv6uOlwWw4y+wfjviHhzUreutFy9gT+o06vWoVJIm0x9a8q7In9Ctl9GYdZJnYwRGwXPeyZewJD49bFvrVOQiBnM4ip7Nr8d+OqN1E1Cv27eIeqOpK/Lde9DSIa8P1VHy2QUGSJMscf+9zYomU3X3sC3+7j4Vgu9l67GD72OTXnp9q9LZ2fYWwLGKpNNHU7IQnr/MGGb11qnl3i94b+Id3B1/7e1hrpcllQOPiFGGaqIkE8eK2r3PDkvaEyzOEaaDEE0Qm7G02aE8BuTn3+fDzbgejZPuV1e090CIb4L+9RXQ7dmOH4j443heD8t/OUgi3T0SPFWzv2+om0llM0+D0ix+h93q+TR+C7WYrBNv1aB17fyzRW1PXadzaAJFbsKnDMpoEvF7WGIEIIagNKsykd/dQtMjgx4tHOh/G+JhcJgyD5oXdgCKxu4+sRXyP3i5qTxCGQXvQHCNa3EGOxTeiPJhZucNqN0GW0fYOx944Vu6/Bbi9BNOEaAzyq/PfTlMItwHrKfhsg4Skg48+IZ3fstvq/vgLeu22b3OHYLvZeqxg+5hsCEFrjbw6UX7tpzpILEvk8g81Y2G+DwV+Rm+9zj+sbq1Kt9lAkmQyB+ONCdzkR3LZPIDbrZToD2oMpwZJcJtiTzAaNfq1CkiS3b1Mmm5PmDW3X/5b/foCTBMpGkPZ2p77A8boY9PHjhzrBrim8d5/m8lBIhWY/9br72AItwHqKYBtkNp98YrsUFvdTqPu29wh2G62HjPYPhVt6nPZhLJgercz1JJ3PHlnfO6FtuQqX6K3vG/skNgqoiUSg3nmB8F5k8vmVfPcbs0bSWeIZnPLTTZBy9gTulcXWHofORolOimRy3k/QP/tgwzDBlxAyReQEsn1+287LUS1ZN8u7IKqzeW/HYnozwHnbgrhNiA9FbANCpQKR8ds7R8CcPnt17621Q3BdrMVgu3myI/ntEyUbJN139QhXSwu3JJ33dFbvd2mVbaBIztI2po4z9hX+atNLjN7PVrXduQvuX+EJPvfmnfRElPCMukM7AmRrSJKIrkZ5cFaDcxqGQB158BupjBPBDQI/221hOi0bf/t9nz+21l7mPd3JITbUK4KCpTyewfsHL8A4PrNd9QHBb03WSHY+qMQbDdPm/jcNiGxrNuoD1ryKmS2d2bPsaHR2/rFOUJYRFNpYtnsYJ7ZE60iuWx4G+3b66HWvPuDNUYVpD1h2t6MVoNexf6QENs/AlnejPJgd9dYvS6SqtqAO8dYp3zz394N/LeRKGxt++a/nVch3AagpxC1DQqUMsVt9l5+BMDd6QmVq0tf5w/i3Idg648eI9iG/lr/9VgSywBqg79Pmd3dkd+xxxS9NfU+jRu7w1VmStetdSSXOQff176NFYqoieT8G5qhpewJN5eY/R5yJEJsx0uiYXD2hNH2vOeD9rwpT+15p5XY8sd/ayJuL21iT2chkZ4KuEHVvw3h1meFYOuuVH6Lg48/A6B8ecHdoMe4XwrBdnP1WMH2Q9Gyz3XT3AZ+RW+b5TJ6r4eiRTy15N3U6G3j+grTMNBicZKDslZ+RG+9aB57gt5q0hnYKNIBteZduAOWZdG5tCtQaPktlGR6bntCIOXBnO15I9H1+2+7bUTt3n+7M+a/dSoI/20Itz4qBFt3JTJZDj/9PpIkUbu94ebta1/nD8F2cxWCbSinvFwTq04sczl4qCXv7KYO8+1j/Gd+Rm/dGjuk9w8eGjtsYnJZ6/IcS9dRYrGH2rfLAu4yGvEGt1v0yraNLr5/CLIyl8XAKb/Kg1m1CmZzuD2v9KT9t14Uwq1PCsHWXbFkiqPvfY4syzQqJS6/+8bX+UOw3VyFYPt49NSit4to0jlo3N5gmSZaPE584FmdOseE87DMuV00eutUqzRo7KC+b+zgbf3VJpcJ06Q5APHEzh7yoEbvMlo2ejtqT7jC7HWRNI2YpzrIi9sTZs014r+9vkToOlIkilLcnWusU77YE2Ct/tsQbh+JHivYRuJxjj//SRRFpV2vcfH1V76+C4Zgu7kKwfbxadOef1CJZfNcm5ZpUru2v/ZdV/TWUyezGdFbhKA+aJiQ2tlD1rTBj/2P3nrRNMDtVcv0G41Aa98ubE8QwrYnCIGWzaOmNsOegGWi3wzKg2XzSMmUr/aE4cdnQaq7/3a8/u2i/ttZCuHWB62qvW5QCgqUtGiUZ5//JKqq0Wk2OPvyC4S12FeJkxSC7ebqsYFtmDjmj+b7xv/xnO/69RUIQTyTJRJPzDze7+itX2t0qhV6rSayLJPZd2/sMA6Cs/9uz5tcNkvNi1MQdu3bSAC1b+fViD2h06Y7sCfE9g+RlM2wJ4h2C6NyB4C2sw+KupQ9wX//7Xj929l7Gt2f1+vocVPZBugp2BGCkKJpHH/+U2iRGL1Om7Mf/z6Wafo2fwi2m6vHCLah3uspnQ+/EsuMfp9GaVAv1tHUYZOit5Pk2tihUESNxQZ7mD33qpPLhmvfpvYPkWR57dHbkejy7bVtT1A1oruzO8DNa0+YdnqnnUezdIvV7YCiou6O2ybmac87a+w6/LdeFcLtEnoKYBsELMmqyrPPf4poLE6/2+X0ix9hGoZ/84dgu7EKwTaU39HbjUgs431ZsORWAWXwlf70+Sf8bAOit/1Wi3a1goREdsWlwTzNMTTmfe1bjcRuMLVvl7InDKLLWjaHms74ak9waq7yYNeD8mCJ+cuDja87fezIsVP9t1fv/bf54lL+Wy8K4XZBhWDrMqcsc/z9nyCWSGL0+5z++EcY/b5v84dgu7kKwfbp6CmdG7+it71Wi069jiTLZHbGE3aW0aqjt3ZjB0EsmyOSSg/2EEz0dhmwQgiaF3b5rXhhGzUWn71gwBqJLnc7dEs3AMT2vNkT5oJD5+Me4Vj0++/LgxV21loe7L3/1kDc2ZF4MjmIJwP134Zwu6F6lGArSRx973MSqQymoXPyxY/Qu13f5g/BdnPlN9gKEYLturVJ52jToreZnd2Hclow37nahOit0evSKtme0ezhctHboJPL9GaDbqUMEqQGLYTXHb0dsSfc3WD2Okiq+mBPWKoCwjLe3aG57PJgDZBl1N2DlZYHc33+nRaiZrcMprhne4IX9N/OUgi3CyjoqO1jBFskicPPvk8qm8cyTU5//Pv0O23fpg/BdnMVBNgGqU2Ctqeqp5BYNuk6aVUq9DsdZFUlVfS3qcPKo7eXF1iWSSSRJJ7LD/Ywf/R2knxPLrs8R5gmaiJBbKs4WGNU67QntC/uqyfY9oSxQ2buxftX9J7tCYBxc4EwDKRoDKWwPWHr/tkTPPtvK3eIbnfIf+tYZ4b/1uulE8LtnArBdrIOPv6UdL6AZVmcffkF3WbTt7lDsN1chWD7tPVUztf0b77njd4OmjrsLl4WbBOit5Zh0Li+b8t7+PAHzI/SYF40V+1bw6B5ZZe5Su7tI6nq/Av6rOH9WT7bE8bWctz3HGU1TYzrQXmwXAEpnvDVnrBU/VvLgmgMcoW5/LdeFcLtHApLfk3W3quPyRZ3EEJw/vWPaddrvs0dgu3m6jGBbVjqa/V6LIll86pxd4up62ixGIlBxHOaNjl627y5wjR01GiM5JT2wuNRzuWjt140PKZbukNvt5EUhdTe4WCNUX1I9gTP3cvaTcyqbQVQdw9AVpayJ/hSHszQh/y3WxBLzOW/9aLHTWsr1GNPIAsKlnaevyS/u49AcPHNV7QqFd/mDsF2c/XYwPYxybIsLB/rQS+rx3b+3ORXYpmwLOo3dpRumbJgmxC9FZZF/dL2EU9ryztJK08uA5rnpyAgms+jJVOzF8R/wHVfyGFPSAVrTxhffoo94e4aq9dDUjXUnfHudEGWBxtpAz38ULuJaFTtqmDFPRu65/DfzlIItxuixwi2haNjCoNSMlfffUujdOfb3CHYbq5CsF1e9wA76f9pxzw2+f3abkxi2fU1CEEsnSGSSHqYf6FtPSjI6O1IW94pVSD8+nAwS9PsCUanTadsv8+kDo7sJCnHeGf01m9Ng2PbnnDf3MGOkq7TnjBWHkwI5FQGOZ1d6oOGb/7b8i2i3wNFsQHXuc4S9W9DuPWgx+yzDQqWtvYP2Tl+AcD1m++o3Vz7NncItpurEGwXlx+Qui7QXcW5fEyJZabep3FnQ5bf0dtlToPX6O1YW97LQVve3T3kgZ91XdHbWWpdXWDpOkosRnyQJLVZ9oT3zR1ig3bN67InjIzrdTEGvmB1e9ApbI7XIhD/rRBwe2lPFk9AJj/T2uD1+YZwO0OPGWyDUm5nj90XrwC4PXlHZVAexw+FYLu5CsF2MQUFo6uG3EXP6SYxq6+JZffds5Zo6jCPvEZvF1mnU6nQa7eQZYX03ngG+zxzL1IabK7kMtN8SC5L7O4hezj3K5UQdC7vmzvkUQd1hEcOGRuyGnuCWSlhddogK7b/doZW4r/V+4iyDd3kChCJ+vL3O4TbKXrsYBsEMGWK2+x99DEApf9/e38eJEle3vfj78ys++yq7upr+phrd3bn2pVYc1kRBkMICFtIf4BshUJaMLEGGeyQsSUtRMhrOyQj+0dYMhgZvmF7UTgkC8ISEAobvDJISBEckthjZnqO3dmd6e7po6q6q+u+8vr9kdk91dVVXZlZn6zMrH5eGxMwPZnP51OZdbz7Xc+xsY5dfZQjC0jYuhcStuYYpcPqxXSFfri1sOy4oQ7guCNDHZx0b42ucXSwgzYsITqVgRAI6Psw794aWX/Y4rLWXgHtahUczyM6t6CvcRgn3Vu50UCzoKcnzJ4CeN4d6QkAxG19elk4AmFicug86OPONZyeUC1BrVa0D9epOYDjD51rpXsCids+kLA9Sjw9ifnzF8CBw972FvJrq8xik7B1LyRsjeNUbuyo1nX6+rKApXtb3Oo91MHK2kaw071tVSpoVsrgOB6JuVN9j7Pi3hrBWnGZimAyCX8PdxRwOD0hr6cn+P0ITY8+PaHvc1kSIea1560wmWE+vcxye7DdLFRRBPx+YHJ64LmDIHHbAxK2R4lOpHDq0cfAcRxK+Syy915nFpuErXshYWsMtxR8uWEPvTBz393q3vaiXjQ31KEfbnFvS/ujbtNp+MNhfR/OubfHpSfIrSbqO5o72q+4zFFUFQ09l9mfSkPoUXg4bHqCmcd7qD1YuQS5qn3r4Js5NfT0MibjeVVF63+rqkA0DkTjQ/W/JXE7ZtghmMLxBBYuXATH8Sjv5rF19zVmsUnYuhcStsZwm6C0ez/j7t72PafP43441MFYYZmb3VuxXkd9rwAOHBLzbMfyGolj9j2nnt2C3BYhBIMIT2lun7vSE2po7WmFh6G5BYAzn55g5pqYm162pU8vC1qaXmbLeN5WE2pxV/v/6Wmt6O3IuX2XPQSJ2y687NraIZhCsTiWHr8MnudR3Stg87VXmcUmYetevCJsnRzO4Ba3thdu3NuoC8tG1RasspOHIknwh8KITExYWhNwj3tb3tqAqqoIJZIIxGL6PgbvzYp7a4Rji8sUBbVtzR2NTM+C9wcMxRylwG3mtiGLbfCBAILHtFozCrP0BAvTy0bSHqxUgNqoa+N5e7QHMwqJ2w5I2B4mGIli6eJl8IKAWqmIjVdvM3u3JWHrXrwkbJ3AjcKxH3bt0+5rzyI1wQ76DXUo6UMdEmPg3kqtFmp6r9ZO99ZNrcEO5bYW99CuVsDxHGLzxiaXjRRFQWNLS/cIpCYhhCNDu7fM0hPqVcilPQCAb3oe4PmhUojYjefdBmRZG8+bmrL0WidxOyK8JmwD4TCWLl2BIPjQqJTx4PZNqIzeIEjYuhcStsfjFVHbiZv2PGr39jhYFpaVs9uAqiKcSCKg56qywhH3dnsLqqogGI0hlEwOtTc7WoN1U93QJoMFEkn44wl9ncM4mp5Qq6JdLAAch9CcluPqmvSEnSzUdhuc3w/f1FFneZj0hCOxjKYnyFLHeN5Uz/G8gyBxOwK8Jmz9oRCWLl6Bz+dHo1rB+q0VErZDxyNhyyyuA8LWS25tL+zYuxfc21G1BZPabVR2tVzBxMzcwOPNxO6Hne6tIoqo6IN5hnVve8G6Ndih4jJdPLKAaXpCdguKJIIPhhCYOtoNwCzM0hMUBeL+9LLEBPho3B3pCY0a1HJR+/8GxvN2Q+LWZrwmbH2BIJYuXoE/EESrXsODWytQZJlJbBK27oWEbX+8LGo7GZfHwRKW7u3BUIfJyYMpX1bXHuZYQ/EMuLeV7DYUWcslDqcnh9rbKFqD2VFcxhJVkdHQ84ODkxnwwZBr0hPUZgPSnvbLmZCZBQTBHe3B9jrH82qustHPABK3NuI5YesPYOnSFQSCIbSbDazdvAFZkpjEJmHrXkjY9sbrbu0osHJPvFJYZpZWtYpmpQKO55kPdTADK/dWlWUt3QJAYm7+4M3Rra3BDheXzRieXDbK9ASpUka7XHqYnoDBAnVU6QlyIQ+l1QTn88GX6T+lznjs/ucabw+mauN5VRUIR4H4xMB97UPi1ia8JmwFnx+Lly4jGAqj3WxibeU6ZFFkEpuErXshYdubcRW1XntcXiosAx66t4npaUOv/2HdWzPTo47EM+De1nI5SKIIXyCIaI92Ucft7UhsA8ewKS7TJ5fNurC4DEAzuwFVliGEIwikrfdG3mfY9ISDf1dVSNt6ekIsDj6eNJ2eYEt7MLENVZ/2htSUNuTBACRubcBrwpb3+bB48TJC4SjEdgvrN69DarfZxCZh61pI2B7lJLi1rB+fF9zb42CZmlAtFCC2WhD8AUS7vsp3o3s7aB1VVVDZ1qZZxWfnDqaw2eXe9t6DufSE6uY6oALBiQn4o3ors65jnCwuUyUJjZzWgiuQmQHnDziannDovHYL0q7W+cOXmQF8Pku/cBzsa8C5hvNvK0Wo9ar2QT1prD0YiVvGeE7YCgKWHr+EcDQGSWxjbeU6xFaLTWwStq6FhO1Rxl3UduKlx+qlwjKoKspZrRArOTv4q139FONrMnZve3HEvd3NQ2y3IPj9iGb6F0LZ5d4a4VBxWbOJxu7hyWVWsFPgisU9iDUthSXstvSEvV0ojTrAC1p7MBx/T8ymJ1hvD5aFKkmAj5xbYgAcz2Px8UsIxxKQJBFrKzcgNptMYpOwdS8kbI/iJbHHCpaPmdzbh5RzWaiKjEAkgpDelsrSnlzi3kJVUdnSnMb4zCw4QdB/7F73tra9BUWSIIRCCE9O6escZpB7azfNrQ2oigIhGoM/mRo6HrP0BEAb7qAo4CNR8D325kh7MEXW8m+31wzFJXHLEC+5thzPY/GxS4jEk5BlCes3b6DdqDOJTcLWvZCwPcxJSEMgNEbl3iqyjHJOcw7tGMnrhHtbL+yi3WyAF3yIHTNlq/fehh/s0HOPxxaXyajpgjwyPQvOQPcKYLTpCYrYRjOv5WgHZ+bACT7b0xOMPk9UsQ1xR/sGwjc5DfgD7mgP1moABmuBSNwywkvCFhyHU48+jmhyAoosY/3mClq1GpPQJGzdCwnbw5Codd69NRx7BIVlLJ/P+4VlkYkJ+IJBy3Fc494CKG9qnQhi0zMHrc6svqewGOwwiObeLsRaDZwgIDqrf73edQyL4rJhBG67sAOpWQcnCAjpezQrcIfhOIGqlPag1KsAz8M/Mzg9YXDs4//90LHHpScYhMQtA7wnbB9DPJWGosh4cPsmmtUKk9AnUdhyHEfClmVcErYjx8lr4abUhOMw+/oRm03U9vYAjkNiejzc22apiFa9Bp4XEJ/pn09sxL3teR7j1mAAUN3Uxt6GUmn4whF9ncMMW1w2LI0tbbqaL5GELxY3ff6w7u1xAlfMbgKKDC4UhjCRHry2yfzbw/sc8DhMXncSt0PiKWELYP78o0ikp6AoCh7cvoV6ucQk7kkVtl7AC8JW1f8bBSRsj8LqmrjdvR1ZYRmA0rbm3sYzGXC8wDy+Uexwb6OZDAR/QI9lLP7RfQ0+xkqlfuchUqOORkEbThDrmLRmFlvTE5pNNPVWV6HZUwDPuyY9AZIEUU+dECanwQWCQ6UndGO5PZgBSNwOgdeE7dz5R5CcmoaqKth49RbqpSKTuCRs3YtXhO0ooPxad+Im95ZlYVmjXEKrXgcvCIhnDveIZfGcd8K9bVXKaFYr4Dge8Tlj3SAOYjlWXLYJVZbhi0QQSk3q6xzGjuIyMwK3lc9CbrfA+f0IZjSn3zXpCeUS5GoF4Dj4RpyecDSW8XVJ3FrEa8J29ux5TGRmoaoqNl69o31lxgAStu6FhO1DSNQOxgvuLQuccG+TM/2LsA7F6XPp3OjeRtJTB/nEo3RvjXCouEySUMtqvXojs3OGXXSz6QlD/WKhqmhsadc1kEpD0FMozIWwLz1Bym0BsgwuGIKQOjp4wo3pCZ4Wt/fv38dHPvIRnDlzBuFwGOfOncNzzz2HNqMBBP3wmrCdOX0WqZk5qFCxdfdVVPWvaYaFhK17IWH7EBK2xnHqWhl9fjldWGZ6qMPuDmRRhC8YQmTicEslu57/dru37VoVjXIJHMchPjd/8HM3twZr7O5AajbB+3yI6B0sBrm3RmCZniDXq2gXCx2jeTn3pCfIEsSc9guCkJ7yRHqCp8Xt7du3oSgKvvSlL2FlZQW//du/jS9+8Yv49Kc/bduaXhO2meXTSOtNorfvvobyTp5JXBK27oWE7UNI2BKjotdzWlUUlHPaxKfutmB945j6ytf4sUbPN+PehlNp+EIhU/G7GUVrMKjqQXFZeHIKQp8OFmaLy1jTzG1BkUTwwRACen/eYfJOzXJsekK1DLlSPjY9wcz43WHagxnB0+L2ve99L55//nn85E/+JM6ePYv3v//9+Jf/8l/ij//4j21Zz2vCdmpxCVPziwCArddfQymfYxKXhK17IWGrQfm11mFx3U5iYVk/StksoKoIJRIIRMx/3byPmWvayzUbxtHtFlhio456cQ8cOCTmTz3co4Pube9jHv5/sVpBq1QCOA7RuQV9HfPYOppXltHUUyiCmRnwgaMi3G739tj0hPwWIEtaekL6cB55L4ZJTzgSy6TI97S47UWpVEI6fbRlRSetVgvlcvnQn0F4TdhOnlpAZmEZAJC99zpKuSyTuCRs3QsJWw0StcPjxDUc18IyWWyjsqulgiVGNNTBDEbd225xUd7agAoV4WQK/kh0qP3Z5d52U9XbbgXicQT06XGD0hOsXN6hRvOWixCrmkNqtfetWYFrGFl+mJ6QmgQXDJlOTzDj7g6TnjBW4vbu3bv4/Oc/j49+9KPHHveZz3wGyWTy4M/i4uKIdngUO4RTev4UppfOAAByq/ewt73FJC4JW/dCwlaDhK17OInu7aDCslh68mAAAsv4vWDt3nYjNZuo6/UbCQa5t0YGO5j5GrzXOUq7jbr+DWZ07pThD4vBYtJQGMM0tjeZjuYdhBn3VqlWIFc0B9w3PQ9wnKX78jD28edaFbiuFLfPPvvsQXP8fn9u37596JyNjQ28973vxQc/+EE888wzx8b/1Kc+hVKpdPBnfX392OPtcm3tEE6p2XnMLJ8FAOTXV1HQc6OGhYSteyFhq0HCli3k3h73b+Y22qpV0axUwPE8El3ja73t3m5CVVWEEkkEojHm+7PyvjFIwNdz25DbIoRgEOGpjL7OYZwuLlPFNpp57dvW4MwsOEEYeXHZ8d0TtqFKErhgsGf3hG7Mpiew+EzjVLszpC2Qz+exu3t8Rf/Zs2cRCGhNpDc3N/GOd7wDb33rW/HlL3/ZtBArl8tIJpO4GPVB6BI0XhK2E9OzmDv3CABg58E6dtZXmcQlYeteSNhquF3Y8j4f/MEg/MEQAqEQBL9few3oTzNVVSG2WhBbTYhN7X9VlzymYV//Zl/rRl96Rl6jRtbmuf6P77gljlu/17qxyUnMnH8EstjG2isvH3qx9dtnvyV6Hd/vWL7HP/T6Wa/ze63D84d/NrG4jNhUBq1qBTuv3emI1/VZ2iN+r2vfFd7QY+1ea9DjC06kkVhahior2Hv1JhRJ6nkHhK7nfvcxgx5j9z56PWf6x+AQPXMevlAYYmkPTb0grvv6D95T17U55vxB++38dz4ah39+EVBViA/uQ201Td+Xzn8/ct/7aLGWJOP/972XUSqVkEgk0A/r34/YSCaTQSYzOFkZ0Bzbd77znXjTm96E559/nqkQ85KwTU7PHAjb3c0HJ0rYsp9Q7H5ha8fvpF4Utm4VtYFwBJFEAuF4ApFEAv5g/4ryXqiqgkalglpxD7VSEc1q1aadug9VNfaaVlV14GtVhWrb+7iR9TupFgqYbLXgCwYRS6dR7TBw+u3T6LUwe6zR83vtS1HUQwKpsr2F6OQkgrE4gvE4WpXe49x7xVdU5dhfLvrt4Wjsw/dCUdWeAnefVrEAcXIK/mgU0dl5VB6sQcVRoTiI7nW7H2P3Psw9Z1Q0tx4gdvo8/MkUxFIRcs3e94FB++38d6WmpScI8SR8M/MQ1+/px6Pv+cevfVjgHrm2Jl/LrhS3RtnY2MA73vEOLC8v47Of/Szy+YdtrmZnjbVd6YeXhG1iKnMgbAtbm8iv3mcSl4StOyFhq+E2YRuOJxBPTyI+OdlTzIpiS3Nnm01I7XbHfVTB8UKHsxuEIPgRSSQRSSSRASC12yhmt1HMbkMS7e3j3Y2iKEO9F9gpMO3GqmDs+ZhVFaVcFpOLS0jMzB4St0zi96GX0Bsk/swgi21Ud/KIZ2aQmDuFfEVLGTQr/h/u7aiL142R+3JUqB0+p7r5AKlHLiCYSmt9cBv1IwJXVpRD7q0VATxIMB4nkOVmA629XQTTUwjNzqP2xmtHfrno3tOg+IPONyNwpdw2+HAUXEBLT5ALx7caHRz7eIFrBk+L2z/90z/F3bt3cffuXSwsHJ4bPYwA8JKwjU9OYf6RC+DAYS+7hdz9N5ivwQoStsNDwlbDLcLWHwwiOTOLicwMfHqaFAAoiox6pYxGpYxGuYxGtQJFlg3HDYTCiCQnEJ2YQDSZhC8QwNTiEiYXFlHZ3UFhcwNNm10cL8DCvTXiHrKinMshfWoBwWgMwVgMrQ5HnsUvAY65t9ltRCczCERjCCaSaJVLhuPb5d4OWl9q1NEsFBBKpxGdO4XSG68de+7DvQwSk2w/m5r5bfjiCQiBIIJT02jls7YLXMMoMqTcFvzzixBSk1BqlSPpCYNcdTMC1szniitzbkdNZ86tz6Y3OTuEUyydxsKjF8FxHIq5LLZfN/biNAJr15aE7fCQsNVwg7CNpdKYmJlFNJU6eG7LsoRqYReVwi6qxT12ObMch3h6Eum5eUTiyYMfl/I55Ffvj8zJHefc20Hiykrubb81M6fPIDEzg1phF7nX7xo6xwu5t4n5BSRmZtGu15C/c6sjXneeZa+92ZN7q8Xpvz7v8yF94RI4gUdlbRWt0p6+1mHM5t722tugfNbjrpMvnkB04TSgqqjdew1Kq2Vr7q2R/Xb+u2/2FIR4EmqrBfHBPaArPaH7/MGx+5/bkmR89nuveDPn1im85NjGUmksPPo4OI5DKZ8jYTtUvJMnbO36lXashS3HITmV0Zy3jtnv1dIeittbqO4VbPkFBKqKyu4OKrs7CEajmJw7hWRmBsnMNOLpSexsrGNvc8OetTsYNj3Bzdjh3vZzG0vZLBIzM4im0hACAciMx8U75d5Ws9uIZTIIRKIIJSfQLBUNx3fKvVUkCfXcNqJz84jOzaNVKQE93mMGpSdY+frcTHqCVClDrJTgjycRmj2F+uob7kxPCLonPWE836nGnOhECgsXHgfH8Sjv5rF191VmsUnYug8SthpOCVuO4zAxO4dzP/YU5s4/imA4AlmWsLv5AHdf+mus37yBSmHXdnEJAK1aDZt3X8W96y+hXi2DFwRML53G6atPIhAO277+MJh9fhi9nCx63g6zF7P3vd2oo65Pyhq2LZib+t4qsoSqPixoUN9bI8uOarBDfScHudUC7/cjMjWtxR0ctsde+rf2MrKPQWi9b2UIkSj8E6neexi4J5veoxRZm14GdsMdhp06TOLWZliLp0hyAgsXLoLjeFQKO9h8jYSt9XgkbJnFtVHYOjlKNzGVwdkfexNmz5yDPxiEKLaQXX0Dd3/0V8it3oPYbDqyr2a1itXrr2Dj7h1IYhvBSBSnrz6JZGba1nXdkBLiJQYNdUhkpsHZ4IaPKt2ou3dqJZeFIsvwhyMI9xFg/XBqLC9UFdWtTQBAODMN3u/veY7Tk8tUSXzY+3a6d+9b0/th2Pv28HCHuSP773W+GcyeS+LWRliLp3A8gcXHLoLneVT2drHx6h1m72IkbN0HCVvnxFR0IoXTV5/E/CMX4A+GILZb2L53F6+/+DcobG6YKg6zk3I+hzdeeRHV0h54XsDc+Ucxd/5RWwQTC+x6rrh1Ylk/6sU9iM0meJ8PscnJQ//GYqiDGXo5ilbXUmUZFd29jdvk3nZfn15xBrmE3bTLRbSrVXA8j6g+8tbIJRjslBoIMmiNjhjtwg6kZgOc4ENwRhOQrhrukN8GZAlcMAQh7exwB3e+A44Bdgjbpccvg+cFVIt72Lxzm4St5XgkbJnE1P+zCyeErT8UwsJjF7H4+CWEojHIsoTc2j28/tLfYG97yzWDFTqRRRHrN28gt34fKlQkM9NYvnwVQh8HalhGeV/cVO5sNTWhr3ub1b/Cnx6ubaUZMTzsV+NG3NtqPgtFluAPhRFOpU3Ft/oLhpX0hO5zapsPABUITqTgi0S1Y7piODG5rJvm1gNAVeFPpiDo+3QNsgwxt5+eMAUuEGSenmD0s5HErQ2wFk+hWByLj18CLwiolYrYuHOLmfghYes+vCJs7WTUwpYXBGSWT+Pskz+OWCoNVVWwu/kAr7/419jdeOBKUdvN7oN1rK1chyS2EYrGsHz5Kvwhc8MjTjqjdG8r+RxURUYgEkEofrjq2/PubVZPuxiRe9tzHyYfgNRsoFHYAQDE5k71PW5QeoKV928z6Qlys4FWUeuRHJo9BXCcq9xbLT2hrKUnzMwf2f+g81lB4pYxzIVtNIali5chCD7UyyU8uH2T2QctCVv3QcJ29MI2lk7jzJM/jsn5BS2Xfa+AN15+EbnVe5AlaaR7GZZ6uYTVG9fQbjYQCIWxfPkqglH27s4w94gKyzQUWUY5p1WVJ2fscW97rjsS9zYHWZLgC4YQSU8eOf74/R19btlVXHbEvc1uQZUV+CIRBPWcYStXy+7ismZuG4okgg8GEZjUprm6SeBK+S1AlrX0hJS5+987tukQJG5Zwlo8BSPRh8K2Usb6rRUStpbjkbBlEnOMhK3PH8D8o49h4cJF+ANBtJsNrN9ewYPbK2g3GyPbB2vazQZWb1xDo1aFzx/A0qUrCMf794Mk7Kd/aoLmcEYmJuALBg2dY2pdEyGYureKcuDexufmD97Qrbq3PdewobhMlSTUctq+o7PzQJ/PSaeLy6AoaGa1IrjgZAZ8xwAZVyDLEPPadRTSGXD+wMi7J5C4ZQR7YRvB0qUrEHx+NKplPCBhO0Q8ErZMYo6RsJ2YmcWZH/txJCanoKoqdjbWtcKsvcLI9mAnktjG2so11MpFCIJPyyGOxZiuMa7u7TCpCWZfx2KzidreXs+2YP3X6PNzl7m3tZ0cZEmELxB0tXvbTcNia7DBTqmBICZiiOUSxGoF4HkE9a//3eTeKpUS5GrFsfQEErcMYC2eAuEwli5egc/nR6NawfrNFWbV2SRs3QcJ29EJW38wiMWLlzF79jwEwYdGtYx7115Cfu2+J/JqzaDIMtZv3kCtVAQvCFh8/BICHcMnmKwxZtfMCKydxrJeWBZ3QVsw29zb2TnPuLdQVdS2O1qD+fz6WocZRXHZIJrbG4CiwBeLw5dI9l7zyB5GnJ6gyOBCYfAT5ooLe8c2fi6J2yGxQ9guX7oKnz+AZq2K9VskbK3HI2HLJOaY9LBNTs/gzBM/jmhyAooiY/v+67h//RW06rWRrO8EqqriwZ2bqFfLEHx+LF28DH/X199OYfcvTMMw0rZgpSLajQZ4QUBs6nD7pFEPdTCDIfc2n4ckes+9bZWKEA9ag80NDri/9pG9mL/GZtITFLGN5m4OABCangN4fujet0yRJIh6b15fOgP4/SNLTyBxOwTMhW1Id2z3he3NG1AYFbSQsHUfJGxHIyB8/gAWHr+EuXOPgBcE1CslvPHKi9jTG7ePO4osY/3WCpr1GnyBABb19xhm8Ud0H8ehsGxQ7m1yyLZg/fdk/Fim7q2qoJrVWkPFZ83n3jo22AFAdWsDABBMpeHTp/9ZcW/tLi5r7eYht5rg/H4EM1pqi6vSE8pFKPUqwPO2DHfoB4lbi7AWT/5QCEuXLsMfCKJVr2H95g1mldokbN0HCdvRCKJYOo3TT/4YYhMpKIqC7fuvY/XGNccmizmFIklYv3kDrWYDgVAIpx573BWDHtzs3o6SSn5Hn+wVRrjr62XPu7c7O5DENnyBAKKTgxv7D2JU7q3UqKOp5+BH5xb6Hud4cZmqoqGnUQRSk+Attv8bVuAeh5jdAhQFfDgKPjEx8Phh0zUAEreWYC5sg0EsXbwCfyCEVqOOtRUSttbjkbBlEtPjwpbjecyePY+FCxe13PVaFfeunRy3theS2Mb6zRuQJBHhWBxz5x5hFnsc3dtRFpapioxyTvt6OTFjrLDMLE66t8Pk3trp3g5sDba9CVVR4I9GEdB/6bByGewuLpPrVbRLewDHab1vYd69HZZj0wskEZKePuGbmgYE39DpCYMgcWsS1uLJFwhi6dJVBIL7wvY6ZElkEpuErfsgYWu/CApGojh99UlMzMxChYqdzXWsXn8Z7YZ323uxQmw1tV7ZqorEVAaTpxad3pJn3VvmhWW5LKCqiEyk4AuGDJ3D4vVvRwP9o+5tHpLYhuB31r01m56giCLqes5odO5U3w8tK+4t8+Ky3BZUWYYQjsCvF2+5KT1BLhagNOoAL8Cnp9/YmZ5A4tYE7IWt1oMyEAxpPTZXbkAWSdhai0fClklMjwvbiZlZLF95AsFwBGK7ibWV68iv3rclp8urNCplbL9xFwCQWVpGLG2+irkX49g5YZSFZWKziVqxCABIDuneshDDRt1bQ+8ZqorK9ujdWxbpCfV8DnJbhBAIIKwPTDAkXo/sxfx7kJn0BFWS0NR7ywanZ8EJgun17EbKbQKqCj4aBx8b3Ht7GMFP4tYgzIWt3lw9GAqj3WwejM1kAQlb90HC1l6RwPt8OHXhMcyePQ+e16aM3XvlJdTLJVvX9SrF3DYKep7e/PkLCEbYtgizk7EuLNMFYGwqA443Jk48497udrq3meHjWxTapovLFAV1fWBCZHrmQDR2R7GjNZjZGO29XUjNOjhBQFAv3nKTe6u225B2tal8vswMIAi2pSeQuDWAfcI2ArGlC9s2CVtr8UjYMonpYWEbisZw5uqTiKenoKoKsvffwIPbK54bnTtqsvdeR7W0B14QMP/oY0wKzKzea6+mJrCmUS6hXa+DFwTEDbYF64ddqQzDubf7nRNmbXFv+yw7kEGisrlXgNTQRGPEREcLK+6t2eKybprbG4Cqwj+RgmCwr/VI0xP2dqC0moDgg29qRj/++P1YgcTtAFiLJ8Hvx+Kly9rXpq2WLmxbTGKTsHUfJGztFbZaGsJV+PXUnvvXX0FBb+FDDGbz1TsQ2y0EwxHMnDnn9HYMMw6FZf3bgmk5nokZe9qC9aOXwBvW0T3q3u70dG+tvk+OzL0FUNWLUcOTUxD0XtFW3Fvbi8saDbSKWpeH0NwpANxAcTpqpKyenhBPgosMnpxo5XlI4vYYmAtbnx9LF68gFI5CbLewdvM6xBYJW2vxSNgyielRYcsLAuYfuYDZs+fBcTzKhR3cu/YSmrWqbWuOI7IkYvO1O1ChYmJ6BokpBl8XnzD3lvXrsrKThyJJ8IdCCCeTh9eysS2YGVi7t0bXcNK9FasVtMolgOMQnZ3ve5wbista+W2okgQ+GEJAH57hqvSEVhNScRcAtOIyjjednjAIErd9YC9sfVi6dBmhSBRSu421levMem2SsHUfJ1nY2j11LBAOY/nKE0hMZaCqKrKrb2Djzi1mk/xOGvVyCTvrawCA2bPn4bfYJ3PUsHRvBzHatmAKynmtbVLSJvd22MIyM4yTe1vb0r7yDySS8Edj+lrmsb24TJbRyGm/RAQy0+B8PvOb7LEG0/SE3TzUdguczw9halo//vj1zUDitgesxRPv82Hx4hWEIjFIYhurK+yayJOwdR8nXdjaSTw9idNXnjzohrC68goKm5SGMCw7D9ZQKxfBCwJOPfrY0K8zr7m3dhaWWVm3lNXagoWTE0O3BbNrqMNJdG/lVguN3R0AemuwfsfZ4N4aofMUsbQHqV4DxwsIzlgrLrMVVYWoC3AhmQIXCg88xcw1IXHbhR3CduniZYSjmrAlx3aYeCRsmcT0qLDNLJ/GqQuPgxcE1MpF3HvlZTQqFVvXPElsvnoHkthGKBrD1NKy09s50UitFrO2YP0g99aie5vdhirL8IXDCOr9ZA2JVwtrD1tc1tgvLktMQIj2zm11ND2hUYdc2gMAbTQvxzFLTyBx2wFzYSsIWHr8MsLR+IGwZdVInoSt+yBhaw+Cz4fFi5cxOa+NwNzZXGc67ITQkMQ2tl5/DQCQnj+FcHxwH8rjGEXfWzcVlh23BOu2YOTeHr0Xdo7lPfyVv4RaTrs30Y6evd24obhMaTXR2tNyW0Mz8wB3tLjMDswIXGknC1USwQWCEFLDD/jYh8StTfCCoDm2sTgkScT6zRskbC3HI2HLJKYHhe3+tLFocgKKLOPBq7eQX71v23onnepeAcX8NjhwmDv/CJP2YGbxamEZa45rC8aKcXJve8FqLG83jZ085FYLvN+P8H6+qKH9mGfoyWX5bSiSCD4YRCCtPY/sLi4zhaJA0n9ZEFKT4AJBJrm3JG5tgBcELF68jHAsAVkSsb5yA616nU1sEraug4StPcQnpw61+bp3/WVU9Hw3wj6y995Au9VEIBTG9PLpoWJ5zb0dxCgLy4DOtmDGUxNYvH+Mzr3dn1rmrHtrOj1BVVHLas5zJDNzULDVHcUu99ZMcRkUBU19r4GpaXA+/+AFDKzBMj1BqVUgV8oAx2npCd2Pocf5gyBxyxiO57H4+CVEdGG7dvMGWvUak9gkbN0HCVt7mFpcxqlHHwPPC6gW93Dv+stoN9j8gkgcjyLL2NbTE1Kz84h0taMaBVRYpvGwLVjYcFsws2uM0r3t5vDUsofu9Kjd214Meqyt4h7EWg2cwCOqF2z1whXFZeUipHoVHM8jZLC4bNRI+W1AkcGFwuAnhh8JTuKWIQfCNp6ELEtYv7mCVo2ErbV4JGyZxPSYsOUFAacuPI6phUUAWn7t+q0bUGja2EiplYoH43nnzj0Kfog59aNwb0fJMO6tWUbRFqwfdri3R/I9VRWVrJ5bPNM/f7XfGo66twBq21qnllBqsu9gByPY0Rqsm8a2NjjBl0i6srgMsgQxr31T4UtnAJ9/KPeWxC0j9oVtNDGhC9sbzBrKk7B1HyRs2eMPhbB8+Sri6UkoioKNu3fGJr9WVdXRttlhQG71HlrNBvzBIDIOdE8w8/wdZWHZMHuxPLFMtbctmKPu7Y7m3voCAUT0gQPanux1b60Wl3Ui1mpolYoAB0RnnW8NNrC4rKCldYVm2RWXMU1PKBeh1GsAz8OXmdWPPxzP6POCxC0DOJ7H4mOdwnYFzSoJW2vxSNgyiekxYRtJJHH6yhMIRrTpfasr1w4cK6+wL2B7/TFyjNvEr6oo2H7jLgBgYnYOodjgMZn9GDf3dpSMoi1YP0bl3laz+7m3o3Nve8e34N5uaY5oIJEwNdhhkEvai6GLy3ayWnFZgF1xGWuk3BagquCjMfAx6x1bSNwOCcfzWHjs4sNq7lsraFbZ9N4kYes+SNiyJzk9g8WLlyH4/GhUy7h/7WVmryE7sUOYuk3o1ktFFPNZcOAwe/Y8+xf9ANzq3tpVWNbfvXWmLVg/2Lu3O5BEEb5A0HPurdy2NtihF3a3BjtSXOZ3X3GZKrYh7eYBAL7MDMALlq4Didsh4DgOCxcuIpZMQZFlrN9aYdZUnoSt+yBhy57p5TOYO/cIOI5DaSeH1ZXrkMS2LWuxYJTi0y0iN3f/HmRJRCgaQ3pu3nKck+Tesr5tjVIJ7UbDkbZgwwpZI+6tqiqo5jzs3h4a7JDSjjGyloX9WXFvu4vLxJpeXDY9uuIyU6N593agtJqA4IOvz2jeQZC4tQjHcVh47CJiE53CtswkNglb9+F2Yavq/7FGURRbRAkvCFh47CLS85rTkV9fxeZrd6C6UAA57aY6LXJlSUT2/hsAgKnFJfhDoQFnOMcoL9Po24Jp4i8xPXxbMLvc22Gufy2fhyztu7cPq+V7XSur69jl3qqyhHpOK4aKHlMY51RrsG6a2aPFZa7qfYuO9ITEBLhwxPT5JG4twHEcTl24iNhEGopCwna4eCRsh47nMbfWFwhi6fJVxFLa6+fBq7ew82DNlrWGwWlR2Y2T+ynlc6iViuB5AbNnzlmOY+U5Zcfz2+nCMivrVvI7UGQZ/nAY4UTS0Dmm17bp6WXUvd3vnBA/prVWP5x2b+s7OcjtNvhAAGF9KAUr99ZKcdlxMbTJZXpx2cw8YFEn2Jqe0GwMHM17HCRuTaIJ28cR3/9gvnWThK3leCRsh47nMWEbisVw+uoTCO0Xjt245rrBDG4Ttd04tb/tN+5CURREJ1KIT9rz1TjRH1WRUc5pRZZmhjqwYNjCMqPUdvKQJQm+YAjhAbm3bnBvD/1I7RjsMD0DTm+f132WFffWyH5Mu7f57MPJZZPWisvs4NBo3t0cVFEE5w9A0AvgjG6BxK0ZDoSt1qrowe2bqJdLTEKTsHUfJGzZEp+cwtKlq/D5A2jWq7h//RVm7fJY4HZR282o99puNrC7sQ5Ay5W2OprXbvd2nAvLyvpX35HkBHx6X9VB55hNTTDztDIleo24t4qCyn7urYW+vkbdW7vG8rb2CpAaDXCCgMgx6SMsWoMZYWBxmX6tA1OZgylr5mOydW+7gmnDHQAIE9poXqOQuDUKx+HUo48dFrYlErbW4pGwHTqex4Rt+tSCPnGMR2VvF6s3rkFqt2xZyyxeE7WdjHrvu5sP0G414Q8GMXlqcWTrehXWt0ZsNlHb2wM4zlTuLQtG5t7mc1BkfSpbKtURk22OL6tY3edVt7TBDuHJDHh/QDvGSJwjcYd3bwchlvYg1WvgeAFBG4vLhklP6DWa1wgkbo2gC9tEeqpD2BaZhCZh6z5I2DKE4zB77jyml04DAHa3NvDg9k0ossx+LZN4WdR2M6rHoSoKcnpx2eSpU5aLy9zi3rJg5O5tVnNv41OZI+75+Li3+mOcNd+dw2n3VqxW0NbFWHTW+FheI+uzKC7rjtHIbgCqCn9yAkIkCoB9cdmwSDsdo3mTE4bOIXE7CI7DqUcuIJGegqoq2LhDwtZ6PBK2Q8fzkLDlBQGLj13ExPQsVKjYvnf3QBg5yTiJ2k5G9ZgqhV1Ui3vgOB4zp8+OZE27cHNhWT/qpaLWFsznQ2zEuc+jcm+rne7thLPurZXisurWJqACwYkUfOGwdoyR9Q0c083QxWXNJlrFXQD65DKL2DqaV5Ig7mj55r60sec8idsBzD9yAYnJDFRVwYPbtw4mxQwLCVv3QcKWHb5AEMuXryI6kdIKL2/fxN72FvN1zDCuoraTUT3G7P3XoaoKYqk0oh1fHZvB7r6343yr991bO9uCOereyjKq+oTC+DHuZ//9sHNve8c//jy52UBzrwDA3FjeXoyiNVgrl4UqS+CDIfhTWiHfKIrLTKUnlPagNOqG20WSuD2G+UcuILkvbO/cQq24xyQuCVv3QcKWHcFoFKevPhyle//GK6jqb/ROcBJEbTd2P952o4FdPbdw5vS5kb3G3doWbFBqwnFLWElNqOzkoSoyApEIQvGEoXNYMSr3tpLL6q3PIgh1fBXtFfe2lt2Eqqjwx2Lw6/eIlXvbvZaRe3KcSFYVGQ29uCyYedjpwXxMc+6tWcTtDbTX7hk6lsRtH+YfuYDk1LSeinBbS+JnAAlb90HClh3RiRSWDzoi1HD/+ito1WrM1zHKSRO1ndj92HfW1yC2WwiEQkhZnFx2kqaWsUSRZZTzWgs9M23BzLq3pvZE7u3hfxdFNPSv0mPHfN0/qtZggxCLBUjNOjhBQHBa61TBQpyyTU8QAXJurfNQ2KrYePU2M9eJhK37IGHLjomZWSw8dhG8IKBa2sPqjVcc64hwEt3aXth5DVRFQX59FQAwubAIwWAroaHXpcIyAA8nlkUnUvAFAobOMb+v3j8fXe5tFoqiIBCJItgxuMIr7m09n4UqyRBCIQRT2tS1XlFc0RoMQHN7EwDgn0iDD4V7xxgYk/2LzkpeMYnbLubOP3pY2BZI2FqLR8J26HgeErZTS8uYPXseHMehmN/G+q0VxzoikKg9jJ3Xo5TLolGrQhB8mFpcshTDDe6tFwvLxEZDa0fJcYiPuC1YP6yIkEPnd7l8iiShprufCQ+6t6oso6Z/3d85ltdKeoJd7m3nIXKjjnZJ0zz7xWVWOh/Y2vvWICRuO5g9ex4TmZkOYbvLJC4JW/dBwpYRHIe5849iSu95ml9fxdbd1xyp5iG3tj92Xpf9DhgTM3MIhHu7Paxxq3s7akrbmnBKZKZH3hZsWPfW6D2sZLehqgoC0RiC8XhHTGPurVVHnZV729jNa2N5/X6EpzJ9z3NLcVkztw1VkSGEI/Druc52FJcNlZ5gABK3Hew7tpskbIeIR8J26HgeEba8IGDx8UtIZvTXzeuvYufBGtM1jEKidjB2XaN6uYRyYQccx2F6+Ywta4wCLxaW1Yt7EJtNrS1Yx7haJ7HDva3u5AFY63vbcw2DYtvIQzE0llfvFBPJ9B/L2wtLOa5WhGbHKaokoannOgenZwGDGmbUvW8HQeK2A1VVsfnaHVRI2FqMR8J26HgeEba+QABLl68impyAIstYv72Ckt54fZSQW2sOu65VfvU+VFVFLJVGxGCT9U7sHuowzpT224LZWFjG4mkzjHtb1d3bYCyOQCzWEdNe97YXVl5DraK1sbxG1rfDvW0XdiC3muB8fgSntP26rrhsACRuO9h6/TVUdneYxCJh6z5I2LIhEI5g+fITCEWiEMUW7q+8wqxNnhlI1FrDjuvWbjZQ0ItRZk67z701+pDZ9O4cbWFZJZ+Dul901SH8jjuHFf3EBmv3VhZF1PTPZk+6t2A3lrfnMV0HDdsaDFDRzGqv50B6EnwgaGhvdhSXHRG4Bp/TJG47oFQEq/FI2A4dzyPCNhxPYPnKVfiDQbQadaw60OqL3Fp3svNgDbIkIhiJImmhwMkNhWVGcFthmSLLqOS1r+2TegunYfZhp3trZr1utNxbFaF4An59TGzfmC50b7WxvBVtLO9M//vkZGuwzkOkWhViRStYDM5oxXxOFJdZhcQtY0jYuo+TKGwVRWEuFuLpSSxdugxB8KFeKWH1xisQW6Nt9UWilg22tOuRJOxsrAMAphaWRvLeMI6FZZbagukpQdF0GoLfb+gcVtjVFuyIe9tuo76nGVCdnROGeS6P2r2t6d9uBCfSEEIhfb3BWHFvjTCwuCy7BagqfLE4fDFtEIUbisuMQOKWISRs3cdJFbasmZidw/yFx8BxPMqFHazdvAFZkpiv0w9ya9ljx/Xc29qE2G7CHwxaGuzgBvfW6cIyK7TrdTTKZYDjkMgM3xbMDUMdelHZ3oIKFaHkBPwDOnM44d4OesxSo45mcQ/ggKhLBzt0HqKIbTR39eKyjlZmZvfmRHEZiVtGkLB1HyRs2TC1tIzZM+fAgcNedgsbd24Znu/NAhK19sH+NaIiv651zJg8tQB+BIMdqLBMY7+wLD6dOfKGzyrVoN/xo3JvpVYLdX2oUmfurVvc2170dG9VFYF4Av5oTF/PQBwLa/U+xpzgbe3koYht8IEAAukpAO4oLhsEiVsGkLB1HyRsGcBxmDv/yEEP29zafWy/cZftGgMgYWs/rK9xKZdFs16D4PNj8tSC6fPtdG/HubCstleA1GpB8AcQ1adhOY1d7i0AhCYm4NO/2u8b04XurdJuo6EXx5l1b62kAAxdXKYqaOqDKAJTGXB9fmG1o7hsGIFL4nZISNi6DxK2w8PxPBYuPI6kPtRk8/VXsavnU44CSkMYLayvdX7tPgAgNTsPX59Ka5Y44d66rbAMqopyTvsKOXlMwZLRfYx6qEM/jri3zSbqxT1w4BCfcV/ubS+OuLe5baiyAl8kgoA+VrhX6FG1BhuEWC5CqtfA8YLW+xajKS4zEqMfJG6HgISt+yBhOzyCz4elS5cRS6WhKDIe3Lk50h62JGq9T3WvgFq5CJ7nkVkyP5bXDe6t01hxb8t6W7BgLIZAV0cBp9I3bHFvs5p7G06nIQz45cmN7q0qSajv6EWAnekVRtYztCdz+9HOOV4kN7JaOoU/mYIQjmhxHSguMwqJW4uQsHUfJGyHxx8MYunyVYRjCciSiLWb11HVc9xGAQlb52B97XOr9wBoo2FHNZaXJV4sLJNFEdVdvaOAA0MdRuXeivU6GuWS5t7OPnSpveTeNvI5KKIIIRhEKNV/upxrisuaDbRK2mdBsMMxN7u3URWXkbi1AAlb90HCdniCEW04QzAcQbvVxP0br6BRqTBdox+UhuAOWN6DZrWqjeUFh6lF+93bcWwLZoX9wrJYevJIQd9Yubd6W61IehKCPhShb0w3ureKgrr+jVhkZvbgg3uUxWVHzxlQXJbLQpVlCOEI/MkUAGeKy4xA4tYkJGzdBwnb4QnHE1i6fBW+QADNeg2rN15Bu9FgukY/SNS6C5b3Y2d9FSpUJCYzCEaPb7zvRrxYWNaqVdGsVsHxPOJTGRNrmVuHxdNkmBjtWg3NShkcxyPW4VI75d6adUIBoFHYgdxqgff7EZ6a7nueW9xbVZbQ1NMpgtMzQB89NCg9gUVx2SBI3JqAhK37YPlBrKonU9jGUmksXuwYzrByDVK7zXSNfpCwHW9a9TrKO9r0rMzisu3rUWGZRimrVbcnekyK88JI3l577PX19X7ubXQqM7DtnFH3luW35AMfs6qipj+GSGYanCBoPzYQm5V7a1Z4tgu7kFtNcD4/grogd6q47DhI3BqEhK37YC1sWeMFYZucnsGpC4+D53lU9naxdvMGlBENZyBh617YurdrUFUVsVQa4XjC1LnjUlg28rZghQKktghfMIjIRMry2oPWcdq9bVUqaNWqmns7zSb3thd2uret4h6kRgOcICByzAAOu9xbI3EO/1XVJpcBCKSnwAd6p4Q4XVxG4tYAJGzdBwnb4UnPn8LcuUfAcRyKuW08uH1zJMMZxim/VrXwn1dgdY/azQaKep/MzJL33FsWhWWD1xjq9KPxFAWVvNYWjEVhmVmsVrh3Ytq9zWQOnE8zOOHeHmkNpucPhyYz4H3a+GQn3dtBSLUKxKo2ES84rRWXGXFvWRSXUSswRpCwdR8kbIcns3wa08tnAAA7G+vYev01pvH74WVRy0qoelXsDsPOgzUoioJIIonoxISpc8fFvR0GS23BcllAVRFOJOEPhQ2dYzf9RO8w96FZKqHdqIPnBcQyx+feDrMOS/e2m3aljHa1Co7ntOKyPrjHvYXm3qoqfPEEBH3S2iiKy4xC4vYYSNi6DxK2Q8JxmDv/KCbntclR2dU3Dhru243XhO2oRKibhS6reya129jT3ampEeTesmYUhWWsXx5Su43q3h4A97cFM0NP91afWhabngZn4XPbVe5tahJCUOvda9W9tWuww6HWYO0WWgVt0lpoZg7oo28GpSfY9blA4rYPJGzdBwnb4Xg4dWwaqqpi8+4dFDY3mMU/Dq8IW6eFptPr94LVvdvdeABFlhGOxRFNmcsDtbMtGCvcdM/2KW1r6SCxySnwXV/Zu8297YXRPTaKexCbDfCCD9GOrgNecm+leg2tUhHggMgxfWSNjOXtRfeWrLi33TR3slAkCXwwBL8+8tktxWUkbntAwtZ9kLAdDl4QsHhxf+qYok0d03Py7MQr+bVuE5SAO/c0DLIkorDv3i6Y73trF+NcWNaslNGq18ELAmKTUybWMrcOC/fWzH3onXurC/mZGXCcV93bLUAFgskJ+PQpYL224JbWYFAUNPPadQ92dHs4co6FvQ2KMQgSt12QsHUfJGyHQ/D7sXTpCiLxBGRZGtnUMbeLWje6pL1wwx5Z3cvC5saBexvTnR6jOO3eerGwDADK+lCHXqkJ4+Te1vcKkNotCD4/Ih1C3kvurdxqormnTZjrHMtrbF8GjrGQnjDocYjFAqRmA5zgQ2BKe46NqrjsODwvbt///vdjaWkJoVAIc3Nz+IVf+AVsbm5ainWShC3HcSRsWcR0ubD1B4NYvvwEQtEYRLGF1RvX0KiUmcXvh5uFrRvEohWc3jOLe3rIvbUwtcwuXPx0PYQV97ayk4ciy/CHwggnksPvwaR7ayr2MO6tqna4t7OWPjBd4d5mtwFVhT8Wgz8W147pEctdxWXaazqQSoPX84WdLi7zvLh95zvfia9+9au4c+cO/uiP/givv/46PvCBDzi9LdcLWy9AwnY4gpEIlq88gUAohHazgdUb19Cq15jF74dbha1XRW0n4/AYCpta7m0oGkMsPWnqXDs7JxjBi4VlqqKgnNPbgvUY6mD3Puwa6tCL2u4OJFGELxBApOObAS+5t4rYRl0ffBLtyL015MwaOcaCezsIuV5Du1I61BrMCFaKy4zuzPPi9p//83+Ot771rVheXsbb3/52PPvss/jBD34AURQd2xMJ2+EhYTsc4XhcG6frD6BZr2L1xjWIzSaz+L1wa37tOAjCbhwreGPi3krY3dIKGTM2u7dUWKZRzmmpCZGJCfi6mu6z3K8b3Nuq/ljjs8ZF1qGYLnBv67ksVFmBLxJB4Bi33U3ubWu/NVgsDp/uOFtxXlmlJ3he3HZSKBTw+7//+3j7298Ov9/f97hWq4VyuXzoDytI2A4PCdvhiE5MHB6ne+MaJNHecbokakePU4+Pxb0ubG1AliUEI1HETRQ62ck4F5aJzSbqxSLAcUzcW7PPu5G6tzs5KLIEXzCEcMd0Nje5t4MetypLqO9oIr0z99Zt7u2h1mBiG82C5jhr7q211mCsGAtx+2u/9muIRqOYnJzE2toavvGNbxx7/Gc+8xkkk8mDP4uLi0z2QcJ2eEjYDkd8cgoLj10Czwuo7BW0cbqyzCx+L9wmbMdd1HbjxceqSBJ2Nx8AMJ97S4Vl1ijphWXxzNFesG57Dg3j3qqKgoqehhGz6N72XMfmS9T9mBv5HBRJghAMIpTqn77jpHvbTWsnB0USwQeDCOgpR3a0BjOCK8Xts88+e1Dw1O/P7e80LXcAADHHSURBVNu3D47/lV/5Fbz00kt44YUXIAgCfvEXf/HYm/CpT30KpVLp4M/6+vrQeyZhOzwkbIdjYmYW849eAMdxKO3k8OCO/eN03SRsT5qo7WTUj5vFfd/b2tTc23AEcZO5t3bhoqfzsVhxb+vFPYjNJnifD1ET19vutmC2uLf5HBRFRiAcQbDja32j7q1RZ91W91ZRUNfHVkc6CuTc7N52tgYLTLFtDWZW4HKqmz6ddPL5PHZ3d4895uzZswh05Q4BwIMHD7C4uIjvfe97eNvb3mZovXK5jGQyiScSYQgWhCAJ2+Fg/RRkXpDhclELAJOnFpBZOg0AKGxvInvvdabxe+GWt46TKmj7wfr96Ni1hnx/mVpcQmZhGc16DfdfecnUuWa72xi9LkYfkpHHPmhNfkA/1uOWOG79fusmZ+cwtbyMdr2GjZUbhs/rt5TZ4/k+/9Dv571+3G9Nnj/88+SpBcSnZ9GqVbHz6kMzrNd167VOv3vTtUzP/fTcd48f9nrch37EcUhfuAghEEBtawMNvdCs1xUQul4PvY4x8ti799T7nO5jDv979Mwj8IXCaBd20dI7KXTfHyP76/47z3NoyzL+v5fuoFQqIZFI9Iii4ev7Lw6SyWSQyWQsnbsvGlqtFsst9YWE7XCQsB2ezPLpg3G6+Qer2FlfYxq/G7eIWoCEbS9UqCMVuMNQ2NrE5NwCQpEoYuk0qgX7+y8PQlXZ9xMfNf2eA5WdPCYXFxGIRBGMxdCqVm1Zp981VFS1r5Adds1uKrksYplpBKMxBGJxtKsVfW/qkc/GXvtVVGXgLx/99tMrXq91B14PVUU9u4344hLCmRk0C7tQFQUq+mW0du7r6DG99tBN956MnNP9eJvZTcSWzyGQSkMs7kJptaAo6iGBa+QxHNmbCffWlWkJRvnhD3+I//yf/zNefvllrK6u4jvf+Q5+7ud+DufOnTPs2g4DCdvhIGE7PLPnHjkQttn7b5wYYXuSUxCMMKprM+zzQZEkFLa1zglmp5Y53RaMBXYVlvVdT5JQ2dkB4ExbsH70+4p+mNxbRRRR29Uea3xm1vLejqzTK+3Axo4Tzb1dSHo6SbhjtHA3rMby9j6mu1PC8SfJ9RraZXtagxkVuJ4Wt5FIBH/8x3+Md73rXbhw4QI+8pGP4OrVq/jud7+LoN5I2C5I2A4HCdvh4DgOpy48honpGahQsXn3Dgp6eyW7cIOwJVFrHK9cp/2pZaFozPTUMjNQYZlGSR90EE2lIfgOdxWysl87R/KaXbObSnYbqqoilEjCH4l07I1t7m3PPTLKvQWAenYLABCeyhzksVq9iiNrDZZ72BpMiLJrDWYUV6YlGOXKlSv4zne+M/J1SdgOBwnb4eB4HgsXHkd0IgVVVfDg1Vu2f53rFmFLmGMUKQpGvrY8DlmSUNjexNSpRUwuLJoaDa0oCvPJkoB3UhOOu/b97n27XkezUkEoHkc8k0Fxy9hET7uvCYuUhW7kdhv1vQKi6UnEZ+ZQYFSLoKhHc29Zvta6r3WrVIRYr8MfiSCSmUFtu/c9kxXlSO6toRQGA/fWbHrCfmuw0OQ0QjNzqL1RRS85272/Yd9P9vG0c+sEJGyHg4TtcPA+H5YuXUZ0IgVFlrF2a2XshS25tcMxims37HOksLkBRZERjsURTaUGn2ARN7q3o55YBnS0BeuRmjBWQx0AVHTXMzQxAV8w1BHXW+7tvqANTWbA6457r7Pc2hrMr38rYyStwMrksm5I3JqAhO1wkLAdDp8/gOVLVxCOJSBLIlZvXke9VGQWvxduELbE8Lj9OsqSiIL+4T21wKbv+LC44MsKQ1hpC1Yr7EJqt+ELBBA1kQpiti1YP0bZFkxqNlEv7YEDh9isd3NvxWoF7WoVHM9prcHMxLKwXu9jjAjTjr8oCpp57RepYGYa4I21BmMBiVuDkLAdDhK2w+EPBrF0+QqCkSjEdgv3b1xDU6/+tQOnR+mSW8seu68nG/dWQTiWQCSZNHyeF4Y6DGIYd9AKqqqirA866FVY5rbX3rDubXVb7xebmoTgf9hC1O3ubfePDtzbVBpCQKsrcrt7KxYLkFsNcIIPQb0gbhTuLYlbA5CwHQ4StsMRCIexdPkqAqEw2s0GVm9cQ7tRZxa/G3Jrxxc3X1tZFFHUm9ZPnnKHe8sKJwvL+q1dyecAVUUokUAgHLa+wIB1zBaW2eHetus1NCtlcByHGMPOCcPsyQpSvYaW3oXAM+4tgIaeGhJIT4LX5xPYXVxG4nYAJGyHg4TtcISiMSxdvgp/IIhmo4bVlWsQW01m8bsht3b8sfMaD/v82d14AFVVEU1OIByPGz7PrrZg45Ca0A+p3T7I1++Ve9t/LdNLMYFV7m10agq872Et/TDurdG2qyzd2/q29jiCEykIIS2H2O3urVyrQqyWB7YG644yzPsJidtjIGE7HCRshyMcT2Dx0mX4fH40qhWs3bgGqd1mFr8bp4UtMTrcKnCldgslPUfPTveWCss09tuCxaemwHeNSh23tmCtSgWteg0cxyOWMS7m7dyTFaRmA83iHgAgOvNQKBpyPo0c01PYm08R6D6kmdVbg8UTECJRLa7JkbpG1wZI3PaFhO1wkLAdjuhECosXL0MQfKiVi1i7eR2yJDGL341TwpbcWqKbnY11qFARS6URjEYNn0furfnCsmalglatDo4XEJsyPhXU7mtix1AHAKjormc0kwE3oIWcq93b7BagAoFEEr5w5Mjx+1h1b62kJwz6DFHaLbT2dgEAwRn73VsStz0gYTscJGyHIz45hYXHLoLneVT2drF+awWKLDOL342TwpZwDre6t2KziXJeK3ays3OCFwvL7HiplnOaU56YPjr9ahRtwUbp3jZLRYjNBnjBh2jHtC873gPtfH3JrRYaulCMzs53rDmYXseMbLDDThaqLEMIheFPai3/rBSXGYHEbRckbIeDhO1wJKdnMP/oBXAch9JODg/u3IJq45hRJ4QtubXuwa33Yd+9jaenEDjGmerG7SN5nbzefQvLdnagyDL8oTDCiaTxeH0eCqvHaJt7q6dixKZnBn5Au9u93QZUFf5YDP5orO+aRtzbXthRXKbKMpo7+63BZgCutwRl8QwicdsBCdvhIGE7HKm5ecydewQcOOxlt7D52h3bvv9zqtWXW8XUScauezLM86vdaKCyuwMAmDy1wGpLRzD62MchNaHvOYqMSj4PwH731k6M7rO+V4DUbkPw+xGdnHp4vsfcW0Vso6G/RqKzw+fejqq4rL23C7ndAuf3I6BffzvcWxK3NkHCdth4TMO5XthOLSxh5vRZAMDO5jq237jLLHY3lIZAdOPGe7OzsQ4ASExl4A8GHd6NMbxeWBaZSMEXCAw4ejBOtAXrxxHhpKqo6C3njLQFc7N7W8ttQ1UU+CJRBOKJvmv2cm+tFpcdPcZkcZmqopnTW4NNZsDpnSustAY7DhK3jOE4ErbDx2MazvXCdnr5DKYWlwAAubX7yK/eZxa7G0pDIPphxz0a5vnWqtVQLe6B4zik5427t1RYZr6wTGw2US8WAY7zdFsww+7tzg5kSYQvEES4Y0LbqNxbVsuokoTGjua6R0x2TugZb0TurVQpQ6pXwfE8gtP9f8EYpriMxC1DWOtQErYM4rlc2M6ePY/0/CkAwPa917Gru1V2QGkIhNfYfz0kp2cg+P22rEGFZRqlrJYLGZ/KHPnscbItmB3uraoqqOqFdPHZ/pX7D4/vtS/r7m3vNSzm3ua1Ii1fOIxgcqJvfFe5t9BbgwHwJ1PgQ9oQEZbpCSRuGUHClkU8puHcLWw5DvOPXMDEzCxUqNi8ewd7+mhFOyBhSxjBbe5tvVxCvVoGz/NIz80PPkHH7e6tGwvL6sU9iM2WlouanjQez2XurVGqO/mDQrpQRyHdqN4rmT2XZBl1vbuIl9xbudlAu7QHAAiZaA1mFBK3DCBhyyIe03CuFrYcz2PhwuNITGWgqgo27txCSX9zsoNRC9uTmIbg9ip9M7hN4O4+0Nzbidm5I4MGWDFuz1er1/ugLdjM0dQEr7i3hosEZRlV/St9u3NvjRcuWnNvGzs5KJIEIRhEcCJ95Ph9XOfe5rYBRYEQicIX03KGrQx26AWJ2yEhYcsiHtNw7he2j11ELJWGoihYv30TlcIuk9i9cELYjguKohj+Y+R4L+Gm+1jdK6BZr0EQfEjNOu/eGsGrhWXlfA6qoiAYjSF4THupUeyF9bq9RFM1n4WqKgjG4gjEHj5ez7m3ioK6/otJZGb2QJj0Cm/nWF4jgx0OtQaTRDQL2i8YWu5tb/1j5TKRuB0CErYs4jEN52phy/t8WLp0GdHkBGRZwvqtG6jpYxRZ40SrLzcJIivYLUa9LHZZMJR7q+fepubnB06WsptxLixTJAmVXe2X7ZMw1EERRdT0xxs/5qvxg7hudm9385DbIoRAAKGU8bQSbW9G9nX0ZyzSE1q7eSiSCD4YhF8v7mPh3pK4tQgJWxbxmIZztbAV/H4sXbqCcCwBWRKxdvM66uUSk9jdUBqCMZwWm24Xum66p+WdPFrNBnw+PyYMfIW8j5lrS4VlGmW9LVg0PQleb9M0DF4Y6qBCRSiRhE8vbNLiuuf5bwhVRT2vt3TrGFDB0r21JT1BUdDM7w92mAZ4Qf9xlws8eOlDkLi1AAlbFvGYhnO1sPUFgli+fBWhSBSi2ML9G9fQrFaZxO6G3NrBuFFQunFPgLsEX2HjAQAgPXeK/ZuwSbxSWGbFvW3VamhWtTZN8amMibVMb89WjF5bud1CY0/7Bi0+O/rcW5Z9b5uFXcitFni/H+FJ4/dO25s1WLi3YrEAudUEJ/gQNPGcOw4StyYhYcsiHtNwrha2/lAIy5evIBAKo91qYu3GdbQbdSaxuyFh2x+3u6T7uHGPbrnPpXwWktiGPxhEomOyFEvc8lg7GeTe2kFZbwuW6NHz1o2FZSzcWwAIp9IQAg8Hhngt9xaqiro+oCKcmT5I4XG9e4uHrcEC6Slwetu/YdxbErcmIGHLIh7TcK4WtoFwGMuXrsIfDKHVrGP1xjW0mw0msbshYXsUrwjaXnh130aw+lxVVRWFrQ0A5kbyer2wbPAaQ5zbZ+1qYReyKMIXDCIyMTGSvdiB0WsrNupolEvgwCHWo1OEEdySe9vcK0BqNsH7fAh5yL2VahWI1QrAcaYGO/SDxK1BSNiyiMc0nKuFbTAaxdLlq/AFAmjWq1i9cQ1Su8UkdjejFLZeyK8dJ2Holsfilnu+t70FWZYQjEQRTaVsWcO4+LBleeZYeX9QFQXlvFbFnughNNzo3prhOPc2Ojl1KNfYqnvpJPvubSQzDU5vn+cJ9za3Bagq/IkJ8GHjgx16QeLWACRsWcRjGs7VwjYcT2Dp0hX4fH40qmWsrlyHLIpMYnczamHrZtwiBO3ADY+LbaW8tViKLKOoi5BJF4zkNYJnC8tyWUBVEU4m4QuGDJ/ntrZgRp+37WoFrVoVHMcjlhm9e8sy97ZV3IPUaIATBISnjna9OI5eV2tUgx2UVhOt/cEO04O7VxwHidsBkLBlEY9pOFcL20gyicWLlyAIPtTKRazdvAFFkpjE7oaErcY4i9pOTsrjHERhcwOqqiCSSCIcTzi6l3EuLJNaLdT0Qqsko6EOfffgNvc2kznUcs6L7m1Nz2ENT2bACZoTbdW97YVd7m0rvw11f7BD3PpgBxK3x0DClkU8puFcLWxjqTQWH78EnhdQLRawfmsFiiwzid0NCduTK/YcdSFd4N5KYhtFvXWQXbm3bnzOO1FYVtIHA8SmMkz6C9sv4odbt1kqQmw2wAs+RE06nvu4xb1tl0sQ63VwAo9IxjvurSpJaO0OHuwwCBK3fSBhyyIe03CuFrbxySmcuvA4OI5HubCDB7dvQrVBhIxyOINb82tPqqjtxMlr4IbnRGFjAypUxFJpBCMRp7czEK8WljVKJbQbDfCCgNik8cEAVvZi51CHfhzn3sampw8JAS+6t3XdvQ1NZg7yiN3g3h6dZHb43w8GOwSsD3YgcdsDErYs4jENx/wDlaU4SE7PYP7RC+A4DqV8Fht3btkiQE+6W0ui9ihevx5Wn9PtZgOV3R0AQHr+FMstHUCFZRrl3H5bMHsLy8zCoi1YL+p7BUhiG4I/gEja3KSvfVzj3lbKEGtVcDyHcMf9M3KJWLq3ptMTVGODHY6DxG0XJGxZxGMazhZhy4rU7Bzmzj0CDhz2slvYvPsqs9idnGRhS6L2eJy4Nm5IT9jd1IY6JKYy8AUChs6hwjLzVPJ5qIqMQCSCYCxm+Dy3if6+I4e7BZOqoqoL+riBaXhue5zd1Lb13Nv0JHi9f2wverm3hkSwxcdvbLBDw/JgBxK3HZCwZRGPaThXC9v0qQXMnDkHQPug3X7jLrPYnZxUYUui1jhOXCunnyvNahW1chEcxyM1N+/oXsa5sEyRZVTymkue9EhbsGHvR20nD1mW4AuGEJp42HLOzHuxW9xbsVZFW+8fGzHp3vZiZO4tgKaeInLcYId+kLi1CRK2DOK5WNhOLS5jeuk0ACD/YBW51XvMYndykoUtYR6vXjerz/PCpjbUYWJmFrzez3MQVFhmnv3CskgqBcHX3/3rxm2upuFUE0VBLZ8DMF7ubSiVBu/v/y0HS/eW2WCHmj7YITP4PnRC4tYGSNgyiOdiYTt9+gymFhYBANnVN7CzvsYsdicnsXCM3NrhGeX1c/p5U90roFmvQRB8mJgdri/mKPBqYVm7XkejXAHH84hPW+siYHgPDri3vdzAaj4HRVEQiEQRiMU74nrPvZXqNbQrZc29nRmNe2v1vCPu7f5gh+QE+FDY8FokbhlDwpZBPBcL29mz55Ge0wpYtu/dPXCOWDNKYesGSNSyxYsC17p7q+XepmfnDb//2uHeut2922fYwrJ4ZvpIDp+ThWV2ratIEmp60WJ8dozc24k0hECw73Fuc2+VZhPt8h4AIDRj/BdYErcMIWHLIJ6Lhe3c+UcxMTMLFSo2797Bnv5mwZqTKGwJ9pyU61rayUNsN+ELBJAw2c/TCdxeWNbvfaFW2IXUbsMXCCA6YXz08Sjagtk11KGa24aqqgjFk/CHH7acG/YeOuLeNupolUsAB9vcW6utwQbFaeaywP5gh2i890ldkLhlBAlbBvHcKmw5DqcuPIZkZhqqqmLj1dso6flYrDlJwpbcWvsZ1fV11L1VVRQ2NwGYG+pgaokRu7dOFpYdd045p73vJabZTCxz+1AHud1GvVgAAMQs5t46kSPdj7puyASTKQjHjFS26t72gs1gBxHNguaiBwyORiZxywAStgziuVTYcjyPhQuPI56egqoqeHDn5kF/TdacNGFLjIaTcK2LuW3IsoRAKIxYOm3oHGoLZp5yLgeoKkKJBPxh4/mPLPcycvdWr9gPp1KHvs73pHvbbKBVKnrSvW3t5qBIEvhg/5SKTkjcDgkJWwbxXCpseUHA4uOXEEuloSgy1m+toLpXYBK7m1EIWzcUjpFb6wyjuOZOureKLB+kCaXn7XFvjeIV99bK2rLYRrWgvQf2SgEZRVsw0/GHdG/FRgONcgkcOMRmBruGbndva9tbgAoEkxMQjinQcoN7e+hHioJmbhOtbWN1LiRuh4CELYN4bha2Fy8hkkhCliWs3byBWqnIJHYnoxqn67SoBU6Gg+hmvCRwrbC3tQlVVRCJJxCKGcvL83pbsGEYtrAsNpUBxxtrv6atZ2m5kXPcSN7o5NTBGFvAm+6t3GqiWdQKtKIuc28HDnYoFdEq7RnaF4lbi5CwZRDPpcJW8PmwdOkKwrEEZEnE2s3raFTKTGJ3clLSEMitdQ9euQ9WXhuS2EZpR8sJTc87O9TBCCzagjlRWNYol9Gu18ELAmJT1sbTGt4Do8KyYd9q29UKWvUaOI5H1EDRotvd23pOc28DiSR8x6SXGHVvrQ52MILVe0fi1gIkbBnEc6mw9fkDWLp0BaFoDJLYxurKNTSrVSaxOzlJwpZwF3bfEyefc7sb2leW8ckp+A3m5lFbMPPsD3VI9CjucWNhmdl1e7q3etpLLDMNjn8onbzp3rbQ1AvlItMP22v1eiS9BK4R7HJvjULi1iQkbBnEc6uwDQSxdPkKgpEoxHYLqyvX0KrXmcTu5CQIW3Jr3Y0X7o2V10m7UUe1WAAHDun5Uzbsii1eLSyr7uxAkWUEIhGE4sZSQKzuxS3ubbNUhNhqghd8iE5lBh7vdve2ltWGIwQSCfg62pwZgaV7a6W4zAgkbk1AwpZBPJcKW38ohOXLVxAIhdFuNbG6cg3tRoNJ7E5OQuGYF4QTYe99cta91YY6JKdnIHTkR44arxSWHfee1NfZlGVUdrSuMYnpoy2yxta91XNvY9MzhwZZeNG9VdptNPQC6ciMc+5t7/OGfy6QuDUICVsG8VwqbAPhMJYvXYU/GEKrWcfqjWsQm00msTsZ98Ixcmu9h9sFrpXXTL1cQqNWAc8LhkfynuTCMquUs1pqQjSVguAPGD7PybZgw65dL+xCEkUI/gAiKWMt57pxk3tbz21r7m08Dl8kaupct7u3JG4NQMKWQTyXCttgJIKlS1fgCwTQrNeweuMapHaLSexOToKwJQi3sO/epubmD+VHuhGvFpa1G3U0ymWA4zzTFszsur02Us3r3SK6hjpY7Rqwj2PubWEXABAdoXvLYrDDINz9qncBJGwZxHOpsA3FYpqw9QfQqFWwtnINsigyid3JOAtbcmu9zzi6t5XdHbRbTfh8fiQM5EcCVFhmhZL+NX18OnPoa/rB61lariejHupQ28lDkWX4Q2GEEklrcV3o3vpjMfijMVPnWnVve8Zi7N6SuD0GErYM4rlU2IbjCSxevAzB50e9WsbaynXIksQkdifjLmyJ8WAc72VhS+ucQIVl+2sMvcQRant7kNptCP4AohMp9gt04JahDqoso7qTB2B9JK8ZbHdvRRENfermoKllbnBvjV5PErd9IGHLIJ5LhW0kkcTixUsQBB9q5SLWb96AIstMYndCwpbwEnbdU6fc21IuC1mWEAxHEE0ZE15udm/dWFgGVdVG8gJITHu7LVg/eo7kzWehqgqCsTgC0Ye5qmaep71+GemVmjAK6rms5t5G3e/eGoXEbQ9I2DKI51JhG51IYeHxS+B5AdXiHtZvrZCwNcFJSEPYnxpn9s844GaBaxZFllHUvzZPz7nfvfUq5VwOUFWEEgn4jxkI0I0b24IZfZ4qooi6PoZ4LNxbqdO9HY/cWxK3XZCwZRDPpcI2lp7EwmOPg+d5VPZ28eD2ClQbPsztFjpOtfoaN1HLWqSOs+h1A1auZWFrE6qqIpqcQDBqrhp81Hi1sEwW26jqQu8kubf7bcFCyQn4gqGDn3vXvd2GqqjwR6PwGxxfvY8b3VsStx2QsB0ylg2ii5WgSkxlcOrRx8BxPEq7eTy4c8sW4TEKYesE4yBsnRKdXhO64+TeSu0WyrtafuTk/IKhc9ycmmA31gvL9A4Ck1PgeMHEeubXstu9NYrUaqJe2gMHTut7OwD3u7cSGvprJTLt/tzbQZC49RBuF7asYfUhm5yewdwjj4LjOBTz29h89TbzT5tRiBdKQzCP24Sl2/bTD7fecyvXbXdTawsWn5yCL2BsJK9TuL2wrN97ULNSRqteBy8IiE9NWV/AwFp2Y2aoQ1UX9ZHJSfAdA0O86t428lnb3Vsjl4bFWF4Stx6B5Yehqp4cYTsxO4e5c4+AA4e97Ba27r7GJG4n45xf60W8IiDdvkc77r8Tz+NWrYZaqQiO45Cemzd0jpvdWycLy45jf6iD2dQEli+BUbu37VoVrVoVHMePnXtrpe+t1YfHom1bNyRuPQBrYcsSNwvb9PwpzJ45BwDY3drA9ht3mcTthIStO/CKoO2FV/ftFMO4t8mZGfCC8a/NvYoTfVSruzta/9dwGKF4wta17H65WBnJG53KHBoY4lX3tp7LQlUU+CIR+BncR6fcWxK3LoeErTUmTy1ievkMAGBnYw25+28widvJOApbr6UhjJMwdKNAHxf3tlbcQ7NRgyD4kDTgsAHO/YLHorBs8BpDnNtP+MkyKjtaxX1ixn2FZXa4gwDQLBUhNhvgBR+iBgaGuN29VWUJDb2Pb9RC7q1b3FsSty6GhK01ppaWkVlaBgDk1u4jv7bKJG4n4ypsvYAbRSBr3PTY3Pi8sHJ99jY3AcBwaoIZqLBMY39iWXQiBcEfMLGe+bXMFpaZjWPm/beS0x53bHrm0KS2YV/Hjrm3+dyBextwnXtrbE0Sty6FhK01ppfPYOrUIgAgu/oGdjfWmcTtZBxbfblRwHQz7oK2Gzc9XtbPDyfc29JODpLUhj8YQnySTdGTXXi1sExsNNAolwGOQyIzbfg8K2s5Ra/UhHqhAEnUJrVFUumBMXp3DRguz9su99ZK5wSW7i31uR0jSNhaY+bsuYNRm9v37qKwucEkbifj2hHBzbhJ5DnBuD7+UT/XVUXB3vYWACA9T4VlA+MP6d7GM5lDLubg9cyvZda9tWuoA1QVVX1SW/dQB0+7t7Lz7q1VSNy6DBK21pg7/whSM3NQoWLz9VcPPsRYMm7C1u35teMq6qzi9LVw23PFUmrC9hZUVUE4lkA4bq7VkRdxorCstrcHqd2GEAggOmFs7PEgvODe1nbzWkFdKIxQIjkwhifc2/2+tw53TqA+tx6HhK0FOA7zj1xAMjMDVVWx+dodlHLZ4eN2MY7C1q2QqO2P09fG6+kJsiiilNcctv1veQbhlHvrhsKy4/bQd21V1UbywnxhmRvbghm+p7KMmi4Gx8e9zWrubTiMgAHBPohRurckbl0CCVsLcBxOPXoBiakMVFXFxqu3UNbzhFhCwnY0OC3cvARdJw1rbcG0dKVYehL+oLuHOniVci4HqCpC8QT84bCtazn1Uug51CGXhaqqCMbi8EesjXse1m1n697KaOxov6h4LfeWxK0LIGFrHo7jsHDhccTTU1BVBQ/u3ESlsMtgd4cZJ2Hr1jQEErXWcOqaed29bTfqqBYL4MDZ4t6yxKuFZbLYRrVQAGB+qIPZtY5j1EMdZFFEfU/7HIp3ubfDrtfLvR3Fa6e+k/Oke0vi1mFI2JqH43ksPH4JsVQaiiJj/dYKqnsFBrs7zLgJW7dBonZ4xkXgDsMw7m0yw36oAxWWaZT0iWWxySlT15hlYRkrrAx1CE1MQOgY9zzsUAczkHtL4tZRSNiahxcELD5+CdHkBBRZE7a1UnH4zXVBwtZeSNSyw6lfElg+r0bt3tZLRTTrVfCCgAkDDpvXccK9bVbKaNXr4AUBsR6t18ahLVgvpGYTjVIRHDjEe+Qcd0Pu7f7Pjh43jMAlcesQJGzNwwsCFi9eQiSRhCxLWLt1HfVyicHuDmOnUBh1D1u3CVtya+3jJF9XK4+9sKUNdUjNurst2CgKy1jsoRdl3b3tlZpw/Hrm13KqLVhP91Yvao5MToH3+Tpik3t73F5YQuLWAUjYmkfw+bB06QrCsQRkScTaynU0KhUGuzuM3cJ2lLhJ2JKoHQ2jvsZedm/L+RwksQ1/MOj6oQ5epbq7o7XHCocRYtR6zQvubbtaQateA8fxiPYYZtHNSXRve2HUvTUCidsRQ8LWPILfj6VLVxCKxiCJbayuXEOzVmWwu8OMi7B1U+EYidrR42WBOwxmH7eqqtjL2jfUgSVeLSxTZBmVnR0A5gvLvNwWDACq+6OIp6bBcQ+lFrm3x++FFSRuRwgJW/P4/AEsXbqCYCQKsd3C6so1tOp1Brt7iN0C7KSmIZCodQ6vXvtRu3J2DnWgwjKNsv4VfTSVhuD3s9zSEdzUFqxR3IPYbkHw+RAx8M2Ad9xb2RPu7diI21arhSeffBIcx+Hll192ejtHIGFrHn8wiKXLVxAMR9BuNbG6cg3tRoPB7h5ChWPsIbfWHYzyHrglPcHsY5ZFESXdjUrNudu9ZYET7m27XkejXAY4DvEeX9F7rS2YOfdW7xjRVVjmZfe2rveSd7t7Ozbi9ld/9Vcxb/CrpVFzkoQtq6/E/aEQli5dRSAURrvZwNrKNYjNJoMdPoSELXtI1LoLuh+DKehtweKTU8yHOlBhmca+e5vITAMcZ2I982u5yb2t7+5AliT4AkGEDYwiHnbvo/jMaXgk93YsxO03v/lNvPDCC/jsZz/r9FaOcNKELQsC4TCWL12FPxhEq1nH6so1iK0Wk9j7jIuwdUt+Lbm17mVU98Wr7m2rXke1uAcOnGH3ljBHrVCA1G5DCAQQNSDyjMDyPdauoQ6qqqCmfzMwzEjeXu6tmZG8JzH31jf4EHeTzWbxzDPP4Otf/zoikYihc1qtFlodYqlU0tpJyYwvMAlba3B+PxQOqJRLeHDnJmRRZBYbGC9h6wZI1HoAVQVnwjGziizL4Hk2nskwuzV7bm5jHYFoFJKsGPocMPc4VXAGdmRozwbu46A4siofKnA6usbxMY5fvt9jVbG7tYXk9DRkANIRZaZaWvO469rvHL7PP/T7uam1FYDjD/98L7uNQGoS7VYLEsdBleWO2MbX5A3+rN/eesXstX6v69D9k1J2G0IyBanVgoSHj6nXdoyK8F576bVnWQ846HPH0+JWVVV86EMfwsc+9jE89dRTuH//vqHzPvOZz+Df/Jt/c+Tnr5TYFioRFqnmgI2c07sgiDFjVL+EuOOXLlNUc/gres+xl0IRwE2nd+EMq5tO74A9r606unylUkEy2T8tglNdaLs8++yz+Pf//t8fe8ytW7fwwgsv4Ktf/Sq++93vQhAE3L9/H2fOnMFLL72EJ598su+53c5tsVjE8vIy1tbWjr1YxGHK5TIWFxexvr6ORCLh9HY8A103a9B1swZdN2vQdbMGXTdr0HUzhqqqqFQqmJ+fP/bbE1c6t//iX/wLfOhDHzr2mLNnz+I73/kOvv/97yPYVQTw1FNP4ed//ufxe7/3ez3PDQaDR84BgGQySU8qCyQSCbpuFqDrZg26btag62YNum7WoOtmDbpugzFiQrpS3GYyGWQymYHHfe5zn8Nv/MZvHPx9c3MT73nPe/CVr3wFb3nLW+zcIkEQBEEQBOFCXClujbK0tHTo77FYDABw7tw5LCwsOLElgiAIgiAIwkHGohXYsASDQTz33HM9UxWI/tB1swZdN2vQdbMGXTdr0HWzBl03a9B1Y4srC8oIgiAIgiAIwgrk3BIEQRAEQRBjA4lbgiAIgiAIYmwgcUsQBEEQBEGMDSRuCYIgCIIgiLGBxG0fWq0WnnzySXAch5dfftnp7bie97///VhaWkIoFMLc3Bx+4Rd+AZubYzhykCH379/HRz7yEZw5cwbhcBjnzp3Dc889h3a77fTWXM9v/uZv4u1vfzsikQgmJiac3o5r+cIXvoDTp08jFArhLW95C/7qr/7K6S25nr/4i7/AT/3UT2F+fh4cx+HrX/+601tyPZ/5zGfwt/7W30I8Hsf09DR+5md+Bnfu3HF6W67nv/yX/4KrV68eDG5429vehm9+85tOb2ssIHHbh1/91V/F/Py809vwDO985zvx1a9+FXfu3MEf/dEf4fXXX8cHPvABp7flam7fvg1FUfClL30JKysr+O3f/m188YtfxKc//Wmnt+Z62u02PvjBD+KXfumXnN6Ka/nKV76CT37yk3juuefw4osv4oknnsB73vMe5HI5p7fmamq1Gp544gl84QtfcHornuG73/0uPv7xj+MHP/gB/vRP/xSiKOInf/InUavVnN6aq1lYWMBv/dZv4Uc/+hH+5m/+Bn/37/5d/PRP/zRWVlac3pr3UYkj/J//83/Uxx57TF1ZWVEBqC+99JLTW/Ic3/jGN1SO49R2u+30VjzFf/gP/0E9c+aM09vwDM8//7yaTCad3oYrefOb36x+/OMfP/i7LMvq/Py8+pnPfMbBXXkLAOrXvvY1p7fhOXK5nApA/e53v+v0VjxHKpVS/+t//a9Ob8PzkHPbRTabxTPPPIP/8T/+ByKRiNPb8SSFQgG///u/j7e//e3w+/1Ob8dTlEolpNNpp7dBeJx2u40f/ehHePe7333wM57n8e53vxvf//73HdwZcRIolUoAQO9lJpBlGX/4h3+IWq2Gt73tbU5vx/OQuO1AVVV86EMfwsc+9jE89dRTTm/Hc/zar/0aotEoJicnsba2hm984xtOb8lT3L17F5///Ofx0Y9+1OmtEB5nZ2cHsixjZmbm0M9nZmawvb3t0K6Ik4CiKPjlX/5l/O2//bdx+fJlp7fjeq5fv45YLIZgMIiPfexj+NrXvoaLFy86vS3PcyLE7bPPPguO4479c/v2bXz+859HpVLBpz71Kae37AqMXrd9fuVXfgUvvfQSXnjhBQiCgF/8xV+EegIH4Jm9bgCwsbGB9773vfjgBz+IZ555xqGdO4uV60YQhLv4+Mc/jhs3buAP//APnd6KJ7hw4QJefvll/PCHP8Qv/dIv4emnn8bNmzed3pbnORHjd/P5PHZ3d4895uzZs/jZn/1Z/Mmf/Ak4jjv4uSzLEAQBP//zP4/f+73fs3urrsLodQsEAkd+/uDBAywuLuJ73/veifuKxex129zcxDve8Q689a1vxZe//GXw/In4nfMIVp5vX/7yl/HLv/zLKBaLNu/OW7TbbUQiEfyv//W/8DM/8zMHP3/66adRLBbpWxWDcByHr33ta4euIdGfT3ziE/jGN76Bv/iLv8CZM2ec3o4nefe7341z587hS1/6ktNb8TQ+pzcwCjKZDDKZzMDjPve5z+E3fuM3Dv6+ubmJ97znPfjKV76Ct7zlLXZu0ZUYvW69UBQFgNZS7aRh5rptbGzgne98J970pjfh+eefP7HCFhju+UYcJhAI4E1vehO+/e1vHwgzRVHw7W9/G5/4xCec3Rwxdqiqin/6T/8pvva1r+HP//zPSdgOgaIoJ/JzkzUnQtwaZWlp6dDfY7EYAODcuXNYWFhwYkue4Ic//CH++q//Gj/xEz+BVCqF119/Hb/+67+Oc+fOnTjX1gwbGxt4xzvegeXlZXz2s59FPp8/+LfZ2VkHd+Z+1tbWUCgUsLa2BlmWD3pRnz9//uB1e9L55Cc/iaeffhpPPfUU3vzmN+N3fud3UKvV8OEPf9jprbmaarWKu3fvHvz93r17ePnll5FOp498RhAaH//4x/EHf/AH+MY3voF4PH6Q151MJhEOhx3enXv51Kc+hfe9731YWlpCpVLBH/zBH+DP//zP8X//7/91emvex9FeDS7n3r171ArMANeuXVPf+c53qul0Wg0Gg+rp06fVj33sY+qDBw+c3pqref7551UAPf8Qx/P000/3vG5/9md/5vTWXMXnP/95dWlpSQ0EAuqb3/xm9Qc/+IHTW3I9f/Znf9bzufX00087vTXX0u997Pnnn3d6a67mH/2jf6QuLy+rgUBAzWQy6rve9S71hRdecHpbY8GJyLklCIIgCIIgTgYnN8GPIAiCIAiCGDtI3BIEQRAEQRBjA4lbgiAIgiAIYmwgcUsQBEEQBEGMDSRuCYIgCIIgiLGBxC1BEARBEAQxNpC4JQiCIAiCIMYGErcEQRAEQRDE2EDiliAIgiAIghgbSNwSBEEQBEEQYwOJW4IgCI+yPz39X//rf33o7wRBECcZTqV3Q4IgCE/yu7/7u/D5fHjttdcgCALe97734e/8nb/j9LYIgiAchZxbgiAIj/JP/sk/QalUwuc+9zn81E/91BFh+453vAMcx4HjOLz88suG437oQx86OO/rX/86200TBEHYDIlbgiAIj/LFL34RyWQS/+yf/TP8yZ/8Cf7yL//yyDHPPPMMtra2cPny5YOffeELX8Dp06cRCoXwlre8BX/1V3916Jz/9J/+E7a2tmzfP0EQhB2QuCUIgvAoH/3oR/GP//E/RjQaxW/91m/hJ37iJ44cE4lEMDs7C5/PBwD4yle+gk9+8pN47rnn8OKLL+KJJ57Ae97zHuRyuYNzkskkZmdnR/Y4CIIgWELiliAIwmX8z//5PxEOhw+5px/+8Idx9epVlEqlg59xHAfgYUHZ/t+P4z/+x/+IZ555Bh/+8Idx8eJFfPGLX0QkEsF//+//ne2DIAiCcAgStwRBEC7jH/7Df4hHH30U/+7f/TsAwHPPPYf/9//+H775zW8imUxajttut/GjH/0I7373uw9+xvM83v3ud+P73//+0PsmCIJwAz6nN0AQBEEchuM4/OZv/iY+8IEPYHZ2Fp///Ofxl3/5lzh16tRQcXd2diDLMmZmZg79fGZmBrdv3x4qNkEQhFsgcUsQBOFC/v7f//u4ePEi/u2//bd44YUXcOnSJae3RBAE4QkoLYEgCMKFfOtb38Lt27d7Oq1WmZqagiAIyGazh36ezWapgIwgiLGBxC1BEITLePHFF/GzP/uz+G//7b/hXe96F37913+dSdxAIIA3velN+Pa3v33wM0VR8O1vfxtve9vbmKxBEAThNJSWQBAE4SLu37+Pv/f3/h4+/elP4+d+7udw9uxZvO1tb8OLL76IH//xHx86/ic/+Uk8/fTTeOqpp/DmN78Zv/M7v4NarYYPf/jDDHZPEAThPCRuCYIgXEKhUMB73/te/PRP/zSeffZZAMBb3vIWvO9978OnP/1pfOtb3xp6jX/wD/4B8vk8/tW/+lfY3t7Gk08+iW9961vMUh8IgiCchsQtQRCES0in0z27Fvzv//2/ma7ziU98Ap/4xCeYxiQIgnALlHNLEAQxxvzu7/4uYrEYrl+/bvicj33sY4jFYjbuiiAIwj44VVVVpzdBEARBsGdjYwONRgMAsLS0hEAgYOi8XC6HcrkMAJibm0M0GrVtjwRBEKwhcUsQBEEQBEGMDZSWQBAEQRAEQYwNJG4JgiAIgiCIsYHELUEQBEEQBDE2kLglCIIgCIIgxgYStwRBEARBEMTYQOKWIAiCIAiCGBtI3BIEQRAEQRBjA4lbgiAIgiAIYmwgcUsQBEEQBEGMDSRuCYIgCIIgiLHh/w8JY1FN5WXJaAAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "IbsfhoWQmSlr" + }, + "execution_count": null, + "outputs": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMCXVjR6HT+aA9YlWJYI8AH", + "include_colab_link": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/CM20315/CM20315_BackgroundMaths.ipynb b/CM20315/CM20315_BackgroundMaths.ipynb new file mode 100644 index 0000000..61151e8 --- /dev/null +++ b/CM20315/CM20315_BackgroundMaths.ipynb @@ -0,0 +1,105 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyP2uQebA3i1KuIqkrgmngWg", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "# **CM20315 Background Mathematics**\n", + "\n", + "The purpose of this Python notebook is to make sure you can use CoLab and to familiarize yourself with some of the background mathematical concepts that you are going to need to understand deep learning.

It's not meant to be difficult and it may be that you know some or all of this information already.

Maths is *NOT* a spectator sport. You won't learn it by just listening to lectures or reading books. It really helps to interact with it and explore yourself.

Work through the cells below. In various places you will see the words **\"TO DO\"**. Follow the instructions at these places. If you can't figure out what is going on or how to complete the section, feel free to ask your fellow students or the TAs in the practical session or via Moodle. This does not count toward your final marks, but completeing it will help you do well in your coursework and exam and reduce your stress levels later on.\n" + ], + "metadata": { + "id": "s5zzKSOusPOB" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "aUAjBbqzivMY" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "x = np.arange\n", + "\n", + "x = np.arange(0.01,10, 0.01)\n", + "y = np.log(x)\n", + "\n", + "\n", + "fig, ax = plt.subplots()\n", + "fig.set_size_inches(5.0,5.0, forward=True)\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([-5,3])\n", + "ax.set_xlim([0,10])\n", + "plt.savefig('Log.svg', format='svg')\n", + "plt.show" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 342 + }, + "id": "9WbDlaVksItZ", + "outputId": "66350910-8b3d-431b-cc3d-3e81f17b4a27" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 2 + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/CM20315/CM20315_Convolution_I.ipynb b/CM20315/CM20315_Convolution_I.ipynb new file mode 100644 index 0000000..34152ac --- /dev/null +++ b/CM20315/CM20315_Convolution_I.ipynb @@ -0,0 +1,432 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOdO9HZNZ/DwsTSc7M8PBTl", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Convolution I \n", + "\n", + "This notebook investigates the convolution operation. It asks you to hand code a convolution so we can be sure that we are computing the same thing as in PyTorch. The subsequent notebooks use the convolutional layers in PyTorch directly." + ], + "metadata": { + "id": "VB_crnDGASX-" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import torch\n", + "# Set to print in reasonable form\n", + "np.set_printoptions(precision=3, floatmode=\"fixed\")\n", + "torch.set_printoptions(precision=3)" + ], + "metadata": { + "id": "YAoWDUb_DezG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "This routine performs convolution in PyTorch" + ], + "metadata": { + "id": "eAwYWXzAElHG" + } + }, + { + "cell_type": "code", + "source": [ + "# Perform convolution in PyTorch\n", + "def conv_pytorch(image, conv_weights, stride=1, pad =1):\n", + " # Convert image and kernel to tensors\n", + " image_tensor = torch.from_numpy(image) # (batchSize, channelsIn, imageHeightIn, =imageWidthIn)\n", + " conv_weights_tensor = torch.from_numpy(conv_weights) # (channelsOut, channelsIn, kernelHeight, kernelWidth) \n", + " # Do the convolution\n", + " output_tensor = torch.nn.functional.conv2d(image_tensor, conv_weights_tensor, stride=stride, padding=pad) \n", + " # Convert back from PyTorch and return\n", + " return(output_tensor.numpy()) # (batchSize channelsOut imageHeightOut imageHeightIn)" + ], + "metadata": { + "id": "xsmUIN-3BlWr" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "First we'll start with the simplest 2D convolution. Just one channel in and one channel out. A single image in the batch." + ], + "metadata": { + "id": "A3Sm8bUWtDNO" + } + }, + { + "cell_type": "code", + "source": [ + "# Perform convolution in numpy\n", + "def conv_numpy_1(image, weights, pad=1):\n", + " \n", + " # Perform zero padding \n", + " if pad != 0:\n", + " image = np.pad(image, ((0, 0), (0 ,0), (pad, pad), (pad, pad)),'constant')\n", + " \n", + " # Get sizes of image array and kernel weights\n", + " batchSize, channelsIn, imageHeightIn, imageWidthIn = image.shape\n", + " channelsOut, channelsIn, kernelHeight, kernelWidth = weights.shape\n", + "\n", + " # Get size of output arrays\n", + " imageHeightOut = np.floor(1 + imageHeightIn - kernelHeight).astype(int)\n", + " imageWidthOut = np.floor(1 + imageWidthIn - kernelWidth).astype(int)\n", + "\n", + " # Create output\n", + " out = np.zeros((batchSize, channelsOut, imageHeightOut, imageWidthOut), dtype=np.float32) \n", + " \n", + " for c_y in range(imageHeightOut):\n", + " for c_x in range(imageWidthOut):\n", + " for c_kernel_y in range(kernelHeight):\n", + " for c_kernel_x in range(kernelWidth):\n", + " # TODO -- Retrieve the image pixel and the weight from the convolution\n", + " # Only one image in batch, one input channel and one output channel, so these indices should all be zero\n", + " # Replace the two lines below\n", + " this_pixel_value = 1.0\n", + " this_weight = 1.0\n", + " \n", + " # Multiply these together and add to the output at this position\n", + " out[0, 0, c_y, c_x] += np.sum(this_pixel_value * this_weight) \n", + " \n", + " return out" + ], + "metadata": { + "id": "EF8FWONVLo1Q" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set random seed so we always get same answer\n", + "np.random.seed(1) \n", + "n_batch = 1\n", + "image_height = 4\n", + "image_width = 6\n", + "channels_in = 1\n", + "kernel_size = 3\n", + "channels_out = 1\n", + "\n", + "# Create random input image\n", + "input_image= np.random.normal(size=(n_batch, channels_in, image_height, image_width))\n", + "# Create random convolution kernel weights\n", + "conv_weights = np.random.normal(size=(channels_out, channels_in, kernel_size, kernel_size))\n", + "\n", + "# Perform convolution using PyTorch\n", + "conv_results_pytorch = conv_pytorch(input_image, conv_weights, stride=1, pad=1)\n", + "print(\"PyTorch Results\")\n", + "print(conv_results_pytorch)\n", + "\n", + "# Perform convolution in numpy\n", + "print(\"Your results\")\n", + "conv_results_numpy = conv_numpy_1(input_image, conv_weights)\n", + "print(conv_results_numpy)" + ], + "metadata": { + "id": "iw9KqXZTHN8v" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's now add in the possibility of using different strides" + ], + "metadata": { + "id": "IYj_lxeGzaHX" + } + }, + { + "cell_type": "code", + "source": [ + "# Perform convolution in numpy\n", + "def conv_numpy_2(image, weights, stride=1, pad=1):\n", + " \n", + " # Perform zero padding \n", + " if pad != 0:\n", + " image = np.pad(image, ((0, 0), (0 ,0), (pad, pad), (pad, pad)),'constant')\n", + " \n", + " # Get sizes of image array and kernel weights\n", + " batchSize, channelsIn, imageHeightIn, imageWidthIn = image.shape\n", + " channelsOut, channelsIn, kernelHeight, kernelWidth = weights.shape\n", + "\n", + " # Get size of output arrays\n", + " imageHeightOut = np.floor(1 + (imageHeightIn - kernelHeight) / stride).astype(int)\n", + " imageWidthOut = np.floor(1 + (imageWidthIn - kernelWidth) / stride).astype(int)\n", + " \n", + " # Create output\n", + " out = np.zeros((batchSize, channelsOut, imageHeightOut, imageWidthOut), dtype=np.float32) \n", + " \n", + " for c_y in range(imageHeightOut):\n", + " for c_x in range(imageWidthOut):\n", + " for c_kernel_y in range(kernelHeight):\n", + " for c_kernel_x in range(kernelWidth):\n", + " # TODO -- Retrieve the image pixel and the weight from the convolution\n", + " # Only one image in batch, one input channel and one output channel, so these indices should all be zero\n", + " # Replace the two lines below\n", + " this_pixel_value = 1.0\n", + " this_weight = 1.0\n", + "\n", + " # Multiply these together and add to the output at this position\n", + " out[0, 0, c_y, c_x] += np.sum(this_pixel_value * this_weight) \n", + " \n", + " return out" + ], + "metadata": { + "id": "GiujmLhqHN1F" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set random seed so we always get same answer\n", + "np.random.seed(1) \n", + "n_batch = 1\n", + "image_height = 12\n", + "image_width = 10\n", + "channels_in = 1\n", + "kernel_size = 3\n", + "channels_out = 1\n", + "stride = 2\n", + "\n", + "# Create random input image\n", + "input_image= np.random.normal(size=(n_batch, channels_in, image_height, image_width))\n", + "# Create random convolution kernel weights\n", + "conv_weights = np.random.normal(size=(channels_out, channels_in, kernel_size, kernel_size))\n", + "\n", + "# Perform convolution using PyTorch\n", + "conv_results_pytorch = conv_pytorch(input_image, conv_weights, stride, pad=1)\n", + "print(\"PyTorch Results\")\n", + "print(conv_results_pytorch)\n", + "\n", + "# Perform convolution in numpy\n", + "print(\"Your results\")\n", + "conv_results_numpy = conv_numpy_2(input_image, conv_weights, stride, pad=1)\n", + "print(conv_results_numpy)" + ], + "metadata": { + "id": "FeJy6Bvozgxq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll introduce multiple input and output channels" + ], + "metadata": { + "id": "3flq1Wan2gX-" + } + }, + { + "cell_type": "code", + "source": [ + "# Perform convolution in numpy\n", + "def conv_numpy_3(image, weights, stride=1, pad=1):\n", + " \n", + " # Perform zero padding \n", + " if pad != 0:\n", + " image = np.pad(image, ((0, 0), (0 ,0), (pad, pad), (pad, pad)),'constant')\n", + " \n", + " # Get sizes of image array and kernel weights\n", + " batchSize, channelsIn, imageHeightIn, imageWidthIn = image.shape\n", + " channelsOut, channelsIn, kernelHeight, kernelWidth = weights.shape\n", + "\n", + " # Get size of output arrays\n", + " imageHeightOut = np.floor(1 + (imageHeightIn - kernelHeight) / stride).astype(int)\n", + " imageWidthOut = np.floor(1 + (imageWidthIn - kernelWidth) / stride).astype(int)\n", + " \n", + " # Create output\n", + " out = np.zeros((batchSize, channelsOut, imageHeightOut, imageWidthOut), dtype=np.float32) \n", + " \n", + " for c_y in range(imageHeightOut):\n", + " for c_x in range(imageWidthOut):\n", + " for c_channel_out in range(channelsOut):\n", + " for c_channel_in in range(channelsIn):\n", + " for c_kernel_y in range(kernelHeight):\n", + " for c_kernel_x in range(kernelWidth):\n", + " # TODO -- Retrieve the image pixel and the weight from the convolution\n", + " # Only one image in batch so this index should be zero\n", + " # Replace the two lines below\n", + " this_pixel_value = 1.0\n", + " this_weight = 1.0\n", + "\n", + " # Multiply these together and add to the output at this position\n", + " out[0, c_channel_out, c_y, c_x] += np.sum(this_pixel_value * this_weight) \n", + " return out" + ], + "metadata": { + "id": "AvdRWGiU2ppX" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set random seed so we always get same answer\n", + "np.random.seed(1) \n", + "n_batch = 1\n", + "image_height = 4\n", + "image_width = 6\n", + "channels_in = 5\n", + "kernel_size = 3\n", + "channels_out = 2\n", + "\n", + "# Create random input image\n", + "input_image= np.random.normal(size=(n_batch, channels_in, image_height, image_width))\n", + "# Create random convolution kernel weights\n", + "conv_weights = np.random.normal(size=(channels_out, channels_in, kernel_size, kernel_size))\n", + "\n", + "# Perform convolution using PyTorch\n", + "conv_results_pytorch = conv_pytorch(input_image, conv_weights, stride=1, pad=1)\n", + "print(\"PyTorch Results\")\n", + "print(conv_results_pytorch)\n", + "\n", + "# Perform convolution in numpy\n", + "print(\"Your results\")\n", + "conv_results_numpy = conv_numpy_3(input_image, conv_weights, stride=1, pad=1)\n", + "print(conv_results_numpy)" + ], + "metadata": { + "id": "mdSmjfvY4li2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll do the full convolution with multiple images (batch size > 1), and multiple input channels, multiple output channels." + ], + "metadata": { + "id": "Q2MUFebdsJbH" + } + }, + { + "cell_type": "code", + "source": [ + "# Perform convolution in numpy\n", + "def conv_numpy_4(image, weights, stride=1, pad=1):\n", + " \n", + " # Perform zero padding \n", + " if pad != 0:\n", + " image = np.pad(image, ((0, 0), (0 ,0), (pad, pad), (pad, pad)),'constant')\n", + " \n", + " # Get sizes of image array and kernel weights\n", + " batchSize, channelsIn, imageHeightIn, imageWidthIn = image.shape\n", + " channelsOut, channelsIn, kernelHeight, kernelWidth = weights.shape\n", + "\n", + " # Get size of output arrays\n", + " imageHeightOut = np.floor(1 + (imageHeightIn - kernelHeight) / stride).astype(int)\n", + " imageWidthOut = np.floor(1 + (imageWidthIn - kernelWidth) / stride).astype(int)\n", + " \n", + " # Create output\n", + " out = np.zeros((batchSize, channelsOut, imageHeightOut, imageWidthOut), dtype=np.float32) \n", + " \n", + " for c_batch in range(batchSize):\n", + " for c_y in range(imageHeightOut):\n", + " for c_x in range(imageWidthOut):\n", + " for c_channel_out in range(channelsOut):\n", + " for c_channel_in in range(channelsIn):\n", + " for c_kernel_y in range(kernelHeight):\n", + " for c_kernel_x in range(kernelWidth):\n", + " # TODO -- Retrieve the image pixel and the weight from the convolution\n", + " # Replace the two lines below\n", + " this_pixel_value = 1.0\n", + " this_weight = 1.0\n", + " \n", + " # Multiply these together and add to the output at this position\n", + " out[c_batch, c_channel_out, c_y, c_x] += np.sum(this_pixel_value * this_weight) \n", + " return out" + ], + "metadata": { + "id": "5WePF-Y-sC1y" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1w2GEBtqAM2P" + }, + "outputs": [], + "source": [ + "# Set random seed so we always get same answer\n", + "np.random.seed(1) \n", + "n_batch = 2\n", + "image_height = 4\n", + "image_width = 6\n", + "channels_in = 5\n", + "kernel_size = 3\n", + "channels_out = 2\n", + "\n", + "# Create random input image\n", + "input_image= np.random.normal(size=(n_batch, channels_in, image_height, image_width))\n", + "# Create random convolution kernel weights\n", + "conv_weights = np.random.normal(size=(channels_out, channels_in, kernel_size, kernel_size))\n", + "\n", + "# Perform convolution using PyTorch\n", + "conv_results_pytorch = conv_pytorch(input_image, conv_weights, stride=1, pad=1)\n", + "print(\"PyTorch Results\")\n", + "print(conv_results_pytorch)\n", + "\n", + "# Perform convolution in numpy\n", + "print(\"Your results\")\n", + "conv_results_numpy = conv_numpy_4(input_image, conv_weights, stride=1, pad=1)\n", + "print(conv_results_numpy)" + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "Lody75JB5By7" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Convolution_II.ipynb b/CM20315/CM20315_Convolution_II.ipynb new file mode 100644 index 0000000..4d87123 --- /dev/null +++ b/CM20315/CM20315_Convolution_II.ipynb @@ -0,0 +1,253 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyN4fpyg0d75XccLLsNahur1", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Convolution II -- MNIST1D\n", + "\n", + "This notebook investigates what happens when we use convolutional layers instead of fully-connected layers for the MNIST-1D from the coursework.\n", + "\n", + "We'll build the network from figure 10.7 in the notes.\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment \n", + "# or download from my github to your local machine if you are doing this locally\n", + "if not os.path.exists('./train_data_x.npy'):\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_y.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_y.npy " + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "\n", + "# TODO Create a model with the following layers\n", + "# 1. Convolutional layer, (input=length 40 and 1 channel, kernel size 3x3, stride 2, padding=\"valid\", 15 output channels ) \n", + "# 2. ReLU\n", + "# 3. Convolutional layer, (input=length 19 and 15 channels, kernel size 3x3, stride 2, padding=\"valid\", 15 output channels )\n", + "# 4. ReLU\n", + "# 5. Convolutional layer, (input=length 9 and 15 channels, kernel size 3x3, stride 2, padding=\"valid\", 15 output channels)\n", + "# 6. ReLU\n", + "# 7. Flatten (converts 4x15) to length 60\n", + "# 8. Linear layer (input size = 60, output size = 10)\n", + "# References:\n", + "# https://pytorch.org/docs/1.13/generated/torch.nn.Conv1d.html?highlight=conv1d#torch.nn.Conv1d\n", + "# https://pytorch.org/docs/stable/generated/torch.nn.Flatten.html\n", + "# https://pytorch.org/docs/1.13/generated/torch.nn.Linear.html?highlight=linear#torch.nn.Linear\n", + "\n", + "# Replace the following function which just runs a standard fully connected network\n", + "# The flatten at the beginning is because we are passing in the data in a slightly different format.\n", + "model = nn.Sequential(\n", + "nn.Flatten(),\n", + "nn.Linear(40, 100),\n", + "nn.ReLU(),\n", + "nn.Linear(100, 100),\n", + "nn.ReLU(),\n", + "nn.Linear(100, 10))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch[:,None,:])\n", + " # compute the loss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train[:,None,:])\n", + " pred_val = model(x_val[:,None,:])\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + " \n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part I: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_I_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Convolution_III.ipynb b/CM20315/CM20315_Convolution_III.ipynb new file mode 100644 index 0000000..ce0039f --- /dev/null +++ b/CM20315/CM20315_Convolution_III.ipynb @@ -0,0 +1,648 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyM4FAP7pqe8LpKfmixZN07G", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Convolution III -- MNIST\n", + "\n", + "This notebook builds a proper network for 2D convolution. It works with the MNIST dataset, which was the original classic dataset for classifying images. The network will take a 28x28 grayscale image and classify it into one of 10 classes representing a digit.\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import torch\n", + "import torchvision\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "import torch.optim as optim\n", + "import matplotlib.pyplot as plt\n", + "import random" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to load the train and test data straight into a dataloader class\n", + "# that will provide the batches\n", + "batch_size_train = 64\n", + "batch_size_test = 1000\n", + "train_loader = torch.utils.data.DataLoader(\n", + " torchvision.datasets.MNIST('/files/', train=True, download=True,\n", + " transform=torchvision.transforms.Compose([\n", + " torchvision.transforms.ToTensor(),\n", + " torchvision.transforms.Normalize(\n", + " (0.1307,), (0.3081,))\n", + " ])),\n", + " batch_size=batch_size_train, shuffle=True)\n", + "\n", + "test_loader = torch.utils.data.DataLoader(\n", + " torchvision.datasets.MNIST('/files/', train=False, download=True,\n", + " transform=torchvision.transforms.Compose([\n", + " torchvision.transforms.ToTensor(),\n", + " torchvision.transforms.Normalize(\n", + " (0.1307,), (0.3081,))\n", + " ])),\n", + " batch_size=batch_size_test, shuffle=True)" + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": 2, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's draw some of the training data\n", + "examples = enumerate(test_loader)\n", + "batch_idx, (example_data, example_targets) = next(examples)\n", + "\n", + "fig = plt.figure()\n", + "for i in range(6):\n", + " plt.subplot(2,3,i+1)\n", + " plt.tight_layout()\n", + " plt.imshow(example_data[i][0], cmap='gray', interpolation='none')\n", + " plt.title(\"Ground Truth: {}\".format(example_targets[i]))\n", + " plt.xticks([])\n", + " plt.yticks([])\n", + "plt.show()" + ], + "metadata": { + "id": "8bKADvLHbiV5", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 284 + }, + "outputId": "ec39acb8-05e0-48ae-cb6e-1b8578d00e68" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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jx5e3qZNmyR+/vnnq7s7QKpwhgIAiIKCAgCIok5d8jr77LO9/Kqrrkrili1bem2bb+5/6+vXr0/i888/32vbbDO/7vbv37+sfqL2CMdNnz59vHz48OFJHF5GBTY1nKEAAKKgoAAAoqCgAACiqHVzKO48ydVXX+217bHHHl4+bty4JL733nu9tvvvv9/LDzjggCR+5ZVXvLZjjz22pL6i9nNvJ5ekhg0bejnzJnC54+PMM8/02i6//HIvX7duXRJPnDjRa7vpppu8/Pvvv4/VxYriDAUAEAUFBQAQReouebVt29bLjzzySC+/5pprknjt2rVe24gRI7z8tttuS+L58+fnPW64L1d462jv3r2TeMyYMXn3i9rn5z//eRKHt6IvWrSouruDFNtqq628/MEHH0zi008/3Wszxni5tTaJDzzwQK9thx128PIBAwaU1c/qwhkKACAKCgoAIAoKCgAgilTMobz//vtJvOuuu3ptjRs39vJPP/00ie+44w6vLVwluBhffvllEi9YsMBrC29Hrl+/fsnHQfo0aNDAyydPnpzEO+64o9c2ffr06ugSUqp169ZefuONN3p5r169cr525MiRXv6b3/wm57Z77713Cb2reZyhAACioKAAAKKgoAAAoqi2OZT9998/icePH++17bXXXkkcLhXvzplI/hPz5s2bF61/X3/9dRIvX77cawvnUFC3hMuruPMmc+fO9douvfTSko+z5ZZbJnGLFi28Nnfpn0mTJpV8DMT3y1/+MonD965wKR7XtGnTvHzUqFFenm8O5ZZbbimih+nBGQoAIAoKCgAgimq75OXebrfnnnt6be5lrvCU8qKLLvLyL774ogK9k7p3757EHTt2rMgxkA7bbbedl5988sk5tw3H35IlSwo+zp/+9CcvP+mkk5K4Xbt2Xpu7hA+XvGqWe1ld8lcmDy9xhbcCu5e1PvjgA68tXF4ln3C5p9qCMxQAQBQUFABAFBQUAEAU1TaH4i5n0b9/f6/NvU1z9OjRXlul5kzCJRLCJzqi7jruuOO8/LDDDvPyr776KolXrlyZd1+NGjVK4mHDhnlt4RP7Fi5cmMQzZszw2o4++ugk/vWvf+21PfTQQ3n7gLjCuY7mzZsn8cUXX+y1hb/zfD755BMvX7p06UaPIUnNmjUreL9pwhkKACAKCgoAIAoKCgAgihpZvv6BBx6oluO4j9EM50wGDx7s5dtss03B+w2XsEbtctBBB+Vtd+f73nvvvbzbustyhEtpzJkzx8vdeZJwDLlzKq1atcp7TFTW8ccf7+XuY58feeSRkvcbzt01adIkid3HAddmnKEAAKKgoAAAokjFExtLFT5Nr2fPnl7u3p7srnZcLvfWwVmzZnltLJuRTu6K0X369PHa1q5d6+XnnHNOEru3BUvSY4895uXucirhfsKn+a1YsSKJw0texpgcPUdNc28jX7duXcGvC5dPCZficVefris4QwEAREFBAQBEQUEBAERRq+dQOnXq5OX33HNPyftyn8wXLqGf74l+4ZIJSKdzzz03icNlLT788EMv33rrrZM4XPbkhBNO8HJ33qRv375e2xNPPJGzP+F+3NtGp06dmvN1qLzVq1d7eefOnZN4v/3289reeOMNL3fnxp555hmvLXxKZ125VdjFGQoAIAoKCgAgCgoKACCKWj2HEl7rnD17tpe3bds2iV977TWvLVx2+u23307iZcuWeW2vvvqql7vXRs866yyv7b777quq26gGDRo08PJu3brl3Dacs3j44YeT2P2cifTT5VROP/30JP7oo4/y9qlr165JfMEFF3ht8+fPT2J3Pg/Vb8KECV7uzneFS6/cfPPNXn7llVcmcbiEjrtcvSRttdVWSdy4cePSOpsynKEAAKKgoAAAoqjVl7xefvllLz/00EO93H0S37x587w2dxmMqoRP13vhhReS+JBDDvHamjZtWtIxENe2227r5R07dsy57ZFHHunlHTp0SOK33nrLawtXoi3md3zMMcckccOGDb22K664IondpT5Q/fI9IXPkyJF5c1e4UvUZZ5zh5aecckoSh6ufh08RHTp0aM7jpAlnKACAKCgoAIAoKCgAgChq9RxKVcK5j1KFy5IvXLgwid2n8EnSgAEDkviaa66JcnwUr3v37gVv686ZhAYOHOjlxcyZhEu8uLefPv30017biBEjCt4vqtfjjz+exOGS9OESOu5cSPg7zrf0fbgMS219KixnKACAKCgoAIAoKCgAgCjq9BxKpbjLkvfq1ctrc6+5z5w502t76qmnKtsxJGJdg27fvr2Xv/TSSwW/Nlymo127dkk8ZMiQ8jqGauPOfYSP8Q3zYrhzsaFtttnGy7fffvskXrVqVcnHrDTOUAAAUVBQAABRcMmrBO4yLkuW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6KNzti1atMjLP/nkk4L3++STT5bUhtqpa9euSTx+/HivLZwXcW8xv+mmm7y2lStX5jzGscce6+WnnHKKl1900UVJPHr0aK9t4cKFOfeL9ArnZrt165Zz2xUrVnj54MGDk7iYOZQ04wwFABAFBQUAEAUFBQAQRernUHr06JGzberUqdXYE9RmV1xxRRJX9dmSjh07JvG8efMKPoa7LJD008+huEu8hE/oYw6l5qxevdrL//Of/3i5u4TTZpv5f4OHn1E7/fTTk3jEiBFe2/r1673c/VxSuKRLPuHnptKEMxQAQBQUFABAFKl/YmN4q527nEp4+lmO1q1bJ/ExxxzjtYXLv7geeughL3/llVei9alQPLHxp7p37+7lTz31lNsfry1cBuWPf/xjScd0L2FIUtu2bb38zTffLGm/FcQTGzciHA8DBw50++O15Xv/dMecJE2bNs3L3dWnq3ofnjRpUhL/6le/8tq++eabvK+tEJ7YCACoHAoKACAKCgoAIIrUz6EsX77cy90nOBYzh9KqVSsvD+c+DjrooCSuV6+e17Zu3Tovd9vDPrjLb7zxxhsF968czKH81H333eflffv2TeJ//OMfXpt7m7D006d7Fiq8tj1q1CgvP+CAA5K4mNuRK4g5lI3Yeeedvfycc85J4htuuMFrK+b9M+TOx1S1n/bt2yfxBx98UPIxI2IOBQBQORQUAEAUFBQAQBSpX3olvHf7zDPPTOLw8yKffvqplx933HFJPHToUK/tiy++8PKxY8cm8fDhw722cIlq9xGhf/3rX7222267LYm7dOkipIN7vTqcIyl1zkTyl1O58sorcx5T8pesD+dtkB7he8PNN9+cxC+99JLX5i7pI0knnHBC5TpWC3CGAgCIgoICAIgi9Ze8Bg0a5OUnnXRSEk+YMCHva93VPadPn+619erVy8u//vrrgvvkbvvAAw94bWPGjEni3r1752xD9Srn9s583Esebdq0yXtMd4XhcLXhcIkhpNPrr7/u5eH7yKmnnprEjz32WLTj3nXXXUl87bXXem0vv/xytOOUizMUAEAUFBQAQBQUFABAFKlfeiXkXrPu1KmT1xYukeLObzz33HOV7ViWO28zZ84cr+3AAw+syDFZeuWn3Nt5JX8ZnJYtW3ptH374oZf//e9/z7nfrl27erk7b1LV0uaLFi1K4g4d/FUramgOhaVXytS4cWMvv+qqq5L4kksuyftad9mm8GmOxbj++uuT+JZbbvHawvfEiFh6BQBQORQUAEAUFBQAQBS1bg4l7ZYuXZrE4dL24XX9WJhDqZr7+YBwCfLw8yP5lhXPN09S1RyK+2hhdzmPGsQcSpG22GILLx8/fryXH3/88QXvy13uafbs2V5b+FkTd7mnkDvu3EcFS/7S+5L01VdfFdy/KjCHAgCoHAoKACCK1C+9Utu4lzLC1WdRcyZOnJjEM2bM8Nrcy2GS1K9fv4L327Zt2yRu1KhR3m1XrlxZ8H6RTuHHD4pZUfyzzz7zcvcW4wULFnht4XIqQ4YMSeIjjjgi5zFOPvlkL//FL37h5c8//3whXS0ZZygAgCgoKACAKCgoAIAouG04ss6dOyexe91ekpo1a1aRY3LbcM2ZNWtWEv/sZz/z2sJ/W82bN0/ilCxXz23DG9GqVSsvHzBgQBJfeOGFXlsx758HHXSQl4dLM+XTpEmTJA7fV9x5nLA/4RL6ffr0KfiYVeC2YQBA5VBQAABRUFAAAFHwORSgCOFnTRo2bJjE4dIroZTMm6AKo0eP9vJDDz20pP2MGzfOy8PHJBTjyy+/TOKpU6d6bfk+C1Op5Z5y4QwFABAFBQUAEAWXvIAiuEutSP5KxeEtm8XcUoqa4z7xUPrpciWucAXx8EmL77zzThKHtxjneypjuIpxeAv6aaedlsQdO3bM2afwGLfffnvOY1YCZygAgCgoKACAKCgoAIAoUj+H8uqrr3q5uwT4Lbfc4rWFy5LXBPcWvqpuI0Xt07VrVy93f8fh75vbhGuHcE4i39xXOEcRbuu+P9166615j+uOl+22285rK+bJj26f1q5d67VFfEJjQThDAQBEQUEBAESR+kteDz/8sJcPHz48icOnnL399ttevmbNmor1a4P69et7+eWXX57Es2fPrvjxUb3c24Sl/JdHJkyYUOnuIGWOOuqogrd1L3mVc4u5e6ty//79vbbXX3+95P2WgjMUAEAUFBQAQBQUFABAFKmfQ7nvvvu8vGXLlkk8cOBAr23nnXf28qFDhybxzJkzK9A7f85EkrbddtskDm9rRt3jXgcPl+W4//77q7s7KMHcuXO9vFu3bjXUk9zcFYanTZvmtY0dOzaJly9fXm192hjOUAAAUVBQAABRUFAAAFGkfg4ldMUVVyRx+DmUQYMGeXmPHj2S+PPPP/faxo8fn/MY77//vpeHyyL07NkziTt37uy1uU9pe/HFF3MeA3WD+/mBfMuTI73c9xRJmjJlipdPnjw5icMndhbj3nvv9XJ3mZRnnnnGawvndVatWpXEP/zwQ8l9qDTOUAAAUVBQAABRmGI+8m+MSfUj6HbddVcvd1eGdS9TSf4T0Ir16KOPJnG4vMbEiRNL3m+prLWpXtY47eOmGOGl0lNOOSWJw6V/OnToUC19KsOb1tpUd7IujZ06ZqNjhzMUAEAUFBQAQBQUFABAFLXutuF8Fi9e7OVjxozZaAyUKpxzdPPwVoE0o6YAAACWSURBVE9gU8MZCgAgCgoKACAKCgoAIIo69TmUTRWfQ0GJ+BwKSsXnUAAAlUNBAQBEQUEBAERBQQEAREFBAQBEQUEBAERR7NIrKyR9VomOoGQta7oDBWDcpBNjB6Xa6Ngp6nMoAADkwiUvAEAUFBQAQBQUFABAFBQUAEAUFBQAQBQUFABAFBQUAEAUFBQAQBQUFABAFP8PSTV0oIqXHNoAAAAASUVORK5CYII=\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network. This is a more typical way to define a network than the sequential structure. We define a class for the network, and define the parameters in the constructor. Then we use a function called forward to actually run the network. " + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "from os import X_OK\n", + "# TODO Change this class to implement\n", + "# 1. A valid convolution with kernel size 5, 1 input channel and 10 output channels\n", + "# 2. A max pooling operation over a 2x2 area\n", + "# 3. A Relu\n", + "# 4. A valid convolution with kernel size 5, 10 input channels and 20 output channels\n", + "# 5. A 2D Dropout layer\n", + "# 6. A max pooling operation over a 2x2 area\n", + "# 7. A relu\n", + "# 8. A flattening operation\n", + "# 9. A fully connected layer mapping from (whatever dimensions we are at-- find out using .shape) to 50 \n", + "# 10. A ReLU\n", + "# 11. A fully connected layer mapping from 50 to 10 dimensions\n", + "# 12. A softmax function.\n", + "\n", + "# Replace this class which implements a minimal network (which still does okay)\n", + "class Net(nn.Module):\n", + " def __init__(self):\n", + " super(Net, self).__init__()\n", + " # Valid convolution, 1 channel in, 3 channels out, stride 1, kernel size = 5\n", + " self.conv1 = nn.Conv2d(1, 3, kernel_size=5)\n", + " # Dropout for convolutions\n", + " self.drop = nn.Dropout2d()\n", + " # Fully connected layer\n", + " self.fc1 = nn.Linear(432, 10)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.drop(x)\n", + " x = F.max_pool2d(x,2)\n", + " x = F.relu(x)\n", + " x = x.flatten(1)\n", + " x = self.fc1(x)\n", + " x = F.log_softmax(x)\n", + " return x" + ], + "metadata": { + "id": "EQkvw2KOPVl7" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "qWZtkCZcU_dg" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Create network\n", + "model = Net()\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "# Define optimizer\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def train(epoch):\n", + " model.train()\n", + " # Get each \n", + " for batch_idx, (data, target) in enumerate(train_loader):\n", + " optimizer.zero_grad()\n", + " output = model(data)\n", + " loss = F.nll_loss(output, target)\n", + " loss.backward()\n", + " optimizer.step()\n", + " # Store results\n", + " if batch_idx % 10 == 0:\n", + " print('Train Epoch: {} [{}/{}]\\tLoss: {:.6f}'.format(\n", + " epoch, batch_idx * len(data), len(train_loader.dataset), loss.item()))" + ], + "metadata": { + "id": "xKQd9PzkQ766" + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def test():\n", + " model.eval()\n", + " test_loss = 0\n", + " correct = 0\n", + " with torch.no_grad():\n", + " for data, target in test_loader:\n", + " output = model(data)\n", + " test_loss += F.nll_loss(output, target, size_average=False).item()\n", + " pred = output.data.max(1, keepdim=True)[1]\n", + " correct += pred.eq(target.data.view_as(pred)).sum()\n", + " test_loss /= len(test_loader.dataset)\n", + " print('\\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " 100. * correct / len(test_loader.dataset)))" + ], + "metadata": { + "id": "Byn-f7qWRLxX" + }, + "execution_count": 8, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Get initial performance\n", + "test()\n", + "# Train for three epochs\n", + "n_epochs = 3\n", + "for epoch in range(1, n_epochs + 1):\n", + " train(epoch)\n", + " test()" + ], + "metadata": { + "id": "YgLaex1pfhqz", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "96b4a0e4-94b3-4eba-ea1a-53f6f5ee8792" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + ":34: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " x = F.log_softmax(x)\n", + "/usr/local/lib/python3.8/dist-packages/torch/nn/_reduction.py:42: UserWarning: size_average and reduce args will be deprecated, please use reduction='sum' instead.\n", + " warnings.warn(warning.format(ret))\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "Test set: Avg. loss: 2.6743, Accuracy: 593/10000 (6%)\n", + "\n", + "Train Epoch: 1 [0/60000]\tLoss: 3.022157\n", + "Train Epoch: 1 [640/60000]\tLoss: 2.232255\n", + "Train Epoch: 1 [1280/60000]\tLoss: 2.339070\n", + "Train Epoch: 1 [1920/60000]\tLoss: 2.123211\n", + "Train Epoch: 1 [2560/60000]\tLoss: 1.977328\n", + "Train Epoch: 1 [3200/60000]\tLoss: 1.794155\n", + "Train Epoch: 1 [3840/60000]\tLoss: 1.607425\n", + "Train Epoch: 1 [4480/60000]\tLoss: 1.265900\n", + "Train Epoch: 1 [5120/60000]\tLoss: 1.380399\n", + "Train Epoch: 1 [5760/60000]\tLoss: 1.443841\n", + "Train Epoch: 1 [6400/60000]\tLoss: 0.962643\n", + "Train Epoch: 1 [7040/60000]\tLoss: 1.050701\n", + "Train Epoch: 1 [7680/60000]\tLoss: 0.882971\n", + "Train Epoch: 1 [8320/60000]\tLoss: 1.056942\n", + "Train Epoch: 1 [8960/60000]\tLoss: 1.204123\n", + "Train Epoch: 1 [9600/60000]\tLoss: 0.875873\n", + "Train Epoch: 1 [10240/60000]\tLoss: 0.952260\n", + "Train Epoch: 1 [10880/60000]\tLoss: 0.751124\n", + "Train Epoch: 1 [11520/60000]\tLoss: 0.867441\n", + "Train Epoch: 1 [12160/60000]\tLoss: 0.956779\n", + "Train Epoch: 1 [12800/60000]\tLoss: 0.679759\n", + "Train Epoch: 1 [13440/60000]\tLoss: 0.949922\n", + "Train Epoch: 1 [14080/60000]\tLoss: 0.859521\n", + "Train Epoch: 1 [14720/60000]\tLoss: 0.948663\n", + "Train Epoch: 1 [15360/60000]\tLoss: 0.584370\n", + "Train Epoch: 1 [16000/60000]\tLoss: 0.865371\n", + "Train Epoch: 1 [16640/60000]\tLoss: 0.726936\n", + "Train Epoch: 1 [17280/60000]\tLoss: 0.598072\n", + "Train Epoch: 1 [17920/60000]\tLoss: 0.849646\n", + "Train Epoch: 1 [18560/60000]\tLoss: 0.793431\n", + "Train Epoch: 1 [19200/60000]\tLoss: 0.720634\n", + "Train Epoch: 1 [19840/60000]\tLoss: 0.770133\n", + "Train Epoch: 1 [20480/60000]\tLoss: 0.888984\n", + "Train Epoch: 1 [21120/60000]\tLoss: 0.595875\n", + "Train Epoch: 1 [21760/60000]\tLoss: 0.750772\n", + "Train Epoch: 1 [22400/60000]\tLoss: 0.829312\n", + "Train Epoch: 1 [23040/60000]\tLoss: 0.896843\n", + "Train Epoch: 1 [23680/60000]\tLoss: 0.762636\n", + "Train Epoch: 1 [24320/60000]\tLoss: 0.806846\n", + "Train Epoch: 1 [24960/60000]\tLoss: 0.767578\n", + "Train Epoch: 1 [25600/60000]\tLoss: 0.746623\n", + "Train Epoch: 1 [26240/60000]\tLoss: 0.742440\n", + "Train Epoch: 1 [26880/60000]\tLoss: 1.142117\n", + "Train Epoch: 1 [27520/60000]\tLoss: 0.772795\n", + "Train Epoch: 1 [28160/60000]\tLoss: 0.555436\n", + "Train Epoch: 1 [28800/60000]\tLoss: 0.763470\n", + "Train Epoch: 1 [29440/60000]\tLoss: 0.632003\n", + "Train Epoch: 1 [30080/60000]\tLoss: 0.836483\n", + "Train Epoch: 1 [30720/60000]\tLoss: 0.704554\n", + "Train Epoch: 1 [31360/60000]\tLoss: 0.862588\n", + "Train Epoch: 1 [32000/60000]\tLoss: 0.582613\n", + "Train Epoch: 1 [32640/60000]\tLoss: 0.784028\n", + "Train Epoch: 1 [33280/60000]\tLoss: 0.758522\n", + "Train Epoch: 1 [33920/60000]\tLoss: 0.778791\n", + "Train Epoch: 1 [34560/60000]\tLoss: 0.849997\n", + "Train Epoch: 1 [35200/60000]\tLoss: 0.836082\n", + "Train Epoch: 1 [35840/60000]\tLoss: 0.448398\n", + "Train Epoch: 1 [36480/60000]\tLoss: 0.729314\n", + "Train Epoch: 1 [37120/60000]\tLoss: 0.811088\n", + "Train Epoch: 1 [37760/60000]\tLoss: 0.592963\n", + "Train Epoch: 1 [38400/60000]\tLoss: 0.642293\n", + "Train Epoch: 1 [39040/60000]\tLoss: 0.784302\n", + "Train Epoch: 1 [39680/60000]\tLoss: 0.694944\n", + "Train Epoch: 1 [40320/60000]\tLoss: 0.720275\n", + "Train Epoch: 1 [40960/60000]\tLoss: 0.536233\n", + "Train Epoch: 1 [41600/60000]\tLoss: 0.715839\n", + "Train Epoch: 1 [42240/60000]\tLoss: 0.557930\n", + "Train Epoch: 1 [42880/60000]\tLoss: 0.652230\n", + "Train Epoch: 1 [43520/60000]\tLoss: 0.686960\n", + "Train Epoch: 1 [44160/60000]\tLoss: 0.562727\n", + "Train Epoch: 1 [44800/60000]\tLoss: 0.728505\n", + "Train Epoch: 1 [45440/60000]\tLoss: 0.874868\n", + "Train Epoch: 1 [46080/60000]\tLoss: 0.713117\n", + "Train Epoch: 1 [46720/60000]\tLoss: 0.727794\n", + "Train Epoch: 1 [47360/60000]\tLoss: 0.747727\n", + "Train Epoch: 1 [48000/60000]\tLoss: 0.631520\n", + "Train Epoch: 1 [48640/60000]\tLoss: 0.515534\n", + "Train Epoch: 1 [49280/60000]\tLoss: 0.695285\n", + "Train Epoch: 1 [49920/60000]\tLoss: 0.690564\n", + "Train Epoch: 1 [50560/60000]\tLoss: 0.696663\n", + "Train Epoch: 1 [51200/60000]\tLoss: 0.637634\n", + "Train Epoch: 1 [51840/60000]\tLoss: 0.722715\n", + "Train Epoch: 1 [52480/60000]\tLoss: 0.832013\n", + "Train Epoch: 1 [53120/60000]\tLoss: 0.594781\n", + "Train Epoch: 1 [53760/60000]\tLoss: 0.613957\n", + "Train Epoch: 1 [54400/60000]\tLoss: 0.836092\n", + "Train Epoch: 1 [55040/60000]\tLoss: 0.635827\n", + "Train Epoch: 1 [55680/60000]\tLoss: 0.623362\n", + "Train Epoch: 1 [56320/60000]\tLoss: 0.540473\n", + "Train Epoch: 1 [56960/60000]\tLoss: 0.780923\n", + "Train Epoch: 1 [57600/60000]\tLoss: 0.476055\n", + "Train Epoch: 1 [58240/60000]\tLoss: 0.905469\n", + "Train Epoch: 1 [58880/60000]\tLoss: 0.700290\n", + "Train Epoch: 1 [59520/60000]\tLoss: 0.500782\n", + "\n", + "Test set: Avg. loss: 0.2170, Accuracy: 9355/10000 (94%)\n", + "\n", + "Train Epoch: 2 [0/60000]\tLoss: 0.530213\n", + "Train Epoch: 2 [640/60000]\tLoss: 0.954322\n", + "Train Epoch: 2 [1280/60000]\tLoss: 0.627641\n", + "Train Epoch: 2 [1920/60000]\tLoss: 0.694282\n", + "Train Epoch: 2 [2560/60000]\tLoss: 0.490609\n", + "Train Epoch: 2 [3200/60000]\tLoss: 0.518218\n", + "Train Epoch: 2 [3840/60000]\tLoss: 0.511994\n", + "Train Epoch: 2 [4480/60000]\tLoss: 0.575610\n", + "Train Epoch: 2 [5120/60000]\tLoss: 0.760527\n", + "Train Epoch: 2 [5760/60000]\tLoss: 0.618076\n", + "Train Epoch: 2 [6400/60000]\tLoss: 0.551507\n", + "Train Epoch: 2 [7040/60000]\tLoss: 0.661573\n", + "Train Epoch: 2 [7680/60000]\tLoss: 0.503254\n", + "Train Epoch: 2 [8320/60000]\tLoss: 0.611196\n", + "Train Epoch: 2 [8960/60000]\tLoss: 0.568107\n", + "Train Epoch: 2 [9600/60000]\tLoss: 0.680320\n", + "Train Epoch: 2 [10240/60000]\tLoss: 0.749674\n", + "Train Epoch: 2 [10880/60000]\tLoss: 0.766421\n", + "Train Epoch: 2 [11520/60000]\tLoss: 0.720416\n", + "Train Epoch: 2 [12160/60000]\tLoss: 0.552917\n", + "Train Epoch: 2 [12800/60000]\tLoss: 0.642536\n", + "Train Epoch: 2 [13440/60000]\tLoss: 0.564653\n", + "Train Epoch: 2 [14080/60000]\tLoss: 0.562467\n", + "Train Epoch: 2 [14720/60000]\tLoss: 0.683435\n", + "Train Epoch: 2 [15360/60000]\tLoss: 0.638271\n", + "Train Epoch: 2 [16000/60000]\tLoss: 0.667720\n", + "Train Epoch: 2 [16640/60000]\tLoss: 0.417489\n", + "Train Epoch: 2 [17280/60000]\tLoss: 0.661206\n", + "Train Epoch: 2 [17920/60000]\tLoss: 0.586723\n", + "Train Epoch: 2 [18560/60000]\tLoss: 0.577134\n", + "Train Epoch: 2 [19200/60000]\tLoss: 0.882659\n", + "Train Epoch: 2 [19840/60000]\tLoss: 0.705308\n", + "Train Epoch: 2 [20480/60000]\tLoss: 0.621367\n", + "Train Epoch: 2 [21120/60000]\tLoss: 0.451295\n", + "Train Epoch: 2 [21760/60000]\tLoss: 0.589745\n", + "Train Epoch: 2 [22400/60000]\tLoss: 0.653456\n", + "Train Epoch: 2 [23040/60000]\tLoss: 0.404559\n", + "Train Epoch: 2 [23680/60000]\tLoss: 0.613846\n", + "Train Epoch: 2 [24320/60000]\tLoss: 0.720263\n", + "Train Epoch: 2 [24960/60000]\tLoss: 0.446476\n", + "Train Epoch: 2 [25600/60000]\tLoss: 0.905395\n", + "Train Epoch: 2 [26240/60000]\tLoss: 0.574859\n", + "Train Epoch: 2 [26880/60000]\tLoss: 0.779760\n", + "Train Epoch: 2 [27520/60000]\tLoss: 0.447516\n", + "Train Epoch: 2 [28160/60000]\tLoss: 0.553814\n", + "Train Epoch: 2 [28800/60000]\tLoss: 0.724654\n", + "Train Epoch: 2 [29440/60000]\tLoss: 0.451007\n", + "Train Epoch: 2 [30080/60000]\tLoss: 0.357663\n", + "Train Epoch: 2 [30720/60000]\tLoss: 0.534665\n", + "Train Epoch: 2 [31360/60000]\tLoss: 0.912386\n", + "Train Epoch: 2 [32000/60000]\tLoss: 0.635334\n", + "Train Epoch: 2 [32640/60000]\tLoss: 0.611335\n", + "Train Epoch: 2 [33280/60000]\tLoss: 0.498800\n", + "Train Epoch: 2 [33920/60000]\tLoss: 0.726310\n", + "Train Epoch: 2 [34560/60000]\tLoss: 0.618861\n", + "Train Epoch: 2 [35200/60000]\tLoss: 0.498235\n", + "Train Epoch: 2 [35840/60000]\tLoss: 0.556707\n", + "Train Epoch: 2 [36480/60000]\tLoss: 0.828103\n", + "Train Epoch: 2 [37120/60000]\tLoss: 0.459869\n", + "Train Epoch: 2 [37760/60000]\tLoss: 0.699695\n", + "Train Epoch: 2 [38400/60000]\tLoss: 0.746511\n", + "Train Epoch: 2 [39040/60000]\tLoss: 0.620254\n", + "Train Epoch: 2 [39680/60000]\tLoss: 0.685517\n", + "Train Epoch: 2 [40320/60000]\tLoss: 0.444510\n", + "Train Epoch: 2 [40960/60000]\tLoss: 0.607820\n", + "Train Epoch: 2 [41600/60000]\tLoss: 0.453002\n", + "Train Epoch: 2 [42240/60000]\tLoss: 0.575601\n", + "Train Epoch: 2 [42880/60000]\tLoss: 0.521206\n", + "Train Epoch: 2 [43520/60000]\tLoss: 0.505593\n", + "Train Epoch: 2 [44160/60000]\tLoss: 0.494645\n", + "Train Epoch: 2 [44800/60000]\tLoss: 0.445350\n", + "Train Epoch: 2 [45440/60000]\tLoss: 1.022786\n", + "Train Epoch: 2 [46080/60000]\tLoss: 0.934101\n", + "Train Epoch: 2 [46720/60000]\tLoss: 0.581446\n", + "Train Epoch: 2 [47360/60000]\tLoss: 0.565760\n", + "Train Epoch: 2 [48000/60000]\tLoss: 0.418244\n", + "Train Epoch: 2 [48640/60000]\tLoss: 1.008578\n", + "Train Epoch: 2 [49280/60000]\tLoss: 0.604322\n", + "Train Epoch: 2 [49920/60000]\tLoss: 0.721556\n", + "Train Epoch: 2 [50560/60000]\tLoss: 0.521967\n", + "Train Epoch: 2 [51200/60000]\tLoss: 0.410529\n", + "Train Epoch: 2 [51840/60000]\tLoss: 0.719665\n", + "Train Epoch: 2 [52480/60000]\tLoss: 0.718958\n", + "Train Epoch: 2 [53120/60000]\tLoss: 0.678785\n", + "Train Epoch: 2 [53760/60000]\tLoss: 0.497077\n", + "Train Epoch: 2 [54400/60000]\tLoss: 0.617133\n", + "Train Epoch: 2 [55040/60000]\tLoss: 0.468108\n", + "Train Epoch: 2 [55680/60000]\tLoss: 0.576436\n", + "Train Epoch: 2 [56320/60000]\tLoss: 0.433144\n", + "Train Epoch: 2 [56960/60000]\tLoss: 0.715489\n", + "Train Epoch: 2 [57600/60000]\tLoss: 0.386602\n", + "Train Epoch: 2 [58240/60000]\tLoss: 0.258836\n", + "Train Epoch: 2 [58880/60000]\tLoss: 0.300112\n", + "Train Epoch: 2 [59520/60000]\tLoss: 0.549713\n", + "\n", + "Test set: Avg. loss: 0.1792, Accuracy: 9485/10000 (95%)\n", + "\n", + "Train Epoch: 3 [0/60000]\tLoss: 0.411068\n", + "Train Epoch: 3 [640/60000]\tLoss: 0.617724\n", + "Train Epoch: 3 [1280/60000]\tLoss: 0.573067\n", + "Train Epoch: 3 [1920/60000]\tLoss: 0.783076\n", + "Train Epoch: 3 [2560/60000]\tLoss: 0.673770\n", + "Train Epoch: 3 [3200/60000]\tLoss: 0.554354\n", + "Train Epoch: 3 [3840/60000]\tLoss: 0.984257\n", + "Train Epoch: 3 [4480/60000]\tLoss: 0.530157\n", + "Train Epoch: 3 [5120/60000]\tLoss: 0.612170\n", + "Train Epoch: 3 [5760/60000]\tLoss: 0.679237\n", + "Train Epoch: 3 [6400/60000]\tLoss: 0.645367\n", + "Train Epoch: 3 [7040/60000]\tLoss: 0.436184\n", + "Train Epoch: 3 [7680/60000]\tLoss: 0.745752\n", + "Train Epoch: 3 [8320/60000]\tLoss: 0.474170\n", + "Train Epoch: 3 [8960/60000]\tLoss: 0.337120\n", + "Train Epoch: 3 [9600/60000]\tLoss: 0.746035\n", + "Train Epoch: 3 [10240/60000]\tLoss: 0.606994\n", + "Train Epoch: 3 [10880/60000]\tLoss: 0.590475\n", + "Train Epoch: 3 [11520/60000]\tLoss: 0.506705\n", + "Train Epoch: 3 [12160/60000]\tLoss: 0.531224\n", + "Train Epoch: 3 [12800/60000]\tLoss: 0.573767\n", + "Train Epoch: 3 [13440/60000]\tLoss: 0.489704\n", + "Train Epoch: 3 [14080/60000]\tLoss: 0.381763\n", + "Train Epoch: 3 [14720/60000]\tLoss: 0.788660\n", + "Train Epoch: 3 [15360/60000]\tLoss: 0.398151\n", + "Train Epoch: 3 [16000/60000]\tLoss: 0.673685\n", + "Train Epoch: 3 [16640/60000]\tLoss: 0.442040\n", + "Train Epoch: 3 [17280/60000]\tLoss: 0.400728\n", + "Train Epoch: 3 [17920/60000]\tLoss: 0.665893\n", + "Train Epoch: 3 [18560/60000]\tLoss: 0.680546\n", + "Train Epoch: 3 [19200/60000]\tLoss: 0.699877\n", + "Train Epoch: 3 [19840/60000]\tLoss: 0.656768\n", + "Train Epoch: 3 [20480/60000]\tLoss: 0.564827\n", + "Train Epoch: 3 [21120/60000]\tLoss: 0.575950\n", + "Train Epoch: 3 [21760/60000]\tLoss: 0.414778\n", + "Train Epoch: 3 [22400/60000]\tLoss: 0.561424\n", + "Train Epoch: 3 [23040/60000]\tLoss: 0.688791\n", + "Train Epoch: 3 [23680/60000]\tLoss: 0.567774\n", + "Train Epoch: 3 [24320/60000]\tLoss: 0.525123\n", + "Train Epoch: 3 [24960/60000]\tLoss: 0.697168\n", + "Train Epoch: 3 [25600/60000]\tLoss: 0.623199\n", + "Train Epoch: 3 [26240/60000]\tLoss: 0.404254\n", + "Train Epoch: 3 [26880/60000]\tLoss: 0.565381\n", + "Train Epoch: 3 [27520/60000]\tLoss: 0.609798\n", + "Train Epoch: 3 [28160/60000]\tLoss: 0.753811\n", + "Train Epoch: 3 [28800/60000]\tLoss: 0.389456\n", + "Train Epoch: 3 [29440/60000]\tLoss: 0.436780\n", + "Train Epoch: 3 [30080/60000]\tLoss: 0.636898\n", + "Train Epoch: 3 [30720/60000]\tLoss: 0.599510\n", + "Train Epoch: 3 [31360/60000]\tLoss: 0.629284\n", + "Train Epoch: 3 [32000/60000]\tLoss: 0.505906\n", + "Train Epoch: 3 [32640/60000]\tLoss: 0.741626\n", + "Train Epoch: 3 [33280/60000]\tLoss: 0.642386\n", + "Train Epoch: 3 [33920/60000]\tLoss: 0.635572\n", + "Train Epoch: 3 [34560/60000]\tLoss: 0.639967\n", + "Train Epoch: 3 [35200/60000]\tLoss: 0.720257\n", + "Train Epoch: 3 [35840/60000]\tLoss: 0.478147\n", + "Train Epoch: 3 [36480/60000]\tLoss: 0.685794\n", + "Train Epoch: 3 [37120/60000]\tLoss: 0.421208\n", + "Train Epoch: 3 [37760/60000]\tLoss: 0.584400\n", + "Train Epoch: 3 [38400/60000]\tLoss: 0.702878\n", + "Train Epoch: 3 [39040/60000]\tLoss: 0.667306\n", + "Train Epoch: 3 [39680/60000]\tLoss: 0.369802\n", + "Train Epoch: 3 [40320/60000]\tLoss: 0.655229\n", + "Train Epoch: 3 [40960/60000]\tLoss: 0.490676\n", + "Train Epoch: 3 [41600/60000]\tLoss: 0.446377\n", + "Train Epoch: 3 [42240/60000]\tLoss: 0.393590\n", + "Train Epoch: 3 [42880/60000]\tLoss: 0.618019\n", + "Train Epoch: 3 [43520/60000]\tLoss: 0.411980\n", + "Train Epoch: 3 [44160/60000]\tLoss: 0.757768\n", + "Train Epoch: 3 [44800/60000]\tLoss: 0.506138\n", + "Train Epoch: 3 [45440/60000]\tLoss: 0.457559\n", + "Train Epoch: 3 [46080/60000]\tLoss: 0.427676\n", + "Train Epoch: 3 [46720/60000]\tLoss: 0.525319\n", + "Train Epoch: 3 [47360/60000]\tLoss: 0.454945\n", + "Train Epoch: 3 [48000/60000]\tLoss: 0.300189\n", + "Train Epoch: 3 [48640/60000]\tLoss: 0.571119\n", + "Train Epoch: 3 [49280/60000]\tLoss: 0.796717\n", + "Train Epoch: 3 [49920/60000]\tLoss: 0.410930\n", + "Train Epoch: 3 [50560/60000]\tLoss: 0.679963\n", + "Train Epoch: 3 [51200/60000]\tLoss: 0.625742\n", + "Train Epoch: 3 [51840/60000]\tLoss: 0.506195\n", + "Train Epoch: 3 [52480/60000]\tLoss: 0.527920\n", + "Train Epoch: 3 [53120/60000]\tLoss: 0.477663\n", + "Train Epoch: 3 [53760/60000]\tLoss: 0.429325\n", + "Train Epoch: 3 [54400/60000]\tLoss: 0.561766\n", + "Train Epoch: 3 [55040/60000]\tLoss: 0.622166\n", + "Train Epoch: 3 [55680/60000]\tLoss: 0.454855\n", + "Train Epoch: 3 [56320/60000]\tLoss: 0.564210\n", + "Train Epoch: 3 [56960/60000]\tLoss: 0.408687\n", + "Train Epoch: 3 [57600/60000]\tLoss: 0.639709\n", + "Train Epoch: 3 [58240/60000]\tLoss: 0.516085\n", + "Train Epoch: 3 [58880/60000]\tLoss: 0.692927\n", + "Train Epoch: 3 [59520/60000]\tLoss: 0.301529\n", + "\n", + "Test set: Avg. loss: 0.1659, Accuracy: 9509/10000 (95%)\n", + "\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Run network on data we got before and show predictions\n", + "output = model(example_data)\n", + "\n", + "fig = plt.figure()\n", + "for i in range(6):\n", + " plt.subplot(2,3,i+1)\n", + " plt.tight_layout()\n", + " plt.imshow(example_data[i][0], cmap='gray', interpolation='none')\n", + " plt.title(\"Prediction: {}\".format(\n", + " output.data.max(1, keepdim=True)[1][i].item()))\n", + " plt.xticks([])\n", + " plt.yticks([])\n", + "plt.show()" + ], + "metadata": { + "id": "o7fRUAy9Se1B", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 320 + }, + "outputId": "de0d09a1-092d-4653-b6f6-c2d191c33441" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + ":34: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n", + " x = F.log_softmax(x)\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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HOG4GTZsmJePHz8+icPLqEBTwxkKACAKCgoAIAoKCgAgigY3h5KeJ7nqqqu8tn333dfLH3300SS+++67vbZ7773Xyw899NAkfumll7y2U089taS+ouFL304uSa1atfJy5k2Qlh4fQ4cO9douu+wyL9+2bVsSz5w502u7/vrrvfzf//53rC6WFWcoAIAoKCgAgCiq7pJXt27dvPyEE07w8muuuSaJt27d6rXdc889Xn7bbbcl8dKlS/MeN9xXWnjr6LnnnpvEU6dOzbtfNDzf+c53kji8FX3lypWV7g6q2E477eTlf/jDH5J4yJAhXpuZeblzLom7d+/ute22225ePnr06Dr1s1I4QwEAREFBAQBEQUEBAERRFXMo77zzThJ37NjRa2vbtq2Xf/TRR0l8xx13eG3hKsHF2LhxYxIvW7bMawtvR27RokXJx0H1admypZc/9thjSbzHHnt4bXPnzq1El1ClDjjgAC+/7rrrvPycc87J+dpJkyZ5+U9/+tOc2377298uoXf1jzMUAEAUFBQAQBQUFABAFBWbQznkkEOSePr06V7b/vvvn8ThUvHpORPJf2Le+++/H61/mzdvTuK1a9d6beEcChqXcHmV9LzJe++957X96le/Kvk4zZs3T+JOnTp5bemlf2bNmlXyMRDf9773vSQOf3eFS/GkzZkzx8snT57s5fnmUG666aYielg9OEMBAERBQQEARFGxS17p2+32228/ry19mSs8pbz44ou9/JNPPilD76TTTjstiXv16lWWY6A6tGvXzsvPPPPMnNuG42/16tUFH+e3v/2tl59xxhlJ3KNHD68tvYQPl7zqV/qyuuSvTB5e4gpvBU5f1nr33Xe9tnB5lXzC5Z4aCs5QAABRUFAAAFFQUAAAUVRsDiW9nMWoUaO8tvRtmlOmTPHayjVnEi6RED7REY3X6aef7uXHHnusl3/22WdJvH79+rz7at26dRKPGzfOawuf2LdixYoknjdvntd20kknJfFPfvITr+3+++/P2wfEFc517LXXXkn8y1/+0msLf+b5LFmyxMvXrFlT4zEkac899yx4v9WEMxQAQBQUFABAFBQUAEAU9bJ8/X333VeR46QfoxnOmdx4441evvPOOxe833AJazQshx12WN729Hzf22+/nXfb9LIc4VIaixYt8vL0PEk4htJzKl26dMl7TJRX//79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TdLLPYXS4y79qGDJX3pfkj777LOC+1cL5lAAAOVDQQEARFH1S680NOlLGeHqs6g/M2fOTOJ58+Z5benLYZI0YsSIgvfbrVu3JG7dunXebdevX1/wflGdwo8fFLOi+PLly708fYvxsmXLvLZwOZWbb745iY8//vicxzjzzDO9/JhjjvHyZ599tpCulowzFABAFBQUAEAUFBQAQBTcNhxZnz59kjh93V6S9txzz7Ick9uG68/rr7+exEceeaTXFv7f2muvvZK4Spar57bhGnTp0sXLR48encQXXXSR11bM78/DDjvMy8OlmfJp3759Eoe/V9LzOGF/wiX0hw0bVvAxa8FtwwCA8qGgAACioKAAAKLgcyhAEcLPmrRq1SqJw6VXQlUyb4JaTJkyxcuPPvrokvbz6KOPenn4mIRibNy4MYlnz57tteX7LEy5lnvKhTMUAEAUFBQAQBRc8gKKkF5qRfJXKg5v2SzmllLUn/QTD6WvL1eSFq4gHj5p8a233kri8BbjfE9lDFcxDm9BP/vss5O4V69eOfsUHuP222/Pecxy4AwFABAFBQUAEAUFBQAQRdXPocyfP9/L00uA33TTTV5buCx5fUjfwlfbbaRoePr16+fl6Z9x+PPmNuGGIZyTyDf3Fc5RhNumfz/deuuteY+bHi/t2rXz2op58mO6T1u3bvXaIj6hsSCcoQAAoqCgAACiqPpLXg888ICXjx8/PonDp5y9+eabXr5ly5ay9esrLVq08PLLLrssiRcsWFD246Oy0rcJS/kvj8yYMaPc3UGVOfHEEwveNn3Jqy63mKdvVR41apTX9sorr5S831JwhgIAiIKCAgCIgoICAIii6udQJk6c6OWdO3dO4ksvvdRr23vvvb38lltuSeJXX321DL3z50wkaZdddkni8LZmND7p6+Dhshz33ntvpbuDErz33ntefvLJJ9dTT3JLrzA8Z84cr23atGlJvHbt2or1qSacoQAAoqCgAACioKAAAKKo+jmU0OWXX57E4edQxowZ4+UDBw5M4o8//thrmz59es5jvPPOO14eLoswePDgJO7Tp4/Xln5K2/PPP5/zGGgc0p8fyLc8OapX+neKJD3xxBNe/thjjyVx+MTOYtx9991enl4m5amnnvLawnmdDRs2JPH27dtL7kO5cYYCAIiCggIAiMKK+ci/mVX1I+g6duzo5emVYdOXqST/CWjF+tOf/pTE4fIaM2fOLHm/pXLOVfWyxtU+booRXiodNGhQEodL//Ts2bMifaqDhc65qu5kYxo7jUyNY4czFABAFBQUAEAUFBQAQBQN7rbhfFatWuXlU6dOrTEGShXOOabz8FZPoKnhDAUAEAUFBQAQBQUFABBFo/ocSlPF51BQIj6HglLxORQAQPlQUAAAUVBQAABRUFAAAFFQUAAAUVBQAABRFLv0yjpJy8vREZSsc313oACMm+rE2EGpahw7RX0OBQCAXLjkBQCIgoICAIiCggIAiIKCAgCIgoICAIiCggIAiIKCAo1z6QYAAAATSURBVACIgoICAIiCggIAiOL/AyWSUozBZgCEAAAAAElFTkSuQmCC\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "I reckon you probably know enough to download imagenet and reproduce AlexNet. You probably have to do that locally (or pay Google for CoLab space) as there are more than a million images involved though. Good project for the Xmas holidays... build AlexNet, build VGG, build ResNet200." + ], + "metadata": { + "id": "g-9j4p8flcpB" + } + } + ] +} diff --git a/CM20315/CM20315_Coursework_I.ipynb b/CM20315/CM20315_Coursework_I.ipynb new file mode 100644 index 0000000..ce452fd --- /dev/null +++ b/CM20315/CM20315_Coursework_I.ipynb @@ -0,0 +1,447 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyONQTuflJTEoNl63WNZdEf7", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework I -- Model hyperparameters\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNist 1D dataset. \n", + "\n", + "In this coursework, you need to modify the **model hyperparameters** (only) to improve the performance over the current attempt. This could mean the number of layers, the number of hidden units per layer, or the type of activation function, or any combination of the three. \n", + "\n", + "The only constraint is that you MUST use a fully connected network (no convolutional networks for now if you have read ahead in the book).\n", + "\n", + "You don't have to improve the performance much. A few tenths of a percent is fine. It just has to be better to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu\n", + "\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment \n", + "# or download from my github to your local machine if you are doing this locally\n", + "if not os.path.exists('./train_data_x.npy'):\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_y.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_y.npy " + ], + "metadata": { + "id": "wScBGXXFVadm", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "970c192f-33ad-45ee-dc12-b1b9a30b50d7" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2022-11-21 12:37:03-- https://github.com/udlbook/udlbook/raw/main/practicals/train_data_x.npy\n", + "Resolving github.com (github.com)... 140.82.114.3\n", + "Connecting to github.com (github.com)|140.82.114.3|:443... connected.\n", + "HTTP request sent, awaiting response... 302 Found\n", + "Location: https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/train_data_x.npy [following]\n", + "--2022-11-21 12:37:04-- https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/train_data_x.npy\n", + "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", + "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 1280128 (1.2M) [application/octet-stream]\n", + "Saving to: ‘train_data_x.npy’\n", + "\n", + "train_data_x.npy 100%[===================>] 1.22M --.-KB/s in 0.05s \n", + "\n", + "2022-11-21 12:37:04 (22.9 MB/s) - ‘train_data_x.npy’ saved [1280128/1280128]\n", + "\n", + "--2022-11-21 12:37:04-- https://github.com/udlbook/udlbook/raw/main/practicals/train_data_y.npy\n", + "Resolving github.com (github.com)... 140.82.112.3\n", + "Connecting to github.com (github.com)|140.82.112.3|:443... connected.\n", + "HTTP request sent, awaiting response... 302 Found\n", + "Location: https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/train_data_y.npy [following]\n", + "--2022-11-21 12:37:04-- https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/train_data_y.npy\n", + "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", + "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 32128 (31K) [application/octet-stream]\n", + "Saving to: ‘train_data_y.npy’\n", + "\n", + "train_data_y.npy 100%[===================>] 31.38K --.-KB/s in 0.002s \n", + "\n", + "2022-11-21 12:37:04 (13.9 MB/s) - ‘train_data_y.npy’ saved [32128/32128]\n", + "\n", + "--2022-11-21 12:37:04-- https://github.com/udlbook/udlbook/raw/main/practicals/val_data_x.npy\n", + "Resolving github.com (github.com)... 140.82.113.3\n", + "Connecting to github.com (github.com)|140.82.113.3|:443... connected.\n", + "HTTP request sent, awaiting response... 302 Found\n", + "Location: https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/val_data_x.npy [following]\n", + "--2022-11-21 12:37:04-- https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/val_data_x.npy\n", + "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", + "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 640128 (625K) [application/octet-stream]\n", + "Saving to: ‘val_data_x.npy’\n", + "\n", + "val_data_x.npy 100%[===================>] 625.12K --.-KB/s in 0.04s \n", + "\n", + "2022-11-21 12:37:05 (14.1 MB/s) - ‘val_data_x.npy’ saved [640128/640128]\n", + "\n", + "--2022-11-21 12:37:05-- https://github.com/udlbook/udlbook/raw/main/practicals/val_data_y.npy\n", + "Resolving github.com (github.com)... 140.82.114.4\n", + "Connecting to github.com (github.com)|140.82.114.4|:443... connected.\n", + "HTTP request sent, awaiting response... 302 Found\n", + "Location: https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/val_data_y.npy [following]\n", + "--2022-11-21 12:37:05-- https://raw.githubusercontent.com/udlbook/udlbook/main/practicals/val_data_y.npy\n", + "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...\n", + "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 16128 (16K) [application/octet-stream]\n", + "Saving to: ‘val_data_y.npy’\n", + "\n", + "val_data_y.npy 100%[===================>] 15.75K --.-KB/s in 0s \n", + "\n", + "2022-11-21 12:37:05 (31.0 MB/s) - ‘val_data_y.npy’ saved [16128/16128]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "869f360f-3f9b-4e3a-f8c6-cd69fb331709" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Train data: 4000 examples (columns), each of which has 40 dimensions (rows)\n", + "Validation data: 2000 examples (columns), each of which has 40 dimensions (rows)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# YOU SHOULD ONLY CHANGE THIS CELL!\n", + "\n", + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": 4, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + " \n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part I: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_I_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "777de5cf-c31d-4519-c7d3-e363e08d394c" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 0, train loss 1.573925, train error 61.75, val loss 1.666198, percent error 67.85\n", + "Epoch 1, train loss 1.318168, train error 48.25, val loss 1.471983, percent error 57.95\n", + "Epoch 2, train loss 1.130921, train error 40.03, val loss 1.360329, percent error 53.45\n", + "Epoch 3, train loss 0.984176, train error 35.20, val loss 1.256625, percent error 48.10\n", + "Epoch 4, train loss 0.868384, train error 30.20, val loss 1.191934, percent error 45.30\n", + "Epoch 5, train loss 0.814746, train error 30.00, val loss 1.242606, percent error 48.25\n", + "Epoch 6, train loss 0.693850, train error 23.90, val loss 1.149572, percent error 43.70\n", + "Epoch 7, train loss 0.624264, train error 20.93, val loss 1.142540, percent error 41.20\n", + "Epoch 8, train loss 0.549854, train error 18.22, val loss 1.117410, percent error 40.55\n", + "Epoch 9, train loss 0.495227, train error 16.35, val loss 1.105867, percent error 40.25\n", + "Epoch 10, train loss 0.404633, train error 11.82, val loss 1.047640, percent error 37.90\n", + "Epoch 11, train loss 0.368226, train error 10.32, val loss 1.084517, percent error 40.00\n", + "Epoch 12, train loss 0.339168, train error 9.15, val loss 1.097698, percent error 38.50\n", + "Epoch 13, train loss 0.302940, train error 7.68, val loss 1.099108, percent error 37.25\n", + "Epoch 14, train loss 0.306518, train error 8.75, val loss 1.152268, percent error 39.40\n", + "Epoch 15, train loss 0.267522, train error 6.88, val loss 1.133403, percent error 38.20\n", + "Epoch 16, train loss 0.229632, train error 5.25, val loss 1.121083, percent error 37.15\n", + "Epoch 17, train loss 0.207498, train error 3.75, val loss 1.153062, percent error 38.00\n", + "Epoch 18, train loss 0.196556, train error 3.93, val loss 1.190135, percent error 37.40\n", + "Epoch 19, train loss 0.188664, train error 3.85, val loss 1.224324, percent error 37.10\n", + "Epoch 20, train loss 0.151122, train error 1.68, val loss 1.188515, percent error 36.50\n", + "Epoch 21, train loss 0.141133, train error 1.62, val loss 1.186356, percent error 36.30\n", + "Epoch 22, train loss 0.131978, train error 1.05, val loss 1.210334, percent error 37.10\n", + "Epoch 23, train loss 0.126643, train error 0.93, val loss 1.222403, percent error 37.15\n", + "Epoch 24, train loss 0.121445, train error 0.93, val loss 1.234944, percent error 36.60\n", + "Epoch 25, train loss 0.112892, train error 0.80, val loss 1.249163, percent error 36.35\n", + "Epoch 26, train loss 0.106721, train error 0.57, val loss 1.257951, percent error 37.40\n", + "Epoch 27, train loss 0.101724, train error 0.40, val loss 1.266331, percent error 36.90\n", + "Epoch 28, train loss 0.100189, train error 0.43, val loss 1.280694, percent error 37.50\n", + "Epoch 29, train loss 0.093124, train error 0.40, val loss 1.289725, percent error 37.50\n", + "Epoch 30, train loss 0.087898, train error 0.35, val loss 1.291468, percent error 36.75\n", + "Epoch 31, train loss 0.085375, train error 0.30, val loss 1.301522, percent error 37.60\n", + "Epoch 32, train loss 0.083599, train error 0.25, val loss 1.310020, percent error 37.40\n", + "Epoch 33, train loss 0.082141, train error 0.25, val loss 1.312388, percent error 37.00\n", + "Epoch 34, train loss 0.080171, train error 0.18, val loss 1.320177, percent error 37.05\n", + "Epoch 35, train loss 0.077832, train error 0.18, val loss 1.328110, percent error 37.40\n", + "Epoch 36, train loss 0.076884, train error 0.22, val loss 1.327245, percent error 36.75\n", + "Epoch 37, train loss 0.074366, train error 0.15, val loss 1.332270, percent error 37.35\n", + "Epoch 38, train loss 0.072928, train error 0.12, val loss 1.339683, percent error 37.25\n", + "Epoch 39, train loss 0.071071, train error 0.10, val loss 1.341762, percent error 37.20\n", + "Epoch 40, train loss 0.070039, train error 0.12, val loss 1.346855, percent error 37.35\n", + "Epoch 41, train loss 0.069533, train error 0.10, val loss 1.355226, percent error 37.45\n", + "Epoch 42, train loss 0.068655, train error 0.10, val loss 1.354576, percent error 37.60\n", + "Epoch 43, train loss 0.067851, train error 0.12, val loss 1.354539, percent error 37.05\n", + "Epoch 44, train loss 0.066937, train error 0.07, val loss 1.359383, percent error 37.70\n", + "Epoch 45, train loss 0.066291, train error 0.05, val loss 1.364250, percent error 37.55\n", + "Epoch 46, train loss 0.065502, train error 0.05, val loss 1.365553, percent error 37.55\n", + "Epoch 47, train loss 0.064782, train error 0.07, val loss 1.366146, percent error 37.55\n", + "Epoch 48, train loss 0.064185, train error 0.05, val loss 1.368595, percent error 37.35\n", + "Epoch 49, train loss 0.063420, train error 0.07, val loss 1.373254, percent error 37.45\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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fo4UULIQEclH165dc7RRGDt2LK+88goA3333HV988cVByaJVq1Z06tQJgJNOOolly5YlLd6SpGQhIqVTAVcAyVKzZs39z6dPn86///1vPvroI2rUqEHPnj3zbMNQrVq1/c8rV67Mjh07khJrSdMNbhGRSO3atdmyZUue723atIn69etTo0YNlixZwn//+98kR5daurIQEYk0bNiQHj160L59e6pXr07jxo33v9enTx8effRR2rZty/HHH0/37t1TGGnyWejDr2zS4Eci5cvixYtp27ZtqsMoV/I6pmY2290zirIdFUOJiEhcShYiIhKXkoWIiMSlZCEiInEpWYiISFxKFiIiEpeShYhIMdWqVQuAlStXcvHFF+e5TM+ePYlXxX/MmDFs3759/3xp7PJcyUJE5BAdeeSRvPTSS8VeP3eyKI1dnitZiIhEhg0bxrhx4/bP33XXXYwcOZLevXvTpUsXTjzxRF577bWD1lu2bBnt27cHYMeOHVx22WW0bduWCy64IEffUDfccAMZGRm0a9eOO++8EwidE65cuZIzzjiDM844Awhdnq9btw6ABx54gPbt29O+fXvGRP1lLVu2jLZt23L99dfTrl07zjrrrBLvg0rdfYhIqZSCHsoZMGAAN998MzfddBMAL7zwAv/6178YMmQIderUYd26dXTv3p3zzjsv3/GtH3nkEWrUqMHixYuZN28eXbp02f/eqFGjaNCgAXv37qV3797MmzePIUOG8MADDzBt2jQOO+ywHNuaPXs2Tz75JDNmzMDd6datG7FYjPr16ye9K3RdWYiIRDp37szatWtZuXIln376KfXr1+eII47gjjvuoEOHDpx55pmsWLGCNWvW5LuNd999d/9Ju0OHDnTo0GH/ey+88AJdunShc+fOLFy4kEWLFhUYz/vvv88FF1xAzZo1qVWrFhdeeCHvvfcekPyu0HVlISKlUqp6KL/kkkt46aWXWL16NQMGDOCZZ54hMzOT2bNnk5aWRsuWLfPsmjyepUuXcv/99/Pxxx9Tv359Bg0aVKztZEl2V+i6shARyWbAgAFMmjSJl156iUsuuYRNmzZx+OGHk5aWxrRp0/jmm28KXP/000/n2WefBWDBggXMmzcPgM2bN1OzZk3q1q3LmjVrePPNN/evk1/X6Keddhqvvvoq27dvZ9u2bbzyyiucdtppCfy0hacr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7PvNN91Xry7yYRCRYijryeJoYCbwZZQ4qsVbv1atWv7kk0+6u/uuXbs8Fov5xIkT3d1927ZtHovFfNKkSe7uvnHjRo/FYj558mR3d88cPdpj4FOGDnV391WrVnksFvM333zT3d2//fZbj8ViPnXqVHd3/+qrrzwWi/n06dPd3X3JkiUei8X8gw8+cHf3+fPneywW85kzZ7q7+5w5czwWi/mcOXPc3X3mzJkei8V8/vz57u7+wQcfeCwW8yVLlri7+/Tp0z0Wi/lXX33l7u5Tp071WCzm3377rbu7v/nmmx6LxXxVdEafMmWKx2Ix//e/M71VK/e6dSd7+/Yx3xhlikmTJnksFvNt27a5u/vEiRM9Fov5rl273N39ySef9NNPj/mLL4acCePdrLdfckm4KrnqqnFeuXIfr1vX/emn3R98cIz369dv/5dt9OjRfuGFF+6fv+WWe71t2wF+9NHhW1Wp0ghv2nSgP/20++bN7sOHD/dLLhnkf/2r+8UXu1erNszhejcLy8OtDjf6kUe6n3uue7duQ/3cc4f6J5+EJHbDDTf6rbfeun9/119/vQ8bNmz//KBBg3z48OH75wcOHOgjRozYPz9gwAC/9957989feOGFPnr06P3z/fr18zFjxuyf79Onj48bN27/fO/evX38+PH752OxWLG+eytXuv/jH5neo0fMp0yZ4u75f/feemuqL1/uPn78V96qVcyvvXa6jxjhPmTIEm/ZMubXXfeBjxjhfttt871Ll5h/+GHB37158+b755+7//rXH3ijRjHv23eJ//zn7ldcMd2PPjrmI0d+5S+84D569FTv1i3mX31V8HcvMzPT3d0nT57ssdjB370VK7b5vHnuv/vdRO/RI+d3LxaL7T+W48eP9969e++ff+ihcd6zZx///HP3b791HzlyjPft28937877u3fvvff6gAED9s+PGDHCBw4c6Hv3hu/ezTcP9wsvHORz5rh/9JH7FVcM8z59rveXX3Z/9ln3s8661U899UYfNSpcnXfsONTbth3qF13kftFF7hkZN3q/frf6kiXhSjv3d+/yywf5wIHDfeRI9/POc69RY6DXrj3Cjz/ePSPD/fDDB3ibNvf6FVe4X3ede8uWF3q3bqN98GD3wYPdW7To5yefPGb/fPPmfbxHj3H755s27e1nnjne777bfexY9zZtYj506JP+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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "# if not os.path.exists('./test_data_x.npy'):\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_x.npy\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_y.npy\n", + "\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": 8, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Coursework_II.ipynb b/CM20315/CM20315_Coursework_II.ipynb new file mode 100644 index 0000000..851d64c --- /dev/null +++ b/CM20315/CM20315_Coursework_II.ipynb @@ -0,0 +1,292 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMaHUorNXKELJbeWcOVBYrr", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework II -- Training hyperparameters\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNist 1D dataset. \n", + "\n", + "In this coursework, you need to modify the **training hyperparameters** (only) to improve the performance over the current attempt. This could mean the training algorithm, learning rate, learning rate schedule, momentum term, initialization etc. \n", + "\n", + "You don't have to improve the performance much. A few tenths of a percent is fine. It just has to be better to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu\n", + "\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment \n", + "# or download from my github to your local machine if you are doing this locally\n", + "if not os.path.exists('./train_data_x.npy'):\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_y.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_y.npy " + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# YOU SHOULD NOT CHANGE THIS CELL!\n", + "\n", + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + " \n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part II: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_II_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "# if not os.path.exists('./test_data_x.npy'):\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_x.npy\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_y.npy\n", + "\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "zXccksoD1Eww" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Coursework_III.ipynb b/CM20315/CM20315_Coursework_III.ipynb new file mode 100644 index 0000000..639d64a --- /dev/null +++ b/CM20315/CM20315_Coursework_III.ipynb @@ -0,0 +1,290 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMcvUAtcMw0yuDfUkbsEDLD", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework III -- Regularization\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNist 1D dataset. \n", + "\n", + "In this coursework, you need add **regularization** of some kind to improve the performance. Anything from chapter 8 of the book or anything else you can find is fine *except* early stopping. You must not change the model hyperparameters or the training algorithm.\n", + "\n", + "You don't have to improve the performance much. A few tenths of a percent is fine. It just has to be better to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu\n", + "\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment \n", + "# or download from my github to your local machine if you are doing this locally\n", + "if not os.path.exists('./train_data_x.npy'):\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/train_data_y.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_x.npy\n", + " !wget https://github.com/udlbook/udlbook/raw/main/practicals/val_data_y.npy " + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + " \n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part III: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_III_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "# if not os.path.exists('./test_data_x.npy'):\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_x.npy\n", + "# !wget https://github.com/udlbook/udlbook/raw/main/practicals/test_data_y.npy\n", + "\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "zXccksoD1Eww" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Coursework_IV.ipynb b/CM20315/CM20315_Coursework_IV.ipynb new file mode 100644 index 0000000..dfdb5e9 --- /dev/null +++ b/CM20315/CM20315_Coursework_IV.ipynb @@ -0,0 +1,222 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyNb1nfymw3lpvyBHaCFRvMI", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework IV\n", + "\n", + "This coursework explores the geometry of high dimensional spaces. It doesn't behave how you would expect and all your intuitions are wrong! You will write code and it will give you three numerical answers that you need to type into Moodle." + ], + "metadata": { + "id": "EjLK-kA1KnYX" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4ESMmnkYEVAb" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import scipy.special as sci" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (a)\n", + "\n", + "In part (a) of the practical, we investigate how close random points are in 2D, 100D, and 1000D. In each case, we generate 1000 points and calculate the Euclidean distance between each pair. You should find that in 1000D, the furthest two points are only slightly further apart than the nearest points. Weird!" + ], + "metadata": { + "id": "MonbPEitLNgN" + } + }, + { + "cell_type": "code", + "source": [ + "# Fix the random seed so we all have the same random numbers\n", + "np.random.seed(0)\n", + "n_data = 1000\n", + "# Create 1000 data examples (columns) each with 2 dimensions (rows)\n", + "n_dim = 2\n", + "x_2D = np.random.normal(size=(n_dim,n_data))\n", + "# Create 1000 data examples (columns) each with 100 dimensions (rows)\n", + "n_dim = 100\n", + "x_100D = np.random.normal(size=(n_dim,n_data))\n", + "# Create 1000 data examples (columns) each with 1000 dimensions (rows)\n", + "n_dim = 1000\n", + "x_1000D = np.random.normal(size=(n_dim,n_data))\n", + "\n", + "# These values should be the same, otherwise your answer will be wrong\n", + "# Get in touch if they are not!\n", + "print('Sum of your data is %3.3f, Should be %3.3f'%(np.sum(x_1000D),1036.321))" + ], + "metadata": { + "id": "vZSHVmcWEk14" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def distance_ratio(x):\n", + " # TODO -- replace the two lines below to calculate the largest and smallest Euclidean distance between \n", + " # the data points in the columns of x. DO NOT include the distance between the data point\n", + " # and itself (which is obviously zero)\n", + " smallest_dist = 1.0\n", + " largest_dist = 1.0\n", + " \n", + " # Calculate the ratio and return\n", + " dist_ratio = largest_dist / smallest_dist\n", + " return dist_ratio" + ], + "metadata": { + "id": "PhVmnUs8ErD9" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print('Ratio of largest to smallest distance 2D: %3.3f'%(distance_ratio(x_2D)))\n", + "print('Ratio of largest to smallest distance 100D: %3.3f'%(distance_ratio(x_100D)))\n", + "print('Ratio of largest to smallest distance 1000D: %3.3f'%(distance_ratio(x_1000D)))\n", + "print('**Note down the last of these three numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "0NdPxfn5GQuJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (b)\n", + "\n", + "In part (b) of the practical we calculate the volume of a hypersphere of radius 0.5 (i.e., of diameter 1) as a function of the radius. You will find that the volume decreases to almost nothing in high dimensions. All of the volume is in the corners of the unit hypercube (which always has volume 1). Double weird.\n", + "\n", + "Note that you you can check your answer by doing the calculation for 2D using the standard formula for the area of a circle and making sure it matches." + ], + "metadata": { + "id": "b2FYKV1SL4Z7" + } + }, + { + "cell_type": "code", + "source": [ + "def volume_of_hypersphere(diameter, dimensions):\n", + " # Formula iven in Problem 8.7 of the notes in Moodle (probably a different problem number on book site)\n", + " # You will need sci.special.gamma()\n", + " # Check out: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.gamma.html\n", + " # Also use this value for pi\n", + " pi = np.pi\n", + " # TODO replace this code with formula for the volume of a hypersphere\n", + " volume = 1.0\n", + "\n", + " return volume\n", + " " + ], + "metadata": { + "id": "CZoNhD8XJaHR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "diameter = 1.0\n", + "for c_dim in range(1,11):\n", + " print(\"Volume of unit diameter hypersphere in %d dimensions is %3.3f\"%(c_dim, volume_of_hypersphere(diameter, c_dim)))\n", + "print('**Note down the last of these ten numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "fNTBlg_GPEUh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (c)\n", + "\n", + "In part (c) of the coursework, you will calculate what proportion of the volume of a hypersphere is in the outer 1% of the radius/diameter. Calculate the volume of a hypersphere and then the volume of a hypersphere with 0.99 of the radius and then figure out the proportion (a number between 0 and 1). You'll see that by the time we get to 300 dimensions most of the volume is in the outer 1 percent. Extremely weird!" + ], + "metadata": { + "id": "GdyMeOBmoXyF" + } + }, + { + "cell_type": "code", + "source": [ + "def get_prop_of_volume_in_outer_1_percent(dimension):\n", + " # TODO -- replace this line\n", + " proportion = 1.0\n", + "\n", + " return proportion" + ], + "metadata": { + "id": "8_CxZ2AIpQ8w" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# While we're here, let's look at how much of the volume is in the outer 1% of the radius\n", + "for c_dim in [1,2,10,20,50,100,150,200,250,300]:\n", + " print('Proportion of volume in outer 1 percent of radius in %d dimensions =%3.3f'%(c_dim, get_prop_of_volume_in_outer_1_percent(c_dim)))\n", + "print('**Note down the last of these ten numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "LtMDIn2qPVfJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "Qbxb-eHHQCS7" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Deep.ipynb b/CM20315/CM20315_Deep.ipynb new file mode 100644 index 0000000..1607e2c --- /dev/null +++ b/CM20315/CM20315_Deep.ipynb @@ -0,0 +1,448 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOtP/O21RVLxAeEBIwV0aZt", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **Deep neural networks**\n", + "\n", + "In this notebook, we'll experiment with feeding one neural network into another as in figure 4.1 from the book." + ], + "metadata": { + "id": "MaKn8CFlzN8E" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8ClURpZQzI6L" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation" + ], + "metadata": { + "id": "YdmveeAUz4YG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a shallow neural network with, one input, one output, and three hidden units\n", + "def shallow_1_1_3(x, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31):\n", + " # Initial lines\n", + " pre_1 = theta_10 + theta_11 * x\n", + " pre_2 = theta_20 + theta_21 * x\n", + " pre_3 = theta_30 + theta_31 * x\n", + " # Activation functions\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + " # Weight activations\n", + " w_act_1 = phi_1 * act_1\n", + " w_act_2 = phi_2 * act_2\n", + " w_act_3 = phi_3 * act_3\n", + " # Combine weighted activation and add y offset\n", + " y = phi_0 + w_act_1 + w_act_2 + w_act_3\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ], + "metadata": { + "id": "ximCLwIfz8kj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# # Plot the shallow neural network. We'll assume input in is range [-1,1] and output [-1,1]\n", + "# If the plot_all flag is set to true, then we'll plot all the intermediate stages as in Figure 3.3 \n", + "def plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False, x_data=None, y_data=None):\n", + "\n", + " # Plot intermediate plots if flag set\n", + " if plot_all:\n", + " fig, ax = plt.subplots(3,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0,0].plot(x,pre_1,'r-'); ax[0,0].set_ylabel('Preactivation')\n", + " ax[0,1].plot(x,pre_2,'b-'); ax[0,1].set_ylabel('Preactivation')\n", + " ax[0,2].plot(x,pre_3,'g-'); ax[0,2].set_ylabel('Preactivation')\n", + " ax[1,0].plot(x,act_1,'r-'); ax[1,0].set_ylabel('Activation')\n", + " ax[1,1].plot(x,act_2,'b-'); ax[1,1].set_ylabel('Activation')\n", + " ax[1,2].plot(x,act_3,'g-'); ax[1,2].set_ylabel('Activation')\n", + " ax[2,0].plot(x,w_act_1,'r-'); ax[2,0].set_ylabel('Weighted Act')\n", + " ax[2,1].plot(x,w_act_2,'b-'); ax[2,1].set_ylabel('Weighted Act')\n", + " ax[2,2].plot(x,w_act_3,'g-'); ax[2,2].set_ylabel('Weighted Act')\n", + "\n", + " for plot_y in range(3):\n", + " for plot_x in range(3):\n", + " ax[plot_y,plot_x].set_xlim([-1,1]);ax[plot_x,plot_y].set_ylim([-1,1])\n", + " ax[plot_y,plot_x].set_aspect(1.0)\n", + " ax[2,plot_y].set_xlabel('Input, $x$');\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x,y)\n", + " ax.set_xlabel('Input'); ax.set_ylabel('Output')\n", + " ax.set_xlim([-1,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(1.0)\n", + " if x_data is not None:\n", + " ax.plot(x_data, y_data, 'mo')\n", + " for i in range(len(x_data)):\n", + " ax.plot(x_data[i], y_data[i],)\n", + " plt.show()" + ], + "metadata": { + "id": "btrt7BX20gKD" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's define two networks. We'll put the prefixes n1_ and n2_ before all the variables to make it clear which network is which. We'll just consider the inputs and outputs over the range [-1,1]. If you set the \"plot_all\" flat to True, you can see the details of how they were created." + ], + "metadata": { + "id": "LxBJCObC-NTY" + } + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the first neural network\n", + "n1_theta_10 = 0.0 ; n1_theta_11 = -1.0\n", + "n1_theta_20 = 0 ; n1_theta_21 = 1.0\n", + "n1_theta_30 = -0.67 ; n1_theta_31 = 1.0\n", + "n1_phi_0 = 1.0; n1_phi_1 = -2.0; n1_phi_2 = -3.0; n1_phi_3 = 9.3\n", + "\n", + "# Define a range of input values\n", + "n1_in = np.arange(-1,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "n1_out, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(n1_in, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "# And then plot it\n", + "plot_neural(n1_in, n1_out, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False)" + ], + "metadata": { + "id": "JRebvurv22pT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the second neural network\n", + "n2_theta_10 = -0.6 ; n2_theta_11 = -1.0\n", + "n2_theta_20 = 0.2 ; n2_theta_21 = 1.0\n", + "n2_theta_30 = -0.5 ; n2_theta_31 = 1.0\n", + "n2_phi_0 = 0.5; n2_phi_1 = -1.0; n2_phi_2 = -1.5; n2_phi_3 = 2.0\n", + "\n", + "# Define a range of input values\n", + "n2_in = np.arange(-1,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "n2_out, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(n2_in, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "# And then plot it\n", + "plot_neural(n2_in, n2_out, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False)" + ], + "metadata": { + "id": "ZRjWu8i9239X" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll consider feeding output of the first network into the second one." + ], + "metadata": { + "id": "qOcj2Rof-o20" + } + }, + { + "cell_type": "code", + "source": [ + "# # Plot two shallow neural networks and the composition of the two \n", + "def plot_neural_two_components(x_in, net1_out, net2_out, net12_out=None):\n", + "\n", + " # Plot the two networks separately\n", + " fig, ax = plt.subplots(1,2)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0].plot(x_in, net1_out,'r-')\n", + " ax[0].set_xlabel('Net 1 input'); ax[0].set_ylabel('Net 1 output')\n", + " ax[0].set_xlim([-1,1]);ax[0].set_ylim([-1,1])\n", + " ax[0].set_aspect(1.0)\n", + " ax[1].plot(x_in, net2_out,'b-')\n", + " ax[1].set_xlabel('Net 2 input'); ax[1].set_ylabel('Net 2 output')\n", + " ax[1].set_xlim([-1,1]);ax[1].set_ylim([-1,1])\n", + " ax[1].set_aspect(1.0)\n", + " plt.show()\n", + "\n", + " if net12_out is not None:\n", + " # Plot their composition\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x_in ,net12_out,'g-')\n", + " ax.set_xlabel('Net 1 Input'); ax.set_ylabel('Net 2 Output')\n", + " ax.set_xlim([-1,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(1.0)\n", + " plt.show()" + ], + "metadata": { + "id": "ZB2HTalOE40X" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Display the two inputs\n", + "x = np.arange(-1,1,0.001)\n", + "# We run the first and second neural networks for each of these input values\n", + "net1_out, *_ = shallow_1_1_3(x, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "net2_out, *_ = shallow_1_1_3(x, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "# Plot both graphs\n", + "plot_neural_two_components(x, net1_out, net2_out)" + ], + "metadata": { + "id": "K6Tmecgu7uqt" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# Take a piece of paper and draw what you think will happen when we feed the \n", + "# output of the first network into the second one. Draw the relationship between\n", + "# the input of the first network and the output of the second one." + ], + "metadata": { + "id": "NUQVop9-Xta1" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now let's see if your predictions were right \n", + "\n", + "# TODO feed the output of first network into second network (replace this line)\n", + "net12_out = np.zeros_like(x)\n", + "# Plot all three graphs\n", + "plot_neural_two_components(x, net1_out, net2_out, net12_out)" + ], + "metadata": { + "id": "Yq7GH-MCIyPI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now we'll change things a up a bit. What happens if we change the second network? (note the *-1 change)\n", + "net1_out, *_ = shallow_1_1_3(x, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "net2_out, *_ = shallow_1_1_3(x, ReLU, n2_phi_0, n2_phi_1*-1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out)" + ], + "metadata": { + "id": "BMlLkLbdEuPu" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# Take a piece of paper and draw what you think will happen when we feed the \n", + "# output of the first network into the second one now that we have changed it. Draw the relationship between\n", + "# the input of the first network and the output of the second one." + ], + "metadata": { + "id": "Of6jVXLTJ688" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# When you have a prediction, run this code to see if you were right\n", + "net12_out, *_ = shallow_1_1_3(net1_out, ReLU, n2_phi_0, n2_phi_1*-1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out, net12_out)" + ], + "metadata": { + "id": "PbbSCaSeK6SM" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's change things again. What happens if we change the firsrt network? (note the changes)\n", + "net1_out, *_ = shallow_1_1_3(x, ReLU, n1_phi_0, n1_phi_1*0.5, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "net2_out, *_ = shallow_1_1_3(x, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out)" + ], + "metadata": { + "id": "b39mcSGFK9Fd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# Take a piece of paper and draw what you think will happen when we feed the \n", + "# output of the first network now we have changed it into the original second network. Draw the relationship between\n", + "# the input of the first network and the output of the second one." + ], + "metadata": { + "id": "MhO40cC_LW9I" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# When you have a prediction, run this code to see if you were right\n", + "net12_out, *_ = shallow_1_1_3(net1_out, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out, net12_out)" + ], + "metadata": { + "id": "Akwo-hnPLkNr" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's change things again. What happens if the first network and second networks are the same?\n", + "net1_out, *_ = shallow_1_1_3(x, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "net2_out_new, *_ = shallow_1_1_3(x, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out_new)" + ], + "metadata": { + "id": "TJ7wXKpRLl_E" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# Take a piece of paper and draw what you think will happen when we feed the \n", + "# output of the first network into the original second network. Draw the relationship between\n", + "# the input of the first network and the output of the second one." + ], + "metadata": { + "id": "dJbbh6R7NG9k" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# When you have a prediction, run this code to see if you were right\n", + "net12_out, *_ = shallow_1_1_3(net1_out, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "plot_neural_two_components(x, net1_out, net2_out_new, net12_out)" + ], + "metadata": { + "id": "BiZZl3yNM2Bq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# Contemplate what you think will happen when we feed the \n", + "# output of the original first network into a second copy of the original first network, and then \n", + "# the output of that into the original second network (so now we have a three layer network)\n", + "# How many total linear regions will we have in the output? \n", + "net123_out, *_ = shallow_1_1_3(net12_out, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "plot_neural_two_components(x, net12_out, net2_out, net123_out)" + ], + "metadata": { + "id": "BSd51AkzNf7-" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TO DO\n", + "# How many linear regions would there be if we ran N copies of the first network, feeding the result of the first \n", + "# into the second, the second into the third and so on, and then passed the result into the original second\n", + "# network (blue curve above)\n", + "\n", + "# Take away conclusions: with very few parameters, we can make A LOT of linear regions, but\n", + "# they depend on one another in complex ways that quickly become to difficult to understand intuitively." + ], + "metadata": { + "id": "HqzePCLOVQK7" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Deep2.ipynb b/CM20315/CM20315_Deep2.ipynb new file mode 100644 index 0000000..31df371 --- /dev/null +++ b/CM20315/CM20315_Deep2.ipynb @@ -0,0 +1,317 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyP87B9tfgXpVQdlQBUGw4mg", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **Deep neural networks #2**\n", + "\n", + "In this notebook, we'll investigate converting neural networks to matrix form." + ], + "metadata": { + "id": "MaKn8CFlzN8E" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8ClURpZQzI6L" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation" + ], + "metadata": { + "id": "YdmveeAUz4YG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a shallow neural network with, one input, one output, and three hidden units\n", + "def shallow_1_1_3(x, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31):\n", + " # Initial lines\n", + " pre_1 = theta_10 + theta_11 * x\n", + " pre_2 = theta_20 + theta_21 * x\n", + " pre_3 = theta_30 + theta_31 * x\n", + " # Activation functions\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + " # Weight activations\n", + " w_act_1 = phi_1 * act_1\n", + " w_act_2 = phi_2 * act_2\n", + " w_act_3 = phi_3 * act_3\n", + " # Combine weighted activation and add y offset\n", + " y = phi_0 + w_act_1 + w_act_2 + w_act_3\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ], + "metadata": { + "id": "ximCLwIfz8kj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# # Plot the shallow neural network. We'll assume input in is range [-1,1] and output [-1,1]\n", + "def plot_neural(x, y):\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x.T,y.T)\n", + " ax.set_xlabel('Input'); ax.set_ylabel('Output')\n", + " ax.set_xlim([-1,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(1.0)\n", + " plt.show()" + ], + "metadata": { + "id": "btrt7BX20gKD" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's define a networks. We'll just consider the inputs and outputs over the range [-1,1]. If you set the \"plot_all\" flat to True, you can see the details of how it was created." + ], + "metadata": { + "id": "LxBJCObC-NTY" + } + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the first neural network\n", + "n1_theta_10 = 0.0 ; n1_theta_11 = -1.0\n", + "n1_theta_20 = 0 ; n1_theta_21 = 1.0\n", + "n1_theta_30 = -0.67 ; n1_theta_31 = 1.0\n", + "n1_phi_0 = 1.0; n1_phi_1 = -2.0; n1_phi_2 = -3.0; n1_phi_3 = 9.3\n", + "\n", + "# Define a range of input values\n", + "n1_in = np.arange(-1,1,0.01).reshape([1,-1])\n", + "\n", + "# We run the neural network for each of these input values\n", + "n1_out, *_ = shallow_1_1_3(n1_in, ReLU, n1_phi_0, n1_phi_1, n1_phi_2, n1_phi_3, n1_theta_10, n1_theta_11, n1_theta_20, n1_theta_21, n1_theta_30, n1_theta_31)\n", + "# And then plot it\n", + "plot_neural(n1_in, n1_out)" + ], + "metadata": { + "id": "JRebvurv22pT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll define the same neural network, but this time, we will use matrix form. When you get this right, it will draw the same plot as above." + ], + "metadata": { + "id": "XCJqo_AjfAra" + } + }, + { + "cell_type": "code", + "source": [ + "beta_0 = np.zeros((3,1))\n", + "Omega_0 = np.zeros((3,1))\n", + "beta_1 = np.zeros((1,1))\n", + "Omega_1 = np.zeros((1,3))\n", + "\n", + "# TODO Fill in the values of the beta and Omega matrices with the n1_theta and n1_phi parameters that define the network above\n", + "# !!! NOTE THAT MATRICES ARE CONVENTIONALLY INDEXED WITH a_11 IN THE TOP LEFT CORNER, BUT NDARRAYS START AT [0,0]\n", + "# To get you started I've filled in a couple:\n", + "beta_0[0,0] = n1_theta_10\n", + "Omega_0[0,0] = n1_theta_11\n", + "\n", + "\n", + "# Make sure that input data matrix has different inputs in its columns\n", + "n_data = n1_in.size\n", + "n_dim_in = 1\n", + "n1_in_mat = np.reshape(n1_in,(n_dim_in,n_data))\n", + "\n", + "# This runs the network for ALL of the inputs, x at once so we can draw graph\n", + "h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(Omega_0,n1_in_mat))\n", + "n1_out = np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(Omega_1,h1)\n", + "\n", + "# Draw the network and check that it looks the same as the non-matrix case\n", + "plot_neural(n1_in, n1_out)" + ], + "metadata": { + "id": "MR0AecZYfACR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll feed the output of the first network into the second one." + ], + "metadata": { + "id": "qOcj2Rof-o20" + } + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the second neural network\n", + "n2_theta_10 = -0.6 ; n2_theta_11 = -1.0\n", + "n2_theta_20 = 0.2 ; n2_theta_21 = 1.0\n", + "n2_theta_30 = -0.5 ; n2_theta_31 = 1.0\n", + "n2_phi_0 = 0.5; n2_phi_1 = -1.0; n2_phi_2 = -1.5; n2_phi_3 = 2.0\n", + "\n", + "# Define a range of input values\n", + "n2_in = np.arange(-1,1,0.01)\n", + "\n", + "# We run the second neural network on the output of the first network\n", + "n2_out, *_ = \\\n", + " shallow_1_1_3(n1_out, ReLU, n2_phi_0, n2_phi_1, n2_phi_2, n2_phi_3, n2_theta_10, n2_theta_11, n2_theta_20, n2_theta_21, n2_theta_30, n2_theta_31)\n", + "# And then plot it\n", + "plot_neural(n1_in, n2_out)" + ], + "metadata": { + "id": "ZRjWu8i9239X" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "beta_0 = np.zeros((3,1))\n", + "Omega_0 = np.zeros((3,1))\n", + "beta_1 = np.zeros((3,1))\n", + "Omega_1 = np.zeros((3,3))\n", + "beta_2 = np.zeros((1,1))\n", + "Omega_2 = np.zeros((1,3))\n", + "\n", + "# TODO Fill in the values of the beta and Omega matrices for with the n1_theta, n1_phi, n2_theta, and n2_phi parameters \n", + "# that define the composition of the two networks above (see eqn 4.5 for Omega1 and beta1 albeit in different notation)\n", + "# !!! NOTE THAT MATRICES ARE CONVENTIONALLY INDEXED WITH a_11 IN THE TOP LEFT CORNER, BUT NDARRAYS START AT [0,0] SO EVERYTHING IS OFFSET\n", + "# To get you started I've filled in a few:\n", + "beta_0[0,0] = n1_theta_10\n", + "Omega_0[0,0] = n1_theta_11\n", + "beta_1[0,0] = n2_theta_10 + n2_theta_11 * n1_phi_0\n", + "Omega_1[0,0] = n2_theta_11 * n1_phi_1\n", + "\n", + "\n", + "\n", + "# Make sure that input data matrix has different inputs in its columns\n", + "n_data = n1_in.size\n", + "n_dim_in = 1\n", + "n1_in_mat = np.reshape(n1_in,(n_dim_in,n_data))\n", + "\n", + "# This runs the network for ALL of the inputs, x at once so we can draw graph (hence extra np.ones term)\n", + "h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(Omega_0,n1_in_mat))\n", + "h2 = ReLU(np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(Omega_1,h1))\n", + "n1_out = np.matmul(beta_2,np.ones((1,n_data))) + np.matmul(Omega_2,h2)\n", + "\n", + "# Draw the network and check that it looks the same as the non-matrix version\n", + "plot_neural(n1_in, n1_out)" + ], + "metadata": { + "id": "ZB2HTalOE40X" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's make a deep network with 3 hidden layers. It will have d_i=4 inputs, d_1=5 neurons in the first layer, d_2=2 neurons in the second layer and d_3=4 neurons in the third layer, and d_o = 1 output. Consults figure 4.6 for guidance." + ], + "metadata": { + "id": "0VANqxH2kyS4" + } + }, + { + "cell_type": "code", + "source": [ + "# define sizes\n", + "D_i=4; D_1=5; D_2=2; D_3=4; D_o=1\n", + "# We'll choose the inputs and parameters of this network randomly using np.random.normal\n", + "# For example, we'll set the input using\n", + "n_data = 10;\n", + "x = np.random.normal(size=(D_i, n_data))\n", + "# TODO initialize the parameters randomly but with the correct sizes\n", + "# Replace the lines below\n", + "beta_0 = np.random.normal(size=(1,1))\n", + "Omega_0 = np.random.normal(size=(1,1))\n", + "beta_1 = np.random.normal(size=(1,1))\n", + "Omega_1 = np.random.normal(size=(1,1))\n", + "beta_2 = np.random.normal(size=(1,1))\n", + "Omega_2 = np.random.normal(size=(1,1))\n", + "beta_3 = np.random.normal(size=(1,1))\n", + "Omega_3 = np.random.normal(size=(1,1))\n", + "\n", + "# If you set the above sizes to the correct values then, the following code will run \n", + "h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(Omega_0,x));\n", + "h2 = ReLU(np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(Omega_1,h1));\n", + "h3 = ReLU(np.matmul(beta_2,np.ones((1,n_data))) + np.matmul(Omega_2,h2));\n", + "y = np.matmul(beta_3,np.ones((1,n_data))) + np.matmul(Omega_3,h3)\n", + "\n", + "if h1.shape[0] is not D_1 or h1.shape[1] is not n_data:\n", + " print(\"h1 is wrong shape\")\n", + "if h2.shape[0] is not D_2 or h1.shape[1] is not n_data:\n", + " print(\"h2 is wrong shape\")\n", + "if h3.shape[0] is not D_3 or h1.shape[1] is not n_data:\n", + " print(\"h3 is wrong shape\")\n", + "if y.shape[0] is not D_o or h1.shape[1] is not n_data:\n", + " print(\"Output is wrong shape\")\n", + "\n", + "# Print the inputs and outputs\n", + "print(x)\n", + "print(y)" + ], + "metadata": { + "id": "RdBVAc_Rj22-" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Gradients_I.ipynb b/CM20315/CM20315_Gradients_I.ipynb new file mode 100644 index 0000000..3d15e80 --- /dev/null +++ b/CM20315/CM20315_Gradients_I.ipynb @@ -0,0 +1,420 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyMDEfAZvjcjpvBNmdrYv3EW", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# CM20315 Gradients I\n", + "\n", + "We're going to investigate how to take the derivatives of functions where one operation is composed with another, which is composed with a third and so on. For example, consider the function:\n", + "\n", + "\\begin{equation}\n", + " y = \\beta_4+\\omega_4\\cdot \\log\\biggl[\\beta_3+\\omega_3\\cdot\\cos\\Bigl[\\beta_2+\\omega_2\\cdot\\exp\\bigl[\\beta_1+\\omega_1\\cdot\\sin[\\beta_0+\\omega_0x]\\bigr]\\Bigr]\\biggr],\n", + "\\end{equation}\n", + "\n", + "which is a composition of the functions $\\log[\\bullet], \\cos[\\bullet],\\exp[\\bullet],\\sin[\\bullet]$. I chose these just because you probably already know the derivatives of these functions:\n", + "\n", + "\\begin{eqnarray*}\n", + "\\frac{\\partial \\log[z]}{\\partial z} = \\frac{1}{z}\\quad\\quad \\frac{\\partial \\cos[z]}{\\partial z} = -\\sin[z] \\quad\\quad \\frac{\\partial \\exp[z]}{\\partial z} = \\exp[z] \\quad\\quad \\frac{\\partial \\sin[z]}{\\partial z} = -\\cos[z].\n", + "\\end{eqnarray*}\n", + "\n", + "Suppose that we know the current values of $\\beta_{0},\\beta_{1},\\beta_{2},\\beta_{3},\\beta_{4},\\omega_{0},\\omega_{1},\\omega_{2},\\omega_{3},\\omega_{4}$, and $x$. We could obviously calculate $y$. But we also want to know how $y$ changes when we make a small change to $\\beta_{0},\\beta_{1},\\beta_{2},\\beta_{3},\\beta_{4},\\omega_{0},\\omega_{1},\\omega_{2},\\omega_{3}$, or $\\omega_{4}$. In other words, we want to compute the ten derivatives:\n", + "\n", + "\\begin{eqnarray*}\n", + "\\frac{\\partial y}{\\partial \\beta_{0}}, \\quad \\frac{\\partial y}{\\partial \\beta_{1}}, \\quad \\frac{\\partial y}{\\partial \\beta_{2}}, \\quad \\frac{\\partial y }{\\partial \\beta_{3}}, \\quad\n", + "\\frac{\\partial y}{\\partial \\beta_{4}}, \\quad \\frac{\\partial y}{\\partial \\omega_{0}}, \\quad \\frac{\\partial y}{\\partial \\omega_{1}}, \\quad \\frac{\\partial y}{\\partial \\omega_{2}}, \\quad \\frac{\\partial y}{\\partial \\omega_{3}}, \\quad\\mbox{and} \\quad \\frac{\\partial y}{\\partial \\omega_{4}}.\n", + "\\end{eqnarray*}" + ], + "metadata": { + "id": "1DmMo2w63CmT" + } + }, + { + "cell_type": "code", + "source": [ + "# import library\n", + "import numpy as np" + ], + "metadata": { + "id": "RIPaoVN834Lj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's first define the original function for $y$:" + ], + "metadata": { + "id": "32-ufWhc3v2c" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AakK_qen3BpU" + }, + "outputs": [], + "source": [ + "def fn(x, beta0, beta1, beta2, beta3, beta4, omega0, omega1, omega2, omega3, omega4):\n", + " return beta4 + omega4 * np.log(beta3+omega3 * np.cos(beta2 + omega2 * np.exp(beta1 + omega1 * np.sin(beta0 + omega0 * x))))" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll choose some values for the betas and the omegas and x and compute the output of the function:" + ], + "metadata": { + "id": "y7tf0ZMt5OXt" + } + }, + { + "cell_type": "code", + "source": [ + "beta0 = 1.0; beta1 = 2.0; beta2 = -3.0; beta3 = 0.4; beta4 = -0.3\n", + "omega0 = 0.1; omega1 = -0.4; omega2 = 2.0; omega3 = 3.0; omega4 = -0.5\n", + "x = 2.3\n", + "y_func = fn(x,beta0,beta1,beta2,beta3,beta4,omega0,omega1,omega2,omega3,omega4)\n", + "print('y=%3.3f'%y_func)" + ], + "metadata": { + "id": "pwvOcCxr41X_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Computing derivatives by hand\n", + "\n", + "We could compute expressions for the derivatives by hand and write code to compute them directly. Some of them are easy. For example:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial y}{\\partial \\beta_{4}} = 1,\n", + "\\end{equation}\n", + "\n", + "but some have very complex expressions, even for this relatively simple original equation. For example:\n", + "\n", + "\\begin{eqnarray*}\n", + "\\frac{\\partial y}{\\partial \\omega_{0}} &=& \n", + "-\\frac{\\omega_{1}\\omega_{2}\\omega_{3}\\omega_{4} x \\cos[\\beta_{0}\\!+\\!\\omega_{0}x]\\cdot\\exp\\bigl[\\omega_{1}\\sin[\\beta_{0}\\!+\\!\\omega_{0}x]\\!+\\!\\beta_{1}\\bigr]\\cdot\\sin\\Bigl[\\omega_{2}\\exp\\bigl[\\omega_{1}\\sin[\\beta_{0}\\!+\\!\\omega_{0}x]\\!+\\!\\beta_{1}\\bigr]\\!+\\!\\beta_{2}\\Bigr]}\n", + "{\\omega_{3}\\cos[\\omega_{2}\\exp[\\omega_{1}\\sin[\\beta_{0}\\!+\\!\\omega_{0}x]\\!+\\!\\beta_{1}]\\!+\\!\\beta_{2}]\\!+\\!\\beta_{3}}.\n", + "\\end{eqnarray*}" + ], + "metadata": { + "id": "u5w69NeT64yV" + } + }, + { + "cell_type": "code", + "source": [ + "dydbeta4_func = 1\n", + "dydomega0_func = -omega1*omega2*omega3*omega4*x * np.cos(beta0+omega0*x) * \\\n", + " np.exp(omega1 * np.sin(beta0+omega0*x)+beta1) * \\\n", + " np.sin(omega2 * np.exp(omega1 * np.sin(beta0+omega0 *x)+beta1)+beta2)/ \\\n", + " (omega3 * np.cos(omega2 * np.exp(omega1 * np.sin(beta0+omega0*x)+beta1)+beta2)+beta3)" + ], + "metadata": { + "id": "7t22hALp5zkq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's make sure these are correct using finite differences:" + ], + "metadata": { + "id": "iRh4hnu3-H3n" + } + }, + { + "cell_type": "code", + "source": [ + "dydbeta4_fd = (fn(x,beta0,beta1,beta2,beta3,beta4+0.0001,omega0,omega1,omega2,omega3,omega4)-fn(x,beta0,beta1,beta2,beta3,beta4,omega0,omega1,omega2,omega3,omega4))/0.0001\n", + "dydomega0_fd = (fn(x,beta0,beta1,beta2,beta3,beta4,omega0+0.0001,omega1,omega2,omega3,omega4)-fn(x,beta0,beta1,beta2,beta3,beta4,omega0,omega1,omega2,omega3,omega4))/0.0001\n", + "\n", + "print('dydbeta4: Function value = %3.3f, Finite difference value = %3.3f'%(dydbeta4_func,dydbeta4_fd))\n", + "print('dydomega0: Function value = %3.3f, Finite difference value = %3.3f'%(dydomega0_func,dydomega0_fd))" + ], + "metadata": { + "id": "1O3XmXMx-HlZ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The code to calculate $\\partial y/ \\partial \\omega_0$ is a bit of a nightmare. It's easy to make mistakes, and you can see that some parts of it are repeated (for example, the $\\sin[\\bullet]$ term), which suggests some kind of redundancy in the calculations. The goal of this practical is to compute the derivatives in a much simpler way. There will be three steps:" + ], + "metadata": { + "id": "wS4IPjZAKWTN" + } + }, + { + "cell_type": "markdown", + "source": [ + "**Step 1:** Write the original equations as a series of intermediate calculations. We change \n", + "\n", + "\\begin{equation}\n", + " y = \\beta_4+\\omega_4\\cdot \\log\\biggl[\\beta_3+\\omega_3\\cdot\\cos\\Bigl[\\beta_2+\\omega_2\\cdot\\exp\\bigl[\\beta_1+\\omega_1\\cdot\\sin[\\beta_0+\\omega_0x]\\bigr]\\Bigr]\\biggr]\n", + "\\end{equation}\n", + "\n", + "to \n", + "\n", + "\\begin{eqnarray}\n", + "f_{0} &=& \\beta_{0} + \\omega_{0} x\\nonumber\\\\\n", + "h_{1} &=& \\sin[f_{0}]\\nonumber\\\\\n", + "f_{1} &=& \\beta_{1} + \\omega_{1}h_{1}\\nonumber\\\\\n", + "h_{2} &=& \\exp[f_{1}]\\nonumber\\\\\n", + "f_{2} &=& \\beta_{2} + \\omega_{2} h_{2}\\nonumber\\\\\n", + "h_{3} &=& \\cos[f_{2}]\\nonumber\\\\\n", + "f_{3} &=& \\beta_{3} + \\omega_{3}h_{3}\\nonumber\\\\\n", + "h_{4} &=& \\log[f_{3}]\\nonumber\\\\\n", + "y &=& \\beta_{4} + \\omega_{4} h_{4}\n", + "\\end{eqnarray}\n", + "\n", + "and compute and store the values of all of these intermediate values. We'll need them to compute the derivatives.
This is called the **forward pass**." + ], + "metadata": { + "id": "8UWhvDeNDudz" + } + }, + { + "cell_type": "code", + "source": [ + "# TODO compute all the f_k and h_k terms \n", + "# Replace the code below\n", + "\n", + "f0 = 1\n", + "h1 = 1\n", + "f1 = 1\n", + "h2 = 1\n", + "f2 = 1\n", + "h3 = 1\n", + "f3 = 1\n", + "h4 = 1\n", + "y = 1" + ], + "metadata": { + "id": "ZWKAq6HC90qV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's check we got that right:\n", + "print(\"f0: true value = %3.3f, your value = %3.3f\"%(1.230, f0))\n", + "print(\"h1: true value = %3.3f, your value = %3.3f\"%(0.942, h1))\n", + "print(\"f1: true value = %3.3f, your value = %3.3f\"%(1.623, f1))\n", + "print(\"h2: true value = %3.3f, your value = %3.3f\"%(5.068, h2))\n", + "print(\"f2: true value = %3.3f, your value = %3.3f\"%(7.137, f2))\n", + "print(\"h3: true value = %3.3f, your value = %3.3f\"%(0.657, h3))\n", + "print(\"f3: true value = %3.3f, your value = %3.3f\"%(2.372, f3))\n", + "print(\"h4: true value = %3.3f, your value = %3.3f\"%(0.864, h4))\n", + "print(\"y_func = %3.3f, y = %3.3f\"%(y_func, y))\n" + ], + "metadata": { + "id": "ibxXw7TUW4Sx" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**Step 2:** Compute the derivatives of $y$ with respect to the intermediate quantities that we just calculated, but in reverse order:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial y}{\\partial h_4}, \\quad \\frac{\\partial y}{\\partial f_3}, \\quad \\frac{\\partial y}{\\partial h_3}, \\quad \\frac{\\partial y}{\\partial f_2}, \\quad\n", + "\\frac{\\partial y}{\\partial h_2}, \\quad \\frac{\\partial y}{\\partial f_1}, \\quad \\frac{\\partial y}{\\partial h_1}, \\quad\\mbox{and} \\quad \\frac{\\partial y}{\\partial f_0}.\n", + "\\end{eqnarray}\n", + "\n", + "The first of these derivatives is straightforward:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial y}{\\partial h_{4}} = \\frac{\\partial }{\\partial h_{4}} \\beta_{4} + \\omega_{4} h_{4} = \\omega_{4}.\n", + "\\end{equation}\n", + "\n", + "The second derivative can be calculated using the chain rule:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial y}{\\partial f_{3}} = \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}.\n", + "\\end{equation}\n", + "\n", + "The left-hand side asks how $y$ changes when $f_{3}$ changes. The right-hand side says we can decompose this into (i) how $y$ changes when $h_{4}$ changes and how $h_{4}$ changes when $f_{4}$ changes. So you get a chain of events happening: $f_{3}$ changes $h_{4}$, which changes $y$, and the derivatives represent the effects of this chain. Notice that we computed the first of these derivatives already and the other one is the derivative of $\\log[f_{3}]$ is simply $1/f_{3}$. We calculated $f_{3}$ in step 1.\n", + "\n", + "We can continue in this way, computing the derivatives of the output with respect to these intermediate quantities:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial y}{\\partial h_{3}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}=\\frac{\\partial y}{\\partial f_{3}} \\frac{\\partial f_{3}}{\\partial h_{3}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial f_{2}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}} = \\frac{\\partial y}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial h_{2}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{2}}{\\partial h_{2}}=\\frac{\\partial y}{\\partial f_{2}}\\frac{\\partial f_{2}}{\\partial h_{2}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial f_{1}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{2}}{\\partial f_{1}}=\\frac{\\partial y}{\\partial h_{2}}\\frac{\\partial h_{2}}{\\partial f_{1}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial h_{1}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{2}}{\\partial f_{1}}\\frac{\\partial f_{1}}{\\partial h_{1}}=\\frac{\\partial y}{\\partial f_{1}}\\frac{\\partial f_{1}}{\\partial h_{1}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial f_{0}} &=& \\frac{\\partial y}{\\partial h_{4}} \\frac{\\partial h_{4}}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{2}}{\\partial f_{1}}\\frac{\\partial f_{1}}{\\partial h_{1}}\\frac{\\partial h_{1}}{\\partial f_{0}}=\\frac{\\partial y}{\\partial h_{1}}\\frac{\\partial h_{1}}{\\partial f_{0}}.\n", + "\\end{eqnarray}\n", + "\n", + "In each case, we have already computed all of the terms except the last one in the previous step, and the last term is simple to evaluate. This is called the **backward pass**." + ], + "metadata": { + "id": "jay8NYWdFHuZ" + } + }, + { + "cell_type": "code", + "source": [ + "# TODO -- Compute the derivatives of the output with respect\n", + "# to the intermediate computations h_k and f_k (i.e, run the backward pass)\n", + "# I've done the first two for you. You replace the code below:\n", + "dydh4 = omega4\n", + "dydf3 = dydh4 * (1/f3)\n", + "# Replace the code below\n", + "dydh3 = 1\n", + "dydf2 = 1\n", + "dydh2 = 1\n", + "dydf1 = 1\n", + "dydh1 = 1\n", + "dydf0 = 1 " + ], + "metadata": { + "id": "gCQJeI--Egdl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's check we got that right\n", + "print(\"dydh3: true value = %3.3f, your value = %3.3f\"%(-0.632, dydh3))\n", + "print(\"dydf2: true value = %3.3f, your value = %3.3f\"%(0.476, dydf2))\n", + "print(\"dydh2: true value = %3.3f, your value = %3.3f\"%(0.953, dydh2))\n", + "print(\"dydf1: true value = %3.3f, your value = %3.3f\"%(4.830, dydf1))\n", + "print(\"dydh1: true value = %3.3f, your value = %3.3f\"%(-1.932, dydh1))\n", + "print(\"dydf0: true value = %3.3f, your value = %3.3f\"%(-0.646, dydf0))" + ], + "metadata": { + "id": "dS1OrLtlaFr7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**Step 3:** Now we will find how $y$ changes when we change the $\\beta$ and $\\omega$ terms. The first two are easy:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial y}{\\partial \\beta_{4}} &=& \\frac{\\partial }{\\partial \\beta_{4}}(\\beta_{4} + \\omega_{4} h_{4}) = 1\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial \\omega_{4}} &=& \\frac{\\partial }{\\partial \\omega_{4}}(\\beta_{4} + \\omega_{4} h_{4}) = h_{4}.\n", + "\\end{eqnarray}\n", + "\n", + "The remaining terms are calculated using the chain rule again:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial y}{\\partial \\beta_{3}} &=& \\frac{\\partial y}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial \\beta_{3}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial \\omega_{3}} &=& \\frac{\\partial y}{\\partial f_{3}}\\frac{\\partial f_{3}}{\\partial \\omega_{3}}\n", + "\\end{eqnarray}\n", + "\n", + "where we already computed the first term of each right-hand side in Step 2, and the second terms are also easy to compute. By the same logic, the other terms are:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial y}{\\partial \\beta_{k}} &=& \\frac{\\partial y}{\\partial f_{k}}\\frac{\\partial f_{k}}{\\partial \\beta_{k}}\\nonumber \\\\\n", + "\\frac{\\partial y}{\\partial \\omega_{k}} &=& \\frac{\\partial y}{\\partial f_{k}}\\frac{\\partial f_{k}}{\\partial \\omega_{k}}\n", + "\\end{eqnarray}\n", + "\n", + "for $k=2,1,0$." + ], + "metadata": { + "id": "FlzlThQPGpkU" + } + }, + { + "cell_type": "code", + "source": [ + "# TODO -- Calculate the final derivatives with respect to the beta and omega terms\n", + "\n", + "dydbeta4 = 1\n", + "dydomega4 = 1\n", + "dydbeta3 = 1\n", + "dydomega3 = 1\n", + "dydbeta2 = 1\n", + "dydomega2 = 1\n", + "dydbeta1 = 1\n", + "dydomega1 = 1\n", + "dydbeta0 = 1\n", + "dydomega0 = 1\n" + ], + "metadata": { + "id": "1I2BhqZhGMK6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's check we got them right\n", + "print('dydbeta4: Your value = %3.3f, Function value = %3.3f, Finite difference value = %3.3f'%(dydbeta4, dydbeta4_func,dydbeta4_fd))\n", + "print('dydomega4: Your value = %3.3f, True value = %3.3f'%(dydomega4, 0.864))\n", + "print('dydbeta3: Your value = %3.3f, True value = %3.3f'%(dydbeta3, -0.211))\n", + "print('dydomega3: Your value = %3.3f, True value = %3.3f'%(dydomega3, -0.139))\n", + "print('dydbeta2: Your value = %3.3f, True value = %3.3f'%(dydbeta2, 0.476))\n", + "print('dydomega2: Your value = %3.3f, True value = %3.3f'%(dydomega2, 2.415))\n", + "print('dydbeta1: Your value = %3.3f, True value = %3.3f'%(dydbeta1, 4.830))\n", + "print('dydomega1: Your value = %3.3f, True value = %3.3f'%(dydomega1, 4.552))\n", + "print('dydbeta0: Your value = %3.3f, True value = %3.3f'%(dydbeta0, -0.646))\n", + "print('dydomega0: Your value = %3.3f, Function value = %3.3f, Finite difference value = %3.3f'%(dydomega0, dydomega0_func,dydomega0_fd))" + ], + "metadata": { + "id": "38eiOn2aHgHI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Using this method, we can compute the derivatives quite easily without needing to compute very complicated expressions. This is exactly the same way that the derivatives of the parameters are computed in the backpropagation algorithm. In fact, this basically *is* the backpropagation algorithm." + ], + "metadata": { + "id": "N2ZhrR-2fNa1" + } + } + ] +} diff --git a/CM20315/CM20315_Gradients_II.ipynb b/CM20315/CM20315_Gradients_II.ipynb new file mode 100644 index 0000000..d98b315 --- /dev/null +++ b/CM20315/CM20315_Gradients_II.ipynb @@ -0,0 +1,350 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyNUus+txeW8v5HpKHIRwUMo", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Gradients II: Backpropagation algorithm\n", + "\n", + "In this practical, we'll investigate the backpropagation algorithm. This computes the gradients of the loss with respect to all of the parameters (weights and biases) in the network. We'll use these gradients when we run stochastic gradient descent." + ], + "metadata": { + "id": "L6chybAVFJW2" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LdIDglk1FFcG" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "source": [ + "First let's define a neural network. We'll just choose the weights and biases randomly for now" + ], + "metadata": { + "id": "nnUoI0m6GyjC" + } + }, + { + "cell_type": "code", + "source": [ + "# Set seed so we always get the same random numbers\n", + "np.random.seed(0)\n", + "\n", + "# Number of layers\n", + "K = 5\n", + "# Number of neurons per layer\n", + "D = 6\n", + "# Input layer\n", + "D_i = 1\n", + "# Output layer \n", + "D_o = 1\n", + "\n", + "# Make empty lists \n", + "all_weights = [None] * (K+1)\n", + "all_biases = [None] * (K+1)\n", + "\n", + "# Create input and output layers\n", + "all_weights[0] = np.random.normal(size=(D, D_i))\n", + "all_weights[-1] = np.random.normal(size=(D_o, D))\n", + "all_biases[0] = np.random.normal(size =(D,1))\n", + "all_biases[-1]= np.random.normal(size =(D_o,1))\n", + "\n", + "# Create intermediate layers\n", + "for layer in range(1,K):\n", + " all_weights[layer] = np.random.normal(size=(D,D))\n", + " all_biases[layer] = np.random.normal(size=(D,1)) " + ], + "metadata": { + "id": "WVM4Tc_jGI0Q" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation" + ], + "metadata": { + "id": "jZh-7bPXIDq4" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's run our random network. The weight matrices $\\boldsymbol\\Omega_{1\\ldots K}$ are the entries of the list \"all_weights\" and the biases $\\boldsymbol\\beta_{1\\ldots k}$ are the entries of the list \"all_biases\"\n", + "\n", + "We know that we will need the activations $\\mathbf{f}_{0\\ldots K}$ and the activations $\\mathbf{h}_{1\\ldots K}$ for the forward pass of backpropagation, so we'll store and return these as well. \n" + ], + "metadata": { + "id": "5irtyxnLJSGX" + } + }, + { + "cell_type": "code", + "source": [ + "def compute_network_output(net_input, all_weights, all_biases):\n", + "\n", + " # Retrieve number of layers\n", + " K = len(all_weights) -1\n", + "\n", + " # We'll store the pre-activations at each layer in a list \"all_f\"\n", + " # and the activations in a second list[all_h]. \n", + " all_f = [None] * (K+1)\n", + " all_h = [None] * (K+1)\n", + "\n", + " #For convenience, we'll set \n", + " # all_h[0] to be the input, and all_f[K] will be the output\n", + " all_h[0] = net_input\n", + "\n", + " # Run through the layers, calculating all_f[0...K-1] and all_h[1...K]\n", + " for layer in range(K):\n", + " # Update preactivations and activations at this layer according to eqn 7.5\n", + " # Remmember to use np.matmul for matrix multiplications\n", + " # TODO -- Replace the lines below\n", + " all_f[layer] = all_h[layer]\n", + " all_h[layer+1] = all_f[layer]\n", + "\n", + " # Compute the output from the last hidden layer\n", + " # TO DO -- Replace the line below\n", + " all_f[K] = np.zeros_like(all_biases[-1])\n", + "\n", + " # Retrieve the output\n", + " net_output = all_f[K]\n", + "\n", + " return net_output, all_f, all_h" + ], + "metadata": { + "id": "LgquJUJvJPaN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define in input\n", + "net_input = np.ones((D_i,1)) * 1.2\n", + "# Compute network output\n", + "net_output, all_f, all_h = compute_network_output(net_input,all_weights, all_biases)\n", + "print(\"True output = %3.3f, Your answer = %3.3f\"%(1.907, net_output[0,0]))" + ], + "metadata": { + "id": "IN6w5m2ZOhnB" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's define a loss function. We'll just use the least squares loss function. We'll also write a function to compute dloss_doutpu" + ], + "metadata": { + "id": "SxVTKp3IcoBF" + } + }, + { + "cell_type": "code", + "source": [ + "def least_squares_loss(net_output, y):\n", + " return np.sum((net_output-y) * (net_output-y))\n", + "\n", + "def d_loss_d_output(net_output, y):\n", + " return 2*(net_output -y); " + ], + "metadata": { + "id": "6XqWSYWJdhQR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "y = np.ones((D_o,1)) * 20.0\n", + "loss = least_squares_loss(net_output, y)\n", + "print(\"y = %3.3f Loss = %3.3f\"%(y, loss))" + ], + "metadata": { + "id": "njF2DUQmfttR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the derivatives of the network. We already computed the forward pass. Let's compute the backward pass." + ], + "metadata": { + "id": "98WmyqFYWA-0" + } + }, + { + "cell_type": "code", + "source": [ + "# We'll need the indicator function\n", + "def indicator_function(x):\n", + " x_in = np.array(x)\n", + " x_in[x_in>=0] = 1\n", + " x_in[x_in<0] = 0\n", + " return x_in\n", + "\n", + "# Main backward pass routine\n", + "def backward_pass(all_weights, all_biases, all_f, all_h, y):\n", + " # We'll store the derivatives dl_dweights and dl_dbiases in lists as well\n", + " all_dl_dweights = [None] * (K+1)\n", + " all_dl_dbiases = [None] * (K+1)\n", + " # And we'll store the derivatives of the loss with respect to the activation and preactivations in lists\n", + " all_dl_df = [None] * (K+1)\n", + " all_dl_dh = [None] * (K+1)\n", + " # Again for convenience we'll stick with the convention that all_h[0] is the net input and all_f[k] in the net output\n", + "\n", + " # Compute derivatives of net output with respect to loss\n", + " all_dl_df[K] = np.array(d_loss_d_output(all_f[K],y))\n", + "\n", + " # Now work backwards through the network\n", + " for layer in range(K,-1,-1):\n", + " # TODO Calculate the derivatives of biases at layer from all_dl_df[K]. (eq 7.13, line 1)\n", + " # NOTE! To take a copy of matrix X, use Z=np.array(X)\n", + " # REPLACE THIS LINE\n", + " all_dl_dbiases[layer] = np.zeros_like(all_biases[layer])\n", + "\n", + " # TODO Calculate the derivatives of weight at layer from all_dl_df[K] and all_h[K] (eq 7.13, line 2)\n", + " # Don't forget to use np.matmul\n", + " # REPLACE THIS LINE\n", + " all_dl_dweights[layer] = np.zeros_like(all_weights[layer])\n", + "\n", + " # TODO: calculate the derivatives of activations from weight and derivatives of next preactivations (eq 7.13, line 3 second part)\n", + " # REPLACE THIS LINE\n", + " all_dl_dh[layer] = np.zeros_like(all_h[layer])\n", + "\n", + " if layer > 0:\n", + " # TODO Calculate the derivatives of the pre-activation f with respect to activation h (eq 7.13, line 3, first part)\n", + " # REPLACE THIS LINE\n", + " all_dl_df[layer-1] = np.zeros_like(all_f[layer-1])\n", + "\n", + " return all_dl_dweights, all_dl_dbiases" + ], + "metadata": { + "id": "LJng7WpRPLMz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "all_dl_dweights, all_dl_dbiases = backward_pass(all_weights, all_biases, all_f, all_h, y)" + ], + "metadata": { + "id": "9A9MHc4sQvbp" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "np.set_printoptions(precision=3)\n", + "# Make space for derivatives computed by finite differences\n", + "all_dl_dweights_fd = [None] * (K+1)\n", + "all_dl_dbiases_fd = [None] * (K+1)\n", + "\n", + "# Let's test if we have the derivatives right using finite differences\n", + "delta_fd = 0.000001\n", + "\n", + "# For every layer\n", + "for layer in range(K):\n", + " dl_dbias = np.zeros_like(all_dl_dbiases[layer])\n", + " # For every element in the bias\n", + " for row in range(all_biases[layer].shape[0]):\n", + " # Take copy of biases We'll change one element each time\n", + " all_biases_copy = [np.array(x) for x in all_biases]\n", + " all_biases_copy[layer][row] += delta_fd\n", + " network_output_1, *_ = compute_network_output(net_input, all_weights, all_biases_copy)\n", + " network_output_2, *_ = compute_network_output(net_input, all_weights, all_biases)\n", + " dl_dbias[row] = (least_squares_loss(network_output_1, y) - least_squares_loss(network_output_2,y))/delta_fd\n", + " all_dl_dbiases_fd[layer] = np.array(dl_dbias)\n", + " print(\"Bias %d, derivatives from backprop:\"%(layer))\n", + " print(all_dl_dbiases[layer])\n", + " print(\"Bias %d, derivatives from finite differences\"%(layer))\n", + " print(all_dl_dbiases_fd[layer])\n", + "\n", + "\n", + "# For every layer\n", + "for layer in range(K):\n", + " dl_dweight = np.zeros_like(all_dl_dweights[layer])\n", + " # For every element in the bias\n", + " for row in range(all_weights[layer].shape[0]):\n", + " for col in range(all_weights[layer].shape[1]):\n", + " # Take copy of biases We'll change one element each time\n", + " all_weights_copy = [np.array(x) for x in all_weights]\n", + " all_weights_copy[layer][row][col] += delta_fd\n", + " network_output_1, *_ = compute_network_output(net_input, all_weights_copy, all_biases)\n", + " network_output_2, *_ = compute_network_output(net_input, all_weights, all_biases)\n", + " dl_dweight[row][col] = (least_squares_loss(network_output_1, y) - least_squares_loss(network_output_2,y))/delta_fd\n", + " all_dl_dweights_fd[layer] = np.array(dl_dweight)\n", + " print(\"Weight %d, derivatives from backprop:\"%(layer))\n", + " print(all_dl_dweights[layer])\n", + " print(\"Weight %d, derivatives from finite differences\"%(layer))\n", + " print(all_dl_dweights_fd[layer])" + ], + "metadata": { + "id": "PK-UtE3hreAK" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "gtokc0VX0839" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Gradients_III.ipynb b/CM20315/CM20315_Gradients_III.ipynb new file mode 100644 index 0000000..e691d04 --- /dev/null +++ b/CM20315/CM20315_Gradients_III.ipynb @@ -0,0 +1,351 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyPr1jNETAJLP27xFPVEC09J", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Initialization\n", + "\n", + "In this practical, we'll investigate the what happens to the activations and the forward pass if we don't initialize the parameters sensibly." + ], + "metadata": { + "id": "L6chybAVFJW2" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LdIDglk1FFcG" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "source": [ + "First let's define a neural network. We'll just choose the weights and biases randomly for now" + ], + "metadata": { + "id": "nnUoI0m6GyjC" + } + }, + { + "cell_type": "code", + "source": [ + "def init_params(K, D, sigma_sq_omega):\n", + " # Set seed so we always get the same random numbers\n", + " np.random.seed(0)\n", + "\n", + " # Input layer\n", + " D_i = 1\n", + " # Output layer \n", + " D_o = 1\n", + "\n", + " # Make empty lists \n", + " all_weights = [None] * (K+1)\n", + " all_biases = [None] * (K+1)\n", + "\n", + " # Create input and output layers\n", + " all_weights[0] = np.random.normal(size=(D, D_i))*np.sqrt(sigma_sq_omega)\n", + " all_weights[-1] = np.random.normal(size=(D_o, D)) * np.sqrt(sigma_sq_omega)\n", + " all_biases[0] = np.zeros((D,1))\n", + " all_biases[-1]= np.zeros((D_o,1))\n", + "\n", + " # Create intermediate layers\n", + " for layer in range(1,K):\n", + " all_weights[layer] = np.random.normal(size=(D,D))*np.sqrt(sigma_sq_omega)\n", + " all_biases[layer] = np.zeros((D,1)) \n", + "\n", + " return all_weights, all_biases" + ], + "metadata": { + "id": "WVM4Tc_jGI0Q" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation" + ], + "metadata": { + "id": "jZh-7bPXIDq4" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def compute_network_output(net_input, all_weights, all_biases):\n", + "\n", + " # Retrieve number of layers\n", + " K = len(all_weights) -1\n", + "\n", + " # We'll store the pre-activations at each layer in a list \"all_f\"\n", + " # and the activations in a second list[all_h]. \n", + " all_f = [None] * (K+1)\n", + " all_h = [None] * (K+1)\n", + "\n", + " #For convenience, we'll set \n", + " # all_h[0] to be the input, and all_f[K] will be the output\n", + " all_h[0] = net_input\n", + "\n", + " # Run through the layers, calculating all_f[0...K-1] and all_h[1...K]\n", + " for layer in range(K):\n", + " # Update preactivations and activations at this layer according to eqn 7.5\n", + " all_f[layer] = all_biases[layer] + np.matmul(all_weights[layer], all_h[layer])\n", + " all_h[layer+1] = ReLU(all_f[layer])\n", + "\n", + " # Compute the output from the last hidden layer\n", + " all_f[K] = all_biases[K] + np.matmul(all_weights[K], all_h[K])\n", + "\n", + " # Retrieve the output\n", + " net_output = all_f[K]\n", + "\n", + " return net_output, all_f, all_h" + ], + "metadata": { + "id": "LgquJUJvJPaN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate how this the size of the outputs vary as we change the initialization variance:\n" + ], + "metadata": { + "id": "bIUrcXnOqChl" + } + }, + { + "cell_type": "code", + "source": [ + "# Number of layers\n", + "K = 5\n", + "# Number of neurons per layer\n", + "D = 8\n", + " # Input layer\n", + "D_i = 1\n", + "# Output layer \n", + "D_o = 1\n", + "# Set variance of initial weights to 1\n", + "sigma_sq_omega = 1.0\n", + "# Initialize parameters\n", + "all_weights, all_biases = init_params(K,D,sigma_sq_omega)\n", + "\n", + "n_data = 1000\n", + "data_in = np.random.normal(size=(1,n_data))\n", + "net_output, all_f, all_h = compute_network_output(data_in, all_weights, all_biases)\n", + "\n", + "for layer in range(K):\n", + " print(\"Layer %d, std of hidden units = %3.3f\"%(layer, np.std(all_h[layer])))" + ], + "metadata": { + "id": "A55z3rKBqO7M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You can see that the values of the hidden units are increasing on average (the variance is across all hidden units at the layer \n", + "# and the 1000 training examples\n", + "\n", + "# TO DO \n", + "# Change this to 50 layers with 80 hidden units per layer\n", + "\n", + "# TO DO \n", + "# Now experiment with sigma_sq_omega to try to stop the variance of the forward computation explode" + ], + "metadata": { + "id": "VL_SO4tar3DC" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's define a loss function. We'll just use the least squares loss function. We'll also write a function to compute dloss_doutput\n" + ], + "metadata": { + "id": "SxVTKp3IcoBF" + } + }, + { + "cell_type": "code", + "source": [ + "def least_squares_loss(net_output, y):\n", + " return np.sum((net_output-y) * (net_output-y))\n", + "\n", + "def d_loss_d_output(net_output, y):\n", + " return 2*(net_output -y); " + ], + "metadata": { + "id": "6XqWSYWJdhQR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Here's the code for the backward pass" + ], + "metadata": { + "id": "98WmyqFYWA-0" + } + }, + { + "cell_type": "code", + "source": [ + "# We'll need the indicator function\n", + "def indicator_function(x):\n", + " x_in = np.array(x)\n", + " x_in[x_in>=0] = 1\n", + " x_in[x_in<0] = 0\n", + " return x_in\n", + "\n", + "# Main backward pass routine\n", + "def backward_pass(all_weights, all_biases, all_f, all_h, y):\n", + " # We'll store the derivatives dl_dweights and dl_dbiases in lists as well\n", + " all_dl_dweights = [None] * (K+1)\n", + " all_dl_dbiases = [None] * (K+1)\n", + " # And we'll store the derivatives of the loss with respect to the activation and preactivations in lists\n", + " all_dl_df = [None] * (K+1)\n", + " all_dl_dh = [None] * (K+1)\n", + " # Again for convenience we'll stick with the convention that all_h[0] is the net input and all_f[k] in the net output\n", + "\n", + " # Compute derivatives of net output with respect to loss\n", + " all_dl_df[K] = np.array(d_loss_d_output(all_f[K],y))\n", + "\n", + " # Now work backwards through the network\n", + " for layer in range(K,-1,-1):\n", + " # Calculate the derivatives of biases at layer from all_dl_df[K]. (eq 7.13, line 1)\n", + " all_dl_dbiases[layer] = np.array(all_dl_df[layer])\n", + " # Calculate the derivatives of weight at layer from all_dl_df[K] and all_h[K] (eq 7.13, line 2)\n", + " all_dl_dweights[layer] = np.matmul(all_dl_df[layer], all_h[layer].transpose())\n", + "\n", + " # Calculate the derivatives of activations from weight and derivatives of next preactivations (eq 7.13, line 3 second part)\n", + " all_dl_dh[layer] = np.matmul(all_weights[layer].transpose(), all_dl_df[layer])\n", + " # Calculate the derivatives of the pre-activation f with respect to activation h (eq 7.13, line 3, first part)\n", + " if layer > 0:\n", + " all_dl_df[layer-1] = indicator_function(all_f[layer-1]) * all_dl_dh[layer]\n", + "\n", + " return all_dl_dweights, all_dl_dbiases, all_dl_dh, all_dl_df" + ], + "metadata": { + "id": "LJng7WpRPLMz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's look at what happens to the magnitude of the gradients on the way back." + ], + "metadata": { + "id": "phFnbthqwhFi" + } + }, + { + "cell_type": "code", + "source": [ + "# Number of layers\n", + "K = 5\n", + "# Number of neurons per layer\n", + "D = 8\n", + " # Input layer\n", + "D_i = 1\n", + "# Output layer \n", + "D_o = 1\n", + "# Set variance of initial weights to 1\n", + "sigma_sq_omega = 1.0\n", + "# Initialize parameters\n", + "all_weights, all_biases = init_params(K,D,sigma_sq_omega)\n", + "\n", + "# For simplicity we'll just consider the gradients of the weights and biases between the first and last hidden layer\n", + "n_data = 100\n", + "aggregate_dl_df = [None] * (K+1)\n", + "for layer in range(1,K):\n", + " # These 3D arrays will store the gradients for every data point\n", + " aggregate_dl_df[layer] = np.zeros((D,n_data))\n", + "\n", + "\n", + "# We'll have to compute the derivatives of the parameters for each data point separately\n", + "for c_data in range(n_data):\n", + " data_in = np.random.normal(size=(1,1))\n", + " y = np.zeros((1,1))\n", + " net_output, all_f, all_h = compute_network_output(data_in, all_weights, all_biases)\n", + " all_dl_dweights, all_dl_dbiases, all_dl_dh, all_dl_df = backward_pass(all_weights, all_biases, all_f, all_h, y)\n", + " for layer in range(1,K):\n", + " aggregate_dl_df[layer][:,c_data] = np.squeeze(all_dl_df[layer])\n", + "\n", + "for layer in range(1,K):\n", + " print(\"Layer %d, std of dl_dh = %3.3f\"%(layer, np.std(aggregate_dl_df[layer].ravel())))\n" + ], + "metadata": { + "id": "9A9MHc4sQvbp" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You can see that the values of the hidden units are increasing on average (the variance is across all hidden units at the layer \n", + "# and the 1000 training examples\n", + "\n", + "# TO DO \n", + "# Change this to 50 layers with 80 hidden units per layer\n", + "\n", + "# TO DO \n", + "# Now experiment with sigma_sq_omega to try to stop the variance of the gradients exploding" + ], + "metadata": { + "id": "gtokc0VX0839" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Intro.ipynb b/CM20315/CM20315_Intro.ipynb new file mode 100644 index 0000000..ba811db --- /dev/null +++ b/CM20315/CM20315_Intro.ipynb @@ -0,0 +1,298 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMTtWwAtwIZJoIsfGehxMMC", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "# **CM20315 Background Mathematics**\n", + "\n", + "The purpose of this Python notebook is to make sure you can use CoLab and to familiarize yourself with some of the background mathematical concepts that you are going to need to understand deep learning.

It's not meant to be difficult and it may be that you know some or all of this information already.

Maths is *NOT* a spectator sport. You won't learn it by just listening to lectures or reading books. It really helps to interact with it and explore yourself.

Work through the cells below, running each cell in turn. In various places you will see the words **\"TO DO\"**. Follow the instructions at these places. If you can't figure out what is going on or how to complete the section, feel free to ask your fellow students or the TAs in the practical session or via Moodle. This does not count toward your final marks, but complete=ing it will help you do well in your coursework and exam and reduce your stress levels later on.\n" + ], + "metadata": { + "id": "s5zzKSOusPOB" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aUAjBbqzivMY" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Linear functions**
In this course, we will be using the term *linear equation* to mean a weighted sum of inputs plus an offset. If there is just one input $x$, then this is a straight line:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega x,\\end{equation}
\n", + "\n", + "where $\\beta$ is the y-intercept of the linear and $\\omega$ is the slope of the line. When there are two inputs $x_{1}$ and $x_{2}$, then this becomes:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega_1 x_1 + \\omega_2 x_2.\\end{equation}

\n", + "\n", + "Any other functions are by definition **non-linear**.\n", + "\n", + "\n" + ], + "metadata": { + "id": "WV2Dl6owme2d" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with just one input, x\n", + "def linear_function_1D(x,beta,omega):\n", + " # TODO -- replace the code lin below with formula for 1D linear equation\n", + " y = x\n", + " return y" + ], + "metadata": { + "id": "WeFK4AvTotd8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the 1D linear function \n", + "\n", + "# Define an array of x values from 0 to 10 with increments of 0.1\n", + "# https://numpy.org/doc/stable/reference/generated/numpy.arange.html\n", + "x = np.arange(0.0,10.0, 0.01) \n", + "# Compute y using the function you filled in above\n", + "beta = 0.0; omega = 1.0\n", + "y = linear_function_1D(x,beta,omega)\n", + "\n", + "# Plot this function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([0,10]);ax.set_xlim([0,10])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.show\n", + "\n", + "# TODO -- experiment with changing the values of beta and omega\n", + "# to understand what they do. Try to make a line\n", + "# that crosses the y-axis at y=10 and the x-axis at x=5" + ], + "metadata": { + "id": "eimhJ8_jpmEp" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate a 2D linear function" + ], + "metadata": { + "id": "AedfvD9dxShZ" + } + }, + { + "cell_type": "code", + "source": [ + "# Code to draw 2D function -- read it so you know what is going on, but you don't have to change it\n", + "def draw_2D_function(x1_mesh, x2_mesh, y):\n", + " fig, ax = plt.subplots()\n", + " fig.set_size_inches(7,7)\n", + " ax.contourf(x1_mesh, x2_mesh, y, levels=256 ,cmap = 'hot', vmin=-10,vmax=10.0)\n", + " ax.set_xlabel('x1');ax.set_ylabel('x2')\n", + " levels = np.arange(-10,10,1.0)\n", + " ax.contour(x1_mesh, x2_mesh, y, levels, cmap='winter')\n", + " plt.show()" + ], + "metadata": { + "id": "57Gvkk-Ir_7b" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with two inputs, x1 and x2\n", + "def linear_function_2D(x1,x2,beta,omega1,omega2):\n", + " # TODO -- replace the code line below with formula for 2D linear equation\n", + " y = x1\n", + " return y" + ], + "metadata": { + "id": "YxeNhrXMzkZR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the 2D function\n", + "\n", + "# Make 2D array of x and y points\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# Compute the 2D function for given values of omega1, omega2\n", + "beta = 0.0; omega1 = 1.0; omega2 = -0.5\n", + "y = linear_function_2D(x1,x2,beta, omega1, omega2)\n", + "\n", + "# Draw the function. \n", + "# Color represents y value (brighter = higher value)\n", + "# Black = -10 or less, White = +10 or more\n", + "# 0 = mid orange\n", + "# Lines are contours where value is equal\n", + "draw_2D_function(x1,x2,y)\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_1 to zero\n", + "# Change the code and see if you are right.\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_2 to zero\n", + "# Change the code and see if you are right.\n", + "\n", + "#TODO \n", + "# Predict what this plot will look like if you set beta to -5\n", + "# Change the code and see if you are correct\n" + ], + "metadata": { + "id": "rn_UBRDBysmR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Often we will want to compute many linear functions at the same time. For example, we might have three inputs, $x_1$, $x_2$, and $x_3$ and want to compute two linear functions giving $y_1$ and $y_2$. Of course, we could do this by just running each equation separately,

\n", + "\n", + "\\begin{eqnarray}y_1 &=& \\beta_1 + \\omega_{11} x_1 + \\omega_{12} x_2 + \\omega_{13} x_3\\\\\n", + "y_2 &=& \\beta_2 + \\omega_{21} x_1 + \\omega_{22} x_2 + \\omega_{23} x_3.\n", + "\\end{eqnarray}
\n", + "\n", + "However, we can write it more compactly with vectors and matrices:\n", + "\n", + "\\begin{equation}\n", + "\\begin{bmatrix} y_1\\\\ y_2 \\end{bmatrix} = \\begin{bmatrix}\\beta_{1}\\\\\\beta_{2}\\end{bmatrix}+ \\begin{bmatrix}\\omega_{11}&\\omega_{12}&\\omega_{13}\\\\\\omega_{21}&\\omega_{22}&\\omega_{23}\\end{bmatrix}\\begin{bmatrix}x_{1}\\\\x_{2}\\\\x_{3}\\end{bmatrix},\n", + "\\end{equation}
\n", + "or \n", + "\n", + "\\begin{equation}\n", + "\\mathbf{y} = \\boldsymbol\\beta +\\boldsymbol\\Omega\\mathbf{x}.\n", + "\\end{equation}\n", + "\n", + "for short. Here, lowercase bold symbols are used for vectors. Upper case bold symbols are used for matrices.\n", + "\n" + ], + "metadata": { + "id": "i8tLwpls476R" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with three inputs, x1, x2, and x_3\n", + "def linear_function_3D(x1,x2,x3,beta,omega1,omega2,omega3):\n", + " # TODO -- replace the code below with formula for a single 3D linear equation\n", + " y = x1\n", + " return y" + ], + "metadata": { + "id": "MjHXMavh9IUz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's compute two linear equations, using both the individual equations and the vector / matrix form and check they give the same answer" + ], + "metadata": { + "id": "fGzVJQ6N-mHJ" + } + }, + { + "cell_type": "code", + "source": [ + "# Define the parameters\n", + "beta1 = 0.5; beta2 = 0.2\n", + "omega11 = -1.0 ; omega12 = 0.4; omega13 = -0.3\n", + "omega21 = 0.1 ; omega22 = 0.1; omega23 = 1.2\n", + "\n", + "# Define the inputs\n", + "x1 = 4 ; x2 =-1; x3 = 2\n", + "\n", + "# Compute using the individual equations\n", + "y1 = linear_function_3D(x1,x2,x3,beta1,omega11,omega12,omega13)\n", + "y2 = linear_function_3D(x1,x2,x3,beta2,omega21,omega22,omega23)\n", + "print(\"Individual equations\")\n", + "print('y1 = %3.3f\\ny2 = %3.3f'%((y1,y2)))\n", + "\n", + "# Define vectors and matrices\n", + "beta_vec = np.array([[beta1],[beta2]])\n", + "omega_mat = np.array([[omega11,omega12,omega13],[omega21,omega22,omega23]])\n", + "x_vec = np.array([[x1], [x2], [x3]])\n", + "\n", + "# Compute with vector/matrix form\n", + "y_vec = beta_vec+np.matmul(omega_mat, x_vec)\n", + "print(\"Matrix/vector form\")\n", + "print('y1= %3.3f\\ny2 = %3.3f'%((y_vec[0],y_vec[1])))\n" + ], + "metadata": { + "id": "Swd_bFIE9p2n" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "(Optional, but highly recommended) Think that you have this down? Here's some stuff to think about:
\n", + "\n", + "1. A single linear equation with three inputs (i.e. **linear_function_3D()**) associates a value y with each point in a 3D space ($x_1$,$x_2$,$x_3$). Is it possible to visualize this? What value is at position (0,0,0)?\n", + "\n", + "2. Write code to compute three linear equations with two inputs ($x_1$, $x_2$) using both the individual equations and the matrix form (you can make up any values for the inputs $\\beta_{i}$ and the slopes $\\omega_{ij}$." + ], + "metadata": { + "id": "3LGRoTMLU8ZU" + } + } + ] +} diff --git a/CM20315/CM20315_Intro_Answers.ipynb b/CM20315/CM20315_Intro_Answers.ipynb new file mode 100644 index 0000000..1eff4fe --- /dev/null +++ b/CM20315/CM20315_Intro_Answers.ipynb @@ -0,0 +1,454 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyMg86EZ/EnmCZeOUvVnj73U", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "# **CM20315 Background Mathematics**\n", + "\n", + "The purpose of this Python notebook is to make sure you can use CoLab and to familiarize yourself with some of the background mathematical concepts that you are going to need to understand deep learning.

It's not meant to be difficult and it may be that you know some or all of this information already.

Maths is *NOT* a spectator sport. You won't learn it by just listening to lectures or reading books. It really helps to interact with it and explore yourself.

Work through the cells below, running each cell in turn. In various places you will see the words **\"TO DO\"**. Follow the instructions at these places. If you can't figure out what is going on or how to complete the section, feel free to ask your fellow students or the TAs in the practical session or via Moodle. This does not count toward your final marks, but complete=ing it will help you do well in your coursework and exam and reduce your stress levels later on.\n" + ], + "metadata": { + "id": "s5zzKSOusPOB" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aUAjBbqzivMY" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Linear functions**
In this course, we will be using the term *linear equation* to mean a weighted sum of inputs plus an offset. If there is just one input $x$, then this is a straight line:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega x,\\end{equation}
\n", + "\n", + "where $\\beta$ is the y-intercept of the linear and $\\omega$ is the slope of the line. When there are two inputs $x_{1}$ and $x_{2}$, then this becomes:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega_1 x_1 + \\omega_2 x_2.\\end{equation}

\n", + "\n", + "Any other functions are by definition **non-linear**.\n", + "\n", + "\n" + ], + "metadata": { + "id": "WV2Dl6owme2d" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with just one input, x\n", + "def linear_function_1D(x,beta,omega):\n", + " # TODO -- replace the code lin below with formula for 1D linear equation\n", + " y = x\n", + " # ANSWER\n", + " y = beta + omega * x\n", + " # END_ANSWER\n", + " return y" + ], + "metadata": { + "id": "WeFK4AvTotd8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the 1D linear function \n", + "\n", + "# Define an array of x values from 0 to 10 with increments of 0.1\n", + "# https://numpy.org/doc/stable/reference/generated/numpy.arange.html\n", + "x = np.arange(0.0,10.0, 0.01) \n", + "# Compute y using the function you filled in above\n", + "beta = 0.0; omega = 1.0\n", + "# ANSWER\n", + "beta = 10.0; omega = -2.0\n", + "# END_ANSWER\n", + "y = linear_function_1D(x,beta,omega)\n", + "\n", + "# Plot this function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([0,10]);ax.set_xlim([0,10])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.show\n", + "\n", + "# TODO -- experiment with changing the values of beta and omega\n", + "# to understand what they do. Try to make a line\n", + "# that crosses the y-axis at y=10 and the x-axis at x=5" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 301 + }, + "id": "eimhJ8_jpmEp", + "outputId": "5678a055-d865-4a3f-f55c-c2c7cae1f713" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 51 + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate a 2D linear function" + ], + "metadata": { + "id": "AedfvD9dxShZ" + } + }, + { + "cell_type": "code", + "source": [ + "# Code to draw 2D function -- read it so you know what is going on, but you don't have to change it\n", + "def draw_2D_function(x1_mesh, x2_mesh, y):\n", + " fig, ax = plt.subplots()\n", + " fig.set_size_inches(7,7)\n", + " pos = ax.contourf(x1_mesh, x2_mesh, y, levels=256 ,cmap = 'hot', vmin=-10,vmax=10.0)\n", + " fig.colorbar(pos, ax=ax)\n", + " ax.set_xlabel('x1');ax.set_ylabel('x2')\n", + " levels = np.arange(-10,10,1.0)\n", + " ax.contour(x1_mesh, x2_mesh, y, levels, cmap='winter')\n", + " plt.show()" + ], + "metadata": { + "id": "57Gvkk-Ir_7b" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with two inputs, x1 and x2\n", + "def linear_function_2D(x1,x2,beta,omega1,omega2):\n", + " # TODO -- replace the code line below with formula for 2D linear equation\n", + " y = x1\n", + " # ANSWER\n", + " y = beta + omega1 * x1 + omega2 * x2\n", + " # END_ANSWER\n", + " return y" + ], + "metadata": { + "id": "YxeNhrXMzkZR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the 2D function\n", + "\n", + "# Make 2D array of x and y points\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# Compute the 2D function for given values of omega1, omega2\n", + "beta = 0.0; omega1 = 1.0; omega2 = -0.5\n", + "y = linear_function_2D(x1,x2,beta, omega1, omega2)\n", + "\n", + "# Draw the function. \n", + "# Color represents y value (brighter = higher value)\n", + "# Black = -10 or less, White = +10 or more\n", + "# 0 = mid orange\n", + "# Lines are contours where value is equal\n", + "draw_2D_function(x1,x2,y)\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_1 to zero\n", + "# Change the code and see if you are right.\n", + "# ANSWER: It will no longer change in x1-direction #END_ANSWER\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_2 to zero\n", + "# Change the code and see if you are right.\n", + "# ANSWER: It will no longer change in the x2-direction # END_ANSWER\n", + "\n", + "#TODO \n", + "# Predict what this plot will look like if you set beta to -5\n", + "# Change the code and see if you are correct\n", + "# ANSWER: The whole plot will become darker # END_ANSWER" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 442 + }, + "id": "rn_UBRDBysmR", + "outputId": "c085ac8a-a246-428c-ab81-2b09fe7a3eed" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Often we will want to compute many linear functions at the same time. For example, we might have three inputs, $x_1$, $x_2$, and $x_3$ and want to compute two linear functions giving $y_1$ and $y_2$. Of course, we could do this by just running each equation separately,

\n", + "\n", + "\\begin{eqnarray}y_1 &=& \\beta_1 + \\omega_{11} x_1 + \\omega_{12} x_2 + \\omega_{13} x_3\\\\\n", + "y_2 &=& \\beta_2 + \\omega_{21} x_1 + \\omega_{22} x_2 + \\omega_{23} x_3.\n", + "\\end{eqnarray}
\n", + "\n", + "However, we can write it more compactly with vectors and matrices:\n", + "\n", + "\\begin{equation}\n", + "\\begin{bmatrix} y_1\\\\ y_2 \\end{bmatrix} = \\begin{bmatrix}\\beta_{1}\\\\\\beta_{2}\\end{bmatrix}+ \\begin{bmatrix}\\omega_{11}&\\omega_{12}&\\omega_{13}\\\\\\omega_{21}&\\omega_{22}&\\omega_{23}\\end{bmatrix}\\begin{bmatrix}x_{1}\\\\x_{2}\\\\x_{3}\\end{bmatrix},\n", + "\\end{equation}
\n", + "or \n", + "\n", + "\\begin{equation}\n", + "\\mathbf{y} = \\boldsymbol\\beta +\\boldsymbol\\Omega\\mathbf{x}.\n", + "\\end{equation}\n", + "\n", + "for short. Here, lowercase bold symbols are used for vectors. Upper case bold symbols are used for matrices.\n", + "\n" + ], + "metadata": { + "id": "i8tLwpls476R" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a linear function with three inputs, x1, x2, and x_3\n", + "def linear_function_3D(x1,x2,x3,beta,omega1,omega2,omega3):\n", + " # TODO -- replace the code below with formula for a single 3D linear equation\n", + " y = x1\n", + " # ANSWER\n", + " y = beta + omega1 * x1 + omega2 * x2 + omega3 * x3\n", + " # END_ANSWER\n", + " return y" + ], + "metadata": { + "id": "MjHXMavh9IUz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's compute two linear equations, using both the individual equations and the vector / matrix form and check they give the same answer" + ], + "metadata": { + "id": "fGzVJQ6N-mHJ" + } + }, + { + "cell_type": "code", + "source": [ + "# Define the parameters\n", + "beta1 = 0.5; beta2 = 0.2\n", + "omega11 = -1.0 ; omega12 = 0.4; omega13 = -0.3\n", + "omega21 = 0.1 ; omega22 = 0.1; omega23 = 1.2\n", + "\n", + "# Define the inputs\n", + "x1 = 4 ; x2 =-1; x3 = 2\n", + "\n", + "# Compute using the individual equations\n", + "y1 = linear_function_3D(x1,x2,x3,beta1,omega11,omega12,omega13)\n", + "y2 = linear_function_3D(x1,x2,x3,beta2,omega21,omega22,omega23)\n", + "print(\"Individual equations\")\n", + "print('y1 = %3.3f\\ny2 = %3.3f'%((y1,y2)))\n", + "\n", + "# Define vectors and matrices\n", + "beta_vec = np.array([[beta1],[beta2]])\n", + "omega_mat = np.array([[omega11,omega12,omega13],[omega21,omega22,omega23]])\n", + "x_vec = np.array([[x1], [x2], [x3]])\n", + "\n", + "# Compute with vector/matrix form\n", + "y_vec = beta_vec+np.matmul(omega_mat, x_vec)\n", + "print(\"Matrix/vector form\")\n", + "print('y1= %3.3f\\ny2 = %3.3f'%((y_vec[0],y_vec[1])))\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Swd_bFIE9p2n", + "outputId": "44f83ce2-a2d0-4d88-9b23-b554965c8697" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Individual equations\n", + "y1 = -4.500\n", + "y2 = 2.900\n", + "Matrix/vector form\n", + "y1= -4.500\n", + "y2 = 2.900\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "(Optional, but highly recommended) Think that you have this down? Here's some stuff to think about:
\n", + "\n", + "1. A single linear equation with three inputs (i.e. **linear_function_3D()**) associates a value y with each point in a 3D space ($x_1$,$x_2$,$x_3$). Is it possible to visualize this? What value is at position (0,0,0)?\n", + "\n", + "2. Write code to compute three linear equations with two inputs ($x_1$, $x_2$) using both the individual equations and the matrix form (you can make up any values for the inputs $\\beta_{i}$ and the slopes $\\omega_{ij}$." + ], + "metadata": { + "id": "3LGRoTMLU8ZU" + } + }, + { + "cell_type": "markdown", + "source": [ + "# ANSWER\n", + "Question 1: No, there is no easy way to visualize this -- it's a three dimensional volume with a different value at each position. The best we would be able to do is to print out a set of slices showing the heatmap for ($x_1$,$x_2$) as in the 2D example above for a series of different values of $x_{3}$ but it's still hard to get the overall idea. In four dimensions or higher, it becomes really impossible to visualize. Spoiler... we will have linear equations with thousands of dimensions! Position (0,0,0) has the value $\\beta$. It's still the y-offset.\n", + "# END_ANSWER" + ], + "metadata": { + "id": "7qdt7v8oXLSM" + } + }, + { + "cell_type": "code", + "source": [ + "# ANSWER\n", + "#Question 2:\n", + "\n", + "# Define the parameters\n", + "beta1 = 0.5; beta2 = 0.2 ; beta3 = -0.1\n", + "omega11 = -1.0 ; omega12 = 0.4; \n", + "omega21 = 0.1 ; omega22 = 0.1; \n", + "omega31 = 0.4 ; omega32 = -0.7\n", + "\n", + "# Define the inputs\n", + "x1 = 4 ; x2 =-1;\n", + "\n", + "# Compute using the individual equations\n", + "y1 = linear_function_2D(x1,x2,beta1,omega11,omega12)\n", + "y2 = linear_function_2D(x1,x2,beta2,omega21,omega22)\n", + "y3 = linear_function_2D(x1,x2,beta3,omega31,omega32)\n", + "print(\"Individual equations\")\n", + "print('y1 = %3.3f\\ny2 = %3.3f'%((y1,y2)))\n", + "\n", + "# Define vectors and matrices\n", + "beta_vec = np.array([[beta1],[beta2],[beta3]])\n", + "omega_mat = np.array([[omega11,omega12],[omega21,omega22],[omega31,omega32]])\n", + "x_vec = np.array([[x1], [x2]])\n", + "\n", + "# Compute with vector/matrix form\n", + "y_vec = beta_vec+np.matmul(omega_mat, x_vec)\n", + "print(\"Matrix/vector form\")\n", + "print('y1= %3.3f\\ny2 = %3.3f'%((y_vec[0],y_vec[1])))\n", + "# END_ANSWER" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1NlOoJEizWEN", + "outputId": "b2d111fb-c44e-488e-b7a1-b4f98508b20f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Individual equations\n", + "y1 = -3.900\n", + "y2 = 0.500\n", + "Matrix/vector form\n", + "y1= -3.900\n", + "y2 = 0.500\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "7Y5zdKtKZAB2" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Loss.ipynb b/CM20315/CM20315_Loss.ipynb new file mode 100644 index 0000000..8761997 --- /dev/null +++ b/CM20315/CM20315_Loss.ipynb @@ -0,0 +1,564 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyNWvWC97VuIGwu4VTE1XbO6", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Loss functions\n", + "\n", + "In this practical, we'll investigate loss functions. In part 1 (this notebook), we'll investigate univariate regression (where the output data $y$ is continuous. Our formulation will be based on the normal/Gaussian distribution.\n", + "\n", + "We'll compute loss functions for maximum likelihood, minimum negative log likelihood, and least squares and show that they all imply that we should use the same parameter values\n", + "\n", + "In part II, we'll investigate binary classification (where the output data is 0 or 1). This will be based on the Bernoulli distribution\n", + "\n", + "In part III we'll investigate multiclass classification (where the output data is 0,1, or, 2). This will be based on the categorical distribution." + ], + "metadata": { + "id": "jSlFkICHwHQF" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PYMZ1x-Pv1ht" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt\n", + "# Import math Library\n", + "import math" + ] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation\n", + "\n", + "# Define a shallow neural network\n", + "def shallow_nn(x, beta_0, omega_0, beta_1, omaga_1):\n", + " # Make sure that input data is (1 x n_data) array\n", + " n_data = x.size\n", + " x = np.reshape(x,(1,n_data))\n", + "\n", + " # This runs the network for ALL of the inputs, x at once so we can draw graph\n", + " h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(omega_0,x))\n", + " y = np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(omega_1,h1)\n", + " return y" + ], + "metadata": { + "id": "Fv7SZR3tv7mV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Utility function for plotting data\n", + "def plot_univariate_regression(x_model, y_model, x_data = None, y_data = None, sigma_model = None, title= None):\n", + " # Make sure model data are 1D arrays\n", + " x_model = np.squeeze(x_model)\n", + " y_model = np.squeeze(y_model)\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x_model,y_model)\n", + " if sigma_model is not None:\n", + " ax.fill_between(x_model, y_model-2*sigma_model, y_model+2*sigma_model, color='lightgray')\n", + " ax.set_xlabel('Input, $x$'); ax.set_ylabel('Output, $y$')\n", + " ax.set_xlim([0,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(0.5)\n", + " if title is not None:\n", + " ax.set_title(title)\n", + " if x_data is not None:\n", + " ax.plot(x_data, y_data, 'ko')\n", + " plt.show()" + ], + "metadata": { + "id": "NRR67ri_1TzN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Univariate regression" + ], + "metadata": { + "id": "PsgLZwsPxauP" + } + }, + { + "cell_type": "code", + "source": [ + "# Get parameters for model -- we can call this function to easily reset them\n", + "def get_parameters():\n", + " # And we'll create a network that approximately fits it\n", + " beta_0 = np.zeros((3,1)); # formerly theta_x0\n", + " omega_0 = np.zeros((3,1)); # formerly theta_x1\n", + " beta_1 = np.zeros((1,1)); # formerly phi_0\n", + " omega_1 = np.zeros((1,3)); # formerly phi_x\n", + "\n", + " beta_0[0,0] = 0.3; beta_0[1,0] = -1.0; beta_0[2,0] = -0.5\n", + " omega_0[0,0] = -1.0; omega_0[1,0] = 1.8; omega_0[2,0] = 0.65\n", + " beta_1[0,0] = 0.1;\n", + " omega_1[0,0] = -2.0; omega_1[0,1] = -1.0; omega_1[0,2] = 7.0\n", + "\n", + " return beta_0, omega_0, beta_1, omega_1" + ], + "metadata": { + "id": "pUT9Ain_HRim" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's create some 1D training data\n", + "x_train = np.array([0.09291784,0.46809093,0.93089486,0.67612654,0.73441752,0.86847339,\\\n", + " 0.49873225,0.51083168,0.18343972,0.99380898,0.27840809,0.38028817,\\\n", + " 0.12055708,0.56715537,0.92005746,0.77072270,0.85278176,0.05315950,\\\n", + " 0.87168699,0.58858043])\n", + "y_train = np.array([-0.25934537,0.18195445,0.651270150,0.13921448,0.09366691,0.30567674,\\\n", + " 0.372291170,0.20716968,-0.08131792,0.51187806,0.16943738,0.3994327,\\\n", + " 0.019062570,0.55820410,0.452564960,-0.1183121,0.02957665,-1.24354444, \\\n", + " 0.248038840,0.26824970])\n", + "\n", + "# Get parameters for the model\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "sigma = 0.2\n", + "\n", + "# Define a range of input values\n", + "x_model = np.arange(0,1,0.01)\n", + "# Run the model to get values to plot and plot it.\n", + "y_model = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "plot_univariate_regression(x_model, y_model, x_train, y_train, sigma_model = sigma)\n" + ], + "metadata": { + "id": "VWzNOt1swFVd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The blue line is the mean prediction of the model and the gray area represents plus/minus two standard deviations. This model fits okay, but could be improved. Let's compute the loss. We'll compute the the least squares error, the likelihood, the negative log likelihood." + ], + "metadata": { + "id": "MvVX6tl9AEXF" + } + }, + { + "cell_type": "code", + "source": [ + "# Return probability under normal distribution for input x\n", + "def normal_distribution(y, mu, sigma):\n", + " # TODO-- write in the equation for the normal distribution \n", + " # Equation 5.7 from the notes (you will need np.sqrt() and np.exp(), and math.pi)\n", + " # Don't use the numpy version -- that's cheating!\n", + " # Replace the line below\n", + " prob = np.zeros_like(y)\n", + " return prob" + ], + "metadata": { + "id": "YaLdRlEX0FkU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.119,normal_distribution(1,-1,2.3)))" + ], + "metadata": { + "id": "4TSL14dqHHbV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's plot the Gaussian distribution.\n", + "y_gauss = np.arange(-5,5,0.1)\n", + "mu = 0; sigma = 1.0\n", + "gauss_prob = normal_distribution(y_gauss, mu, sigma)\n", + "fig, ax = plt.subplots()\n", + "ax.plot(y_gauss, gauss_prob)\n", + "ax.set_xlabel('Input, $y$'); ax.set_ylabel('Probability $Pr(y)$')\n", + "ax.set_xlim([-5,5]);ax.set_ylim([0,1.0])\n", + "plt.show()\n", + "\n", + "# TODO \n", + "# 1. Predict what will happen if we change to mu=1 and leave sigma=1\n", + "# Answer:\n", + "# Now change the code above and see if you were correct.\n", + "# 2. Predict what will happen if we leave mu = 0 and change sigma to 2.0\n", + "# Answer:\n", + "# 3. Predict what will happen if we leave mu = 0 and change sigma to 0.5\n", + "# Answer:" + ], + "metadata": { + "id": "A2HcmNfUMIlj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the likelihood using this function" + ], + "metadata": { + "id": "R5z_0dzQMF35" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the likelihood of all of the data under the model\n", + "def compute_likelihood(y_train, mu, sigma):\n", + " # TODO -- compute the likelihood of the data -- the product of the normal probabilities for each data point\n", + " # Top line of equation 5.3 in the notes\n", + " # You will need np.prod() and the normal_distribution function you used above\n", + " # Replace the line below\n", + " likelihood = 0\n", + " return likelihood" + ], + "metadata": { + "id": "zpS7o6liCx7f" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this for a homoscedastic (constant sigma) model\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "mu_pred = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "# Set the standard deviation to something reasonable\n", + "sigma = 0.2\n", + "# Compute the likelihood\n", + "likelihood = compute_likelihood(y_train, mu_pred, sigma)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(0.000010624,likelihood))" + ], + "metadata": { + "id": "1hQxBLoVNlr2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "You can see that this gives a very small answer, even for this small 1D dataset, and with the model fitting quite well. This is because it is the product of several probabilities, which are all quite small themselves.\n", + "This will get out of hand pretty quickly with real datasets -- the likelihood will get so small that we can't represent it with normal finite-precision math\n", + "\n", + "This is why we use negative log likelihood" + ], + "metadata": { + "id": "HzphKgPfOvlk" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the negative log likelihood of the data under the model\n", + "def compute_negative_log_likelihood(y_train, mu, sigma):\n", + " # TODO -- compute the likelihood of the data -- don't use the likelihood function above -- compute the negative sum of the log probabilities\n", + " # Bottom line of equation 5.4 in the notes\n", + " # You will need np.sum(), np.log()\n", + " # Replace the line below\n", + " nll = 0\n", + " return nll" + ], + "metadata": { + "id": "dsT0CWiKBmTV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this for a homoscedastic (constant sigma) model\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "mu_pred = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "# Set the standard deviation to something reasonable\n", + "sigma = 0.2\n", + "# Compute the log likelihood\n", + "nll = compute_negative_log_likelihood(y_train, mu_pred, sigma)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(11.452419564,nll))" + ], + "metadata": { + "id": "nVxUXg9rQmwI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For good measure, let's compute the sum of squares as well" + ], + "metadata": { + "id": "-S8bXApoWVLG" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the squared distance between the predicted \n", + "def compute_sum_of_squares(y_train, y_pred):\n", + " # TODO -- compute the sum of squared distances between the training data and the model prediction\n", + " # Eqn 5.10 in the notes. Make sure that you understand this, and ask questions if you don't\n", + " # Replace the line below\n", + " sum_of_squares = 0;\n", + " return sum_of_squares" + ], + "metadata": { + "id": "I1pjFdHCF4JZ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this again\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "y_pred = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "# Compute the log likelihood\n", + "sum_of_squares = compute_sum_of_squares(y_train, y_pred)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(2.020992572,sum_of_squares))" + ], + "metadata": { + "id": "2C40fskIHBx7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate finding the maximum likelihood / minimum log likelihood / least squares solution. For simplicity, we'll assume that all the parameters are correct except one and look at how the likelihood, log likelihood, and sum of squares change as we manipulate the last parameter. We'll start with overall y offset, beta_1 (formerly phi_0)" + ], + "metadata": { + "id": "OgcRojvPWh4V" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a range of values for the parameter\n", + "beta_1_vals = np.arange(0,1.0,0.01)\n", + "# Create some arrays to store the likelihoods, negative log likelihoods and sum of squares\n", + "likelihoods = np.zeros_like(beta_1_vals)\n", + "nlls = np.zeros_like(beta_1_vals)\n", + "sum_squares = np.zeros_like(beta_1_vals)\n", + "\n", + "# Initialise the parameters\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "sigma = 0.2\n", + "for count in range(len(beta_1_vals)):\n", + " # Set the value for the parameter\n", + " beta_1[0,0] = beta_1_vals[count]\n", + " # Run the network with new parameters\n", + " mu_pred = y_pred = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + " # Compute and store the three values\n", + " likelihoods[count] = compute_likelihood(y_train, mu_pred, sigma)\n", + " nlls[count] = compute_negative_log_likelihood(y_train, mu_pred, sigma)\n", + " sum_squares[count] = compute_sum_of_squares(y_train, y_pred)\n", + " # Draw the model for every 20th parameter setting\n", + " if count % 20 == 0:\n", + " # Run the model to get values to plot and plot it.\n", + " y_model = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + " plot_univariate_regression(x_model, y_model, x_train, y_train, sigma_model = sigma, title=\"beta1[0]=%3.3f\"%(beta_1[0,0]))\n" + ], + "metadata": { + "id": "pFKtDaAeVU4U" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now let's plot the likelihood, negative log likelihood, and least squares as a function the value of the offset beta1\n", + "fig, ax = plt.subplots(1,3)\n", + "fig.set_size_inches(10.5, 3.5)\n", + "fig.tight_layout(pad=3.0)\n", + "ax[0].plot(beta_1_vals, likelihoods); ax[0].set_xlabel('beta_1[0]'); ax[0].set_ylabel('likelihood')\n", + "ax[1].plot(beta_1_vals, nlls); ax[1].set_xlabel('beta_1[0]'); ax[1].set_ylabel('negative log likelihood')\n", + "ax[2].plot(beta_1_vals, sum_squares); ax[2].set_xlabel('beta_1[0]'); ax[2].set_ylabel('sum of squares')\n", + "plt.show()" + ], + "metadata": { + "id": "UHXeTa9MagO6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Hopefully, you can see that the maximum of the likelihood fn is at the same position as the minimum negative log likelihood\n", + "# and the least squares solutions\n", + "# Let's check that:\n", + "print(\"Maximum likelihood = %3.3f, at beta_1=%3.3f\"%( (likelihoods[np.argmax(likelihoods)],beta_1_vals[np.argmax(likelihoods)])))\n", + "print(\"Minimum negative log likelihood = %3.3f, at beta_1=%3.3f\"%( (nlls[np.argmin(nlls)],beta_1_vals[np.argmin(nlls)])))\n", + "print(\"Least squares = %3.3f, at beta_1=%3.3f\"%( (sum_squares[np.argmin(sum_squares)],beta_1_vals[np.argmin(sum_squares)])))\n", + "\n", + "# Plot the best model\n", + "beta_1[0,0] = beta_1_vals[np.argmin(sum_squares)]\n", + "y_model = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "plot_univariate_regression(x_model, y_model, x_train, y_train, sigma_model = sigma, title=\"beta1=%3.3f\"%(beta_1[0,0]))" + ], + "metadata": { + "id": "aDEPhddNdN4u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "They all give the same answer. But you can see from the three plots above that the likelihood is very small unless the parameters are almost correct. So in practice, we would work with the negative log likelihood or the least squares.

\n", + "\n", + "For fun, let's do the same thing with the standard deviation parameter of our network. This is not an output of the network (unless we choose to make that the case), but it still affects the likelihood.\n", + "\n" + ], + "metadata": { + "id": "771G8N1Vk5A2" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a range of values for the parameter\n", + "sigma_vals = np.arange(0.1,0.5,0.005)\n", + "# Create some arrays to store the likelihoods, negative log likelihoods and sum of squares\n", + "likelihoods = np.zeros_like(sigma_vals)\n", + "nlls = np.zeros_like(sigma_vals)\n", + "sum_squares = np.zeros_like(sigma_vals)\n", + "\n", + "# Initialise the parameters\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Might as well set to the best offset\n", + "beta_1[0,0] = 0.27\n", + "for count in range(len(sigma_vals)):\n", + " # Set the value for the parameter\n", + " sigma = sigma_vals[count]\n", + " # Run the network with new parameters\n", + " mu_pred = y_pred = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + " # Compute and store the three values\n", + " likelihoods[count] = compute_likelihood(y_train, mu_pred, sigma)\n", + " nlls[count] = compute_negative_log_likelihood(y_train, mu_pred, sigma)\n", + " sum_squares[count] = compute_sum_of_squares(y_train, y_pred)\n", + " # Draw the model for every 20th parameter setting\n", + " if count % 20 == 0:\n", + " # Run the model to get values to plot and plot it.\n", + " y_model = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + " plot_univariate_regression(x_model, y_model, x_train, y_train, sigma_model=sigma, title=\"sigma=%3.3f\"%(sigma))" + ], + "metadata": { + "id": "dMNAr0R8gg82" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now let's plot the likelihood, negative log likelihood, and least squares as a function the value of the offset beta1\n", + "fig, ax = plt.subplots(1,3)\n", + "fig.set_size_inches(10.5, 3.5)\n", + "fig.tight_layout(pad=3.0)\n", + "ax[0].plot(sigma_vals, likelihoods); ax[0].set_xlabel('$\\sigma$'); ax[0].set_ylabel('likelihood')\n", + "ax[1].plot(sigma_vals, nlls); ax[1].set_xlabel('$\\sigma$'); ax[1].set_ylabel('negative log likelihood')\n", + "ax[2].plot(sigma_vals, sum_squares); ax[2].set_xlabel('$\\sigma$'); ax[2].set_ylabel('sum of squares')\n", + "plt.show()" + ], + "metadata": { + "id": "l9jduyHLDAZC" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Hopefully, you can see that the maximum of the likelihood fn is at the same position as the minimum negative log likelihood\n", + "# The least squares solution does not depend on sigma, so it's just flat -- no use here.\n", + "# Let's check that:\n", + "print(\"Maximum likelihood = %3.3f, at beta_1=%3.3f\"%( (likelihoods[np.argmax(likelihoods)],sigma_vals[np.argmax(likelihoods)])))\n", + "print(\"Minimum negative log likelihood = %3.3f, at beta_1=%3.3f\"%( (nlls[np.argmin(nlls)],sigma_vals[np.argmin(nlls)])))\n", + "# Plot the best model\n", + "sigma= sigma_vals[np.argmin(nlls)]\n", + "y_model = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "plot_univariate_regression(x_model, y_model, x_train, y_train, sigma_model = sigma, title=\"beta1=%3.3f, sigma =%3.3f\"%(beta_1[0,0],sigma))" + ], + "metadata": { + "id": "XH7yER52Dxt5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Obviously, to fit the full neural model we would vary all of the 10 parameters of the network in the $\\boldsymbol\\beta_{0},\\boldsymbol\\omega_{0},\\boldsymbol\\beta_{1},\\boldsymbol\\omega_{1}$ (and maybe $\\sigma$) until we find the combination that have the maximum likelihood / minimum negative log likelihood / least squares.

\n", + "\n", + "Here we just varied one at a time as it is easier to see what is going on. This is known as **coordinate descent**.\n" + ], + "metadata": { + "id": "q_KeGNAHEbIt" + } + } + ] +} diff --git a/CM20315/CM20315_Loss_II.ipynb b/CM20315/CM20315_Loss_II.ipynb new file mode 100644 index 0000000..9846d61 --- /dev/null +++ b/CM20315/CM20315_Loss_II.ipynb @@ -0,0 +1,453 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyMLgMUtCcJHjIzHTTqjKVt1", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Loss functions part II\n", + "\n", + "This practical investigates loss functions. In part I we investigated univariate regression (where the output data $y$ is continuous. Our formulation was based on the normal/Gaussian distribution.\n", + "\n", + "In this notebook, we investigate binary classification (where the output data is 0 or 1). This will be based on the Bernoulli distribution\n", + "\n", + "In part III we'll investigate multiclass classification (where the outputs data can take multiple values 1,... K.\n", + "\n", + "We'll compute loss functions with maximum likelihood and minimum negative log likelihood." + ], + "metadata": { + "id": "jSlFkICHwHQF" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PYMZ1x-Pv1ht" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt\n", + "# Import math Library\n", + "import math" + ] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation\n", + "\n", + "# Define a shallow neural network\n", + "def shallow_nn(x, beta_0, omega_0, beta_1, omaga_1):\n", + " # Make sure that input data is (1 x n_data) array\n", + " n_data = x.size\n", + " x = np.reshape(x,(1,n_data))\n", + "\n", + " # This runs the network for ALL of the inputs, x at once so we can draw graph\n", + " h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(omega_0,x))\n", + " model_out = np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(omega_1,h1)\n", + " return model_out" + ], + "metadata": { + "id": "Fv7SZR3tv7mV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Utility function for plotting data\n", + "def plot_binary_classification(x_model, out_model, lambda_model, x_data = None, y_data = None, title= None):\n", + " # Make sure model data are 1D arrays\n", + " x_model = np.squeeze(x_model)\n", + " out_model = np.squeeze(out_model)\n", + " lambda_model = np.squeeze(lambda_model)\n", + "\n", + " fig, ax = plt.subplots(1,2)\n", + " fig.set_size_inches(7.0, 3.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0].plot(x_model,out_model)\n", + " ax[0].set_xlabel('Input, $x$'); ax[0].set_ylabel('Model output')\n", + " ax[0].set_xlim([0,1]);ax[0].set_ylim([-4,4])\n", + " if title is not None:\n", + " ax[0].set_title(title)\n", + " ax[1].plot(x_model,lambda_model)\n", + " ax[1].set_xlabel('Input, $x$'); ax[1].set_ylabel('$\\lambda$ or Pr(y=1|x)')\n", + " ax[1].set_xlim([0,1]);ax[1].set_ylim([-0.05,1.05])\n", + " if title is not None:\n", + " ax[1].set_title(title)\n", + " if x_data is not None:\n", + " ax[1].plot(x_data, y_data, 'ko')\n", + " plt.show()" + ], + "metadata": { + "id": "NRR67ri_1TzN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Binary classification" + ], + "metadata": { + "id": "PsgLZwsPxauP" + } + }, + { + "cell_type": "code", + "source": [ + "# Get parameters for model -- we can call this function to easily reset them\n", + "def get_parameters():\n", + " # And we'll create a network that approximately fits it\n", + " beta_0 = np.zeros((3,1)); # formerly theta_x0\n", + " omega_0 = np.zeros((3,1)); # formerly theta_x1\n", + " beta_1 = np.zeros((1,1)); # formerly phi_0\n", + " omega_1 = np.zeros((1,3)); # formerly phi_x\n", + "\n", + " beta_0[0,0] = 0.3; beta_0[1,0] = -1.0; beta_0[2,0] = -0.5\n", + " omega_0[0,0] = -1.0; omega_0[1,0] = 1.8; omega_0[2,0] = 0.65\n", + " beta_1[0,0] = 2.6;\n", + " omega_1[0,0] = -24.0; omega_1[0,1] = -8.0; omega_1[0,2] = 50.0\n", + "\n", + " return beta_0, omega_0, beta_1, omega_1" + ], + "metadata": { + "id": "pUT9Ain_HRim" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Sigmoid function that maps [-infty,infty] to [0,1]\n", + "def sigmoid(model_out):\n", + " # TODO -- implement the logistic sigmoid function\n", + " # Replace this line:\n", + " sig_model_out = np.zeros_like(model_out)\n", + " return sig_model_out" + ], + "metadata": { + "id": "uFb8h-9IXnIe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's create some 1D training data\n", + "x_train = np.array([0.09291784,0.46809093,0.93089486,0.67612654,0.73441752,0.86847339,\\\n", + " 0.49873225,0.51083168,0.18343972,0.99380898,0.27840809,0.38028817,\\\n", + " 0.12055708,0.56715537,0.92005746,0.77072270,0.85278176,0.05315950,\\\n", + " 0.87168699,0.58858043])\n", + "y_train = np.array([0,1,1,0,0,1,\\\n", + " 1,0,0,1,0,1,\\\n", + " 0,1,1,0,1,0, \\\n", + " 1,1])\n", + "\n", + "# Get parameters for the model\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "\n", + "# Define a range of input values\n", + "x_model = np.arange(0,1,0.01)\n", + "# Run the model to get values to plot and plot it.\n", + "model_out= shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_model = sigmoid(model_out)\n", + "plot_binary_classification(x_model, model_out, lambda_model, x_train, y_train)\n" + ], + "metadata": { + "id": "VWzNOt1swFVd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The left is model output and the right is the model output after the sigmoid has been applied, so it now lies in the range [0,1] and represents the probability, that y=1. The black dots show the training data. We'll compute the the likelihood and the negative log likelihood." + ], + "metadata": { + "id": "MvVX6tl9AEXF" + } + }, + { + "cell_type": "code", + "source": [ + "# Return probability under Bernoulli distribution for input x\n", + "def bernoulli_distribution(y, lambda_param):\n", + " # TODO-- write in the equation for the Bernoulli distribution \n", + " # Equation 5.17 from the notes (you will need np.power)\n", + " # Replace the line below\n", + " prob = np.zeros_like(y)\n", + " return prob" + ], + "metadata": { + "id": "YaLdRlEX0FkU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.8,bernoulli_distribution(0,0.2)))\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.2,bernoulli_distribution(1,0.2)))" + ], + "metadata": { + "id": "4TSL14dqHHbV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the likelihood using this function" + ], + "metadata": { + "id": "R5z_0dzQMF35" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the likelihood of all of the data under the model\n", + "def compute_likelihood(y_train, lambda_param):\n", + " # TODO -- compute the likelihood of the data -- the product of the Bernoulli's probabilities for each data point\n", + " # Top line of equation 5.3 in the notes\n", + " # You will need np.prod() and the bernoulli_distribution function you used above\n", + " # Replace the line below\n", + " likelihood = 0\n", + " return likelihood" + ], + "metadata": { + "id": "sk4EJSPQ41CK" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this \n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_train = sigmoid(model_out)\n", + "# Compute the likelihood\n", + "likelihood = compute_likelihood(y_train, lambda_train)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(0.000070237,likelihood))" + ], + "metadata": { + "id": "1hQxBLoVNlr2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "You can see that this gives a very small answer, even for this small 1D dataset, and with the model fitting quite well. This is because it is the product of several probabilities, which are all quite small themselves.\n", + "This will get out of hand pretty quickly with real datasets -- the likelihood will get so small that we can't represent it with normal finite-precision math\n", + "\n", + "This is why we use negative log likelihood" + ], + "metadata": { + "id": "HzphKgPfOvlk" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the negative log likelihood of the data under the model\n", + "def compute_negative_log_likelihood(y_train, lambda_param):\n", + " # TODO -- compute the likelihood of the data -- don't use the likelihood function above -- compute the negative sum of the log probabilities\n", + " # You will need np.sum(), np.log()\n", + " # Replace the line below\n", + " nll = 0\n", + " return nll" + ], + "metadata": { + "id": "dsT0CWiKBmTV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "# Set the standard deviation to something reasonable\n", + "lambda_train = sigmoid(model_out)\n", + "# Compute the log likelihood\n", + "nll = compute_negative_log_likelihood(y_train, lambda_train)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(9.563639387,nll))" + ], + "metadata": { + "id": "nVxUXg9rQmwI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate finding the maximum likelihood / minimum log likelihood / least squares solution. For simplicity, we'll assume that all the parameters are fixed except one and look at how the likelihood and log likelihood change as we manipulate the last parameter. We'll start with overall y_offset, beta_1 (formerly phi_0)" + ], + "metadata": { + "id": "OgcRojvPWh4V" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the likelihood of all of the data under the model\n", + "def compute_likelihood(y_train, lambda_param):\n", + " # TODO -- compute the likelihood of the data -- the product of the Bernoulli probabilities for each data point\n", + " # Top line of equation 5.3 in the notes\n", + " # You will need np.prod() and the bernoulli_distribution function you used above\n", + " # Replace the line below\n", + " likelihood = 0\n", + " return likelihood" + ], + "metadata": { + "id": "zpS7o6liCx7f" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a range of values for the parameter\n", + "beta_1_vals = np.arange(-2,6.0,0.1)\n", + "# Create some arrays to store the likelihoods, negative log likelihoods\n", + "likelihoods = np.zeros_like(beta_1_vals)\n", + "nlls = np.zeros_like(beta_1_vals)\n", + "\n", + "# Initialise the parameters\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "for count in range(len(beta_1_vals)):\n", + " # Set the value for the parameter\n", + " beta_1[0,0] = beta_1_vals[count]\n", + " # Run the network with new parameters\n", + " model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + " lambda_train = sigmoid(model_out)\n", + " # Compute and store the three values\n", + " likelihoods[count] = compute_likelihood(y_train,lambda_train)\n", + " nlls[count] = compute_negative_log_likelihood(y_train, lambda_train)\n", + " # Draw the model for every 20th parameter setting\n", + " if count % 20 == 0:\n", + " # Run the model to get values to plot and plot it.\n", + " model_out = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + " lambda_model = sigmoid(model_out)\n", + " plot_binary_classification(x_model, model_out, lambda_model, x_train, y_train, title=\"beta_1[0]=%3.3f\"%(beta_1[0,0]))\n" + ], + "metadata": { + "id": "pFKtDaAeVU4U" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now let's plot the likelihood, negative log likelihood, and least squares as a function the value of the offset beta1\n", + "fig, ax = plt.subplots(1,2)\n", + "fig.set_size_inches(10.5, 3.5)\n", + "fig.tight_layout(pad=3.0)\n", + "ax[0].plot(beta_1_vals, likelihoods); ax[0].set_xlabel('beta_1[0]'); ax[0].set_ylabel('likelihood')\n", + "ax[1].plot(beta_1_vals, nlls); ax[1].set_xlabel('beta_1[0]'); ax[1].set_ylabel('negative log likelihood')\n", + "plt.show()" + ], + "metadata": { + "id": "UHXeTa9MagO6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Hopefully, you can see that the maximum of the likelihood fn is at the same position as the minimum negative log likelihood\n", + "# and the least squares solutions\n", + "# Let's check that:\n", + "print(\"Maximum likelihood = %f, at beta_1=%3.3f\"%( (likelihoods[np.argmax(likelihoods)],beta_1_vals[np.argmax(likelihoods)])))\n", + "print(\"Minimum negative log likelihood = %f, at beta_1=%3.3f\"%( (nlls[np.argmin(nlls)],beta_1_vals[np.argmin(nlls)])))\n", + "\n", + "# Plot the best model\n", + "beta_1[0,0] = beta_1_vals[np.argmin(nlls)]\n", + "model_out = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_model = sigmoid(model_out)\n", + "plot_binary_classification(x_model, model_out, lambda_model, x_train, y_train, title=\"beta_1[0]=%3.3f\"%(beta_1[0,0]))\n" + ], + "metadata": { + "id": "aDEPhddNdN4u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "They both give the same answer. But you can see from the likelihood above that the likelihood is very small unless the parameters are almost correct. So in practice, we would work with the negative log likelihood.

\n", + "\n", + "Again, to fit the full neural model we would vary all of the 10 parameters of the network in the $\\boldsymbol\\beta_{0},\\boldsymbol\\omega_{0},\\boldsymbol\\beta_{1},\\boldsymbol\\omega_{1}$ until we find the combination that have the maximum likelihood / minimum negative log likelihood.

\n", + "\n" + ], + "metadata": { + "id": "771G8N1Vk5A2" + } + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "eQ4xeiDgOn0X" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Loss_III.ipynb b/CM20315/CM20315_Loss_III.ipynb new file mode 100644 index 0000000..ef914c9 --- /dev/null +++ b/CM20315/CM20315_Loss_III.ipynb @@ -0,0 +1,447 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyNl/KjOshENtrwKt/IdwaUO", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Loss functions part III\n", + "\n", + "This practical investigates loss functions. In part I we investigated univariate regression (where the output data $y$ is continuous. Our formulation was based on the normal/Gaussian distribution.\n", + "In part II we investigated binary classification (where the output data is 0 or 1). This will be based on the Bernoulli distribution.

\n", + "\n", + "Now we'll investigate multiclass classification (where the outputs data can take multiple values 1,... K, which is based on the categorical distribution\n", + "\n", + "We'll compute loss functions with maximum likelihood and minimum negative log likelihood." + ], + "metadata": { + "id": "jSlFkICHwHQF" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PYMZ1x-Pv1ht" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Used for repmat\n", + "import numpy.matlib\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt\n", + "# Import math Library\n", + "import math" + ] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation\n", + "\n", + "# Define a shallow neural network\n", + "def shallow_nn(x, beta_0, omega_0, beta_1, omaga_1):\n", + " # Make sure that input data is (1 x n_data) array\n", + " n_data = x.size\n", + " x = np.reshape(x,(1,n_data))\n", + "\n", + " # This runs the network for ALL of the inputs, x at once so we can draw graph\n", + " h1 = ReLU(np.matmul(beta_0,np.ones((1,n_data))) + np.matmul(omega_0,x))\n", + " model_out = np.matmul(beta_1,np.ones((1,n_data))) + np.matmul(omega_1,h1)\n", + " return model_out" + ], + "metadata": { + "id": "Fv7SZR3tv7mV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Utility function for plotting data\n", + "def plot_multiclass_classification(x_model, out_model, lambda_model, x_data = None, y_data = None, title= None):\n", + " # Make sure model data are 1D arrays\n", + " n_data = len(x_model)\n", + " n_class = 3\n", + " x_model = np.squeeze(x_model)\n", + " out_model = np.reshape(out_model, (n_class,n_data))\n", + " lambda_model = np.reshape(lambda_model, (n_class,n_data))\n", + "\n", + " fig, ax = plt.subplots(1,2)\n", + " fig.set_size_inches(7.0, 3.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0].plot(x_model,out_model[0,:],'r-')\n", + " ax[0].plot(x_model,out_model[1,:],'g-')\n", + " ax[0].plot(x_model,out_model[2,:],'b-')\n", + " ax[0].set_xlabel('Input, $x$'); ax[0].set_ylabel('Model outputs')\n", + " ax[0].set_xlim([0,1]);ax[0].set_ylim([-4,4])\n", + " if title is not None:\n", + " ax[0].set_title(title)\n", + " ax[1].plot(x_model,lambda_model[0,:],'r-')\n", + " ax[1].plot(x_model,lambda_model[1,:],'g-')\n", + " ax[1].plot(x_model,lambda_model[2,:],'b-')\n", + " ax[1].set_xlabel('Input, $x$'); ax[1].set_ylabel('$\\lambda$ or Pr(y=1|x)')\n", + " ax[1].set_xlim([0,1]);ax[1].set_ylim([-0.1,1.05])\n", + " if title is not None:\n", + " ax[1].set_title(title)\n", + " if x_data is not None:\n", + " for i in range(len(x_data)):\n", + " if y_data[i] ==0:\n", + " ax[1].plot(x_data[i],-0.05, 'r.')\n", + " if y_data[i] ==1:\n", + " ax[1].plot(x_data[i],-0.05, 'g.')\n", + " if y_data[i] ==2:\n", + " ax[1].plot(x_data[i],-0.05, 'b.')\n", + " plt.show()" + ], + "metadata": { + "id": "NRR67ri_1TzN" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Multiclass classification" + ], + "metadata": { + "id": "PsgLZwsPxauP" + } + }, + { + "cell_type": "code", + "source": [ + "# Get parameters for model -- we can call this function to easily reset them\n", + "def get_parameters():\n", + " # And we'll create a network that approximately fits it\n", + " beta_0 = np.zeros((3,1)); # formerly theta_x0\n", + " omega_0 = np.zeros((3,1)); # formerly theta_x1\n", + " beta_1 = np.zeros((3,1)); # NOTE -- there are three outputs now (one for each class, so three output biases)\n", + " omega_1 = np.zeros((3,3)); # NOTE -- there are three outputs now (one for each class, so nine output weights, connecting 3 hidden units to 3 outputs)\n", + "\n", + " beta_0[0,0] = 0.3; beta_0[1,0] = -1.0; beta_0[2,0] = -0.5\n", + " omega_0[0,0] = -1.0; omega_0[1,0] = 1.8; omega_0[2,0] = 0.65\n", + " beta_1[0,0] = 2.0; beta_1[1,0] = -2; beta_1[2,0] = 0.0\n", + " omega_1[0,0] = -24.0; omega_1[0,1] = -8.0; omega_1[0,2] = 50.0\n", + " omega_1[1,0] = -2.0; omega_1[1,1] = 8.0; omega_1[1,2] = -30.0\n", + " omega_1[2,0] = 16.0; omega_1[2,1] = -8.0; omega_1[2,2] =-8\n", + "\n", + " return beta_0, omega_0, beta_1, omega_1" + ], + "metadata": { + "id": "pUT9Ain_HRim" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Softmax function that maps a vector of arbitrary values to a vector of values that are positive and sum to one.\n", + "def softmax(model_out):\n", + " # This operation has to be done separately for every column of the input\n", + " # Compute exponentials of all the elements\n", + " exp_model_out = np.exp(model_out);\n", + " # Sum down the columns\n", + " sum_exp_model_out = np.sum(exp_model_out, axis =0)\n", + " # Divide to normalize\n", + " softmax_model_out = exp_model_out/np.matlib.repmat(sum_exp_model_out, exp_model_out.shape[0], 1)\n", + " return softmax_model_out" + ], + "metadata": { + "id": "uFb8h-9IXnIe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's create some 1D training data\n", + "x_train = np.array([0.09291784,0.46809093,0.93089486,0.67612654,0.73441752,0.86847339,\\\n", + " 0.49873225,0.51083168,0.18343972,0.99380898,0.27840809,0.38028817,\\\n", + " 0.12055708,0.56715537,0.92005746,0.77072270,0.85278176,0.05315950,\\\n", + " 0.87168699,0.58858043])\n", + "y_train = np.array([2,0,1,2,1,0,\\\n", + " 0,2,2,0,2,0,\\\n", + " 2,0,1,2,1,2, \\\n", + " 1,0])\n", + "\n", + "# Get parameters for the model\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "\n", + "# Define a range of input values\n", + "x_model = np.arange(0,1,0.01)\n", + "# Run the model to get values to plot and plot it.\n", + "model_out= shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_model = softmax(model_out)\n", + "plot_multiclass_classification(x_model, model_out, lambda_model, x_train, y_train)\n" + ], + "metadata": { + "id": "VWzNOt1swFVd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The left is model output and the right is the model output after the softmax has been applied, so it now lies in the range [0,1] and represents the probability, that y=0 (red), 1 (green) and 2 (blue) The dots at the bottom show the training data with the same color scheme. So we want the red curve to be high where there are red dots, the green curve to be high where there are green dotsmand the blue curve to be high where there are blue dots We'll compute the the likelihood and the negative log likelihood." + ], + "metadata": { + "id": "MvVX6tl9AEXF" + } + }, + { + "cell_type": "code", + "source": [ + "# Return probability under Bernoulli distribution for input x\n", + "# Complicated code to compute it but just take value from row k of lambda param where y =k, \n", + "def categorical_distribution(y, lambda_param):\n", + " prob = np.zeros_like(y)\n", + " for row_index in range(lambda_param.shape[0]):\n", + " prob = prob + ((y==row_index).astype(int)) * lambda_param[row_index,:]\n", + " return prob" + ], + "metadata": { + "id": "YaLdRlEX0FkU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.2,categorical_distribution(np.array([[0]]),np.array([[0.2],[0.5],[0.3]]))))\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.5,categorical_distribution(np.array([[1]]),np.array([[0.2],[0.5],[0.3]]))))\n", + "print(\"Correct answer = %3.3f, Your answer = %3.3f\"%(0.3,categorical_distribution(np.array([[2]]),np.array([[0.2],[0.5],[0.3]]))))\n", + "\n" + ], + "metadata": { + "id": "4TSL14dqHHbV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the likelihood using this function" + ], + "metadata": { + "id": "R5z_0dzQMF35" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the likelihood of all of the data under the model\n", + "def compute_likelihood(y_train, lambda_param):\n", + " # TODO -- compute the likelihood of the data -- the product of the categorical probabilities for each data point\n", + " # Top line of equation 5.3 in the notes\n", + " # You will need np.prod() and the categorical_distribution function you used above\n", + " # Replace the line below\n", + " likelihood = 0\n", + " return likelihood" + ], + "metadata": { + "id": "zpS7o6liCx7f" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this \n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_train = softmax(model_out)\n", + "# Compute the likelihood\n", + "likelihood = compute_likelihood(y_train, lambda_train)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(0.000000041,likelihood))" + ], + "metadata": { + "id": "1hQxBLoVNlr2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "You can see that this gives a very small answer, even for this small 1D dataset, and with the model fitting quite well. This is because it is the product of several probabilities, which are all quite small themselves.\n", + "This will get out of hand pretty quickly with real datasets -- the likelihood will get so small that we can't represent it with normal finite-precision math\n", + "\n", + "This is why we use negative log likelihood" + ], + "metadata": { + "id": "HzphKgPfOvlk" + } + }, + { + "cell_type": "code", + "source": [ + "# Return the negative log likelihood of the data under the model\n", + "def compute_negative_log_likelihood(y_train, lambda_param):\n", + " # TODO -- compute the likelihood of the data -- don't use the likelihood function above -- compute the negative sum of the log probabilities\n", + " # You will need np.sum(), np.log()\n", + " # Replace the line below\n", + " nll = 0\n", + " return nll" + ], + "metadata": { + "id": "dsT0CWiKBmTV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's test this \n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "# Use our neural network to predict the mean of the Gaussian\n", + "model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + "# Set the standard deviation to something reasonable\n", + "lambda_train = softmax(model_out)\n", + "# Compute the log likelihood\n", + "nll = compute_negative_log_likelihood(y_train, lambda_train)\n", + "# Let's double check we get the right answer before proceeding\n", + "print(\"Correct answer = %9.9f, Your answer = %9.9f\"%(17.015457867,nll))" + ], + "metadata": { + "id": "nVxUXg9rQmwI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's investigate finding the maximum likelihood / minimum log likelihood / least squares solution. For simplicity, we'll assume that all the parameters are fixed except one and look at how the likelihood and log likelihood change as we manipulate the last parameter. We'll start with overall y_offset, beta_1 (formerly phi_0)" + ], + "metadata": { + "id": "OgcRojvPWh4V" + } + }, + { + "cell_type": "code", + "source": [ + "# Define a range of values for the parameter\n", + "beta_1_vals = np.arange(-2,6.0,0.1)\n", + "# Create some arrays to store the likelihoods, negative log likelihoods\n", + "likelihoods = np.zeros_like(beta_1_vals)\n", + "nlls = np.zeros_like(beta_1_vals)\n", + "\n", + "# Initialise the parameters\n", + "beta_0, omega_0, beta_1, omega_1 = get_parameters()\n", + "for count in range(len(beta_1_vals)):\n", + " # Set the value for the parameter\n", + " beta_1[0,0] = beta_1_vals[count]\n", + " # Run the network with new parameters\n", + " model_out = shallow_nn(x_train, beta_0, omega_0, beta_1, omega_1)\n", + " lambda_train = softmax(model_out)\n", + " # Compute and store the three values\n", + " likelihoods[count] = compute_likelihood(y_train,lambda_train)\n", + " nlls[count] = compute_negative_log_likelihood(y_train, lambda_train)\n", + " # Draw the model for every 20th parameter setting\n", + " if count % 20 == 0:\n", + " # Run the model to get values to plot and plot it.\n", + " model_out = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + " lambda_model = softmax(model_out)\n", + " plot_multiclass_classification(x_model, model_out, lambda_model, x_train, y_train, title=\"beta1[0,0]=%3.3f\"%(beta_1[0,0]))\n" + ], + "metadata": { + "id": "pFKtDaAeVU4U" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now let's plot the likelihood, negative log likelihood, and least squares as a function the value of the offset beta1\n", + "fig, ax = plt.subplots(1,2)\n", + "fig.set_size_inches(10.5, 3.5)\n", + "fig.tight_layout(pad=3.0)\n", + "ax[0].plot(beta_1_vals, likelihoods); ax[0].set_xlabel('beta_1[0,0]'); ax[0].set_ylabel('likelihood')\n", + "ax[1].plot(beta_1_vals, nlls); ax[1].set_xlabel('beta_1[0,0]'); ax[1].set_ylabel('negative log likelihood')\n", + "plt.show()" + ], + "metadata": { + "id": "UHXeTa9MagO6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Hopefully, you can see that the maximum of the likelihood fn is at the same position as the minimum negative log likelihood\n", + "# and the least squares solutions\n", + "# Let's check that:\n", + "print(\"Maximum likelihood = %f, at beta_1=%3.3f\"%( (likelihoods[np.argmax(likelihoods)],beta_1_vals[np.argmax(likelihoods)])))\n", + "print(\"Minimum negative log likelihood = %f, at beta_1=%3.3f\"%( (nlls[np.argmin(nlls)],beta_1_vals[np.argmin(nlls)])))\n", + "\n", + "# Plot the best model\n", + "beta_1[0,0] = beta_1_vals[np.argmin(nlls)]\n", + "model_out = shallow_nn(x_model, beta_0, omega_0, beta_1, omega_1)\n", + "lambda_model = softmax(model_out)\n", + "plot_multiclass_classification(x_model, model_out, lambda_model, x_train, y_train, title=\"beta1[0,0]=%3.3f\"%(beta_1[0,0]))\n" + ], + "metadata": { + "id": "aDEPhddNdN4u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "They both give the same answer. But you can see from the likelihood above that the likelihood is very small unless the parameters are almost correct. So in practice, we would work with the negative log likelihood.

\n", + "\n", + "Again, to fit the full neural model we would vary all of the 16 parameters of the network in the $\\boldsymbol\\beta_{0},\\boldsymbol\\omega_{0},\\boldsymbol\\beta_{1},\\boldsymbol\\omega_{1}$ until we find the combination that have the maximum likelihood / minimum negative log likelihood.

\n", + "\n" + ], + "metadata": { + "id": "771G8N1Vk5A2" + } + } + ] +} diff --git a/CM20315/CM20315_Shallow.ipynb b/CM20315/CM20315_Shallow.ipynb new file mode 100644 index 0000000..f19d29d --- /dev/null +++ b/CM20315/CM20315_Shallow.ipynb @@ -0,0 +1,629 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyOxu3uluisAmtb8nx5pmeKr", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **CM20315 Shallow neural networks**\n", + "\n", + "The purpose of this practical is to gain some familiarity with shallow neural networks. It explores using different numbers of inputs and outputs, hidden units and activation functions.

\n", + "\n", + "In various places you will see the words **\"TO DO\"**. Follow the instructions at these places. If you can't figure out what is going on or how to complete the section, feel free to ask your fellow students or the TAs in the practical session or via Moodle. This does not count toward your final marks, but completing it will help you do well in your coursework and exam and reduce your stress levels later on. \n" + ], + "metadata": { + "id": "1Z6LB4Ybn1oN" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hAM55ZjSncOk" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's first construct the shallow neural network with one input, three hidden units, and one output described in section 4.1 of the book." + ], + "metadata": { + "id": "wQDy9UzXpnf5" + } + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " # TODO write code to implement the ReLU and compute the activation at the \n", + " # hidden unit from the preactivation\n", + " # This should work on every element of the ndarray \"preactivation\" at once\n", + " # One way to do this is with the ndarray \"clip\" function\n", + " # https://numpy.org/doc/stable/reference/generated/numpy.ndarray.clip.html\n", + " activation = np.zeros_like(preactivation);\n", + " return activation" + ], + "metadata": { + "id": "OT7h7sSwpkrt" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Make an array of inputs\n", + "z = np.arange(-5,5,0.1)\n", + "RelU_z = ReLU(z)\n", + "\n", + "# Plot the ReLU function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(z,RelU_z,'r-')\n", + "ax.set_xlim([-5,5]);ax.set_ylim([-5,5])\n", + "ax.set_xlabel('z'); ax.set_ylabel('ReLU[z]')\n", + "ax.set_aspect('equal')\n", + "plt.show" + ], + "metadata": { + "id": "okwJmSw9pVNF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a shallow neural network with, one input, one output, and three hidden units\n", + "def shallow_1_1_3(x, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31):\n", + " # TODO Replace the lines below to compute the three initial lines \n", + " # (figure 3.3a-c) from the theta parameters. These are the preactivations\n", + " pre_1 = np.zeros_like(x)\n", + " pre_2 = np.zeros_like(x)\n", + " pre_3 = np.zeros_like(x)\n", + " # Pass these through the ReLU function to compute the activations as in \n", + " # figure 3.3 d-f\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + " # TODO Replace the code below to weight the activations using phi1, phi2 and phi3\n", + " # To create the equivalent of figure 3.3 g-i\n", + " w_act_1 = np.zeros_like(x)\n", + " w_act_2 = np.zeros_like(x)\n", + " w_act_3 = np.zeros_like(x)\n", + " # TODO Replace the code below to combing the weighted activations and add \n", + " # phi_0 to create the output as in figure 3.3 j\n", + " y = np.zeros_like(x)\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ], + "metadata": { + "id": "epk68ZCBu7uJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the shallow neural network. We'll assume input in is range [0,1] and output [-1,1]\n", + "# If the plot_all flag is set to true, then we'll plot all the intermediate stages as in Figure 3.3 \n", + "def plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False, x_data=None, y_data=None):\n", + "\n", + " # Plot intermediate plots if flag set\n", + " if plot_all:\n", + " fig, ax = plt.subplots(3,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0,0].plot(x,pre_1,'r-'); ax[0,0].set_ylabel('Preactivation')\n", + " ax[0,1].plot(x,pre_2,'b-'); ax[0,1].set_ylabel('Preactivation')\n", + " ax[0,2].plot(x,pre_3,'g-'); ax[0,2].set_ylabel('Preactivation')\n", + " ax[1,0].plot(x,act_1,'r-'); ax[1,0].set_ylabel('Activation')\n", + " ax[1,1].plot(x,act_2,'b-'); ax[1,1].set_ylabel('Activation')\n", + " ax[1,2].plot(x,act_3,'g-'); ax[1,2].set_ylabel('Activation')\n", + " ax[2,0].plot(x,w_act_1,'r-'); ax[2,0].set_ylabel('Weighted Act')\n", + " ax[2,1].plot(x,w_act_2,'b-'); ax[2,1].set_ylabel('Weighted Act')\n", + " ax[2,2].plot(x,w_act_3,'g-'); ax[2,2].set_ylabel('Weighted Act')\n", + "\n", + " for plot_y in range(3):\n", + " for plot_x in range(3):\n", + " ax[plot_y,plot_x].set_xlim([0,1]);ax[plot_x,plot_y].set_ylim([-1,1])\n", + " ax[plot_y,plot_x].set_aspect(0.5)\n", + " ax[2,plot_y].set_xlabel('Input, $x$');\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x,y)\n", + " ax.set_xlabel('Input, $y$'); ax.set_ylabel('Output, $y$')\n", + " ax.set_xlim([0,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(0.5)\n", + " if x_data is not None:\n", + " ax.plot(x_data, y_data, 'mo')\n", + " plt.show()" + ], + "metadata": { + "id": "CAr7n1lixuhQ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's run the neural network. If your code is correct, then the final output should look like this:\n", + "![Correct nn output.svg](data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPCEtLSBDcmVhdGVkIHdpdGggbWF0cGxvdGxpYiAoaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pIC0tPgo8c3ZnIGhlaWdodD0iMjg4cHQiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDQzMiAyODgiIHdpZHRoPSI0MzJwdCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiA8ZGVmcz4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoqe3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO30KICA8L3N0eWxlPgogPC9kZWZzPgogPGcgaWQ9ImZpZ3VyZV8xIj4KICA8ZyBpZD0icGF0Y2hfMSI+CiAgIDxwYXRoIGQ9Ik0gMCAyODggCkwgNDMyIDI4OCAKTCA0MzIgMCAKTCAwIDAgCnoKIiBzdHlsZT0iZmlsbDojZmZmZmZmOyIvPgogIDwvZz4KICA8ZyBpZD0iYXhlc18xIj4KICAgPGcgaWQ9InBhdGNoXzIiPgogICAgPHBhdGggZD0iTSAxMTIuNjggMjUyIApMIDMzMC4xMiAyNTIgCkwgMzMwLjEyIDM0LjU2IApMIDExMi42OCAzNC41NiAKegoiIHN0eWxlPSJmaWxsOiNmZmZmZmY7Ii8+CiAgIDwvZz4KICAgPGcgaWQ9Im1hdHBsb3RsaWIuYXhpc18xIj4KICAgIDxnIGlkPSJ4dGlja18xIj4KICAgICA8ZyBpZD0ibGluZTJkXzEiPgogICAgICA8ZGVmcz4KICAgICAgIDxwYXRoIGQ9Ik0gMCAwIApMIDAgMy41IAoiIGlkPSJtMWRhYTNiZmM1MCIgc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7Ii8+CiAgICAgIDwvZGVmcz4KICAgICAgPGc+CiAgICAgICA8dXNlIHN0eWxlPSJzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC44OyIgeD0iMTEyLjY4IiB4bGluazpocmVmPSIjbTFkYWEzYmZjNTAiIHk9IjI1MiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGlkPSJ0ZXh0XzEiPgogICAgICA8IS0tIDAuMCAtLT4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDMxLjc4MTI1IDY2LjQwNjI1IApRIDI0LjE3MTg3NSA2Ni40MDYyNSAyMC4zMjgxMjUgNTguOTA2MjUgClEgMTYuNSA1MS40MjE4NzUgMTYuNSAzNi4zNzUgClEgMTYuNSAyMS4zOTA2MjUgMjAuMzI4MTI1IDEzLjg5MDYyNSAKUSAyNC4xNzE4NzUgNi4zOTA2MjUgMzEuNzgxMjUgNi4zOTA2MjUgClEgMzkuNDUzMTI1IDYuMzkwNjI1IDQzLjI4MTI1IDEzLjg5MDYyNSAKUSA0Ny4xMjUgMjEuMzkwNjI1IDQ3LjEyNSAzNi4zNzUgClEgNDcuMTI1IDUxLjQyMTg3NSA0My4yODEyNSA1OC45MDYyNSAKUSAzOS40NTMxMjUgNjYuNDA2MjUgMzEuNzgxMjUgNjYuNDA2MjUgCnoKTSAzMS43ODEyNSA3NC4yMTg3NSAKUSA0NC4wNDY4NzUgNzQuMjE4NzUgNTAuNTE1NjI1IDY0LjUxNTYyNSAKUSA1Ni45ODQzNzUgNTQuODI4MTI1IDU2Ljk4NDM3NSAzNi4zNzUgClEgNTYuOTg0Mzc1IDE3Ljk2ODc1IDUwLjUxNTYyNSA4LjI2NTYyNSAKUSA0NC4wNDY4NzUgLTEuNDIxODc1IDMxLjc4MTI1IC0xLjQyMTg3NSAKUSAxOS41MzEyNSAtMS40MjE4NzUgMTMuMDYyNSA4LjI2NTYyNSAKUSA2LjU5Mzc1IDE3Ljk2ODc1IDYuNTkzNzUgMzYuMzc1IApRIDYuNTkzNzUgNTQuODI4MTI1IDEzLjA2MjUgNjQuNTE1NjI1IApRIDE5LjUzMTI1IDc0LjIxODc1IDMxLjc4MTI1IDc0LjIxODc1IAp6CiIgaWQ9IkRlamFWdVNhbnMtNDgiLz4KICAgICAgIDxwYXRoIGQ9Ik0gMTAuNjg3NSAxMi40MDYyNSAKTCAyMSAxMi40MDYyNSAKTCAyMSAwIApMIDEwLjY4NzUgMCAKegoiIGlkPSJEZWphVnVTYW5zLTQ2Ii8+CiAgICAgIDwvZGVmcz4KICAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTA0LjcyODQzOCAyNjYuNTk4NDM3KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgICA8dXNlIHg9IjYzLjYyMzA0NyIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iOTUuNDEwMTU2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inh0aWNrXzIiPgogICAgIDxnIGlkPSJsaW5lMmRfMiI+CiAgICAgIDxnPgogICAgICAgPHVzZSBzdHlsZT0ic3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuODsiIHg9IjE1Ni4xNjgiIHhsaW5rOmhyZWY9IiNtMWRhYTNiZmM1MCIgeT0iMjUyIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMiI+CiAgICAgIDwhLS0gMC4yIC0tPgogICAgICA8ZGVmcz4KICAgICAgIDxwYXRoIGQ9Ik0gMTkuMTg3NSA4LjI5Njg3NSAKTCA1My42MDkzNzUgOC4yOTY4NzUgCkwgNTMuNjA5Mzc1IDAgCkwgNy4zMjgxMjUgMCAKTCA3LjMyODEyNSA4LjI5Njg3NSAKUSAxMi45Mzc1IDE0LjEwOTM3NSAyMi42MjUgMjMuODkwNjI1IApRIDMyLjMyODEyNSAzMy42ODc1IDM0LjgxMjUgMzYuNTMxMjUgClEgMzkuNTQ2ODc1IDQxLjg0Mzc1IDQxLjQyMTg3NSA0NS41MzEyNSAKUSA0My4zMTI1IDQ5LjIxODc1IDQzLjMxMjUgNTIuNzgxMjUgClEgNDMuMzEyNSA1OC41OTM3NSAzOS4yMzQzNzUgNjIuMjUgClEgMzUuMTU2MjUgNjUuOTIxODc1IDI4LjYwOTM3NSA2NS45MjE4NzUgClEgMjMuOTY4NzUgNjUuOTIxODc1IDE4LjgxMjUgNjQuMzEyNSAKUSAxMy42NzE4NzUgNjIuNzAzMTI1IDcuODEyNSA1OS40MjE4NzUgCkwgNy44MTI1IDY5LjM5MDYyNSAKUSAxMy43NjU2MjUgNzEuNzgxMjUgMTguOTM3NSA3MyAKUSAyNC4xMjUgNzQuMjE4NzUgMjguNDIxODc1IDc0LjIxODc1IApRIDM5Ljc1IDc0LjIxODc1IDQ2LjQ4NDM3NSA2OC41NDY4NzUgClEgNTMuMjE4NzUgNjIuODkwNjI1IDUzLjIxODc1IDUzLjQyMTg3NSAKUSA1My4yMTg3NSA0OC45MjE4NzUgNTEuNTMxMjUgNDQuODkwNjI1IApRIDQ5Ljg1OTM3NSA0MC44NzUgNDUuNDA2MjUgMzUuNDA2MjUgClEgNDQuMTg3NSAzMy45ODQzNzUgMzcuNjQwNjI1IDI3LjIxODc1IApRIDMxLjEwOTM3NSAyMC40NTMxMjUgMTkuMTg3NSA4LjI5Njg3NSAKegoiIGlkPSJEZWphVnVTYW5zLTUwIi8+CiAgICAgIDwvZGVmcz4KICAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQ4LjIxNjQzOCAyNjYuNTk4NDM3KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgICA8dXNlIHg9IjYzLjYyMzA0NyIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iOTUuNDEwMTU2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy01MCIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inh0aWNrXzMiPgogICAgIDxnIGlkPSJsaW5lMmRfMyI+CiAgICAgIDxnPgogICAgICAgPHVzZSBzdHlsZT0ic3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuODsiIHg9IjE5OS42NTYiIHhsaW5rOmhyZWY9IiNtMWRhYTNiZmM1MCIgeT0iMjUyIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMyI+CiAgICAgIDwhLS0gMC40IC0tPgogICAgICA8ZGVmcz4KICAgICAgIDxwYXRoIGQ9Ik0gMzcuNzk2ODc1IDY0LjMxMjUgCkwgMTIuODkwNjI1IDI1LjM5MDYyNSAKTCAzNy43OTY4NzUgMjUuMzkwNjI1IAp6Ck0gMzUuMjAzMTI1IDcyLjkwNjI1IApMIDQ3LjYwOTM3NSA3Mi45MDYyNSAKTCA0Ny42MDkzNzUgMjUuMzkwNjI1IApMIDU4LjAxNTYyNSAyNS4zOTA2MjUgCkwgNTguMDE1NjI1IDE3LjE4NzUgCkwgNDcuNjA5Mzc1IDE3LjE4NzUgCkwgNDcuNjA5Mzc1IDAgCkwgMzcuNzk2ODc1IDAgCkwgMzcuNzk2ODc1IDE3LjE4NzUgCkwgNC44OTA2MjUgMTcuMTg3NSAKTCA0Ljg5MDYyNSAyNi43MDMxMjUgCnoKIiBpZD0iRGVqYVZ1U2Fucy01MiIvPgogICAgICA8L2RlZnM+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE5MS43MDQ0MzggMjY2LjU5ODQzNylzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSI2My42MjMwNDciIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ2Ii8+CiAgICAgICA8dXNlIHg9Ijk1LjQxMDE1NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTIiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ4dGlja180Ij4KICAgICA8ZyBpZD0ibGluZTJkXzQiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIyNDMuMTQ0IiB4bGluazpocmVmPSIjbTFkYWEzYmZjNTAiIHk9IjI1MiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGlkPSJ0ZXh0XzQiPgogICAgICA8IS0tIDAuNiAtLT4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDMzLjAxNTYyNSA0MC4zNzUgClEgMjYuMzc1IDQwLjM3NSAyMi40ODQzNzUgMzUuODI4MTI1IApRIDE4LjYwOTM3NSAzMS4yOTY4NzUgMTguNjA5Mzc1IDIzLjM5MDYyNSAKUSAxOC42MDkzNzUgMTUuNTMxMjUgMjIuNDg0Mzc1IDEwLjk1MzEyNSAKUSAyNi4zNzUgNi4zOTA2MjUgMzMuMDE1NjI1IDYuMzkwNjI1IApRIDM5LjY1NjI1IDYuMzkwNjI1IDQzLjUzMTI1IDEwLjk1MzEyNSAKUSA0Ny40MDYyNSAxNS41MzEyNSA0Ny40MDYyNSAyMy4zOTA2MjUgClEgNDcuNDA2MjUgMzEuMjk2ODc1IDQzLjUzMTI1IDM1LjgyODEyNSAKUSAzOS42NTYyNSA0MC4zNzUgMzMuMDE1NjI1IDQwLjM3NSAKegpNIDUyLjU5Mzc1IDcxLjI5Njg3NSAKTCA1Mi41OTM3NSA2Mi4zMTI1IApRIDQ4Ljg3NSA2NC4wNjI1IDQ1LjA5Mzc1IDY0Ljk4NDM3NSAKUSA0MS4zMTI1IDY1LjkyMTg3NSAzNy41OTM3NSA2NS45MjE4NzUgClEgMjcuODI4MTI1IDY1LjkyMTg3NSAyMi42NzE4NzUgNTkuMzI4MTI1IApRIDE3LjUzMTI1IDUyLjczNDM3NSAxNi43OTY4NzUgMzkuNDA2MjUgClEgMTkuNjcxODc1IDQzLjY1NjI1IDI0LjAxNTYyNSA0NS45MjE4NzUgClEgMjguMzc1IDQ4LjE4NzUgMzMuNTkzNzUgNDguMTg3NSAKUSA0NC41NzgxMjUgNDguMTg3NSA1MC45NTMxMjUgNDEuNTE1NjI1IApRIDU3LjMyODEyNSAzNC44NTkzNzUgNTcuMzI4MTI1IDIzLjM5MDYyNSAKUSA1Ny4zMjgxMjUgMTIuMTU2MjUgNTAuNjg3NSA1LjM1OTM3NSAKUSA0NC4wNDY4NzUgLTEuNDIxODc1IDMzLjAxNTYyNSAtMS40MjE4NzUgClEgMjAuMzU5Mzc1IC0xLjQyMTg3NSAxMy42NzE4NzUgOC4yNjU2MjUgClEgNi45ODQzNzUgMTcuOTY4NzUgNi45ODQzNzUgMzYuMzc1IApRIDYuOTg0Mzc1IDUzLjY1NjI1IDE1LjE4NzUgNjMuOTM3NSAKUSAyMy4zOTA2MjUgNzQuMjE4NzUgMzcuMjAzMTI1IDc0LjIxODc1IApRIDQwLjkyMTg3NSA3NC4yMTg3NSA0NC43MDMxMjUgNzMuNDg0Mzc1IApRIDQ4LjQ4NDM3NSA3Mi43NSA1Mi41OTM3NSA3MS4yOTY4NzUgCnoKIiBpZD0iRGVqYVZ1U2Fucy01NCIvPgogICAgICA8L2RlZnM+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIzNS4xOTI0MzggMjY2LjU5ODQzNylzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSI2My42MjMwNDciIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ2Ii8+CiAgICAgICA8dXNlIHg9Ijk1LjQxMDE1NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTQiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ4dGlja181Ij4KICAgICA8ZyBpZD0ibGluZTJkXzUiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIyODYuNjMyIiB4bGluazpocmVmPSIjbTFkYWEzYmZjNTAiIHk9IjI1MiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGlkPSJ0ZXh0XzUiPgogICAgICA8IS0tIDAuOCAtLT4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDMxLjc4MTI1IDM0LjYyNSAKUSAyNC43NSAzNC42MjUgMjAuNzE4NzUgMzAuODU5Mzc1IApRIDE2LjcwMzEyNSAyNy4wOTM3NSAxNi43MDMxMjUgMjAuNTE1NjI1IApRIDE2LjcwMzEyNSAxMy45MjE4NzUgMjAuNzE4NzUgMTAuMTU2MjUgClEgMjQuNzUgNi4zOTA2MjUgMzEuNzgxMjUgNi4zOTA2MjUgClEgMzguODEyNSA2LjM5MDYyNSA0Mi44NTkzNzUgMTAuMTcxODc1IApRIDQ2LjkyMTg3NSAxMy45Njg3NSA0Ni45MjE4NzUgMjAuNTE1NjI1IApRIDQ2LjkyMTg3NSAyNy4wOTM3NSA0Mi44OTA2MjUgMzAuODU5Mzc1IApRIDM4Ljg3NSAzNC42MjUgMzEuNzgxMjUgMzQuNjI1IAp6Ck0gMjEuOTIxODc1IDM4LjgxMjUgClEgMTUuNTc4MTI1IDQwLjM3NSAxMi4wMzEyNSA0NC43MTg3NSAKUSA4LjUgNDkuMDc4MTI1IDguNSA1NS4zMjgxMjUgClEgOC41IDY0LjA2MjUgMTQuNzE4NzUgNjkuMTQwNjI1IApRIDIwLjk1MzEyNSA3NC4yMTg3NSAzMS43ODEyNSA3NC4yMTg3NSAKUSA0Mi42NzE4NzUgNzQuMjE4NzUgNDguODc1IDY5LjE0MDYyNSAKUSA1NS4wNzgxMjUgNjQuMDYyNSA1NS4wNzgxMjUgNTUuMzI4MTI1IApRIDU1LjA3ODEyNSA0OS4wNzgxMjUgNTEuNTMxMjUgNDQuNzE4NzUgClEgNDggNDAuMzc1IDQxLjcwMzEyNSAzOC44MTI1IApRIDQ4LjgyODEyNSAzNy4xNTYyNSA1Mi43OTY4NzUgMzIuMzEyNSAKUSA1Ni43ODEyNSAyNy40ODQzNzUgNTYuNzgxMjUgMjAuNTE1NjI1IApRIDU2Ljc4MTI1IDkuOTA2MjUgNTAuMzEyNSA0LjIzNDM3NSAKUSA0My44NDM3NSAtMS40MjE4NzUgMzEuNzgxMjUgLTEuNDIxODc1IApRIDE5LjczNDM3NSAtMS40MjE4NzUgMTMuMjUgNC4yMzQzNzUgClEgNi43ODEyNSA5LjkwNjI1IDYuNzgxMjUgMjAuNTE1NjI1IApRIDYuNzgxMjUgMjcuNDg0Mzc1IDEwLjc4MTI1IDMyLjMxMjUgClEgMTQuNzk2ODc1IDM3LjE1NjI1IDIxLjkyMTg3NSAzOC44MTI1IAp6Ck0gMTguMzEyNSA1NC4zOTA2MjUgClEgMTguMzEyNSA0OC43MzQzNzUgMjEuODQzNzUgNDUuNTYyNSAKUSAyNS4zOTA2MjUgNDIuMzkwNjI1IDMxLjc4MTI1IDQyLjM5MDYyNSAKUSAzOC4xNDA2MjUgNDIuMzkwNjI1IDQxLjcxODc1IDQ1LjU2MjUgClEgNDUuMzEyNSA0OC43MzQzNzUgNDUuMzEyNSA1NC4zOTA2MjUgClEgNDUuMzEyNSA2MC4wNjI1IDQxLjcxODc1IDYzLjIzNDM3NSAKUSAzOC4xNDA2MjUgNjYuNDA2MjUgMzEuNzgxMjUgNjYuNDA2MjUgClEgMjUuMzkwNjI1IDY2LjQwNjI1IDIxLjg0Mzc1IDYzLjIzNDM3NSAKUSAxOC4zMTI1IDYwLjA2MjUgMTguMzEyNSA1NC4zOTA2MjUgCnoKIiBpZD0iRGVqYVZ1U2Fucy01NiIvPgogICAgICA8L2RlZnM+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI3OC42ODA0MzcgMjY2LjU5ODQzNylzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSI2My42MjMwNDciIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ2Ii8+CiAgICAgICA8dXNlIHg9Ijk1LjQxMDE1NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTYiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ4dGlja182Ij4KICAgICA8ZyBpZD0ibGluZTJkXzYiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIzMzAuMTIiIHhsaW5rOmhyZWY9IiNtMWRhYTNiZmM1MCIgeT0iMjUyIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfNiI+CiAgICAgIDwhLS0gMS4wIC0tPgogICAgICA8ZGVmcz4KICAgICAgIDxwYXRoIGQ9Ik0gMTIuNDA2MjUgOC4yOTY4NzUgCkwgMjguNTE1NjI1IDguMjk2ODc1IApMIDI4LjUxNTYyNSA2My45MjE4NzUgCkwgMTAuOTg0Mzc1IDYwLjQwNjI1IApMIDEwLjk4NDM3NSA2OS4zOTA2MjUgCkwgMjguNDIxODc1IDcyLjkwNjI1IApMIDM4LjI4MTI1IDcyLjkwNjI1IApMIDM4LjI4MTI1IDguMjk2ODc1IApMIDU0LjM5MDYyNSA4LjI5Njg3NSAKTCA1NC4zOTA2MjUgMCAKTCAxMi40MDYyNSAwIAp6CiIgaWQ9IkRlamFWdVNhbnMtNDkiLz4KICAgICAgPC9kZWZzPgogICAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMjIuMTY4NDM3IDI2Ni41OTg0Mzcpc2NhbGUoMC4xIC0wLjEpIj4KICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDkiLz4KICAgICAgIDx1c2UgeD0iNjMuNjIzMDQ3IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00NiIvPgogICAgICAgPHVzZSB4PSI5NS40MTAxNTYiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZyBpZD0idGV4dF83Ij4KICAgICA8IS0tIElucHV0LCAkeSQgLS0+CiAgICAgPGRlZnM+CiAgICAgIDxwYXRoIGQ9Ik0gOS44MTI1IDcyLjkwNjI1IApMIDE5LjY3MTg3NSA3Mi45MDYyNSAKTCAxOS42NzE4NzUgMCAKTCA5LjgxMjUgMCAKegoiIGlkPSJEZWphVnVTYW5zLTczIi8+CiAgICAgIDxwYXRoIGQ9Ik0gNTQuODkwNjI1IDMzLjAxNTYyNSAKTCA1NC44OTA2MjUgMCAKTCA0NS45MDYyNSAwIApMIDQ1LjkwNjI1IDMyLjcxODc1IApRIDQ1LjkwNjI1IDQwLjQ4NDM3NSA0Mi44NzUgNDQuMzI4MTI1IApRIDM5Ljg0Mzc1IDQ4LjE4NzUgMzMuNzk2ODc1IDQ4LjE4NzUgClEgMjYuNTE1NjI1IDQ4LjE4NzUgMjIuMzEyNSA0My41NDY4NzUgClEgMTguMTA5Mzc1IDM4LjkyMTg3NSAxOC4xMDkzNzUgMzAuOTA2MjUgCkwgMTguMTA5Mzc1IDAgCkwgOS4wNzgxMjUgMCAKTCA5LjA3ODEyNSA1NC42ODc1IApMIDE4LjEwOTM3NSA1NC42ODc1IApMIDE4LjEwOTM3NSA0Ni4xODc1IApRIDIxLjM0Mzc1IDUxLjEyNSAyNS43MDMxMjUgNTMuNTYyNSAKUSAzMC4wNzgxMjUgNTYgMzUuNzk2ODc1IDU2IApRIDQ1LjIxODc1IDU2IDUwLjA0Njg3NSA1MC4xNzE4NzUgClEgNTQuODkwNjI1IDQ0LjM0Mzc1IDU0Ljg5MDYyNSAzMy4wMTU2MjUgCnoKIiBpZD0iRGVqYVZ1U2Fucy0xMTAiLz4KICAgICAgPHBhdGggZD0iTSAxOC4xMDkzNzUgOC4yMDMxMjUgCkwgMTguMTA5Mzc1IC0yMC43OTY4NzUgCkwgOS4wNzgxMjUgLTIwLjc5Njg3NSAKTCA5LjA3ODEyNSA1NC42ODc1IApMIDE4LjEwOTM3NSA1NC42ODc1IApMIDE4LjEwOTM3NSA0Ni4zOTA2MjUgClEgMjAuOTUzMTI1IDUxLjI2NTYyNSAyNS4yNjU2MjUgNTMuNjI1IApRIDI5LjU5Mzc1IDU2IDM1LjU5Mzc1IDU2IApRIDQ1LjU2MjUgNTYgNTEuNzgxMjUgNDguMDkzNzUgClEgNTguMDE1NjI1IDQwLjE4NzUgNTguMDE1NjI1IDI3LjI5Njg3NSAKUSA1OC4wMTU2MjUgMTQuNDA2MjUgNTEuNzgxMjUgNi40ODQzNzUgClEgNDUuNTYyNSAtMS40MjE4NzUgMzUuNTkzNzUgLTEuNDIxODc1IApRIDI5LjU5Mzc1IC0xLjQyMTg3NSAyNS4yNjU2MjUgMC45NTMxMjUgClEgMjAuOTUzMTI1IDMuMzI4MTI1IDE4LjEwOTM3NSA4LjIwMzEyNSAKegpNIDQ4LjY4NzUgMjcuMjk2ODc1IApRIDQ4LjY4NzUgMzcuMjAzMTI1IDQ0LjYwOTM3NSA0Mi44NDM3NSAKUSA0MC41MzEyNSA0OC40ODQzNzUgMzMuNDA2MjUgNDguNDg0Mzc1IApRIDI2LjI2NTYyNSA0OC40ODQzNzUgMjIuMTg3NSA0Mi44NDM3NSAKUSAxOC4xMDkzNzUgMzcuMjAzMTI1IDE4LjEwOTM3NSAyNy4yOTY4NzUgClEgMTguMTA5Mzc1IDE3LjM5MDYyNSAyMi4xODc1IDExLjc1IApRIDI2LjI2NTYyNSA2LjEwOTM3NSAzMy40MDYyNSA2LjEwOTM3NSAKUSA0MC41MzEyNSA2LjEwOTM3NSA0NC42MDkzNzUgMTEuNzUgClEgNDguNjg3NSAxNy4zOTA2MjUgNDguNjg3NSAyNy4yOTY4NzUgCnoKIiBpZD0iRGVqYVZ1U2Fucy0xMTIiLz4KICAgICAgPHBhdGggZD0iTSA4LjUgMjEuNTc4MTI1IApMIDguNSA1NC42ODc1IApMIDE3LjQ4NDM3NSA1NC42ODc1IApMIDE3LjQ4NDM3NSAyMS45MjE4NzUgClEgMTcuNDg0Mzc1IDE0LjE1NjI1IDIwLjUgMTAuMjY1NjI1IApRIDIzLjUzMTI1IDYuMzkwNjI1IDI5LjU5Mzc1IDYuMzkwNjI1IApRIDM2Ljg1OTM3NSA2LjM5MDYyNSA0MS4wNzgxMjUgMTEuMDMxMjUgClEgNDUuMzEyNSAxNS42NzE4NzUgNDUuMzEyNSAyMy42ODc1IApMIDQ1LjMxMjUgNTQuNjg3NSAKTCA1NC4yOTY4NzUgNTQuNjg3NSAKTCA1NC4yOTY4NzUgMCAKTCA0NS4zMTI1IDAgCkwgNDUuMzEyNSA4LjQwNjI1IApRIDQyLjA0Njg3NSAzLjQyMTg3NSAzNy43MTg3NSAxIApRIDMzLjQwNjI1IC0xLjQyMTg3NSAyNy42ODc1IC0xLjQyMTg3NSAKUSAxOC4yNjU2MjUgLTEuNDIxODc1IDEzLjM3NSA0LjQzNzUgClEgOC41IDEwLjI5Njg3NSA4LjUgMjEuNTc4MTI1IAp6Ck0gMzEuMTA5Mzc1IDU2IAp6CiIgaWQ9IkRlamFWdVNhbnMtMTE3Ii8+CiAgICAgIDxwYXRoIGQ9Ik0gMTguMzEyNSA3MC4yMTg3NSAKTCAxOC4zMTI1IDU0LjY4NzUgCkwgMzYuODEyNSA1NC42ODc1IApMIDM2LjgxMjUgNDcuNzAzMTI1IApMIDE4LjMxMjUgNDcuNzAzMTI1IApMIDE4LjMxMjUgMTguMDE1NjI1IApRIDE4LjMxMjUgMTEuMzI4MTI1IDIwLjE0MDYyNSA5LjQyMTg3NSAKUSAyMS45Njg3NSA3LjUxNTYyNSAyNy41OTM3NSA3LjUxNTYyNSAKTCAzNi44MTI1IDcuNTE1NjI1IApMIDM2LjgxMjUgMCAKTCAyNy41OTM3NSAwIApRIDE3LjE4NzUgMCAxMy4yMzQzNzUgMy44NzUgClEgOS4yODEyNSA3Ljc2NTYyNSA5LjI4MTI1IDE4LjAxNTYyNSAKTCA5LjI4MTI1IDQ3LjcwMzEyNSAKTCAyLjY4NzUgNDcuNzAzMTI1IApMIDIuNjg3NSA1NC42ODc1IApMIDkuMjgxMjUgNTQuNjg3NSAKTCA5LjI4MTI1IDcwLjIxODc1IAp6CiIgaWQ9IkRlamFWdVNhbnMtMTE2Ii8+CiAgICAgIDxwYXRoIGQ9Ik0gMTEuNzE4NzUgMTIuNDA2MjUgCkwgMjIuMDE1NjI1IDEyLjQwNjI1IApMIDIyLjAxNTYyNSA0IApMIDE0LjAxNTYyNSAtMTEuNjI1IApMIDcuNzE4NzUgLTExLjYyNSAKTCAxMS43MTg3NSA0IAp6CiIgaWQ9IkRlamFWdVNhbnMtNDQiLz4KICAgICAgPHBhdGggaWQ9IkRlamFWdVNhbnMtMzIiLz4KICAgICAgPHBhdGggZD0iTSAyNC44MTI1IC01LjA3ODEyNSAKUSAxOC41NjI1IC0xNS41NzgxMjUgMTQuNjI1IC0xOC4xODc1IApRIDEwLjY4NzUgLTIwLjc5Njg3NSA0LjU5Mzc1IC0yMC43OTY4NzUgCkwgLTIuNDg0Mzc1IC0yMC43OTY4NzUgCkwgLTAuOTg0Mzc1IC0xMy4yODEyNSAKTCA0LjIwMzEyNSAtMTMuMjgxMjUgClEgNy45NTMxMjUgLTEzLjI4MTI1IDEwLjU5Mzc1IC0xMS4yMzQzNzUgClEgMTMuMjM0Mzc1IC05LjE4NzUgMTYuNSAtMy4yMTg3NSAKTCAxOS4yODEyNSAyIApMIDcuMTcxODc1IDU0LjY4NzUgCkwgMTYuNzAzMTI1IDU0LjY4NzUgCkwgMjUuNzgxMjUgMTIuNzk2ODc1IApMIDUwLjg3NSA1NC42ODc1IApMIDYwLjI5Njg3NSA1NC42ODc1IAp6CiIgaWQ9IkRlamFWdVNhbnMtT2JsaXF1ZS0xMjEiLz4KICAgICA8L2RlZnM+CiAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAyLjMgMjgwLjI1NjI1KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjA5Mzc1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNzMiLz4KICAgICAgPHVzZSB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyOS40OTIxODggMC4wOTM3NSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExMCIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDkyLjg3MTA5NCAwLjA5Mzc1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtMTEyIi8+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTU2LjM0NzY1NiAwLjA5Mzc1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtMTE3Ii8+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjE5LjcyNjU2MiAwLjA5Mzc1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtMTE2Ii8+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjU4LjkzNTU0NyAwLjA5Mzc1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDQiLz4KICAgICAgPHVzZSB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyOTAuNzIyNjU2IDAuMDkzNzUpIiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy0zMiIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMyMi41MDk3NjYgMC4wOTM3NSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLU9ibGlxdWUtMTIxIi8+CiAgICAgPC9nPgogICAgPC9nPgogICA8L2c+CiAgIDxnIGlkPSJtYXRwbG90bGliLmF4aXNfMiI+CiAgICA8ZyBpZD0ieXRpY2tfMSI+CiAgICAgPGcgaWQ9ImxpbmUyZF83Ij4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDAgMCAKTCAtMy41IDAgCiIgaWQ9Im1hNDAwZWU0MmIxIiBzdHlsZT0ic3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuODsiLz4KICAgICAgPC9kZWZzPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMjUyIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfOCI+CiAgICAgIDwhLS0g4oiSMS4wMCAtLT4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDEwLjU5Mzc1IDM1LjUgCkwgNzMuMTg3NSAzNS41IApMIDczLjE4NzUgMjcuMjAzMTI1IApMIDEwLjU5Mzc1IDI3LjIwMzEyNSAKegoiIGlkPSJEZWphVnVTYW5zLTg3MjIiLz4KICAgICAgPC9kZWZzPgogICAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3NS4wMzQ2ODggMjU1Ljc5OTIxOSlzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy04NzIyIi8+CiAgICAgICA8dXNlIHg9IjgzLjc4OTA2MiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDkiLz4KICAgICAgIDx1c2UgeD0iMTQ3LjQxMjEwOSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iMTc5LjE5OTIxOSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDgiLz4KICAgICAgIDx1c2UgeD0iMjQyLjgyMjI2NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDgiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ5dGlja18yIj4KICAgICA8ZyBpZD0ibGluZTJkXzgiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMjI0LjgyIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfOSI+CiAgICAgIDwhLS0g4oiSMC43NSAtLT4KICAgICAgPGRlZnM+CiAgICAgICA8cGF0aCBkPSJNIDguMjAzMTI1IDcyLjkwNjI1IApMIDU1LjA3ODEyNSA3Mi45MDYyNSAKTCA1NS4wNzgxMjUgNjguNzAzMTI1IApMIDI4LjYwOTM3NSAwIApMIDE4LjMxMjUgMCAKTCA0My4yMTg3NSA2NC41OTM3NSAKTCA4LjIwMzEyNSA2NC41OTM3NSAKegoiIGlkPSJEZWphVnVTYW5zLTU1Ii8+CiAgICAgICA8cGF0aCBkPSJNIDEwLjc5Njg3NSA3Mi45MDYyNSAKTCA0OS41MTU2MjUgNzIuOTA2MjUgCkwgNDkuNTE1NjI1IDY0LjU5Mzc1IApMIDE5LjgyODEyNSA2NC41OTM3NSAKTCAxOS44MjgxMjUgNDYuNzM0Mzc1IApRIDIxLjk2ODc1IDQ3LjQ2ODc1IDI0LjEwOTM3NSA0Ny44MjgxMjUgClEgMjYuMjY1NjI1IDQ4LjE4NzUgMjguNDIxODc1IDQ4LjE4NzUgClEgNDAuNjI1IDQ4LjE4NzUgNDcuNzUgNDEuNSAKUSA1NC44OTA2MjUgMzQuODEyNSA1NC44OTA2MjUgMjMuMzkwNjI1IApRIDU0Ljg5MDYyNSAxMS42MjUgNDcuNTYyNSA1LjA5Mzc1IApRIDQwLjIzNDM3NSAtMS40MjE4NzUgMjYuOTA2MjUgLTEuNDIxODc1IApRIDIyLjMxMjUgLTEuNDIxODc1IDE3LjU0Njg3NSAtMC42NDA2MjUgClEgMTIuNzk2ODc1IDAuMTQwNjI1IDcuNzE4NzUgMS43MDMxMjUgCkwgNy43MTg3NSAxMS42MjUgClEgMTIuMTA5Mzc1IDkuMjM0Mzc1IDE2Ljc5Njg3NSA4LjA2MjUgClEgMjEuNDg0Mzc1IDYuODkwNjI1IDI2LjcwMzEyNSA2Ljg5MDYyNSAKUSAzNS4xNTYyNSA2Ljg5MDYyNSA0MC4wNzgxMjUgMTEuMzI4MTI1IApRIDQ1LjAxNTYyNSAxNS43NjU2MjUgNDUuMDE1NjI1IDIzLjM5MDYyNSAKUSA0NS4wMTU2MjUgMzEgNDAuMDc4MTI1IDM1LjQzNzUgClEgMzUuMTU2MjUgMzkuODkwNjI1IDI2LjcwMzEyNSAzOS44OTA2MjUgClEgMjIuNzUgMzkuODkwNjI1IDE4LjgxMjUgMzkuMDE1NjI1IApRIDE0Ljg5MDYyNSAzOC4xNDA2MjUgMTAuNzk2ODc1IDM2LjI4MTI1IAp6CiIgaWQ9IkRlamFWdVNhbnMtNTMiLz4KICAgICAgPC9kZWZzPgogICAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3NS4wMzQ2ODggMjI4LjYxOTIxOSlzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy04NzIyIi8+CiAgICAgICA8dXNlIHg9IjgzLjc4OTA2MiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDgiLz4KICAgICAgIDx1c2UgeD0iMTQ3LjQxMjEwOSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iMTc5LjE5OTIxOSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTUiLz4KICAgICAgIDx1c2UgeD0iMjQyLjgyMjI2NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTMiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ5dGlja18zIj4KICAgICA8ZyBpZD0ibGluZTJkXzkiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMTk3LjY0Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMTAiPgogICAgICA8IS0tIOKIkjAuNTAgLS0+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDc1LjAzNDY4OCAyMDEuNDM5MjE5KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTg3MjIiLz4KICAgICAgIDx1c2UgeD0iODMuNzg5MDYyIiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSIxNDcuNDEyMTA5IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00NiIvPgogICAgICAgPHVzZSB4PSIxNzkuMTk5MjE5IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy01MyIvPgogICAgICAgPHVzZSB4PSIyNDIuODIyMjY2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inl0aWNrXzQiPgogICAgIDxnIGlkPSJsaW5lMmRfMTAiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMTcwLjQ2Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMTEiPgogICAgICA8IS0tIOKIkjAuMjUgLS0+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDc1LjAzNDY4OCAxNzQuMjU5MjE5KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTg3MjIiLz4KICAgICAgIDx1c2UgeD0iODMuNzg5MDYyIiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSIxNDcuNDEyMTA5IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00NiIvPgogICAgICAgPHVzZSB4PSIxNzkuMTk5MjE5IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy01MCIvPgogICAgICAgPHVzZSB4PSIyNDIuODIyMjY2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy01MyIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inl0aWNrXzUiPgogICAgIDxnIGlkPSJsaW5lMmRfMTEiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMTQzLjI4Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMTIiPgogICAgICA8IS0tIDAuMDAgLS0+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgzLjQxNDM3NSAxNDcuMDc5MjE5KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgICA8dXNlIHg9IjYzLjYyMzA0NyIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iOTUuNDEwMTU2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSIxNTkuMDMzMjAzIiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inl0aWNrXzYiPgogICAgIDxnIGlkPSJsaW5lMmRfMTIiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iMTE2LjEiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBpZD0idGV4dF8xMyI+CiAgICAgIDwhLS0gMC4yNSAtLT4KICAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODMuNDE0Mzc1IDExOS44OTkyMTkpc2NhbGUoMC4xIC0wLjEpIj4KICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDgiLz4KICAgICAgIDx1c2UgeD0iNjMuNjIzMDQ3IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00NiIvPgogICAgICAgPHVzZSB4PSI5NS40MTAxNTYiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTUwIi8+CiAgICAgICA8dXNlIHg9IjE1OS4wMzMyMDMiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTUzIi8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZyBpZD0ieXRpY2tfNyI+CiAgICAgPGcgaWQ9ImxpbmUyZF8xMyI+CiAgICAgIDxnPgogICAgICAgPHVzZSBzdHlsZT0ic3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuODsiIHg9IjExMi42OCIgeGxpbms6aHJlZj0iI21hNDAwZWU0MmIxIiB5PSI4OC45MiIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgIDxnIGlkPSJ0ZXh0XzE0Ij4KICAgICAgPCEtLSAwLjUwIC0tPgogICAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg4My40MTQzNzUgOTIuNzE5MjE5KXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgICA8dXNlIHg9IjYzLjYyMzA0NyIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDYiLz4KICAgICAgIDx1c2UgeD0iOTUuNDEwMTU2IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy01MyIvPgogICAgICAgPHVzZSB4PSIxNTkuMDMzMjAzIiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICA8L2c+CiAgICAgPC9nPgogICAgPC9nPgogICAgPGcgaWQ9Inl0aWNrXzgiPgogICAgIDxnIGlkPSJsaW5lMmRfMTQiPgogICAgICA8Zz4KICAgICAgIDx1c2Ugc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjg7IiB4PSIxMTIuNjgiIHhsaW5rOmhyZWY9IiNtYTQwMGVlNDJiMSIgeT0iNjEuNzQiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgICA8ZyBpZD0idGV4dF8xNSI+CiAgICAgIDwhLS0gMC43NSAtLT4KICAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODMuNDE0Mzc1IDY1LjUzOTIxOSlzY2FsZSgwLjEgLTAuMSkiPgogICAgICAgPHVzZSB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00OCIvPgogICAgICAgPHVzZSB4PSI2My42MjMwNDciIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ2Ii8+CiAgICAgICA8dXNlIHg9Ijk1LjQxMDE1NiIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTUiLz4KICAgICAgIDx1c2UgeD0iMTU5LjAzMzIwMyIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNTMiLz4KICAgICAgPC9nPgogICAgIDwvZz4KICAgIDwvZz4KICAgIDxnIGlkPSJ5dGlja185Ij4KICAgICA8ZyBpZD0ibGluZTJkXzE1Ij4KICAgICAgPGc+CiAgICAgICA8dXNlIHN0eWxlPSJzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC44OyIgeD0iMTEyLjY4IiB4bGluazpocmVmPSIjbWE0MDBlZTQyYjEiIHk9IjM0LjU2Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICAgPGcgaWQ9InRleHRfMTYiPgogICAgICA8IS0tIDEuMDAgLS0+CiAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgzLjQxNDM3NSAzOC4zNTkyMTkpc2NhbGUoMC4xIC0wLjEpIj4KICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNDkiLz4KICAgICAgIDx1c2UgeD0iNjMuNjIzMDQ3IiB4bGluazpocmVmPSIjRGVqYVZ1U2Fucy00NiIvPgogICAgICAgPHVzZSB4PSI5NS40MTAxNTYiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgICA8dXNlIHg9IjE1OS4wMzMyMDMiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ4Ii8+CiAgICAgIDwvZz4KICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZyBpZD0idGV4dF8xNyI+CiAgICAgPCEtLSBPdXRwdXQsICR5JCAtLT4KICAgICA8ZGVmcz4KICAgICAgPHBhdGggZD0iTSAzOS40MDYyNSA2Ni4yMTg3NSAKUSAyOC42NTYyNSA2Ni4yMTg3NSAyMi4zMjgxMjUgNTguMjAzMTI1IApRIDE2LjAxNTYyNSA1MC4yMDMxMjUgMTYuMDE1NjI1IDM2LjM3NSAKUSAxNi4wMTU2MjUgMjIuNjA5Mzc1IDIyLjMyODEyNSAxNC41OTM3NSAKUSAyOC42NTYyNSA2LjU5Mzc1IDM5LjQwNjI1IDYuNTkzNzUgClEgNTAuMTQwNjI1IDYuNTkzNzUgNTYuNDIxODc1IDE0LjU5Mzc1IApRIDYyLjcwMzEyNSAyMi42MDkzNzUgNjIuNzAzMTI1IDM2LjM3NSAKUSA2Mi43MDMxMjUgNTAuMjAzMTI1IDU2LjQyMTg3NSA1OC4yMDMxMjUgClEgNTAuMTQwNjI1IDY2LjIxODc1IDM5LjQwNjI1IDY2LjIxODc1IAp6Ck0gMzkuNDA2MjUgNzQuMjE4NzUgClEgNTQuNzM0Mzc1IDc0LjIxODc1IDYzLjkwNjI1IDYzLjkzNzUgClEgNzMuMDkzNzUgNTMuNjU2MjUgNzMuMDkzNzUgMzYuMzc1IApRIDczLjA5Mzc1IDE5LjE0MDYyNSA2My45MDYyNSA4Ljg1OTM3NSAKUSA1NC43MzQzNzUgLTEuNDIxODc1IDM5LjQwNjI1IC0xLjQyMTg3NSAKUSAyNC4wMzEyNSAtMS40MjE4NzUgMTQuODEyNSA4LjgyODEyNSAKUSA1LjYwOTM3NSAxOS4wOTM3NSA1LjYwOTM3NSAzNi4zNzUgClEgNS42MDkzNzUgNTMuNjU2MjUgMTQuODEyNSA2My45Mzc1IApRIDI0LjAzMTI1IDc0LjIxODc1IDM5LjQwNjI1IDc0LjIxODc1IAp6CiIgaWQ9IkRlamFWdVNhbnMtNzkiLz4KICAgICA8L2RlZnM+CiAgICAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjguOTM0Njg3IDE2Ni44Mylyb3RhdGUoLTkwKXNjYWxlKDAuMSAtMC4xKSI+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjc4MTI1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtNzkiLz4KICAgICAgPHVzZSB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3OC43MTA5MzggMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExNyIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0Mi4wODk4NDQgMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExNiIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4MS4yOTg4MjggMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExMiIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI0NC43NzUzOTEgMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExNyIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMwOC4xNTQyOTcgMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTExNiIvPgogICAgICA8dXNlIHRyYW5zZm9ybT0idHJhbnNsYXRlKDM0Ny4zNjMyODEgMC43ODEyNSkiIHhsaW5rOmhyZWY9IiNEZWphVnVTYW5zLTQ0Ii8+CiAgICAgIDx1c2UgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzc5LjE1MDM5MSAwLjc4MTI1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtMzIiLz4KICAgICAgPHVzZSB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0MTAuOTM3NSAwLjc4MTI1KSIgeGxpbms6aHJlZj0iI0RlamFWdVNhbnMtT2JsaXF1ZS0xMjEiLz4KICAgICA8L2c+CiAgICA8L2c+CiAgIDwvZz4KICAgPGcgaWQ9ImxpbmUyZF8xNiI+CiAgICA8cGF0aCBjbGlwLXBhdGg9InVybCgjcGQyYmE0MzY4ZmUpIiBkPSJNIDExMi42OCAxMTAuNjY0IApMIDExNC44NTQ0IDExMi44Mzg0IApMIDExNy4wMjg4IDExNS4wMTI4IApMIDExOS4yMDMyIDExNy4xODcyIApMIDEyMS4zNzc2IDExOS4zNjE2IApMIDEyMy41NTIgMTIxLjUzNiAKTCAxMjUuNzI2NCAxMjMuNzEwNCAKTCAxMjcuOTAwOCAxMjUuODg0OCAKTCAxMzAuMDc1MiAxMjguMDU5MiAKTCAxMzIuMjQ5NiAxMzAuMjMzNiAKTCAxMzQuNDI0IDEzMi40MDggCkwgMTM2LjU5ODQgMTM0LjU4MjQgCkwgMTM4Ljc3MjggMTM2Ljc1NjggCkwgMTQwLjk0NzIgMTM4LjkzMTIgCkwgMTQzLjEyMTYgMTQxLjEwNTYgCkwgMTQ1LjI5NiAxNDMuMjggCkwgMTQ3LjQ3MDQgMTQ1LjQ1NDQgCkwgMTQ5LjY0NDggMTQ3LjYyODggCkwgMTUxLjgxOTIgMTQ5LjgwMzIgCkwgMTUzLjk5MzYgMTUxLjk3NzYgCkwgMTU2LjE2OCAxNTQuMTUyIApMIDE1OC4zNDI0IDE1Ni4zMjY0IApMIDE2MC41MTY4IDE1OC41MDA4IApMIDE2Mi42OTEyIDE2MC42NzUyIApMIDE2NC44NjU2IDE2Mi44NDk2IApMIDE2Ny4wNCAxNjUuMDI0IApMIDE2OS4yMTQ0IDE2Ny4xOTg0IApMIDE3MS4zODg4IDE2OS4zNzI4IApMIDE3My41NjMyIDE3MS41NDcyIApMIDE3NS43Mzc2IDE3My43MjE2IApMIDE3Ny45MTIgMTc1Ljg5NiAKTCAxODAuMDg2NCAxNzUuODk2IApMIDE4Mi4yNjA4IDE3NS44OTYgCkwgMTg0LjQzNTIgMTc1Ljg5NiAKTCAxODYuNjA5NiAxNzUuODk2IApMIDE4OC43ODQgMTc1Ljg5NiAKTCAxOTAuOTU4NCAxNzUuODk2IApMIDE5My4xMzI4IDE3NS44OTYgCkwgMTk1LjMwNzIgMTc1Ljg5NiAKTCAxOTcuNDgxNiAxNzUuODk2IApMIDE5OS42NTYgMTc1Ljg5NiAKTCAyMDEuODMwNCAxNzUuODk2IApMIDIwNC4wMDQ4IDE3NS44OTYgCkwgMjA2LjE3OTIgMTc1Ljg5NiAKTCAyMDguMzUzNiAxNzUuODk2IApMIDIxMC41MjggMTc1Ljg5NiAKTCAyMTIuNzAyNCAxNzUuODk2IApMIDIxNC44NzY4IDE3NS44OTYgCkwgMjE3LjA1MTIgMTc1Ljg5NiAKTCAyMTkuMjI1NiAxNzUuODk2IApMIDIyMS40IDE3NS44OTYgCkwgMjIzLjU3NDQgMTc4LjA3MDQgCkwgMjI1Ljc0ODggMTgwLjI0NDggCkwgMjI3LjkyMzIgMTgyLjQxOTIgCkwgMjMwLjA5NzYgMTg0LjU5MzYgCkwgMjMyLjI3MiAxODYuNzY4IApMIDIzNC40NDY0IDE4OC45NDI0IApMIDIzNi42MjA4IDE5MS4xMTY4IApMIDIzOC43OTUyIDE5My4yOTEyIApMIDI0MC45Njk2IDE5NS40NjU2IApMIDI0My4xNDQgMTk3LjY0IApMIDI0NS4zMTg0IDE5OS44MTQ0IApMIDI0Ny40OTI4IDIwMS45ODg4IApMIDI0OS42NjcyIDIwNC4xNjMyIApMIDI1MS44NDE2IDIwNi4zMzc2IApMIDI1NC4wMTYgMjA4LjUxMiAKTCAyNTYuMTkwNCAyMTAuNjg2NCAKTCAyNTguMzY0OCAyMTIuODYwOCAKTCAyNjAuNTM5MiAyMTUuMDM1MiAKTCAyNjIuNzEzNiAyMTcuMjA5NiAKTCAyNjQuODg4IDIxOS4zODQgCkwgMjY3LjA2MjQgMjIxLjU1ODQgCkwgMjY5LjIzNjggMjIzLjczMjggCkwgMjcxLjQxMTIgMjI1LjkwNzIgCkwgMjczLjU4NTYgMjI4LjA4MTYgCkwgMjc1Ljc2IDIzMC4yNTYgCkwgMjc3LjkzNDQgMjMyLjQzMDQgCkwgMjgwLjEwODggMjM0LjIyNDI4IApMIDI4Mi4yODMyIDIzMS40NTE5MiAKTCAyODQuNDU3NiAyMjguNjc5NTYgCkwgMjg2LjYzMiAyMjUuOTA3MiAKTCAyODguODA2NCAyMjMuMTM0ODQgCkwgMjkwLjk4MDggMjIwLjM2MjQ4IApMIDI5My4xNTUyIDIxNy41OTAxMiAKTCAyOTUuMzI5NiAyMTQuODE3NzYgCkwgMjk3LjUwNCAyMTIuMDQ1NCAKTCAyOTkuNjc4NCAyMDkuMjczMDQgCkwgMzAxLjg1MjggMjA2LjUwMDY4IApMIDMwNC4wMjcyIDIwMy43MjgzMiAKTCAzMDYuMjAxNiAyMDAuOTU1OTYgCkwgMzA4LjM3NiAxOTguMTgzNiAKTCAzMTAuNTUwNCAxOTUuNDExMjQgCkwgMzEyLjcyNDggMTkyLjYzODg4IApMIDMxNC44OTkyIDE4OS44NjY1MiAKTCAzMTcuMDczNiAxODcuMDk0MTYgCkwgMzE5LjI0OCAxODQuMzIxOCAKTCAzMjEuNDIyNCAxODEuNTQ5NDQgCkwgMzIzLjU5NjggMTc4Ljc3NzA4IApMIDMyNS43NzEyIDE3Ni4wMDQ3MiAKTCAzMjcuOTQ1NiAxNzMuMjMyMzYgCiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzFmNzdiNDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLXdpZHRoOjEuNTsiLz4KICAgPC9nPgogICA8ZyBpZD0icGF0Y2hfMyI+CiAgICA8cGF0aCBkPSJNIDExMi42OCAyNTIgCkwgMTEyLjY4IDM0LjU2IAoiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utd2lkdGg6MC44OyIvPgogICA8L2c+CiAgIDxnIGlkPSJwYXRjaF80Ij4KICAgIDxwYXRoIGQ9Ik0gMzMwLjEyIDI1MiAKTCAzMzAuMTIgMzQuNTYgCiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS13aWR0aDowLjg7Ii8+CiAgIDwvZz4KICAgPGcgaWQ9InBhdGNoXzUiPgogICAgPHBhdGggZD0iTSAxMTIuNjggMjUyIApMIDMzMC4xMiAyNTIgCiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS13aWR0aDowLjg7Ii8+CiAgIDwvZz4KICAgPGcgaWQ9InBhdGNoXzYiPgogICAgPHBhdGggZD0iTSAxMTIuNjggMzQuNTYgCkwgMzMwLjEyIDM0LjU2IAoiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utd2lkdGg6MC44OyIvPgogICA8L2c+CiAgPC9nPgogPC9nPgogPGRlZnM+CiAgPGNsaXBQYXRoIGlkPSJwZDJiYTQzNjhmZSI+CiAgIDxyZWN0IGhlaWdodD0iMjE3LjQ0IiB3aWR0aD0iMjE3LjQ0IiB4PSIxMTIuNjgiIHk9IjM0LjU2Ii8+CiAgPC9jbGlwUGF0aD4KIDwvZGVmcz4KPC9zdmc+Cg==)" + ], + "metadata": { + "id": "T34bszToImKQ" + } + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the neural network\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ], + "metadata": { + "id": "SzIVdp9U-JWb" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's play with the parameters to make sure we understand how they work. The original parameters were:\n", + "\n", + "$\\theta_{10} = 0.3$ ; $\\theta_{20} = -1.0$
\n", + "$\\theta_{20} = -1.0$ ; $\\theta_{21} = 2.0$
\n", + "$\\theta_{30} = -0.5$ ; $\\theta_{31} = 0.65$
\n", + "$\\phi_0 = -0.3; \\phi_1 = 2.0; \\phi_2 = -1.0; \\phi_3 = 7.0$" + ], + "metadata": { + "id": "jhaBSS8oIWSX" + } + }, + { + "cell_type": "code", + "source": [ + "# TODO\n", + "# 1. Predict what effect changing phi_0 will have on the network. \n", + "# Answer:\n", + "# 2. Predict what effect multiplying phi_1, phi_2, phi_3 by 0.5 would have. Check if you are correct\n", + "# Answer:\n", + "# 3. Predict what effect multiplying phi_1 by -1 will have. Check if you are correct.\n", + "# Answer:\n", + "# 4. Predict what effect setting theta_20 to -1.2 will have. Check if you are correct.\n", + "# Answer:\n", + "# 5. Change the parameters so that there are only two \"joints\" (including outside the range of the plot) \n", + "# There are actually three ways to do this. See if you can figure them all out\n", + "# Answer:\n", + "# 6. With the original parameters, the second line segment is flat (i.e. has slope zero)\n", + "# How could you change theta_10 so that all of the segments have non-zero slopes\n", + "# Answer:\n", + "# 7. What do you predict would happen if you multiply theta_20 and theta21 by 0.5, and phi_2 by 2.0?\n", + "# Check if you are correct.\n", + "# Answer:\n", + "# 8. What do you predict would happen if you multiply theta_20 and theta21 by -0.5, and phi_2 by -2.0?\n", + "# Check if you are correct.\n", + "# Answer:\n", + "\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ], + "metadata": { + "id": "ur4arJ8KAQWe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Different activation functions\n", + "\n", + "The ReLU isn't the only kind of activation function. For a long time, people used sigmoid functions. A logistic sigmoid function is defined by the equation\n", + "\n", + "\\begin{equation}\n", + "f[h] = \\frac{1}{1+\\exp{[-10 z ]}}\n", + "\\end{equation}\n", + "\n", + "(Note that the factor of 10 is not standard -- but it allow us to plot on the same axes as the ReLU examples)" + ], + "metadata": { + "id": "1NTT5GTbJSqK" + } + }, + { + "cell_type": "code", + "source": [ + "# Define the sigmoid function\n", + "def sigmoid(preactivation):\n", + " # TODO write code to implement the sigmoid function and compute the activation at the \n", + " # hidden unit from the preactivation. Use the np.exp() function.\n", + " activation = np.zeros_like(preactivation);\n", + " return activation" + ], + "metadata": { + "id": "FEzzQeVoZdV_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Make an array of inputs\n", + "z = np.arange(-1,1,0.01)\n", + "sig_z = sigmoid(z)\n", + "\n", + "# Plot the sigmoid function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(z,sig_z,'r-')\n", + "ax.set_xlim([-1,1]);ax.set_ylim([0,1])\n", + "ax.set_xlabel('z'); ax.set_ylabel('sig[z]')\n", + "plt.show" + ], + "metadata": { + "id": "dIn42wDlKqsv" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's see what happens when we use this activation function in a neural network" + ], + "metadata": { + "id": "uwQHGdC5KpH7" + } + }, + { + "cell_type": "code", + "source": [ + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = 0.3; phi_1 = 0.5; phi_2 = -1.0; phi_3 = 0.9\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, sigmoid, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ], + "metadata": { + "id": "5W9m9MLKLddi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "You probably notice that this gives nice smooth curves. So why don't we use this? Aha... it's not obvious right now, but we will get to it when we learn to fit models." + ], + "metadata": { + "id": "0c4S-XfnSfDx" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Linear activation functions\n", + "\n", + "However, neural networks don't work if the activation function is linear. For example, consider what would happen if the activation function was: \n", + "\n", + "\\begin{equation}\n", + "\\mbox{lin}[z] = a + bz\n", + "\\end{equation}" + ], + "metadata": { + "id": "IA_v_-eLRqek" + } + }, + { + "cell_type": "code", + "source": [ + "# Define the linear activation function\n", + "def lin(preactivation):\n", + " a =0\n", + " b =1\n", + " # Compute linear function\n", + " activation = a+b * preactivation\n", + " # Return\n", + " return activation" + ], + "metadata": { + "id": "fTHJRv0KLjMD" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO \n", + "# 1. The linear activation function above just returns the input: (0+1*z) = z\n", + "# Before running the code Make a prediction about what the ten panels of the drawing will look like\n", + "# Now run the code below to see if you were right. What family of functions can this represent? \n", + " \n", + "# 2. What happens if you change the parameters (a,b) to different values? \n", + "# Try a=0.5, b=-0.4 (don't forget) to run the cell again to update the function\n", + "\n", + "\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = 0.3; phi_1 = 0.5; phi_2 = -1.0; phi_3 = 0.9\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, lin, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ], + "metadata": { + "id": "SauRG8r7TkvP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Least squares loss\n", + "\n", + "Now let's consider fitting the network to data. First we need to define the loss function. We'll use the least squares loss:\n", + "\n", + "\\begin{equation}\n", + "L[\\boldsymbol\\phi] = \\sum_{i=1}^{I}(y_{i}-\\mbox{f}[x_{i},\\boldsymbol\\phi])^2\n", + "\\end{equation}\n", + "\n", + "where $(x_i,y_i)$ is an input/output training pair and $\\mbox{f}[\\bullet,\\boldsymbol\\phi]$ is the neural network with parameters $\\boldsymbol\\phi$. The first term in the brackets is the ground truth output and the second term is the prediction of the model" + ], + "metadata": { + "id": "osonHsEqVp2I" + } + }, + { + "cell_type": "code", + "source": [ + "# Least squares function\n", + "def least_squares_loss(y_train, y_predict):\n", + " # TODO Replace the line below to use compute the sum of squared\n", + " # differences between the real and predicted values of y\n", + " # you will need to use the function np.sum\n", + " loss = 0\n", + " return loss" + ], + "metadata": { + "id": "14d5II-TU46w" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters, run the neural network, and compute the loss\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "x_train = np.array([0.09291784,0.46809093,0.93089486,0.67612654,0.73441752,0.86847339,\\\n", + " 0.49873225,0.51083168,0.18343972,0.99380898,0.27840809,0.38028817,\\\n", + " 0.12055708,0.56715537,0.92005746,0.77072270,0.85278176,0.05315950,\\\n", + " 0.87168699,0.58858043])\n", + "y_train = np.array([-0.15934537,0.18195445,0.451270150,0.13921448,0.09366691,0.30567674,\\\n", + " 0.372291170,0.40716968,-0.08131792,0.41187806,0.36943738,0.3994327,\\\n", + " 0.019062570,0.35820410,0.452564960,-0.0183121,0.02957665,-0.24354444, \\\n", + " 0.148038840,0.26824970])\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True, x_data = x_train, y_data = y_train)\n", + "\n", + "# Run the neural network on the training data\n", + "y_predict, *_ = shallow_1_1_3(x_train, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "\n", + "# Compute the least squares loss and print it out\n", + "loss = least_squares_loss(y_train,y_predict)\n", + "print(\"Loss = %3.3f\"%(loss))\n", + "\n", + "# TODO. Manipulate the parameters (by hand!) to make the function \n", + "# fit the data better and try to reduce the loss to as small a number \n", + "# as possible. The best that I could do was 0.181\n", + "# Tip... start by manipulating phi_0.\n", + "# It's not that easy, so don't spend too much time on this!" + ], + "metadata": { + "id": "o6GXjtRubZ2U" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Networks with two inputs\n", + "\n", + "(Optional) If you are feeling keen, then there is a template below to build a neural network that takes two inputs similar to figure 3.8. " + ], + "metadata": { + "id": "SSQuNtAcisHs" + } + }, + { + "cell_type": "code", + "source": [ + "# Code to draw 2D function -- read it so you know what is going on, but you don't have to change it\n", + "def draw_2D_function(ax, x1_mesh, x2_mesh, y, draw_heatmap=False):\n", + " pos = ax.contourf(x1_mesh, x2_mesh, y, levels=256 ,cmap = 'hot', vmin=-10,vmax=10.0)\n", + " if draw_heatmap:\n", + " fig.colorbar(pos, ax=ax)\n", + " ax.set_xlabel('x1');ax.set_ylabel('x2')\n", + " levels = np.arange(-10,10,1.0)\n", + " ax.contour(x1_mesh, x2_mesh, y, levels, cmap='winter')\n", + "\n", + "# Plot the shallow neural network. We'll assume input in is range [0,10],[0,10] and output [-10,10]\n", + "# If the plot_all flag is set to true, then we'll plot all the intermediate stages as in Figure 3.3 \n", + "def plot_neural_2_inputs(x1,x2, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False):\n", + "\n", + " # Plot intermediate plots if flag set\n", + " if plot_all:\n", + " fig, ax = plt.subplots(3,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " draw_2D_function(ax[0,0], x1,x2,pre_1); ax[0,0].set_title('Preactivation')\n", + " draw_2D_function(ax[0,1], x1,x2,pre_2); ax[0,1].set_title('Preactivation')\n", + " draw_2D_function(ax[0,2], x1,x2,pre_3); ax[0,2].set_title('Preactivation')\n", + " draw_2D_function(ax[1,0], x1,x2,act_1); ax[1,0].set_title('Activation')\n", + " draw_2D_function(ax[1,1], x1,x2,act_2); ax[1,1].set_title('Activation')\n", + " draw_2D_function(ax[1,2], x1,x2,act_3); ax[1,2].set_title('Activation')\n", + " draw_2D_function(ax[2,0], x1,x2,w_act_1); ax[2,0].set_title('Weighted Act')\n", + " draw_2D_function(ax[2,1], x1,x2,w_act_2); ax[2,1].set_title('Weighted Act')\n", + " draw_2D_function(ax[2,2], x1,x2,w_act_3); ax[2,2].set_title('Weighted Act')\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " draw_2D_function(ax,x1,x2,y,draw_heatmap=True)\n", + " ax.set_title('Network ouptut, $y$')\n", + " ax.set_aspect(1.0)\n", + " plt.show()" + ], + "metadata": { + "id": "tyfGcDq_bcQy" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a shallow neural network with, two inputs, one output, and three hidden units\n", + "def shallow_2_1_3(x1,x2, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11,\\\n", + " theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32):\n", + " # TODO Replace the lines below to compute the three initial linear functions \n", + " # (figure 3.8a-c) from the theta parameters. These are the preactivations\n", + " pre_1 = np.zeros_like(x1)\n", + " pre_2 = np.zeros_like(x1)\n", + " pre_3 = np.zeros_like(x1)\n", + " # Pass these through the ReLU function to compute the activations as in \n", + " # figure 3.8 d-f\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + " # TODO Replace the code below to weight the activations using phi1, phi2 and phi3\n", + " # To create the equivalent of figure 3.8 g-i\n", + " w_act_1 = np.zeros_like(x1)\n", + " w_act_2 = np.zeros_like(x1)\n", + " w_act_3 = np.zeros_like(x1)\n", + " # TODO Replace the code below to combing the weighted activations and add \n", + " # phi_0 to create the output as in figure 3.8j\n", + " y = np.zeros_like(x1)\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ], + "metadata": { + "id": "F8T9kYuBpBKO" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the neural network\n", + "theta_10 = 4.0 ; theta_11 = -0.9; theta_12 = 0.0\n", + "theta_20 = 5.0 ; theta_21 = -0.9 ; theta_22 = -0.5\n", + "theta_30 = -5 ; theta_31 = 0.5; theta_32 = 0.9\n", + "phi_0 = 0.0; phi_1 = -1.0; phi_2 = 2.0; phi_3 = 0.6\n", + "\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_2_1_3(x1,x2, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32)\n", + "# And then plot it\n", + "plot_neural_2_inputs(x1,x2, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)\n", + "\n" + ], + "metadata": { + "id": "C8rzVcZnnxia" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Training_I.ipynb b/CM20315/CM20315_Training_I.ipynb new file mode 100644 index 0000000..f1438e8 --- /dev/null +++ b/CM20315/CM20315_Training_I.ipynb @@ -0,0 +1,190 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMUqLjI8VIQXHOYx0I37OmR", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Training\n", + "\n", + "We now have a model and a loss function which we can use to judge how good that model is. It's time to put the \"learning\" into machine learning.\n", + "\n", + "Learning involves finding the parameters that minimize the loss. That might seems like it's not too hard, but modern models might have billions of parameters. There's an exponential number of possible parameter combinations, and there's no way we can make any progress with exhaustive search.\n", + "\n", + "We'll build this up in stages. In this practical, we'll just consider 1D search using a bracketing approach. In part II, we'll extend to fitting the linear regression model (which has a convex loss function). Then in part III, we'll consider non-convex loss functions\n" + ], + "metadata": { + "id": "el8l05WQEO46" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xhmIOLiZELV_" + }, + "outputs": [], + "source": [ + "# import libraries\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "# Let's create a simple 1D function\n", + "def loss_function(phi):\n", + " return 1- 0.5 * np.exp(-(phi-0.65)*(phi-0.65)/0.1) - 0.45 *np.exp(-(phi-0.35)*(phi-0.35)/0.02)\n", + "\n", + "def draw_function(loss_function,a=None, b=None, c=None, d=None):\n", + " # Plot the function \n", + " phi_plot = np.arange(0,1,0.01);\n", + " fig,ax = plt.subplots()\n", + " ax.plot(phi_plot,loss_function(phi_plot),'r-')\n", + " ax.set_xlim(0,1); ax.set_ylim(0,1)\n", + " ax.set_xlabel('$\\phi$'); ax.set_ylabel('$L[\\phi]$')\n", + " if a is not None and b is not None and c is not None and d is not None:\n", + " plt.axvspan(a, d, facecolor='k', alpha=0.2)\n", + " ax.plot([a,a],[0,1],'b-')\n", + " ax.plot([b,b],[0,1],'b-')\n", + " ax.plot([c,c],[0,1],'b-')\n", + " ax.plot([d,d],[0,1],'b-')\n", + " plt.show()\n" + ], + "metadata": { + "id": "qFRe9POHF2le" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Draw this function\n", + "draw_function(loss_function)" + ], + "metadata": { + "id": "TXx1Tpd1Tl-I" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now lets create a line search procedure to find the minimum in the range 0,1" + ], + "metadata": { + "id": "QU5mdGvpTtEG" + } + }, + { + "cell_type": "code", + "source": [ + "def line_search(loss_function, thresh=.0001, max_iter = 10, draw_flag = False):\n", + "\n", + " # Initialize four points along the range we are going to search\n", + " a = 0\n", + " b = 0.33\n", + " c = 0.66\n", + " d = 1.0\n", + " n_iter =0;\n", + " \n", + " # While we haven't found the minimum closely enough\n", + " while np.abs(b-c) > thresh and n_iter < max_iter:\n", + " # Increment iteration counter (just to prevent an infinite loop)\n", + " n_iter = n_iter+1\n", + " # Calculate all four points\n", + " lossa = loss_function(a)\n", + " lossb = loss_function(b)\n", + " lossc = loss_function(c)\n", + " lossd = loss_function(d)\n", + "\n", + " if draw_flag:\n", + " draw_function(loss_function, a,b,c,d)\n", + "\n", + " print('Iter %d, a=%3.3f, b=%3.3f, c=%3.3f, d=%3.3f'%(n_iter, a,b,c,d))\n", + "\n", + " # Rule #1 If point A is less than points B, C, and D then halve values of B,C, and D\n", + " # i.e. bring them closer to the original point\n", + " # TODO REPLACE THE BLOCK OF CODE BELOW WITH THIS RULE\n", + " if (0):\n", + " continue;\n", + "\n", + " # Rule #2 If point b is less than point c then\n", + " # then point d becomes point c, and\n", + " # point b becomes 1/3 between a and new d\n", + " # point c becomes 2/3 between a and new d \n", + " # TODO REPLACE THE BLOCK OF CODE BELOW WITH THIS RULE\n", + " if (0):\n", + " continue;\n", + "\n", + " # Rule #3 If point c is less than point b then\n", + " # then point a becomes point b, and\n", + " # point b becomes 1/3 between new a and d\n", + " # point c becomes 2/3 between new a and d \n", + " # TODO REPLACE THE BLOCK OF CODE BELOW WITH THIS RULE\n", + " if(0):\n", + " continue\n", + "\n", + "\n", + " # TODO -- FINAL SOLUTION IS AVERAGE OF B and C\n", + " # REPLACE THIS LINE\n", + " soln = 1\n", + " \n", + " return soln" + ], + "metadata": { + "id": "K-NTHpAAHlCl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "soln = line_search(loss_function, draw_flag=True)\n", + "print('Soln = %3.3f, loss = %3.3f'%(soln,loss_function(soln)))" + ], + "metadata": { + "id": "YVq6rmaWRD2M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "tOLd0gtdRLLS" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Training_II.ipynb b/CM20315/CM20315_Training_II.ipynb new file mode 100644 index 0000000..ac09b14 --- /dev/null +++ b/CM20315/CM20315_Training_II.ipynb @@ -0,0 +1,427 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyMwBvBF5E8ERRBCqN9x6Dp5", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Training II\n", + "\n", + "We now have a model and a loss function which we can use to judge how good that model is. It's time to put the \"learning\" into machine learning.\n", + "\n", + "Learning involves finding the parameters that minimize the loss. That might seems like it's not too hard, but modern models might have billions of parameters. There's an exponential number of possible parameter combinations, and there's no way we can make any progress with exhaustive search.\n", + "\n", + "In part I we considered 1D search using a bracketing approach. In this part, we'll extend to fitting the linear regression model (which has a convex loss function). Then in part III, we'll consider a non-convex loss function and implement stochastic gradient descent.\n", + "\n", + "\n" + ], + "metadata": { + "id": "el8l05WQEO46" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xhmIOLiZELV_" + }, + "outputs": [], + "source": [ + "# import libraries\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib import cm\n", + "from matplotlib.colors import ListedColormap" + ] + }, + { + "cell_type": "code", + "source": [ + "# Let's create our training data 12 pairs {x_i, y_i}\n", + "# We'll try to fit the straight line model to these data\n", + "data = np.array([[0.03,0.19,0.34,0.46,0.78,0.81,1.08,1.18,1.39,1.60,1.65,1.90],\n", + " [0.67,0.85,1.05,1.00,1.40,1.50,1.30,1.54,1.55,1.68,1.73,1.60]])" + ], + "metadata": { + "id": "4cRkrh9MZ58Z" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's define our model\n", + "def model(phi,x):\n", + " y_pred = phi[0]+phi[1] * x\n", + " return y_pred" + ], + "metadata": { + "id": "WQUERmb2erAe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Draw model\n", + "def draw_model(data,model,phi,title=None):\n", + " x_model = np.arange(0,2,0.01)\n", + " y_model = model(phi,x_model)\n", + "\n", + " fix, ax = plt.subplots()\n", + " ax.plot(data[0,:],data[1,:],'bo')\n", + " ax.plot(x_model,y_model,'m-')\n", + " ax.set_xlim([0,2]);ax.set_ylim([0,2])\n", + " ax.set_xlabel('x'); ax.set_ylabel('y')\n", + " ax.set_aspect('equal')\n", + " if title is not None:\n", + " ax.set_title(title)\n", + " plt.show()" + ], + "metadata": { + "id": "qFRe9POHF2le" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize the parameters and draw the model\n", + "phi = np.zeros((2,1))\n", + "phi[0] = 0.6 # Intercept\n", + "phi[1] = -0.2 # Slope\n", + "draw_model(data,model,phi, \"Initial parameters\")\n" + ], + "metadata": { + "id": "TXx1Tpd1Tl-I" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now lets create compute the sum of squares loss for the training data" + ], + "metadata": { + "id": "QU5mdGvpTtEG" + } + }, + { + "cell_type": "code", + "source": [ + "def compute_loss(data_x, data_y, model, phi):\n", + " # TODO -- Write this function -- replace the line below\n", + " # First make model predictions from data x\n", + " # Then compute the squared difference between the predictions and true y values\n", + " # Then sum them all and return\n", + " loss = 0\n", + " return loss" + ], + "metadata": { + "id": "I7dqTY2Gg7CR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's just test that we got that right" + ], + "metadata": { + "id": "eB5DQvU5hYNx" + } + }, + { + "cell_type": "code", + "source": [ + "loss = compute_loss(data[0,:],data[1,:],model,np.array([[0.6],[-0.2]]))\n", + "print('Your loss = %3.3f, Correct loss = %3.3f'%(loss, 12.367))" + ], + "metadata": { + "id": "Ty05UtEEg9tc" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's plot the whole loss function" + ], + "metadata": { + "id": "F3trnavPiHpH" + } + }, + { + "cell_type": "code", + "source": [ + "def draw_loss_function(compute_loss, data, model, phi_iters = None):\n", + " # Define pretty colormap\n", + " my_colormap_vals_hex =('2a0902', '2b0a03', '2c0b04', '2d0c05', '2e0c06', '2f0d07', '300d08', '310e09', '320f0a', '330f0b', '34100b', '35110c', '36110d', '37120e', '38120f', '39130f', '3a1410', '3b1411', '3c1511', '3d1612', '3e1613', '3f1713', '401714', '411814', '421915', '431915', '451a16', '461b16', '471b17', '481c17', '491d18', '4a1d18', '4b1e19', '4c1f19', '4d1f1a', '4e201b', '50211b', '51211c', '52221c', '53231d', '54231d', '55241e', '56251e', '57261f', '58261f', '592720', '5b2821', '5c2821', '5d2922', '5e2a22', '5f2b23', '602b23', '612c24', '622d25', '632e25', '652e26', '662f26', '673027', '683027', '693128', '6a3229', '6b3329', '6c342a', '6d342a', '6f352b', '70362c', '71372c', '72372d', '73382e', '74392e', '753a2f', '763a2f', '773b30', '783c31', '7a3d31', '7b3e32', '7c3e33', '7d3f33', '7e4034', '7f4134', '804235', '814236', '824336', '834437', '854538', '864638', '874739', '88473a', '89483a', '8a493b', '8b4a3c', '8c4b3c', '8d4c3d', '8e4c3e', '8f4d3f', '904e3f', '924f40', '935041', '945141', '955242', '965343', '975343', '985444', '995545', '9a5646', '9b5746', '9c5847', '9d5948', '9e5a49', '9f5a49', 'a05b4a', 'a15c4b', 'a35d4b', 'a45e4c', 'a55f4d', 'a6604e', 'a7614e', 'a8624f', 'a96350', 'aa6451', 'ab6552', 'ac6552', 'ad6653', 'ae6754', 'af6855', 'b06955', 'b16a56', 'b26b57', 'b36c58', 'b46d59', 'b56e59', 'b66f5a', 'b7705b', 'b8715c', 'b9725d', 'ba735d', 'bb745e', 'bc755f', 'bd7660', 'be7761', 'bf7862', 'c07962', 'c17a63', 'c27b64', 'c27c65', 'c37d66', 'c47e67', 'c57f68', 'c68068', 'c78169', 'c8826a', 'c9836b', 'ca846c', 'cb856d', 'cc866e', 'cd876f', 'ce886f', 'ce8970', 'cf8a71', 'd08b72', 'd18c73', 'd28d74', 'd38e75', 'd48f76', 'd59077', 'd59178', 'd69279', 'd7937a', 'd8957b', 'd9967b', 'da977c', 'da987d', 'db997e', 'dc9a7f', 'dd9b80', 'de9c81', 'de9d82', 'df9e83', 'e09f84', 'e1a185', 'e2a286', 'e2a387', 'e3a488', 'e4a589', 'e5a68a', 'e5a78b', 'e6a88c', 'e7aa8d', 'e7ab8e', 'e8ac8f', 'e9ad90', 'eaae91', 'eaaf92', 'ebb093', 'ecb295', 'ecb396', 'edb497', 'eeb598', 'eeb699', 'efb79a', 'efb99b', 'f0ba9c', 'f1bb9d', 'f1bc9e', 'f2bd9f', 'f2bfa1', 'f3c0a2', 'f3c1a3', 'f4c2a4', 'f5c3a5', 'f5c5a6', 'f6c6a7', 'f6c7a8', 'f7c8aa', 'f7c9ab', 'f8cbac', 'f8ccad', 'f8cdae', 'f9ceb0', 'f9d0b1', 'fad1b2', 'fad2b3', 'fbd3b4', 'fbd5b6', 'fbd6b7', 'fcd7b8', 'fcd8b9', 'fcdaba', 'fddbbc', 'fddcbd', 'fddebe', 'fddfbf', 'fee0c1', 'fee1c2', 'fee3c3', 'fee4c5', 'ffe5c6', 'ffe7c7', 'ffe8c9', 'ffe9ca', 'ffebcb', 'ffeccd', 'ffedce', 'ffefcf', 'fff0d1', 'fff2d2', 'fff3d3', 'fff4d5', 'fff6d6', 'fff7d8', 'fff8d9', 'fffada', 'fffbdc', 'fffcdd', 'fffedf', 'ffffe0')\n", + " my_colormap_vals_dec = np.array([int(element,base=16) for element in my_colormap_vals_hex])\n", + " r = np.floor(my_colormap_vals_dec/(256*256))\n", + " g = np.floor((my_colormap_vals_dec - r *256 *256)/256)\n", + " b = np.floor(my_colormap_vals_dec - r * 256 *256 - g * 256)\n", + " my_colormap = ListedColormap(np.vstack((r,g,b)).transpose()/255.0)\n", + "\n", + " # Make grid of intercept/slope values to plot\n", + " intercepts_mesh, slopes_mesh = np.meshgrid(np.arange(0.0,2.0,0.02), np.arange(-1.0,1.0,0.002))\n", + " loss_mesh = np.zeros_like(slopes_mesh)\n", + " # Compute loss for every set of parameters\n", + " for idslope, slope in np.ndenumerate(slopes_mesh):\n", + " loss_mesh[idslope] = compute_loss(data[0,:], data[1,:], model, np.array([[intercepts_mesh[idslope]], [slope]]))\n", + "\n", + " fig,ax = plt.subplots()\n", + " fig.set_size_inches(8,8)\n", + " ax.contourf(intercepts_mesh,slopes_mesh,loss_mesh,256,cmap=my_colormap)\n", + " ax.contour(intercepts_mesh,slopes_mesh,loss_mesh,40,colors=['#80808080'])\n", + " if phi_iters is not None:\n", + " ax.plot(phi_iters[0,:], phi_iters[1,:],'go-')\n", + " ax.set_ylim([1,-1])\n", + " ax.set_xlabel('Intercept $\\phi_{0}$'); ax.set_ylabel('Slope, $\\phi_{1}$')\n", + " plt.show()" + ], + "metadata": { + "id": "K-NTHpAAHlCl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "draw_loss_function(compute_loss, data, model)" + ], + "metadata": { + "id": "l8HbvIupnTME" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the gradient vector for a given set of parameters:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial L}{\\partial \\boldsymbol\\phi} = \\begin{bmatrix}\\frac{\\partial L}{\\partial \\phi_0} \\\\\\frac{\\partial L}{\\partial \\phi_1} \\end{bmatrix}.\n", + "\\end{equation}" + ], + "metadata": { + "id": "s9Duf05WqqSC" + } + }, + { + "cell_type": "code", + "source": [ + "# These are in the lecture slides and notes, but worth trying to calculate them yourself to \n", + "# check that you get them right. Write out the expression for the sum of squares loss and take the\n", + "# derivative with respect to phi0 and phi1\n", + "def compute_gradient(data_x, data_y, phi):\n", + " # TODO -- write this function, replacing the lines below\n", + " dl_dphi0 = 0.0\n", + " dl_dphi1 = 0.0\n", + "\n", + " # Return the gradient\n", + " return np.array([[dl_dphi0],[dl_dphi1]])" + ], + "metadata": { + "id": "UpswmkL2qwBT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "We can check we got this right using a trick known as **finite differences**. If we evaluate the function and then change one of the parameters by a very small amount and normalize by that amount, we get an approximation to the gradient, so:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial L}{\\partial \\phi_{0}}&\\approx & \\frac{L[\\phi_0+\\delta, \\phi_1]-L[\\phi_0, \\phi_1]}{\\delta}\\\\\n", + "\\frac{\\partial L}{\\partial \\phi_{1}}&\\approx & \\frac{L[\\phi_0, \\phi_1+\\delta]-L[\\phi_0, \\phi_1]}{\\delta}\n", + "\\end{eqnarray}\n", + "\n", + "We don't do this when there are many parameters; for a million parameters, we would have to evaluate the loss function two million times, and usually computing the gradients directly is much more efficient." + ], + "metadata": { + "id": "RS1nEcYVuEAM" + } + }, + { + "cell_type": "code", + "source": [ + "# Compute the gradient using your function\n", + "gradient = compute_gradient(data[0,:],data[1,:], phi)\n", + "print(\"Your gradients: (%3.3f,%3.3f)\"%(gradient[0],gradient[1]))\n", + "# Approximate the gradients with finite differences\n", + "delta = 0.0001\n", + "dl_dphi0_est = (compute_loss(data[0,:],data[1,:],model,phi+np.array([[delta],[0]])) - \\\n", + " compute_loss(data[0,:],data[1,:],model,phi))/delta\n", + "dl_dphi1_est = (compute_loss(data[0,:],data[1,:],model,phi+np.array([[0],[delta]])) - \\\n", + " compute_loss(data[0,:],data[1,:],model,phi))/delta\n", + "print(\"Approx gradients: (%3.3f,%3.3f)\"%(dl_dphi0_est,dl_dphi1_est))\n" + ], + "metadata": { + "id": "QuwAHN7yt-gi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we are ready to perform gradient descent. We'll need to use our line search routine from part I, which I've reproduced here plus the helper function loss_function_1D that converts from a 2D problem to a 1D problem" + ], + "metadata": { + "id": "5EIjMM9Fw2eT" + } + }, + { + "cell_type": "code", + "source": [ + "def loss_function_1D(dist_prop, data, model, phi_start, gradient):\n", + " # Return the loss after moving this far\n", + " return compute_loss(data[0,:], data[1,:], model, phi_start+ gradient * dist_prop)\n", + "\n", + "def line_search(data, model, phi, gradient, thresh=.00001, max_dist = 0.1, max_iter = 15, verbose=False):\n", + " # Initialize four points along the range we are going to search\n", + " a = 0\n", + " b = 0.33 * max_dist\n", + " c = 0.66 * max_dist\n", + " d = 1.0 * max_dist\n", + " n_iter =0;\n", + " \n", + " # While we haven't found the minimum closely enough\n", + " while np.abs(b-c) > thresh and n_iter < max_iter:\n", + " # Increment iteration counter (just to prevent an infinite loop)\n", + " n_iter = n_iter+1\n", + " # Calculate all four points\n", + " lossa = loss_function_1D(a, data, model, phi,gradient)\n", + " lossb = loss_function_1D(b, data, model, phi,gradient)\n", + " lossc = loss_function_1D(c, data, model, phi,gradient)\n", + " lossd = loss_function_1D(d, data, model, phi,gradient)\n", + "\n", + " if verbose:\n", + " print('Iter %d, a=%3.3f, b=%3.3f, c=%3.3f, d=%3.3f'%(n_iter, a,b,c,d))\n", + " print('a %f, b%f, c%f, d%f'%(lossa,lossb,lossc,lossd))\n", + "\n", + " # Rule #1 If point A is less than points B, C, and D then halve points B,C, and D\n", + " if np.argmin((lossa,lossb,lossc,lossd))==0:\n", + " b = b/2\n", + " c = c/2\n", + " d = d/2\n", + " continue;\n", + "\n", + " # Rule #2 If point b is less than point c then\n", + " # then point d becomes point c, and\n", + " # point b becomes 1/3 between a and new d\n", + " # point c becomes 2/3 between a and new d \n", + " if lossb < lossc:\n", + " d = c\n", + " b = a+ (d-a)/3\n", + " c = a+ 2*(d-a)/3\n", + " continue\n", + "\n", + " # Rule #2 If point c is less than point b then\n", + " # then point a becomes point b, and\n", + " # point b becomes 1/3 between new a and d\n", + " # point c becomes 2/3 between new a and d \n", + " a = b\n", + " b = a+ (d-a)/3\n", + " c = a+ 2*(d-a)/3\n", + " \n", + " # Return average of two middle points\n", + " return (b+c)/2.0" + ], + "metadata": { + "id": "XrJ2gQjfw1XP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def gradient_descent_step(phi, data, model):\n", + " # TODO -- update Phi with the gradient descent step\n", + " # 1. Compute the gradient\n", + " # 2. Find the best step size alpha using line search (use minus 1 times the gradient so it searches in the right direction)\n", + " # 3. Update the parameters phi \n", + "\n", + " return phi" + ], + "metadata": { + "id": "YVq6rmaWRD2M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize the parameters and draw the model\n", + "n_steps = 10\n", + "phi_all = np.zeros((2,n_steps+1))\n", + "phi_all[0,0] = 1.6\n", + "phi_all[1,0] = -0.5\n", + "\n", + "# Measure loss and draw initial model\n", + "loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,0:1])\n", + "draw_model(data,model,phi_all[:,0:1], \"Initial parameters, Loss = %f\"%(loss))\n", + "\n", + "for c_step in range (n_steps):\n", + " # Do gradient descent step\n", + " phi_all[:,c_step+1:c_step+2] = gradient_descent_step(phi_all[:,c_step:c_step+1],data, model)\n", + " # Measure loss and draw model\n", + " loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,c_step+1:c_step+2])\n", + " draw_model(data,model,phi_all[:,c_step+1], \"Iteration %d, loss = %f\"%(c_step+1,loss))\n", + "\n", + "draw_loss_function(compute_loss, data, model,phi_all)\n" + ], + "metadata": { + "id": "tOLd0gtdRLLS" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "Oi8ZlH0ptLqA" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Training_III.ipynb b/CM20315/CM20315_Training_III.ipynb new file mode 100644 index 0000000..f91c021 --- /dev/null +++ b/CM20315/CM20315_Training_III.ipynb @@ -0,0 +1,585 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [], + "authorship_tag": "ABX9TyMzgGVp+/BUCXimg7Ip9lhp", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Training III\n", + "\n", + "We now have a model and a loss function which we can use to judge how good that model is. It's time to put the \"learning\" into machine learning.\n", + "\n", + "Learning involves finding the parameters that minimize the loss. That might seems like it's not too hard, but modern models might have billions of parameters. There's an exponential number of possible parameter combinations, and there's no way we can make any progress with exhaustive search.\n", + "\n", + "In part I we considered 1D search using a bracketing approach. In part II we experimented with fitting a linear regression model (which has a convex loss function). In this part, we'll fit the Gabor model, which has a non-convex loss function.\n", + "\n", + "\n" + ], + "metadata": { + "id": "el8l05WQEO46" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xhmIOLiZELV_" + }, + "outputs": [], + "source": [ + "# import libraries\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib import cm\n", + "from matplotlib.colors import ListedColormap" + ] + }, + { + "cell_type": "code", + "source": [ + "# Let's create our training data 30 pairs {x_i, y_i}\n", + "# We'll try to fit the Gabor model to these data\n", + "data = np.array([[-1.920e+00,-1.422e+01,1.490e+00,-1.940e+00,-2.389e+00,-5.090e+00,\n", + " -8.861e+00,3.578e+00,-6.010e+00,-6.995e+00,3.634e+00,8.743e-01,\n", + " -1.096e+01,4.073e-01,-9.467e+00,8.560e+00,1.062e+01,-1.729e-01,\n", + " 1.040e+01,-1.261e+01,1.574e-01,-1.304e+01,-2.156e+00,-1.210e+01,\n", + " -1.119e+01,2.902e+00,-8.220e+00,-1.179e+01,-8.391e+00,-4.505e+00],\n", + " [-1.051e+00,-2.482e-02,8.896e-01,-4.943e-01,-9.371e-01,4.306e-01,\n", + " 9.577e-03,-7.944e-02 ,1.624e-01,-2.682e-01,-3.129e-01,8.303e-01,\n", + " -2.365e-02,5.098e-01,-2.777e-01,3.367e-01,1.927e-01,-2.222e-01,\n", + " 6.352e-02,6.888e-03,3.224e-02,1.091e-02,-5.706e-01,-5.258e-02,\n", + " -3.666e-02,1.709e-01,-4.805e-02,2.008e-01,-1.904e-01,5.952e-01]])" + ], + "metadata": { + "id": "4cRkrh9MZ58Z" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's define our model\n", + "def model(phi,x):\n", + " sin_component = np.sin(phi[0] + 0.06 * phi[1] * x)\n", + " gauss_component = np.exp(-(phi[0] + 0.06 * phi[1] * x) * (phi[0] + 0.06 * phi[1] * x) / 32)\n", + " y_pred= sin_component * gauss_component\n", + " return y_pred" + ], + "metadata": { + "id": "WQUERmb2erAe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Draw model\n", + "def draw_model(data,model,phi,title=None):\n", + " x_model = np.arange(-15,15,0.1)\n", + " y_model = model(phi,x_model)\n", + "\n", + " fix, ax = plt.subplots()\n", + " ax.plot(data[0,:],data[1,:],'bo')\n", + " ax.plot(x_model,y_model,'m-')\n", + " ax.set_xlim([-15,15]);ax.set_ylim([-1,1])\n", + " ax.set_xlabel('x'); ax.set_ylabel('y')\n", + " if title is not None:\n", + " ax.set_title(title)\n", + " plt.show()" + ], + "metadata": { + "id": "qFRe9POHF2le" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize the parmaeters and draw the model\n", + "phi = np.zeros((2,1))\n", + "phi[0] = -5 # Horizontal offset\n", + "phi[1] = 25 # Frequency\n", + "draw_model(data,model,phi, \"Initial parameters\")\n" + ], + "metadata": { + "id": "TXx1Tpd1Tl-I" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now lets create compute the sum of squares loss for the training data" + ], + "metadata": { + "id": "QU5mdGvpTtEG" + } + }, + { + "cell_type": "code", + "source": [ + "def compute_loss(data_x, data_y, model, phi):\n", + " # TODO -- Write this function -- replace the line below\n", + " # TODO -- First make model predictions from data x\n", + " # TODO -- Then compute the squared difference between the predictions and true y values\n", + " # TODO -- Then sum them all and return\n", + " loss = 0\n", + " return loss" + ], + "metadata": { + "id": "I7dqTY2Gg7CR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's just test that we got that right" + ], + "metadata": { + "id": "eB5DQvU5hYNx" + } + }, + { + "cell_type": "code", + "source": [ + "loss = compute_loss(data[0,:],data[1,:],model,np.array([[0.6],[-0.2]]))\n", + "print('Your loss = %3.3f, Correct loss = %3.3f'%(loss, 16.419))" + ], + "metadata": { + "id": "Ty05UtEEg9tc" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's plot the whole loss function" + ], + "metadata": { + "id": "F3trnavPiHpH" + } + }, + { + "cell_type": "code", + "source": [ + "def draw_loss_function(compute_loss, data, model, phi_iters = None):\n", + " # Define pretty colormap\n", + " my_colormap_vals_hex =('2a0902', '2b0a03', '2c0b04', '2d0c05', '2e0c06', '2f0d07', '300d08', '310e09', '320f0a', '330f0b', '34100b', '35110c', '36110d', '37120e', '38120f', '39130f', '3a1410', '3b1411', '3c1511', '3d1612', '3e1613', '3f1713', '401714', '411814', '421915', '431915', '451a16', '461b16', '471b17', '481c17', '491d18', '4a1d18', '4b1e19', '4c1f19', '4d1f1a', '4e201b', '50211b', '51211c', '52221c', '53231d', '54231d', '55241e', '56251e', '57261f', '58261f', '592720', '5b2821', '5c2821', '5d2922', '5e2a22', '5f2b23', '602b23', '612c24', '622d25', '632e25', '652e26', '662f26', '673027', '683027', '693128', '6a3229', '6b3329', '6c342a', '6d342a', '6f352b', '70362c', '71372c', '72372d', '73382e', '74392e', '753a2f', '763a2f', '773b30', '783c31', '7a3d31', '7b3e32', '7c3e33', '7d3f33', '7e4034', '7f4134', '804235', '814236', '824336', '834437', '854538', '864638', '874739', '88473a', '89483a', '8a493b', '8b4a3c', '8c4b3c', '8d4c3d', '8e4c3e', '8f4d3f', '904e3f', '924f40', '935041', '945141', '955242', '965343', '975343', '985444', '995545', '9a5646', '9b5746', '9c5847', '9d5948', '9e5a49', '9f5a49', 'a05b4a', 'a15c4b', 'a35d4b', 'a45e4c', 'a55f4d', 'a6604e', 'a7614e', 'a8624f', 'a96350', 'aa6451', 'ab6552', 'ac6552', 'ad6653', 'ae6754', 'af6855', 'b06955', 'b16a56', 'b26b57', 'b36c58', 'b46d59', 'b56e59', 'b66f5a', 'b7705b', 'b8715c', 'b9725d', 'ba735d', 'bb745e', 'bc755f', 'bd7660', 'be7761', 'bf7862', 'c07962', 'c17a63', 'c27b64', 'c27c65', 'c37d66', 'c47e67', 'c57f68', 'c68068', 'c78169', 'c8826a', 'c9836b', 'ca846c', 'cb856d', 'cc866e', 'cd876f', 'ce886f', 'ce8970', 'cf8a71', 'd08b72', 'd18c73', 'd28d74', 'd38e75', 'd48f76', 'd59077', 'd59178', 'd69279', 'd7937a', 'd8957b', 'd9967b', 'da977c', 'da987d', 'db997e', 'dc9a7f', 'dd9b80', 'de9c81', 'de9d82', 'df9e83', 'e09f84', 'e1a185', 'e2a286', 'e2a387', 'e3a488', 'e4a589', 'e5a68a', 'e5a78b', 'e6a88c', 'e7aa8d', 'e7ab8e', 'e8ac8f', 'e9ad90', 'eaae91', 'eaaf92', 'ebb093', 'ecb295', 'ecb396', 'edb497', 'eeb598', 'eeb699', 'efb79a', 'efb99b', 'f0ba9c', 'f1bb9d', 'f1bc9e', 'f2bd9f', 'f2bfa1', 'f3c0a2', 'f3c1a3', 'f4c2a4', 'f5c3a5', 'f5c5a6', 'f6c6a7', 'f6c7a8', 'f7c8aa', 'f7c9ab', 'f8cbac', 'f8ccad', 'f8cdae', 'f9ceb0', 'f9d0b1', 'fad1b2', 'fad2b3', 'fbd3b4', 'fbd5b6', 'fbd6b7', 'fcd7b8', 'fcd8b9', 'fcdaba', 'fddbbc', 'fddcbd', 'fddebe', 'fddfbf', 'fee0c1', 'fee1c2', 'fee3c3', 'fee4c5', 'ffe5c6', 'ffe7c7', 'ffe8c9', 'ffe9ca', 'ffebcb', 'ffeccd', 'ffedce', 'ffefcf', 'fff0d1', 'fff2d2', 'fff3d3', 'fff4d5', 'fff6d6', 'fff7d8', 'fff8d9', 'fffada', 'fffbdc', 'fffcdd', 'fffedf', 'ffffe0')\n", + " my_colormap_vals_dec = np.array([int(element,base=16) for element in my_colormap_vals_hex])\n", + " r = np.floor(my_colormap_vals_dec/(256*256))\n", + " g = np.floor((my_colormap_vals_dec - r *256 *256)/256)\n", + " b = np.floor(my_colormap_vals_dec - r * 256 *256 - g * 256)\n", + " my_colormap = ListedColormap(np.vstack((r,g,b)).transpose()/255.0)\n", + "\n", + " # Make grid of intercept/slope values to plot\n", + " offsets_mesh, freqs_mesh = np.meshgrid(np.arange(-10,10.0,0.1), np.arange(2.5,22.5,0.1))\n", + " loss_mesh = np.zeros_like(freqs_mesh)\n", + " # Compute loss for every set of parameters\n", + " for idslope, slope in np.ndenumerate(freqs_mesh):\n", + " loss_mesh[idslope] = compute_loss(data[0,:], data[1,:], model, np.array([[offsets_mesh[idslope]], [slope]]))\n", + "\n", + " fig,ax = plt.subplots()\n", + " fig.set_size_inches(8,8)\n", + " ax.contourf(offsets_mesh,freqs_mesh,loss_mesh,256,cmap=my_colormap)\n", + " ax.contour(offsets_mesh,freqs_mesh,loss_mesh,20,colors=['#80808080'])\n", + " if phi_iters is not None:\n", + " ax.plot(phi_iters[0,:], phi_iters[1,:],'go-')\n", + " ax.set_ylim([2.5,22.5])\n", + " ax.set_xlabel('Offset $\\phi_{0}$'); ax.set_ylabel('Frequency, $\\phi_{1}$')\n", + " plt.show()" + ], + "metadata": { + "id": "K-NTHpAAHlCl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "draw_loss_function(compute_loss, data, model)" + ], + "metadata": { + "id": "l8HbvIupnTME" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now let's compute the gradient vector for a given set of parameters:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial L}{\\partial \\boldsymbol\\phi} = \\begin{bmatrix}\\frac{\\partial L}{\\partial \\phi_0} \\\\\\frac{\\partial L}{\\partial \\phi_1} \\end{bmatrix}.\n", + "\\end{equation}" + ], + "metadata": { + "id": "s9Duf05WqqSC" + } + }, + { + "cell_type": "code", + "source": [ + "# These came from writing out the expression for the sum of squares loss and taking the\n", + "# derivative with respect to phi0 and phi1. It was a lot of hassle to get it right!\n", + "def gabor_deriv_phi0(data_x,data_y,phi0, phi1):\n", + " x = 0.06 * phi1 * data_x + phi0\n", + " y = data_y \n", + " cos_component = np.cos(x)\n", + " sin_component = np.sin(x)\n", + " gauss_component = np.exp(-0.5 * x *x / 16)\n", + " deriv = cos_component * gauss_component - sin_component * gauss_component * x / 16\n", + " deriv = 2* deriv * (sin_component * gauss_component - y)\n", + " return np.sum(deriv)\n", + "\n", + "def gabor_deriv_phi1(data_x, data_y,phi0, phi1):\n", + " x = 0.06 * phi1 * data_x + phi0\n", + " y = data_y \n", + " cos_component = np.cos(x)\n", + " sin_component = np.sin(x)\n", + " gauss_component = np.exp(-0.5 * x *x / 16)\n", + " deriv = 0.06 * data_x * cos_component * gauss_component - 0.06 * data_x*sin_component * gauss_component * x / 16\n", + " deriv = 2*deriv * (sin_component * gauss_component - y)\n", + " return np.sum(deriv)\n", + "\n", + "def compute_gradient(data_x, data_y, phi):\n", + " dl_dphi0 = gabor_deriv_phi0(data_x, data_y, phi[0],phi[1])\n", + " dl_dphi1 = gabor_deriv_phi1(data_x, data_y, phi[0],phi[1])\n", + " # Return the gradient\n", + " return np.array([[dl_dphi0],[dl_dphi1]])" + ], + "metadata": { + "id": "UpswmkL2qwBT" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "We can check we got this right using a trick known as **finite differences**. If we evaluate the function and then change one of the parameters by a very small amount and normalize by that amount, we get an approximation to the gradient, so:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial L}{\\partial \\phi_{0}}&\\approx & \\frac{L[\\phi_0+\\delta, \\phi_1]-L[\\phi_0, \\phi_1]}{\\delta}\\\\\n", + "\\frac{\\partial L}{\\partial \\phi_{1}}&\\approx & \\frac{L[\\phi_0, \\phi_1+\\delta]-L[\\phi_0, \\phi_1]}{\\delta}\n", + "\\end{eqnarray}\n", + "\n", + "We don't do this when there are many parameters; for a million parameters, we would have to evaluate the loss function two million times, and usually computing the gradients directly is much more efficient." + ], + "metadata": { + "id": "RS1nEcYVuEAM" + } + }, + { + "cell_type": "code", + "source": [ + "# Compute the gradient using your function\n", + "gradient = compute_gradient(data[0,:],data[1,:], phi)\n", + "print(\"Your gradients: (%3.3f,%3.3f)\"%(gradient[0],gradient[1]))\n", + "# Approximate the gradients with finite differences\n", + "delta = 0.0001\n", + "dl_dphi0_est = (compute_loss(data[0,:],data[1,:],model,phi+np.array([[delta],[0]])) - \\\n", + " compute_loss(data[0,:],data[1,:],model,phi))/delta\n", + "dl_dphi1_est = (compute_loss(data[0,:],data[1,:],model,phi+np.array([[0],[delta]])) - \\\n", + " compute_loss(data[0,:],data[1,:],model,phi))/delta\n", + "print(\"Approx gradients: (%3.3f,%3.3f)\"%(dl_dphi0_est,dl_dphi1_est))\n" + ], + "metadata": { + "id": "QuwAHN7yt-gi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Now we are ready to perform gradient descent. We'll need to use our line search routine from part I, which I've reproduced here plus the helper function loss_function_1D that converts from a 2D problem to a 1D problem" + ], + "metadata": { + "id": "5EIjMM9Fw2eT" + } + }, + { + "cell_type": "code", + "source": [ + "def loss_function_1D(dist_prop, data, model, phi_start, gradient):\n", + " # Return the loss after moving this far\n", + " return compute_loss(data[0,:], data[1,:], model, phi_start+ gradient * dist_prop)\n", + "\n", + "def line_search(data, model, phi, gradient, thresh=.00001, max_dist = 0.1, max_iter = 15, verbose=False):\n", + " # Initialize four points along the range we are going to search\n", + " a = 0\n", + " b = 0.33 * max_dist\n", + " c = 0.66 * max_dist\n", + " d = 1.0 * max_dist\n", + " n_iter =0;\n", + " \n", + " # While we haven't found the minimum closely enough\n", + " while np.abs(b-c) > thresh and n_iter < max_iter:\n", + " # Increment iteration counter (just to prevent an infinite loop)\n", + " n_iter = n_iter+1\n", + " # Calculate all four points\n", + " lossa = loss_function_1D(a, data, model, phi,gradient)\n", + " lossb = loss_function_1D(b, data, model, phi,gradient)\n", + " lossc = loss_function_1D(c, data, model, phi,gradient)\n", + " lossd = loss_function_1D(d, data, model, phi,gradient)\n", + "\n", + " if verbose:\n", + " print('Iter %d, a=%3.3f, b=%3.3f, c=%3.3f, d=%3.3f'%(n_iter, a,b,c,d))\n", + " print('a %f, b%f, c%f, d%f'%(lossa,lossb,lossc,lossd))\n", + "\n", + " # Rule #1 If point A is less than points B, C, and D then halve points B,C, and D\n", + " if np.argmin((lossa,lossb,lossc,lossd))==0:\n", + " b = b/2\n", + " c = c/2\n", + " d = d/2\n", + " continue;\n", + "\n", + " # Rule #2 If point b is less than point c then\n", + " # then point d becomes point c, and\n", + " # point b becomes 1/3 between a and new d\n", + " # point c becomes 2/3 between a and new d \n", + " if lossb < lossc:\n", + " d = c\n", + " b = a+ (d-a)/3\n", + " c = a+ 2*(d-a)/3\n", + " continue\n", + "\n", + " # Rule #2 If point c is less than point b then\n", + " # then point a becomes point b, and\n", + " # point b becomes 1/3 between new a and d\n", + " # point c becomes 2/3 between new a and d \n", + " a = b\n", + " b = a+ (d-a)/3\n", + " c = a+ 2*(d-a)/3\n", + " \n", + " # Return average of two middle points\n", + " return (b+c)/2.0" + ], + "metadata": { + "id": "XrJ2gQjfw1XP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def gradient_descent_step(phi, data, model):\n", + " # Step 1: Compute the gradient\n", + " gradient = compute_gradient(data[0,:],data[1,:], phi)\n", + " # Step 2: Update the parameters -- note we want to search in the negative (downhill direction)\n", + " alpha = line_search(data, model, phi, gradient*-1, max_dist = 2.0)\n", + " phi = phi - alpha * gradient\n", + " return phi" + ], + "metadata": { + "id": "YVq6rmaWRD2M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize the parameters\n", + "n_steps = 21\n", + "phi_all = np.zeros((2,n_steps+1))\n", + "phi_all[0,0] = -1.5\n", + "phi_all[1,0] = 8.5\n", + "\n", + "# Measure loss and draw initial model\n", + "loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,0:1])\n", + "draw_model(data,model,phi_all[:,0:1], \"Initial parameters, Loss = %f\"%(loss))\n", + "\n", + "for c_step in range (n_steps):\n", + " # Do gradient descent step\n", + " phi_all[:,c_step+1:c_step+2] = gradient_descent_step(phi_all[:,c_step:c_step+1],data, model)\n", + " # Measure loss and draw model every 4th step\n", + " if c_step % 4 == 0:\n", + " loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,c_step+1:c_step+2])\n", + " draw_model(data,model,phi_all[:,c_step+1], \"Iteration %d, loss = %f\"%(c_step+1,loss))\n", + "\n", + "draw_loss_function(compute_loss, data, model,phi_all)\n" + ], + "metadata": { + "id": "tOLd0gtdRLLS" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO Experiment with starting the optimization in the previous cell in different places\n", + "# and show that it heads to a local minimum if we don't start it in the right valley" + ], + "metadata": { + "id": "Oi8ZlH0ptLqA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def gradient_descent_step_fixed_learning_rate(phi, data, model, alpha):\n", + " # TODO -- fill in this routine so that we take a fixed size step of size alpha without using line search\n", + "\n", + " return phi" + ], + "metadata": { + "id": "4l-ueLk-oAxV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Initialize the parameters\n", + "n_steps = 21\n", + "phi_all = np.zeros((2,n_steps+1))\n", + "phi_all[0,0] = -1.5\n", + "phi_all[1,0] = 8.5\n", + "\n", + "# Measure loss and draw initial model\n", + "loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,0:1])\n", + "draw_model(data,model,phi_all[:,0:1], \"Initial parameters, Loss = %f\"%(loss))\n", + "\n", + "for c_step in range (n_steps):\n", + " # Do gradient descent step\n", + " phi_all[:,c_step+1:c_step+2] = gradient_descent_step_fixed_learning_rate(phi_all[:,c_step:c_step+1],data, model,alpha =0.2)\n", + " # Measure loss and draw model every 4th step\n", + " if c_step % 4 == 0:\n", + " loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,c_step+1:c_step+2])\n", + " draw_model(data,model,phi_all[:,c_step+1], \"Iteration %d, loss = %f\"%(c_step+1,loss))\n", + "\n", + "draw_loss_function(compute_loss, data, model,phi_all)\n" + ], + "metadata": { + "id": "oi9MX_GRpM41" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO Experiment with the learning rate, alpha. \n", + "# What happens if you set it too large?\n", + "# What happens if you set it too small?" + ], + "metadata": { + "id": "In6sQ5YCpMqn" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def stochastic_gradient_descent_step(phi, data, model, alpha, batch_size):\n", + " # TODO -- fill in this routine so that we take a fixed size step of size alpha but only using a subset (batch) of the data\n", + " # at each step\n", + " # You can use the function np.random.permutation to generate a random permutation of the n_data = data.shape[1] indices\n", + " # and then just choose the first n=batch_size of these indices. Then select compute the gradient update\n", + " # from just the data with these indices. Don't worry about sampling with replacement.\n", + "\n", + "\n", + " return phi" + ], + "metadata": { + "id": "VKTC9-1Gpm3N" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set the random number generator so you always get same numbers (disable if you don't want this)\n", + "np.random.seed(1)\n", + "# Initialize the parameters\n", + "n_steps = 41\n", + "phi_all = np.zeros((2,n_steps+1))\n", + "phi_all[0,0] = 3.5\n", + "phi_all[1,0] = 6.5\n", + "\n", + "# Measure loss and draw initial model\n", + "loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,0:1])\n", + "draw_model(data,model,phi_all[:,0:1], \"Initial parameters, Loss = %f\"%(loss))\n", + "\n", + "for c_step in range (n_steps):\n", + " # Do gradient descent step\n", + " phi_all[:,c_step+1:c_step+2] = stochastic_gradient_descent_step(phi_all[:,c_step:c_step+1],data, model,alpha =0.8, batch_size=5)\n", + " # Measure loss and draw model every 4th step\n", + " if c_step % 8 == 0:\n", + " loss = compute_loss(data[0,:], data[1,:], model, phi_all[:,c_step+1:c_step+2])\n", + " draw_model(data,model,phi_all[:,c_step+1], \"Iteration %d, loss = %f\"%(c_step+1,loss))\n", + "\n", + "draw_loss_function(compute_loss, data, model,phi_all)" + ], + "metadata": { + "id": "469OP_UHskJ4" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO -- Experiment with different learning rates, starting points, batch sizes, number of steps. Get a feel for this." + ], + "metadata": { + "id": "LxE2kTa3s29p" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO -- How about adding a learning rate schedule? Reduce the learning rate by a factor of beta every M iterations" + ], + "metadata": { + "id": "lw4QPOaQTh5e" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/CM20315/CM20315_Transformers.ipynb b/CM20315/CM20315_Transformers.ipynb new file mode 100644 index 0000000..7f1ecc2 --- /dev/null +++ b/CM20315/CM20315_Transformers.ipynb @@ -0,0 +1,634 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMfWL40+ZshPZhweAtQ9Fn6", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Transformers\n", + "\n", + "This practical investigates neural decoding from transformer models. Run the next three cells as they might take a while to run (they have to download some stuff), and then read the next text box while you are waiting." + ], + "metadata": { + "id": "RnIUiieJWu6e" + } + }, + { + "cell_type": "code", + "source": [ + "!pip install transformers" + ], + "metadata": { + "id": "7abjZ9pMVj3k" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "from transformers import GPT2LMHeadModel, GPT2Tokenizer, set_seed\n", + "import torch\n", + "import torch.nn.functional as F\n", + "import numpy as np" + ], + "metadata": { + "id": "sMOyD0zem2Ef" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load model and tokenizer\n", + "model = GPT2LMHeadModel.from_pretrained('gpt2')\n", + "tokenizer = GPT2Tokenizer.from_pretrained('gpt2')" + ], + "metadata": { + "id": "pZgfxbzKWNSR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Decoding from GPT2\n", + "\n", + "This tutorial investigates how to use GPT2 (the forerunner of GPT3) to generate text. There are a number of ways to do this that trade-off the realism of the text against the amount of variation.\n", + "\n", + "At every stage, GPT2 takes an input string and returns a probability for each of the possible subsequent tokens. We can choose what to do with these probability. We could always *greedily choose* the most likely next token, or we could draw a *sample* randomly according to the probabilities. There are also intermediate strategies such as *top-k sampling* and *nucleus sampling*, that have some controlled randomness.\n", + "\n", + "We'll also investigate *beam search* -- the idea is that rather than greedily take the next best token at each stage, we maintain a set of hypotheses (beams)as we add each subsequent token and return the most likely overall hypothesis. This is not necessarily the same result we get from greedily choosing the next token. " + ], + "metadata": { + "id": "TfhAGy0TXEvV" + } + }, + { + "cell_type": "markdown", + "source": [ + "First, let's investigate the token themselves. The code below prints out the vocabulary size and shows 20 random tokens. " + ], + "metadata": { + "id": "vsmO9ptzau3_" + } + }, + { + "cell_type": "code", + "source": [ + "np.random.seed(1)\n", + "print(\"Number of tokens in dictionary = %d\"%(tokenizer.vocab_size))\n", + "for i in range(20):\n", + " index = np.random.randint(tokenizer.vocab_size)\n", + " print(\"Token: %d \"%(index)+tokenizer.decode(torch.tensor(index), skip_special_tokens=True))\n" + ], + "metadata": { + "id": "dmmBNS5GY_yk" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Sampling\n", + "\n", + "Each time we run GPT2 it will take in a set of tokens, and return a probability over each of the possible next tokens. The simplest thing we could do is to just draw a sample from this probability distribution each time." + ], + "metadata": { + "id": "MUM3kLEjbTso" + } + }, + { + "cell_type": "code", + "source": [ + "def sample_next_token(input_tokens, model, tokenizer):\n", + " # Run model to get prediction over next output\n", + " outputs = model(input_ids = input_tokens['input_ids'], attention_mask = input_tokens['attention_mask'])\n", + " # Find prediction\n", + " prob_over_tokens = F.softmax(outputs.logits, dim=-1).detach().numpy()[0,-1]\n", + " # TODO: Draw a random token according to the probabilities\n", + " # Use: https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html\n", + " # Replace this line\n", + " next_token = [5000]\n", + "\n", + " # Append token to sentence\n", + " output_tokens = input_tokens\n", + " output_tokens[\"input_ids\"] = torch.cat((output_tokens['input_ids'],torch.tensor([next_token])),dim=1)\n", + " output_tokens['attention_mask'] = torch.cat((output_tokens['attention_mask'],torch.tensor([[1]])),dim=1)\n", + " output_tokens['last_token_prob'] = prob_over_tokens[next_token]\n", + "\n", + " return output_tokens" + ], + "metadata": { + "id": "TIyNgg0FkJKO" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Expected output:\n", + "# \"The best thing about Bath is that they don't even change or shrink anymore.\"\n", + "\n", + "set_seed(0)\n", + "input_txt = \"The best thing about Bath is\"\n", + "input_tokens = tokenizer(input_txt, return_tensors='pt')\n", + "for i in range(10):\n", + " input_tokens = sample_next_token(input_tokens, model, tokenizer)\n", + " print(tokenizer.decode(input_tokens[\"input_ids\"][0], skip_special_tokens=True))\n", + "\n" + ], + "metadata": { + "id": "BHs-IWaz9MNY" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO Modify the code below by changing the number of tokens generated and the initial sentence\n", + "# to get a feel for how well this works. Since I didn't reset the seed, it will give a different\n", + "# answer every time that you run it.\n", + "\n", + "# TODO Experiment with changing this line:\n", + "input_txt = \"The best thing about Bath is\"\n", + "input_tokens = tokenizer(input_txt, return_tensors='pt')\n", + "# TODO Experiment with changing this line:\n", + "for i in range(10):\n", + " input_tokens = sample_next_token(input_tokens, model, tokenizer)\n", + " print(tokenizer.decode(input_tokens[\"input_ids\"][0], skip_special_tokens=True))" + ], + "metadata": { + "id": "yN98_7WqbvIe" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Greedy token selection\n", + "\n", + "You probably (correctly) got the impression that the text from pure sampling of the probability model can be kind of random. How about if we choose most likely token at each step?\n" + ], + "metadata": { + "id": "7eHFLCeZcmmg" + } + }, + { + "cell_type": "code", + "source": [ + "def get_best_next_token(input_tokens, model, tokenizer):\n", + " # Run model to get prediction over next output\n", + " outputs = model(input_ids = input_tokens['input_ids'], attention_mask = input_tokens['attention_mask'])\n", + " # Find prediction\n", + " prob_over_tokens = F.softmax(outputs.logits, dim=-1).detach().numpy()[0,-1]\n", + "\n", + " # TODO -- find the token index with the maximum probability\n", + " # It should be returns as a list (i.e., put squared brackets around it)\n", + " # Use https://numpy.org/doc/stable/reference/generated/numpy.argmax.html\n", + " # Replace this line\n", + " next_token = [5000]\n", + "\n", + " # Append token to sentence\n", + " output_tokens = input_tokens\n", + " output_tokens[\"input_ids\"] = torch.cat((output_tokens['input_ids'],torch.tensor([next_token])),dim=1)\n", + " output_tokens['attention_mask'] = torch.cat((output_tokens['attention_mask'],torch.tensor([[1]])),dim=1)\n", + " output_tokens['last_token_prob'] = prob_over_tokens[next_token]\n", + " return output_tokens" + ], + "metadata": { + "id": "OhRzynEjxpZF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Expected output:\n", + "# The best thing about Bath is that it's a place where you can go to\n", + "set_seed(0)\n", + "input_txt = \"The best thing about Bath is\"\n", + "input_tokens = tokenizer(input_txt, return_tensors='pt')\n", + "for i in range(10):\n", + " input_tokens = get_best_next_token(input_tokens, model, tokenizer)\n", + " print(tokenizer.decode(input_tokens[\"input_ids\"][0], skip_special_tokens=True))" + ], + "metadata": { + "id": "gKB1Mgndj-Hm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TODO Modify the code below by changing the number of tokens generated and the initial sentence\n", + "# to get a feel for how well this works. \n", + "\n", + "# TODO Experiment with changing this line:\n", + "input_txt = \"The best thing about Bath is\"\n", + "input_tokens = tokenizer(input_txt, return_tensors='pt')\n", + "# TODO Experiment with changing this line:\n", + "for i in range(10):\n", + " input_tokens = get_best_next_token(input_tokens, model, tokenizer)\n", + " print(tokenizer.decode(input_tokens[\"input_ids\"][0], skip_special_tokens=True))" + ], + "metadata": { + "id": "L1YHKaYFfC0M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Top-K sampling\n", + "\n", + "You probably noticed that the greedy strategy produces quite realistic text, but it's kind of boring. It produces generic answers. Also, if this was a chatbot, then we wouldn't necessarily want it to produce the same answer to a question each time. \n", + "\n", + "Top-K sampling is a compromise strategy that samples randomly from the top K most probable tokens. We could just choose them with a uniform distribution, or (as here) we could sample them according to their original probabilities." + ], + "metadata": { + "id": "1ORFXYX_gBDT" + } + }, + { + "cell_type": "code", + "source": [ + "def get_top_k_token(input_tokens, model, tokenizer, k=20):\n", + " # Run model to get prediction over next output\n", + " outputs = model(input_ids = input_tokens['input_ids'], attention_mask = input_tokens['attention_mask'])\n", + " # Find prediction\n", + " prob_over_tokens = F.softmax(outputs.logits, dim=-1).detach().numpy()[0,-1]\n", + "\n", + " # Draw a sample from the top K most likely tokens.\n", + " # Take copy of the probabilities and sort from largest to smallest (use np.sort)\n", + " # TODO -- replace this line\n", + " sorted_prob_over_tokens = prob_over_tokens\n", + "\n", + " # Find the probability at the k'th position\n", + " # TODO -- replace this line\n", + " kth_prob_value = 0.0\n", + "\n", + " # Set all probabilities below this value to zero \n", + " prob_over_tokens[prob_over_tokensthresh)\n", + " print(\"Choosing from %d tokens\"%(thresh_index))\n", + " # TODO: Find the probabilitiy value to threshold \n", + " # Replace this line:\n", + " thresh_prob = sorted_probs_decreasing[thresh_index]\n", + "\n", + " # Set any probabilities less than this to zero \n", + " prob_over_tokens[prob_over_tokens\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework I -- Model hyperparameters\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNIST 1D dataset.\n", + "\n", + "In this coursework, you need to modify the **model hyperparameters** (only) to improve the performance over the current attempt. This could mean the number of layers, the number of hidden units per layer, or the type of activation function, or any combination of the three.\n", + "\n", + "The only constraint is that you MUST use a fully connected network (no convolutional networks for now if you have read ahead in the book).\n", + "\n", + "You must improve the performance by at least 2% to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu\n", + "\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random\n", + "import gdown" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "\n", + "# Run this once to copy the train and validation data to your CoLab environment\n", + "# or download from my github to your local machine if you are doing this locally\n", + "if not os.path.exists('./Data.zip'):\n", + " !gdown 1HtnCrncY6dFCYqzgPf1HtPVAerTpwFRm\n", + " !unzip Data.zip" + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# YOU SHOULD ONLY CHANGE THIS CELL!\n", + "\n", + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + "\n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part I: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_I_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/CM20315_2023/CM20315_Coursework_II.ipynb b/CM20315_2023/CM20315_Coursework_II.ipynb new file mode 100644 index 0000000..0ce1584 --- /dev/null +++ b/CM20315_2023/CM20315_Coursework_II.ipynb @@ -0,0 +1,276 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyM+iKos5DEoHUxL8+9oxA2A", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework II -- Training hyperparameters\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNist 1D dataset.\n", + "\n", + "In this coursework, you need to modify the **training hyperparameters** (only) to improve the performance over the current attempt. This could mean the training algorithm, learning rate, learning rate schedule, momentum term, initialization etc. \n", + "\n", + "You must improve the performance by at least 2% to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random\n", + "import gdown" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment\n", + "if not os.path.exists('./Data.zip'):\n", + " !gdown 1HtnCrncY6dFCYqzgPf1HtPVAerTpwFRm\n", + " !unzip Data.zip" + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy',allow_pickle=True)\n", + "train_data_y = np.load('train_data_y.npy',allow_pickle=True)\n", + "val_data_x = np.load('val_data_x.npy',allow_pickle=True)\n", + "val_data_y = np.load('val_data_y.npy',allow_pickle=True)\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# YOU SHOULD NOT CHANGE THIS CELL!\n", + "\n", + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "print(x_train.shape)\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "print(y_train.shape)\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + "\n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part II: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_II_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/CM20315_2023/CM20315_Coursework_III.ipynb b/CM20315_2023/CM20315_Coursework_III.ipynb new file mode 100644 index 0000000..ebc7cdf --- /dev/null +++ b/CM20315_2023/CM20315_Coursework_III.ipynb @@ -0,0 +1,275 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyNDH1z3I76jjglu3o0LSlZc", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework III -- Regularization\n", + "\n", + "The goal of the coursework is to modify a simple bit of numpy code that trains a network and measures the performance on a validation set for the MNist 1D dataset.\n", + "\n", + "In this coursework, you need add **regularization** of some kind to improve the performance. Anything from chapter 9 of the book or anything else you can find is fine *except* early stopping. You must not change the model hyperparameters or the training algorithm.\n", + "\n", + "You must improve the performance by at least 2% to get full marks.\n", + "\n", + "You will need to upload three things to Moodle:\n", + "1. The image that this notebook saves (click the folder icon on the left on colab to download it)\n", + "2. The lines of code you changed\n", + "3. The whole notebook as a .ipynb file. You can do this on the File menu\n", + "\n", + "\n" + ], + "metadata": { + "id": "t9vk9Elugvmi" + } + }, + { + "cell_type": "code", + "source": [ + "import numpy as np\n", + "import os\n", + "import torch, torch.nn as nn\n", + "from torch.utils.data import TensorDataset, DataLoader\n", + "from torch.optim.lr_scheduler import StepLR\n", + "import matplotlib.pyplot as plt\n", + "import random\n", + "import gdown" + ], + "metadata": { + "id": "YrXWAH7sUWvU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Run this once to copy the train and validation data to your CoLab environment\n", + "if not os.path.exists('./Data.zip'):\n", + " !gdown 1HtnCrncY6dFCYqzgPf1HtPVAerTpwFRm\n", + " !unzip Data.zip" + ], + "metadata": { + "id": "wScBGXXFVadm" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Load in the data\n", + "train_data_x = np.load('train_data_x.npy')\n", + "train_data_y = np.load('train_data_y.npy')\n", + "val_data_x = np.load('val_data_x.npy')\n", + "val_data_y = np.load('val_data_y.npy')\n", + "# Print out sizes\n", + "print(\"Train data: %d examples (columns), each of which has %d dimensions (rows)\"%((train_data_x.shape[1],train_data_x.shape[0])))\n", + "print(\"Validation data: %d examples (columns), each of which has %d dimensions (rows)\"%((val_data_x.shape[1],val_data_x.shape[0])))" + ], + "metadata": { + "id": "8bKADvLHbiV5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Define the network" + ], + "metadata": { + "id": "_sFvRDGrl4qe" + } + }, + { + "cell_type": "code", + "source": [ + "# There are 40 input dimensions and 10 output dimensions for this data\n", + "# The inputs correspond to the 40 offsets in the MNIST1D template.\n", + "D_i = 40\n", + "# The outputs correspond to the 10 digits\n", + "D_o = 10\n", + "\n", + "# Number of hidden units in layers 1 and 2\n", + "D_1 = 100\n", + "D_2 = 100\n", + "\n", + "# create model with two hidden layers\n", + "model = nn.Sequential(\n", + "nn.Linear(D_i, D_1),\n", + "nn.ReLU(),\n", + "nn.Linear(D_1, D_2),\n", + "nn.ReLU(),\n", + "nn.Linear(D_2, D_o))" + ], + "metadata": { + "id": "FslroPJJffrh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# He initialization of weights\n", + "def weights_init(layer_in):\n", + " if isinstance(layer_in, nn.Linear):\n", + " nn.init.kaiming_uniform_(layer_in.weight)\n", + " layer_in.bias.data.fill_(0.0)" + ], + "metadata": { + "id": "YgLaex1pfhqz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# You need all this stuff to ensure that PyTorch is deterministic\n", + "def set_seed(seed):\n", + " torch.manual_seed(seed)\n", + " torch.cuda.manual_seed_all(seed)\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " os.environ['PYTHONHASHSEED'] = str(seed)" + ], + "metadata": { + "id": "zXRmxCQNnL_M" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set seed so always get same result (do not change)\n", + "set_seed(1)\n", + "\n", + "# choose cross entropy loss function (equation 5.24 in the loss notes)\n", + "loss_function = nn.CrossEntropyLoss()\n", + "# construct SGD optimizer and initialize learning rate and momentum\n", + "optimizer = torch.optim.SGD(model.parameters(), lr = 0.05, momentum=0.9)\n", + "# object that decreases learning rate by half every 10 epochs\n", + "scheduler = StepLR(optimizer, step_size=10, gamma=0.5)\n", + "# create 100 dummy data points and store in data loader class\n", + "x_train = torch.tensor(train_data_x.transpose().astype('float32'))\n", + "y_train = torch.tensor(train_data_y.astype('long'))\n", + "x_val= torch.tensor(val_data_x.transpose().astype('float32'))\n", + "y_val = torch.tensor(val_data_y.astype('long'))\n", + "\n", + "# load the data into a class that creates the batches\n", + "data_loader = DataLoader(TensorDataset(x_train,y_train), batch_size=100, shuffle=True, worker_init_fn=np.random.seed(1))\n", + "\n", + "# Initialize model weights\n", + "model.apply(weights_init)\n", + "\n", + "# loop over the dataset n_epoch times\n", + "n_epoch = 50\n", + "# store the loss and the % correct at each epoch\n", + "losses_train = np.zeros((n_epoch))\n", + "errors_train = np.zeros((n_epoch))\n", + "losses_val = np.zeros((n_epoch))\n", + "errors_val = np.zeros((n_epoch))\n", + "\n", + "for epoch in range(n_epoch):\n", + " # loop over batches\n", + " for i, data in enumerate(data_loader):\n", + " # retrieve inputs and labels for this batch\n", + " x_batch, y_batch = data\n", + " # zero the parameter gradients\n", + " optimizer.zero_grad()\n", + " # forward pass -- calculate model output\n", + " pred = model(x_batch)\n", + " # compute the lss\n", + " loss = loss_function(pred, y_batch)\n", + " # backward pass\n", + " loss.backward()\n", + " # SGD update\n", + " optimizer.step()\n", + "\n", + " # Run whole dataset to get statistics -- normally wouldn't do this\n", + " pred_train = model(x_train)\n", + " pred_val = model(x_val)\n", + " _, predicted_train_class = torch.max(pred_train.data, 1)\n", + " _, predicted_val_class = torch.max(pred_val.data, 1)\n", + " errors_train[epoch] = 100 - 100 * (predicted_train_class == y_train).float().sum() / len(y_train)\n", + " errors_val[epoch]= 100 - 100 * (predicted_val_class == y_val).float().sum() / len(y_val)\n", + " losses_train[epoch] = loss_function(pred_train, y_train).item()\n", + " losses_val[epoch]= loss_function(pred_val, y_val).item()\n", + " print(f'Epoch {epoch:5d}, train loss {losses_train[epoch]:.6f}, train error {errors_train[epoch]:3.2f}, val loss {losses_val[epoch]:.6f}, percent error {errors_val[epoch]:3.2f}')\n", + "\n", + " # tell scheduler to consider updating learning rate\n", + " scheduler.step()\n", + "\n", + "# Plot the results\n", + "fig, ax = plt.subplots()\n", + "ax.plot(errors_train,'r-',label='train')\n", + "ax.plot(errors_val,'b-',label='validation')\n", + "ax.set_ylim(0,100); ax.set_xlim(0,n_epoch)\n", + "ax.set_xlabel('Epoch'); ax.set_ylabel('Error')\n", + "ax.set_title('Part III: Validation Result %3.2f'%(errors_val[-1]))\n", + "ax.legend()\n", + "ax.plot([0,n_epoch],[37.45, 37.45],'k:') # Original results. You should be better than this!\n", + "plt.savefig('Coursework_III_Results.png',format='png')\n", + "plt.show()" + ], + "metadata": { + "id": "NYw8I_3mmX5c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Leave this all commented for now\n", + "# We'll see how well you did on the test data after the coursework is submitted\n", + "\n", + "\n", + "# # I haven't given you this yet, leave commented\n", + "# test_data_x = np.load('test_data_x.npy')\n", + "# test_data_y = np.load('test_data_y.npy')\n", + "# x_test = torch.tensor(test_data_x.transpose().astype('float32'))\n", + "# y_test = torch.tensor(test_data_y.astype('long'))\n", + "# pred_test = model(x_test)\n", + "# _, predicted_test_class = torch.max(pred_test.data, 1)\n", + "# errors_test = 100 - 100 * (predicted_test_class == y_test).float().sum() / len(y_test)\n", + "# print(\"Test error = %3.3f\"%(errors_test))" + ], + "metadata": { + "id": "O7nBz-R84QdJ" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/CM20315_2023/CM20315_Coursework_IV.ipynb b/CM20315_2023/CM20315_Coursework_IV.ipynb new file mode 100644 index 0000000..8f98ad5 --- /dev/null +++ b/CM20315_2023/CM20315_Coursework_IV.ipynb @@ -0,0 +1,212 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyMrWYwQrwgJvDza1vhYK9WQ", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Coursework IV\n", + "\n", + "This coursework explores the geometry of high dimensional spaces. It doesn't behave how you would expect and all your intuitions are wrong! You will write code and it will give you three numerical answers that you need to type into Moodle." + ], + "metadata": { + "id": "EjLK-kA1KnYX" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4ESMmnkYEVAb" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import scipy.special as sci" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (a)\n", + "\n", + "In part (a) of the practical, we investigate how close random points are in 2D, 100D, and 1000D. In each case, we generate 1000 points and calculate the Euclidean distance between each pair. You should find that in 1000D, the furthest two points are only slightly further apart than the nearest points. Weird!" + ], + "metadata": { + "id": "MonbPEitLNgN" + } + }, + { + "cell_type": "code", + "source": [ + "# Fix the random seed so we all have the same random numbers\n", + "np.random.seed(0)\n", + "n_data = 1000\n", + "# Create 1000 data examples (columns) each with 2 dimensions (rows)\n", + "n_dim = 2\n", + "x_2D = np.random.normal(size=(n_dim,n_data))\n", + "# Create 1000 data examples (columns) each with 100 dimensions (rows)\n", + "n_dim = 100\n", + "x_100D = np.random.normal(size=(n_dim,n_data))\n", + "# Create 1000 data examples (columns) each with 1000 dimensions (rows)\n", + "n_dim = 1000\n", + "x_1000D = np.random.normal(size=(n_dim,n_data))\n", + "\n", + "# These values should be the same, otherwise your answer will be wrong\n", + "# Get in touch if they are not!\n", + "print('Sum of your data is %3.3f, Should be %3.3f'%(np.sum(x_1000D),1036.321))" + ], + "metadata": { + "id": "vZSHVmcWEk14" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "def distance_ratio(x):\n", + " # TODO -- replace the two lines below to calculate the largest and smallest Euclidean distance between\n", + " # the data points in the columns of x. DO NOT include the distance between the data point\n", + " # and itself (which is obviously zero)\n", + " smallest_dist = 1.0\n", + " largest_dist = 1.0\n", + "\n", + " # Calculate the ratio and return\n", + " dist_ratio = largest_dist / smallest_dist\n", + " return dist_ratio" + ], + "metadata": { + "id": "PhVmnUs8ErD9" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print('Ratio of largest to smallest distance 2D: %3.3f'%(distance_ratio(x_2D)))\n", + "print('Ratio of largest to smallest distance 100D: %3.3f'%(distance_ratio(x_100D)))\n", + "print('Ratio of largest to smallest distance 1000D: %3.3f'%(distance_ratio(x_1000D)))\n", + "print('**Note down the last of these three numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "0NdPxfn5GQuJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (b)\n", + "\n", + "In part (b) of the practical we calculate the volume of a hypersphere of radius 0.5 (i.e., of diameter 1) as a function of the radius. You will find that the volume decreases to almost nothing in high dimensions. All of the volume is in the corners of the unit hypercube (which always has volume 1). Double weird.\n", + "\n", + "Note that you you can check your answer by doing the calculation for 2D using the standard formula for the area of a circle and making sure it matches." + ], + "metadata": { + "id": "b2FYKV1SL4Z7" + } + }, + { + "cell_type": "code", + "source": [ + "def volume_of_hypersphere(diameter, dimensions):\n", + " # Formula given in Problem 8.7 of the notes\n", + " # You will need sci.gamma()\n", + " # Check out: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.gamma.html\n", + " # Also use this value for pi\n", + " pi = np.pi\n", + " # TODO replace this code with formula for the volume of a hypersphere\n", + " volume = 1.0\n", + "\n", + " return volume\n" + ], + "metadata": { + "id": "CZoNhD8XJaHR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "diameter = 1.0\n", + "for c_dim in range(1,11):\n", + " print(\"Volume of unit diameter hypersphere in %d dimensions is %3.3f\"%(c_dim, volume_of_hypersphere(diameter, c_dim)))\n", + "print('**Note down the last of these ten numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "fNTBlg_GPEUh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Part (c)\n", + "\n", + "In part (c) of the coursework, you will calculate what proportion of the volume of a hypersphere is in the outer 1% of the radius/diameter. Calculate the volume of a hypersphere and then the volume of a hypersphere with 0.99 of the radius and then figure out the proportion (a number between 0 and 1). You'll see that by the time we get to 300 dimensions most of the volume is in the outer 1 percent. Extremely weird!" + ], + "metadata": { + "id": "GdyMeOBmoXyF" + } + }, + { + "cell_type": "code", + "source": [ + "def get_prop_of_volume_in_outer_1_percent(dimension):\n", + " # TODO -- replace this line\n", + " proportion = 1.0\n", + "\n", + " return proportion" + ], + "metadata": { + "id": "8_CxZ2AIpQ8w" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# While we're here, let's look at how much of the volume is in the outer 1% of the radius\n", + "for c_dim in [1,2,10,20,50,100,150,200,250,300]:\n", + " print('Proportion of volume in outer 1 percent of radius in %d dimensions =%3.3f'%(c_dim, get_prop_of_volume_in_outer_1_percent(c_dim)))\n", + "print('**Note down the last of these ten numbers, you will need to submit it for your coursework**')" + ], + "metadata": { + "id": "LtMDIn2qPVfJ" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/CM20315_2023/CM20315_Coursework_V_2023.ipynb b/CM20315_2023/CM20315_Coursework_V_2023.ipynb new file mode 100644 index 0000000..483ea94 --- /dev/null +++ b/CM20315_2023/CM20315_Coursework_V_2023.ipynb @@ -0,0 +1,525 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyN7KaQQ63bf52r+b5as0MkK", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **Coursework V: Backpropagation in Toy Model**\n", + "\n", + "This notebook computes the derivatives of a toy function similar (but different from) that in section 7.3 of the book.\n", + "\n", + "Work through the cells below, running each cell in turn. In various places you will see the words \"TO DO\". Follow the instructions at these places and make predictions about what is going to happen or write code to complete the functions. At various points, you will get an answer that you need to copy into Moodle to be marked.\n", + "\n", + "Post to the content forum if you find any mistakes or need to clarify something." + ], + "metadata": { + "id": "pOZ6Djz0dhoy" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Problem setting\n", + "\n", + "We're going to investigate how to take the derivatives of functions where one operation is composed with another, which is composed with a third and so on. For example, consider the model:\n", + "\n", + "\\begin{equation}\n", + " \\mbox{f}[x,\\boldsymbol\\phi] = \\beta_3+\\omega_3\\cdot\\mbox{PReLU}\\Bigl[\\gamma, \\beta_2+\\omega_2\\cdot\\mbox{PReLU}\\bigl[\\gamma, \\beta_1+\\omega_1\\cdot\\mbox{PReLU}[\\gamma, \\beta_0+\\omega_0x]\\bigr]\\Bigr],\n", + "\\end{equation}\n", + "\n", + "with parameters $\\boldsymbol\\phi=\\{\\beta_0,\\omega_0,\\beta_1,\\omega_1,\\beta_2,\\omega_2,\\beta_3,\\omega_3\\}$, where\n", + "\n", + "\\begin{equation}\n", + "\\mbox{PReLU}[\\gamma, z] = \\begin{cases} \\gamma\\cdot z & \\quad z \\leq0 \\\\ z & \\quad z> 0\\end{cases}.\n", + "\\end{equation}\n", + "\n", + "Suppose that we have a binary cross-entropy loss function (equation 5.20 from the book):\n", + "\n", + "\\begin{equation*}\n", + "\\ell_i = -(1-y_{i})\\log\\Bigl[1-\\mbox{sig}[\\mbox{f}[\\mathbf{x}_i,\\boldsymbol\\phi]]\\Bigr] - y_{i}\\log\\Bigl[\\mbox{sig}[\\mbox{f}[\\mathbf{x}_i,\\boldsymbol\\phi]]\\Bigr].\n", + "\\end{equation*}\n", + "\n", + "Assume that we know the current values of $\\beta_{0},\\beta_{1},\\beta_{2},\\beta_{3},\\omega_{0},\\omega_{1},\\omega_{2},\\omega_{3}$, $\\gamma$, $x_i$ and $y_i$. We want to know how $\\ell_i$ changes when we make a small change to $\\beta_{0},\\beta_{1},\\beta_{2},\\beta_{3},\\omega_{0},\\omega_{1},\\omega_{2}$, or $\\omega_{3}$. In other words, we want to compute the eight derivatives:\n", + "\n", + "\\begin{eqnarray*}\n", + "\\frac{\\partial \\ell_i}{\\partial \\beta_{0}}, \\quad \\frac{\\partial \\ell_i}{\\partial \\beta_{1}}, \\quad \\frac{\\partial \\ell_i}{\\partial \\beta_{2}}, \\quad \\frac{\\partial \\ell_i }{\\partial \\beta_{3}}, \\quad \\frac{\\partial \\ell_i}{\\partial \\omega_{0}}, \\quad \\frac{\\partial \\ell_i}{\\partial \\omega_{1}}, \\quad \\frac{\\partial \\ell_i}{\\partial \\omega_{2}}, \\quad\\mbox{and} \\quad \\frac{\\partial \\ell_i}{\\partial \\omega_{3}}.\n", + "\\end{eqnarray*}" + ], + "metadata": { + "id": "1DmMo2w63CmT" + } + }, + { + "cell_type": "code", + "source": [ + "# import library\n", + "import numpy as np" + ], + "metadata": { + "id": "RIPaoVN834Lj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's first define the original function and the loss term:" + ], + "metadata": { + "id": "32-ufWhc3v2c" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AakK_qen3BpU" + }, + "outputs": [], + "source": [ + "# Defines the activation function\n", + "def paramReLU(gamma,x):\n", + " if x > 0:\n", + " return x\n", + " else:\n", + " return x * gamma\n", + "\n", + "# Defines the main function\n", + "def fn(x, beta0, beta1, beta2, beta3, omega0, omega1, omega2, omega3, gamma):\n", + " return beta3+omega3 * paramReLU(gamma, beta2 + omega2 * paramReLU(gamma, beta1 + omega1 * paramReLU(gamma, beta0 + omega0 * x)))\n", + "\n", + "# Logistic sigmoid\n", + "def sig(z):\n", + " return 1./(1+np.exp(-z))\n", + "\n", + "# The loss function (equation 5.20 from book)\n", + "def loss(f,y):\n", + " sig_net_out = sig(f)\n", + " l = -(1-y) * np.log(1-sig_net_out) - y * np.log(sig_net_out)\n", + " return l" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll choose some values for the betas and the omegas and x and compute the output of the function:" + ], + "metadata": { + "id": "y7tf0ZMt5OXt" + } + }, + { + "cell_type": "code", + "source": [ + "beta0 = 1.0; beta1 = -2.0; beta2 = -3.0; beta3 = 0.4\n", + "omega0 = 0.1; omega1 = -0.4; omega2 = 2.0; omega3 = -3.0\n", + "gamma = 0.2\n", + "x = 2.3; y =1.0\n", + "f_val = fn(x,beta0,beta1,beta2,beta3,omega0,omega1,omega2,omega3, gamma)\n", + "l_i_func = loss(f_val, y)\n", + "print('Loss full function = %3.3f'%l_i_func)" + ], + "metadata": { + "id": "pwvOcCxr41X_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Forward pass\n", + "\n", + "We compute a series of intermediate values $f_0, h_0, f_1, h_1, f_2, h_2, f_3$, and finally the loss $\\ell$" + ], + "metadata": { + "id": "W6ZP62T5fU64" + } + }, + { + "cell_type": "code", + "source": [ + "x = 2.3; y =1.0\n", + "gamma = 0.2\n", + "# Compute all the f_k and h_k terms\n", + "# I've done the first two for you\n", + "f0 = beta0+omega0 * x\n", + "h1 = paramReLU(gamma, f0)\n", + "\n", + "\n", + "# TODO: Replace the code below\n", + "f1 = 0\n", + "h2 = 0\n", + "f2 = 0\n", + "h3 = 0\n", + "f3 = 0\n", + "\n", + "\n", + "# Compute the loss and print\n", + "# The answer should be the same as when we computed the full function above\n", + "l_i = loss(f3, y)\n", + "print(\"Loss forward pass = %3.3f\"%(l_i))\n" + ], + "metadata": { + "id": "z-BckTpMf5PL" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Backward pass: Derivative of loss function with respect to function output\n", + "\n", + "Now, we'll compute the derivative $\\frac{dl}{df_3}$ of the loss function with respect to the network output $f_3$. In other words, we are asking how does the loss change as we make a small change in the network output.\n", + "\n", + "Since the loss it itself a function of $\\mbox{sig}[f_3]$ we'll compute this using the chain rule:\n", + "\n", + "\\begin{equation}\n", + "\\frac{dl}{df_3} = \\frac{d\\mbox{sig}[f_3]}{df_3}\\cdot \\frac{dl}{d\\mbox{sig}[f_3]}\n", + "\\end{equation}\n", + "\n", + "Your job is to compute the two quantities on the right hand side.\n" + ], + "metadata": { + "id": "TbFbxz64Xz4I" + } + }, + { + "cell_type": "code", + "source": [ + "# Compute the derivative of the the loss with respect to the function output f_val\n", + "def dl_df(f_val,y):\n", + " # Compute sigmoid of network output\n", + " sig_f_val = sig(f_val)\n", + " # Compute the derivative of loss with respect to network output using chain rule\n", + " dl_df_val = dsig_df(f_val) * dl_dsigf(sig_f_val, y)\n", + " # Return the derivative\n", + " return dl_df_val" + ], + "metadata": { + "id": "ZWKAq6HC90qV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# MOODLE ANSWER # Notebook V 1a: Copy this code when you have finished it.\n", + "\n", + "# Compute the derivative of the logistic sigmoid function with respect to its input (as a closed form solution)\n", + "def dsig_df(f_val):\n", + " # TODO Write this function\n", + " # Replace this line:\n", + " return 1\n", + "\n", + "# Compute the derivative of the loss with respect to the logistic sigmoid (as a closed form solution)\n", + "def dl_dsigf(sig_f_val, y):\n", + " # TODO Write this function\n", + " # Replace this line:\n", + " return 1" + ], + "metadata": { + "id": "lIngYAgPq-5I" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's run that for some f_val, y. Check previous practicals to see how you can check whether your answer is correct." + ], + "metadata": { + "id": "Q-j-i8khXzbK" + } + }, + { + "cell_type": "code", + "source": [ + "y = 0.0\n", + "dl_df3 = dl_df(f3,y)\n", + "print(\"Moodle Answer Notebook V 1b: dldh3=%3.3f\"%(dl_df3))\n", + "\n", + "y= 1.0\n", + "dl_df3 = dl_df(f3,y)\n", + "print(\"Moodle Answer Notebook V 1c: dldh3=%3.3f\"%(dl_df3))" + ], + "metadata": { + "id": "Z7Lb5BibY50H" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Backward pass: Derivative of activation function with respect to preactivations\n", + "\n", + "Write a function to compute the derivative $\\frac{\\partial h}{\\partial f}$ of the activation function (parametric ReLU) with respect to its input.\n" + ], + "metadata": { + "id": "BA7QaOzejzZw" + } + }, + { + "cell_type": "code", + "source": [ + "# MOODLE ANSWER Notebook V 2a: Copy this code when you have finished it.\n", + "\n", + "def dh_df(gamma, f_val):\n", + " # TODO: Write this function\n", + " # Replace this line:\n", + " return 1\n" + ], + "metadata": { + "id": "bBPfPg04j-Qw" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's run that for some values of f_val. Check previous practicals to see how you can check whether your answer is correct." + ], + "metadata": { + "id": "QRNCM0EGk9-w" + } + }, + { + "cell_type": "code", + "source": [ + "f_val_test = 0.6\n", + "dh_df_val = dh_df(gamma, f_val_test)\n", + "print(\"Moodle Answer Notebook V 2b: dhdf=%3.3f\"%(dh_df_val))\n", + "\n", + "f_val_test = -0.4\n", + "dh_df_val = dh_df(gamma, f_val_test)\n", + "print(\"Moodle Answer Notebook V 2c: dhdf=%3.3f\"%(dh_df_val))" + ], + "metadata": { + "id": "bql8VZIGk8Wy" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + " # Backward pass: Compute the derivatives of $l_i$ with respect to the intermediate quantities but in reverse order:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial \\ell_i}{\\partial h_3}, \\quad \\frac{\\partial \\ell_i}{\\partial f_2}, \\quad\n", + "\\frac{\\partial \\ell_i}{\\partial h_2}, \\quad \\frac{\\partial \\ell_i}{\\partial f_1}, \\quad\\frac{\\partial \\ell_i}{\\partial h_1}, \\quad\\mbox{and} \\quad \\frac{\\partial \\ell_i}{\\partial f_0}.\n", + "\\end{eqnarray}\n", + "\n", + "The first of these derivatives can be calculated using the chain rule:\n", + "\n", + "\\begin{equation}\n", + "\\frac{\\partial \\ell_i}{\\partial h_{3}} =\\frac{\\partial f_{3}}{\\partial h_{3}} \\frac{\\partial \\ell_i}{\\partial f_{3}} .\n", + "\\end{equation}\n", + "\n", + "The left-hand side asks how $\\ell_i$ changes when $h_{3}$ changes. The right-hand side says we can decompose this into (i) how $\\ell_i$ changes when $f_{3}$ changes and how $f_{3}$ changes when $h_{3}$ changes. So you get a chain of events happening: $h_{3}$ changes $f_{3}$, which changes $\\ell_i$, and the derivatives represent the effects of this chain. Notice that we computed the first of these derivatives already. The second term is the derivative of $\\beta_{3} + \\omega_{3}h_{3}$ with respect to $h_3$ which is simply $\\omega_3$. \n", + "\n", + "We can continue in this way, computing the derivatives of the output with respect to these intermediate quantities:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial \\ell_i}{\\partial f_{2}} &=& \\frac{\\partial h_{3}}{\\partial f_{2}}\\left(\n", + "\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial \\ell_i}{\\partial f_{3}} \\right)\n", + "\\nonumber \\\\\n", + "\\frac{\\partial \\ell_i}{\\partial h_{2}} &=& \\frac{\\partial f_{2}}{\\partial h_{2}}\\left(\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial \\ell_i}{\\partial f_{3}}\\right)\\nonumber \\\\\n", + "\\frac{\\partial \\ell_i}{\\partial f_{1}} &=& \\frac{\\partial h_{2}}{\\partial f_{1}}\\left( \\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial \\ell_i}{\\partial f_{3}} \\right)\\nonumber \\\\\n", + "\\frac{\\partial \\ell_i}{\\partial h_{1}} &=& \\frac{\\partial f_{1}}{\\partial h_{1}}\\left(\\frac{\\partial h_{2}}{\\partial f_{1}} \\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial \\ell_i}{\\partial f_{3}} \\right)\\nonumber \\\\\n", + "\\frac{\\partial \\ell_i}{\\partial f_{0}} &=& \\frac{\\partial h_{1}}{\\partial f_{0}}\\left(\\frac{\\partial f_{1}}{\\partial h_{1}}\\frac{\\partial h_{2}}{\\partial f_{1}} \\frac{\\partial f_{2}}{\\partial h_{2}}\\frac{\\partial h_{3}}{\\partial f_{2}}\\frac{\\partial f_{3}}{\\partial h_{3}}\\frac{\\partial \\ell_i}{\\partial f_{3}} \\right).\n", + "\\end{eqnarray}\n", + "\n", + "In each case, we have already computed all of the terms except the last one in the previous step, and the last term is simple to evaluate. This is called the **backward pass**." + ], + "metadata": { + "id": "jay8NYWdFHuZ" + } + }, + { + "cell_type": "code", + "source": [ + "x = 2.3; y =1.0\n", + "dldf3 = dl_df(f3,y)" + ], + "metadata": { + "id": "RSC_2CIfKF1b" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# MOODLE ANSWER Notebook V 3a: Copy this code when you have finished it.\n", + "# TODO -- Compute the derivatives of the output with respect\n", + "# to the intermediate computations h_k and f_k (i.e, run the backward pass)\n", + "# I've done the first two for you. You replace the code below:\n", + "# Replace the code below\n", + "dldh3 = 1\n", + "dldf2 = 1\n", + "dldh2 = 1\n", + "dldf1 = 1\n", + "dldh1 = 1\n", + "dldf0 = 1" + ], + "metadata": { + "id": "gCQJeI--Egdl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Finally, we consider how the loss~$\\ell_{i}$ changes when we change the parameters $\\beta_{\\bullet}$ and $\\omega_{\\bullet}$. Once more, we apply the chain rule:\n", + "\n", + "\n", + "\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial \\ell_i}{\\partial \\beta_{k}} &=& \\frac{\\partial f_{k}}{\\partial \\beta_{k}}\\frac{\\partial \\ell_i}{\\partial f_{k}}\\nonumber \\\\\n", + "\\frac{\\partial \\ell_i}{\\partial \\omega_{k}} &=& \\frac{\\partial f_{k}}{\\partial \\omega_{k}}\\frac{\\partial \\ell_i}{\\partial f_{k}}.\n", + "\\end{eqnarray}\n", + "\n", + "\\noindent In each case, the second term on the right-hand side was computed in step 2. When $k>0$, we have~$f_{k}=\\beta_{k}+\\omega_k \\cdot h_{k}$, so:\n", + "\n", + "\\begin{eqnarray}\n", + "\\frac{\\partial f_{k}}{\\partial \\beta_{k}} = 1 \\quad\\quad\\mbox{and}\\quad \\quad \\frac{\\partial f_{k}}{\\partial \\omega_{k}} &=& h_{k}.\n", + "\\end{eqnarray}" + ], + "metadata": { + "id": "FlzlThQPGpkU" + } + }, + { + "cell_type": "code", + "source": [ + "# MOODLE ANSWER Notebook V 3b: Copy this code when you have finished it.\n", + "# TODO -- Calculate the final derivatives with respect to the beta and omega terms\n", + "# Replace these terms\n", + "dldbeta3 = 1\n", + "dldomega3 = 1\n", + "dldbeta2 = 1\n", + "dldomega2 = 1\n", + "dldbeta1 = 1\n", + "dldomega1 = 1\n", + "dldbeta0 = 1\n", + "dldomega0 = 1" + ], + "metadata": { + "id": "1I2BhqZhGMK6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Print the last two values out (enter these into Moodle). Again, think about how you can test whether these are correct.\n", + "print('Moodle Answer Notebook V 3c: dldbeta0=%3.3f'%(dldbeta0))\n", + "print('Moodle Answer Notebook V 3d: dldOmega0=%3.3f'%(dldomega0))" + ], + "metadata": { + "id": "38eiOn2aHgHI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Compute the derivatives of $\\ell_i$ with respect to the parmeter $\\gamma$ of the parametric ReLU function. \n", + "\n", + "In other words, compute:\n", + "\n", + "\\begin{equation}\n", + "\\frac{d\\ell_i}{d\\gamma}\n", + "\\end{equation}\n", + "\n", + "Along the way, we will need to compute derivatives\n", + "\n", + "\\begin{equation}\n", + "\\frac{dh_k(\\gamma,f_{k-1})}{d\\gamma}\n", + "\\end{equation}\n", + "\n", + "This is quite difficult and not worth many marks, so don't spend too much time on it if you are confused!" + ], + "metadata": { + "id": "lhD5AoUHx3DS" + } + }, + { + "cell_type": "code", + "source": [ + "# Computes how an activation changes with a small change in gamma assuming preactivations are f\n", + "# MOODLE ANSWER # Notebook V 4a: Copy this code when you have finished it.\n", + "def dhdgamma(gamma, f):\n", + " # TODO -- Write this function\n", + " # Replace this line\n", + " return 1" + ], + "metadata": { + "id": "yC-9MTQevliP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Compute how the loss changes with gamma\n", + "# Replace this line:\n", + "# MOODLE ANSWER # Notebook V 4b: Copy this code when you have finished it.\n", + "dldgamma = 1" + ], + "metadata": { + "id": "DiNQrveoLuHR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(\"Moodle Answer Notebook V 4c: dldgamma = %3.3f\"%(dldgamma))" + ], + "metadata": { + "id": "YHxmAEnxzy3O" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f335487 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,346 @@ +Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 +International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-NoDerivatives 4.0 International Public +License ("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + c. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + d. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + e. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + f. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + g. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + h. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce and reproduce, but not Share, Adapted Material + for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material, You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + For the avoidance of doubt, You do not have permission under + this Public License to Share Adapted Material. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only and provided You do not Share Adapted Material; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/Notebooks/Chap01/1_1_BackgroundMathematics.ipynb b/Notebooks/Chap01/1_1_BackgroundMathematics.ipynb new file mode 100644 index 0000000..c2fe012 --- /dev/null +++ b/Notebooks/Chap01/1_1_BackgroundMathematics.ipynb @@ -0,0 +1,423 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "view-in-github" + }, + "source": [ + "\"Open" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "s5zzKSOusPOB" + }, + "source": [ + "\n", + "# **Notebook 1.1 -- Background Mathematics**\n", + "\n", + "The purpose of this Python notebook is to make sure you can use CoLab and to familiarize yourself with some of the background mathematical concepts that you are going to need to understand deep learning.

It's not meant to be difficult and it may be that you know some or all of this information already.

Math is *NOT* a spectator sport. You won't learn it by just listening to lectures or reading books. It really helps to interact with it and explore yourself.

Work through the cells below, running each cell in turn. In various places you will see the words **\"TO DO\"**. Follow the instructions at these places and write code to complete the functions. There are also questions interspersed in the text.\n", + "\n", + "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aUAjBbqzivMY" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "WV2Dl6owme2d" + }, + "source": [ + "**Linear functions**
We will be using the term *linear equation* to mean a weighted sum of inputs plus an offset. If there is just one input $x$, then this is a straight line:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega x,\\end{equation} \n", + "\n", + "where $\\beta$ is the y-intercept of the linear and $\\omega$ is the slope of the line. When there are two inputs $x_{1}$ and $x_{2}$, then this becomes:\n", + "\n", + "\\begin{equation}y=\\beta+\\omega_1 x_1 + \\omega_2 x_2.\\end{equation} \n", + "\n", + "Any other functions are by definition **non-linear**.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WeFK4AvTotd8" + }, + "outputs": [], + "source": [ + "# Define a linear function with just one input, x\n", + "def linear_function_1D(x,beta,omega):\n", + " # TODO -- replace the code line below with formula for 1D linear equation\n", + " y = x\n", + "\n", + " return y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "eimhJ8_jpmEp" + }, + "outputs": [], + "source": [ + "# Plot the 1D linear function\n", + "\n", + "# Define an array of x values from 0 to 10 with increments of 0.01\n", + "# https://numpy.org/doc/stable/reference/generated/numpy.arange.html\n", + "x = np.arange(0.0,10.0, 0.01)\n", + "# Compute y using the function you filled in above\n", + "beta = 0.0; omega = 1.0\n", + "\n", + "y = linear_function_1D(x,beta,omega)\n", + "\n", + "# Plot this function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([0,10]);ax.set_xlim([0,10])\n", + "ax.set_xlabel('x'); ax.set_ylabel('y')\n", + "plt.show\n", + "\n", + "# TODO -- experiment with changing the values of beta and omega\n", + "# to understand what they do. Try to make a line\n", + "# that crosses the y-axis at y=10 and the x-axis at x=5" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "AedfvD9dxShZ" + }, + "source": [ + "Now let's investigate a 2D linear function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "57Gvkk-Ir_7b" + }, + "outputs": [], + "source": [ + "# Code to draw 2D function -- read it so you know what is going on, but you don't have to change it\n", + "def draw_2D_function(x1_mesh, x2_mesh, y):\n", + " fig, ax = plt.subplots()\n", + " fig.set_size_inches(7,7)\n", + " pos = ax.contourf(x1_mesh, x2_mesh, y, levels=256 ,cmap = 'hot', vmin=-10,vmax=10.0)\n", + " fig.colorbar(pos, ax=ax)\n", + " ax.set_xlabel('x1');ax.set_ylabel('x2')\n", + " levels = np.arange(-10,10,1.0)\n", + " ax.contour(x1_mesh, x2_mesh, y, levels, cmap='winter')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YxeNhrXMzkZR" + }, + "outputs": [], + "source": [ + "# Define a linear function with two inputs, x1 and x2\n", + "def linear_function_2D(x1,x2,beta,omega1,omega2):\n", + " # TODO -- replace the code line below with formula for 2D linear equation\n", + " y = x1\n", + "\n", + " return y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rn_UBRDBysmR" + }, + "outputs": [], + "source": [ + "# Plot the 2D function\n", + "\n", + "# Make 2D array of x and y points\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# Compute the 2D function for given values of omega1, omega2\n", + "beta = 0.0; omega1 = 1.0; omega2 = -0.5\n", + "y = linear_function_2D(x1,x2,beta, omega1, omega2)\n", + "\n", + "# Draw the function.\n", + "# Color represents y value (brighter = higher value)\n", + "# Black = -10 or less, White = +10 or more\n", + "# 0 = mid orange\n", + "# Lines are contours where value is equal\n", + "draw_2D_function(x1,x2,y)\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_1 to zero\n", + "# Change the code and see if you are right.\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set omega_2 to zero\n", + "# Change the code and see if you are right.\n", + "\n", + "# TODO\n", + "# Predict what this plot will look like if you set beta to -5\n", + "# Change the code and see if you are correct\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "i8tLwpls476R" + }, + "source": [ + "Often we will want to compute many linear functions at the same time. For example, we might have three inputs, $x_1$, $x_2$, and $x_3$ and want to compute two linear functions giving $y_1$ and $y_2$. Of course, we could do this by just running each equation separately,

\n", + "\n", + "\\begin{align}y_1 &=& \\beta_1 + \\omega_{11} x_1 + \\omega_{12} x_2 + \\omega_{13} x_3\\\\\n", + "y_2 &=& \\beta_2 + \\omega_{21} x_1 + \\omega_{22} x_2 + \\omega_{23} x_3.\n", + "\\end{align}\n", + "\n", + "However, we can write it more compactly with vectors and matrices:\n", + "\n", + "\\begin{equation}\n", + "\\begin{bmatrix} y_1\\\\ y_2 \\end{bmatrix} = \\begin{bmatrix}\\beta_{1}\\\\\\beta_{2}\\end{bmatrix}+ \\begin{bmatrix}\\omega_{11}&\\omega_{12}&\\omega_{13}\\\\\\omega_{21}&\\omega_{22}&\\omega_{23}\\end{bmatrix}\\begin{bmatrix}x_{1}\\\\x_{2}\\\\x_{3}\\end{bmatrix},\n", + "\\end{equation}\n", + "or\n", + "\n", + "\\begin{equation}\n", + "\\mathbf{y} = \\boldsymbol\\beta +\\boldsymbol\\Omega\\mathbf{x}.\n", + "\\end{equation}\n", + "\n", + "for short. Here, lowercase bold symbols are used for vectors. Upper case bold symbols are used for matrices.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MjHXMavh9IUz" + }, + "outputs": [], + "source": [ + "# Define a linear function with three inputs, x1, x2, and x_3\n", + "def linear_function_3D(x1,x2,x3,beta,omega1,omega2,omega3):\n", + " # TODO -- replace the code below with formula for a single 3D linear equation\n", + " y = x1\n", + "\n", + " return y" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "fGzVJQ6N-mHJ" + }, + "source": [ + "Let's compute two linear equations, using both the individual equations and the vector / matrix form and check they give the same result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Swd_bFIE9p2n" + }, + "outputs": [], + "source": [ + "# Define the parameters\n", + "beta1 = 0.5; beta2 = 0.2\n", + "omega11 = -1.0 ; omega12 = 0.4; omega13 = -0.3\n", + "omega21 = 0.1 ; omega22 = 0.1; omega23 = 1.2\n", + "\n", + "# Define the inputs\n", + "x1 = 4 ; x2 =-1; x3 = 2\n", + "\n", + "# Compute using the individual equations\n", + "y1 = linear_function_3D(x1,x2,x3,beta1,omega11,omega12,omega13)\n", + "y2 = linear_function_3D(x1,x2,x3,beta2,omega21,omega22,omega23)\n", + "print(\"Individual equations\")\n", + "print('y1 = %3.3f\\ny2 = %3.3f'%((y1,y2)))\n", + "\n", + "# Define vectors and matrices\n", + "beta_vec = np.array([[beta1],[beta2]])\n", + "omega_mat = np.array([[omega11,omega12,omega13],[omega21,omega22,omega23]])\n", + "x_vec = np.array([[x1], [x2], [x3]])\n", + "\n", + "# Compute with vector/matrix form\n", + "y_vec = beta_vec+np.matmul(omega_mat, x_vec)\n", + "print(\"Matrix/vector form\")\n", + "print('y1= %3.3f\\ny2 = %3.3f'%((y_vec[0],y_vec[1])))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "3LGRoTMLU8ZU" + }, + "source": [ + "# Questions\n", + "\n", + "1. A single linear equation with three inputs (i.e. **linear_function_3D()**) associates a value y with each point in a 3D space ($x_1$,$x_2$,$x_3$). Is it possible to visualize this? What value is at position (0,0,0)?\n", + "\n", + "2. Write code to compute three linear equations with two inputs ($x_1$, $x_2$) using both the individual equations and the matrix form (you can make up any values for the inputs $\\beta_{i}$ and the slopes $\\omega_{ij}$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "7Y5zdKtKZAB2" + }, + "source": [ + "# Special functions\n", + "\n", + "Throughout the book, we'll be using some special functions (see Appendix B.1.3). The most important of these are the logarithm and exponential functions. Let's investigate their properties.\n", + "\n", + "We'll start with the exponential function $y=\\exp[x]=e^x$ which maps the real line $[-\\infty,+\\infty]$ to non-negative numbers $[0,+\\infty]$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "c_GkjiY9IWCu" + }, + "outputs": [], + "source": [ + "# Draw the exponential function\n", + "\n", + "# Define an array of x values from -5 to 5 with increments of 0.01\n", + "x = np.arange(-5.0,5.0, 0.01)\n", + "y = np.exp(x) ;\n", + "\n", + "# Plot this function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([0,100]);ax.set_xlim([-5,5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('exp[x]')\n", + "plt.show" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "XyrT8257IWCu" + }, + "source": [ + "# Questions\n", + "\n", + "1. What is $\\exp[0]$? \n", + "2. What is $\\exp[1]$?\n", + "3. What is $\\exp[-\\infty]$?\n", + "4. What is $\\exp[+\\infty]$?\n", + "5. A function is convex if we can draw a straight line between any two points on the function, and the line lies above the function everywhere between these two points. Similarly, a function is concave if a straight line between any two points lies below the function everywhere between these two points. Is the exponential function convex or concave or neither?\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "R6A4e5IxIWCu" + }, + "source": [ + "Now let's consider the logarithm function $y=\\log[x]$. Throughout the book we always use natural (base $e$) logarithms. The log function maps non-negative numbers $[0,\\infty]$ to real numbers $[-\\infty,\\infty]$. It is the inverse of the exponential function. So when we compute $\\log[x]$ we are really asking \"What is the number $y$ so that $e^y=x$?\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fOR7v2iXIWCu" + }, + "outputs": [], + "source": [ + "# Draw the logarithm function\n", + "\n", + "# Define an array of x values from -5 to 5 with increments of 0.01\n", + "x = np.arange(0.01,5.0, 0.01)\n", + "y = np.log(x) ;\n", + "\n", + "# Plot this function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(x,y,'r-')\n", + "ax.set_ylim([-5,5]);ax.set_xlim([0,5])\n", + "ax.set_xlabel('x'); ax.set_ylabel('$\\log[x]$')\n", + "plt.show" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "yYWrL5AXIWCv" + }, + "source": [ + "# Questions\n", + "\n", + "1. What is $\\log[0]$? \n", + "2. What is $\\log[1]$?\n", + "3. What is $\\log[e]$?\n", + "4. What is $\\log[\\exp[3]]$?\n", + "5. What is $\\exp[\\log[4]]$?\n", + "6. What is $\\log[-1]$?\n", + "7. Is the logarithm function concave or convex?\n" + ] + } + ], + "metadata": { + "colab": { + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Notebooks/Chap02/2_1_Supervised_Learning.ipynb b/Notebooks/Chap02/2_1_Supervised_Learning.ipynb new file mode 100644 index 0000000..382f2f4 --- /dev/null +++ b/Notebooks/Chap02/2_1_Supervised_Learning.ipynb @@ -0,0 +1,253 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOmndC0N7dFV7W3Mh5ljOLl", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Notebook 2.1 Supervised Learning\n", + "\n", + "The purpose of this notebook is to explore the linear regression model discussed in Chapter 2 of the book.\n", + "\n", + "Work through the cells below, running each cell in turn. In various places you will see the words \"TO DO\". Follow the instructions at these places and write code to complete the functions. There are also questions interspersed in the text.\n", + "\n", + "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions." + ], + "metadata": { + "id": "sfB2oX2RNvuF" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uoYl2Gn3Nr52" + }, + "outputs": [], + "source": [ + "# Math library\n", + "import numpy as np\n", + "# Plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "# Create some input / output data\n", + "x = np.array([0.03, 0.19, 0.34, 0.46, 0.78, 0.81, 1.08, 1.18, 1.39, 1.60, 1.65, 1.90])\n", + "y = np.array([0.67, 0.85, 1.05, 1.0, 1.40, 1.5, 1.3, 1.54, 1.55, 1.68, 1.73, 1.6 ])\n", + "\n", + "print(x)\n", + "print(y)" + ], + "metadata": { + "id": "MUbTD4znORtd" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define 1D linear regression model\n", + "def f(x, phi0, phi1):\n", + " # TODO : Replace this line with the linear regression model (eq 2.4)\n", + " y = x\n", + "\n", + " return y" + ], + "metadata": { + "id": "lw2dCRHwSW9a" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Function to help plot the data\n", + "def plot(x, y, phi0, phi1):\n", + " fig,ax = plt.subplots()\n", + " ax.scatter(x,y)\n", + " plt.xlim([0,2.0])\n", + " plt.ylim([0,2.0])\n", + " ax.set_xlabel('Input, $x$')\n", + " ax.set_ylabel('Output, $y$')\n", + " # Draw line\n", + " x_line = np.arange(0,2,0.01)\n", + " y_line = f(x_line, phi0, phi1)\n", + " plt.plot(x_line, y_line,'b-',lw=2)\n", + "\n", + " plt.show()" + ], + "metadata": { + "id": "VT4F3xxSOt8C" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set the intercept and slope as in figure 2.2b\n", + "phi0 = 0.4 ; phi1 = 0.2\n", + "# Plot the data and the model\n", + "plot(x,y,phi0,phi1)" + ], + "metadata": { + "id": "AkdZdmhHWuVR" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Function to calculate the loss\n", + "def compute_loss(x,y,phi0,phi1):\n", + "\n", + " # TODO Replace this line with the loss calculation (equation 2.5)\n", + " loss = 0\n", + "\n", + "\n", + " return loss" + ], + "metadata": { + "id": "1-GW218wX44b" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Compute the loss for our current model\n", + "loss = compute_loss(x,y,phi0,phi1)\n", + "print(f'Your Loss = {loss:3.2f}, Ground truth =7.07')" + ], + "metadata": { + "id": "Hgw7_GzBZ8tX" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Set the intercept and slope as in figure 2.2c\n", + "phi0 = 1.60 ; phi1 =-0.8\n", + "# Plot the data and the model\n", + "plot(x,y,phi0,phi1)\n", + "loss = compute_loss(x,y,phi0,phi1)\n", + "print(f'Your Loss = {loss:3.2f}, Ground truth =10.28')" + ], + "metadata": { + "id": "_vZS28-FahGP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# TO DO -- Change the parameters manually to fit the model\n", + "# First fix phi1 and try changing phi0 until you can't make the loss go down any more\n", + "# Then fix phi0 and try changing phi1 until you can't make the loss go down any more\n", + "# Repeat this process until you find a set of parameters that fit the model as in figure 2.2d\n", + "# You can either do this by hand, or if you want to get fancy, write code to descent automatically in this way\n", + "# Start at these values:\n", + "phi0 = 1.60 ; phi1 =-0.8\n", + "\n", + "plot(x,y,phi0,phi1)\n", + "print(f'Your Loss = {compute_loss(x,y,phi0,phi1):3.2f}')" + ], + "metadata": { + "id": "VzpnzdW5d9vj" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Visualizing the loss function\n", + "\n", + "The above process is equivalent to to descending coordinate wise on the loss function
\n", + "\n", + "Now let's plot that function" + ], + "metadata": { + "id": "MNC4qEZognEe" + } + }, + { + "cell_type": "code", + "source": [ + "# Make a 2D grid of possible phi0 and phi1 values\n", + "phi0_mesh, phi1_mesh = np.meshgrid(np.arange(0.0,2.0,0.02), np.arange(-1.0,1.0,0.02))\n", + "\n", + "# Make a 2D array for the losses\n", + "all_losses = np.zeros_like(phi1_mesh)\n", + "# Run through each 2D combination of phi0, phi1 and compute loss\n", + "for indices,temp in np.ndenumerate(phi1_mesh):\n", + " all_losses[indices] = compute_loss(x,y, phi0_mesh[indices], phi1_mesh[indices])\n" + ], + "metadata": { + "id": "ATrU8sqqg2hJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Plot the loss function as a heatmap\n", + "fig = plt.figure()\n", + "ax = plt.axes()\n", + "fig.set_size_inches(7,7)\n", + "levels = 256\n", + "ax.contourf(phi0_mesh, phi1_mesh, all_losses ,levels)\n", + "levels = 40\n", + "ax.contour(phi0_mesh, phi1_mesh, all_losses ,levels, colors=['#80808080'])\n", + "ax.set_ylim([1,-1])\n", + "ax.set_xlabel('Intercept, $\\phi_0$')\n", + "ax.set_ylabel('Slope, $\\phi_1$')\n", + "\n", + "# Plot the position of your best fitting line on the loss function\n", + "# It should be close to the minimum\n", + "ax.plot(phi0,phi1,'ro')\n", + "plt.show()" + ], + "metadata": { + "id": "6OXAjx5xfQkl" + }, + "execution_count": null, + "outputs": [] + } + ] +} diff --git a/Notebooks/Chap03/3_1_Shallow_Networks_I.ipynb b/Notebooks/Chap03/3_1_Shallow_Networks_I.ipynb new file mode 100644 index 0000000..a225f50 --- /dev/null +++ b/Notebooks/Chap03/3_1_Shallow_Networks_I.ipynb @@ -0,0 +1,371 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "view-in-github" + }, + "source": [ + "\"Open" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "1Z6LB4Ybn1oN" + }, + "source": [ + "# **Notebook 3.1 -- Shallow neural networks I**\n", + "\n", + "The purpose of this notebook is to gain some familiarity with shallow neural networks with 1D inputs. It works through an example similar to figure 3.3 and experiments with different activation functions.
\n", + "\n", + "Work through the cells below, running each cell in turn. In various places you will see the words \"TO DO\". Follow the instructions at these places and write code to complete the functions. There are also questions interspersed in the text.\n", + "\n", + "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hAM55ZjSncOk" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "wQDy9UzXpnf5" + }, + "source": [ + "Let's first construct the shallow neural network with one input, three hidden units, and one output described in section 3.1 of the book." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OT7h7sSwpkrt" + }, + "outputs": [], + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " # TODO write code to implement the ReLU and compute the activation at the\n", + " # hidden unit from the preactivation\n", + " # This should work on every element of the ndarray \"preactivation\" at once\n", + " # One way to do this is with the ndarray \"clip\" function\n", + " # https://numpy.org/doc/stable/reference/generated/numpy.ndarray.clip.html\n", + " activation = np.zeros_like(preactivation);\n", + "\n", + " return activation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "okwJmSw9pVNF" + }, + "outputs": [], + "source": [ + "# Make an array of inputs\n", + "z = np.arange(-5,5,0.1)\n", + "RelU_z = ReLU(z)\n", + "\n", + "# Plot the ReLU function\n", + "fig, ax = plt.subplots()\n", + "ax.plot(z,RelU_z,'r-')\n", + "ax.set_xlim([-5,5]);ax.set_ylim([-5,5])\n", + "ax.set_xlabel('z'); ax.set_ylabel('ReLU[z]')\n", + "ax.set_aspect('equal')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "epk68ZCBu7uJ" + }, + "outputs": [], + "source": [ + "# Define a shallow neural network with, one input, one output, and three hidden units\n", + "def shallow_1_1_3(x, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31):\n", + " # TODO Replace the lines below to compute the three initial lines\n", + " # (figure 3.3a-c) from the theta parameters. These are the preactivations\n", + " pre_1 = np.zeros_like(x)\n", + " pre_2 = np.zeros_like(x)\n", + " pre_3 = np.zeros_like(x)\n", + "\n", + " # Pass these through the ReLU function to compute the activations as in\n", + " # figure 3.3 d-f\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + "\n", + " # TODO Replace the code below to weight the activations using phi1, phi2 and phi3\n", + " # To create the equivalent of figure 3.3 g-i\n", + " w_act_1 = np.zeros_like(x)\n", + " w_act_2 = np.zeros_like(x)\n", + " w_act_3 = np.zeros_like(x)\n", + "\n", + " # TODO Replace the code below to combining the weighted activations and add\n", + " # phi_0 to create the output as in figure 3.3 j\n", + " y = np.zeros_like(x)\n", + "\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CAr7n1lixuhQ" + }, + "outputs": [], + "source": [ + "# Plot the shallow neural network. We'll assume input in is range [0,1] and output [-1,1]\n", + "# If the plot_all flag is set to true, then we'll plot all the intermediate stages as in Figure 3.3\n", + "def plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=False, x_data=None, y_data=None):\n", + "\n", + " # Plot intermediate plots if flag set\n", + " if plot_all:\n", + " fig, ax = plt.subplots(3,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " ax[0,0].plot(x,pre_1,'r-'); ax[0,0].set_ylabel('Preactivation')\n", + " ax[0,1].plot(x,pre_2,'b-'); ax[0,1].set_ylabel('Preactivation')\n", + " ax[0,2].plot(x,pre_3,'g-'); ax[0,2].set_ylabel('Preactivation')\n", + " ax[1,0].plot(x,act_1,'r-'); ax[1,0].set_ylabel('Activation')\n", + " ax[1,1].plot(x,act_2,'b-'); ax[1,1].set_ylabel('Activation')\n", + " ax[1,2].plot(x,act_3,'g-'); ax[1,2].set_ylabel('Activation')\n", + " ax[2,0].plot(x,w_act_1,'r-'); ax[2,0].set_ylabel('Weighted Act')\n", + " ax[2,1].plot(x,w_act_2,'b-'); ax[2,1].set_ylabel('Weighted Act')\n", + " ax[2,2].plot(x,w_act_3,'g-'); ax[2,2].set_ylabel('Weighted Act')\n", + "\n", + " for plot_y in range(3):\n", + " for plot_x in range(3):\n", + " ax[plot_y,plot_x].set_xlim([0,1]);ax[plot_x,plot_y].set_ylim([-1,1])\n", + " ax[plot_y,plot_x].set_aspect(0.5)\n", + " ax[2,plot_y].set_xlabel('Input, $x$');\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.plot(x,y)\n", + " ax.set_xlabel('Input, $x$'); ax.set_ylabel('Output, $y$')\n", + " ax.set_xlim([0,1]);ax.set_ylim([-1,1])\n", + " ax.set_aspect(0.5)\n", + " if x_data is not None:\n", + " ax.plot(x_data, y_data, 'mo')\n", + " for i in range(len(x_data)):\n", + " ax.plot(x_data[i], y_data[i],)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SzIVdp9U-JWb" + }, + "outputs": [], + "source": [ + "# Now lets define some parameters and run the neural network\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "T34bszToImKQ" + }, + "source": [ + "If your code is correct, then the final output should look like this:\n", + "" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "jhaBSS8oIWSX" + }, + "source": [ + "Now let's play with the parameters to make sure we understand how they work. The original parameters were:\n", + "\n", + "$\\theta_{10} = 0.3$ ; $\\theta_{11} = -1.0$
\n", + "$\\theta_{20} = -1.0$ ; $\\theta_{21} = 2.0$
\n", + "$\\theta_{30} = -0.5$ ; $\\theta_{31} = 0.65$
\n", + "$\\phi_0 = -0.3; \\phi_1 = 2.0; \\phi_2 = -1.0; \\phi_3 = 7.0$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ur4arJ8KAQWe" + }, + "outputs": [], + "source": [ + "# TODO\n", + "# 1. Predict what effect changing phi_0 will have on the network.\n", + "\n", + "# 2. Predict what effect multiplying phi_1, phi_2, phi_3 by 0.5 would have. Check if you are correct\n", + "\n", + "# 3. Predict what effect multiplying phi_1 by -1 will have. Check if you are correct.\n", + "\n", + "# 4. Predict what effect setting theta_20 to -1.2 will have. Check if you are correct.\n", + "\n", + "# 5. Change the parameters so that there are only two \"joints\" (including outside the range of the plot)\n", + "# There are actually three ways to do this. See if you can figure them all out\n", + "\n", + "# 6. With the original parameters, the second line segment is flat (i.e. has slope zero)\n", + "# How could you change theta_10 so that all of the segments have non-zero slopes\n", + "\n", + "# 7. What do you predict would happen if you multiply theta_20 and theta21 by 0.5, and phi_2 by 2.0?\n", + "# Check if you are correct.\n", + "\n", + "# 8. What do you predict would happen if you multiply theta_20 and theta21 by -0.5, and phi_2 by -2.0?\n", + "# Check if you are correct.\n", + "\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "id": "osonHsEqVp2I" + }, + "source": [ + "# Least squares loss\n", + "\n", + "Now let's consider fitting the network to data. First we need to define the loss function. We'll use the least squares loss:\n", + "\n", + "\\begin{equation}\n", + "L[\\boldsymbol\\phi] = \\sum_{i=1}^{I}(y_{i}-\\text{f}[x_{i},\\boldsymbol\\phi])^2\n", + "\\end{equation}\n", + "\n", + "where $(x_i,y_i)$ is an input/output training pair and $\\text{f}[\\bullet,\\boldsymbol\\phi]$ is the neural network with parameters $\\boldsymbol\\phi$. The first term in the brackets is the ground truth output and the second term is the prediction of the model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "14d5II-TU46w" + }, + "outputs": [], + "source": [ + "# Least squares function\n", + "def least_squares_loss(y_train, y_predict):\n", + " # TODO Replace the line below to compute the sum of squared\n", + " # differences between the real values of y and the predicted values from the model f[x_i,phi]\n", + " # (see figure 2.2 of the book)\n", + " # you will need to use the function np.sum\n", + " loss = 0\n", + "\n", + " return loss" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "o6GXjtRubZ2U" + }, + "outputs": [], + "source": [ + "# Now lets define some parameters, run the neural network, and compute the loss\n", + "theta_10 = 0.3 ; theta_11 = -1.0\n", + "theta_20 = -1.0 ; theta_21 = 2.0\n", + "theta_30 = -0.5 ; theta_31 = 0.65\n", + "phi_0 = -0.3; phi_1 = 2.0; phi_2 = -1.0; phi_3 = 7.0\n", + "\n", + "# Define a range of input values\n", + "x = np.arange(0,1,0.01)\n", + "\n", + "x_train = np.array([0.09291784,0.46809093,0.93089486,0.67612654,0.73441752,0.86847339,\\\n", + " 0.49873225,0.51083168,0.18343972,0.99380898,0.27840809,0.38028817,\\\n", + " 0.12055708,0.56715537,0.92005746,0.77072270,0.85278176,0.05315950,\\\n", + " 0.87168699,0.58858043])\n", + "y_train = np.array([-0.15934537,0.18195445,0.451270150,0.13921448,0.09366691,0.30567674,\\\n", + " 0.372291170,0.40716968,-0.08131792,0.41187806,0.36943738,0.3994327,\\\n", + " 0.019062570,0.35820410,0.452564960,-0.0183121,0.02957665,-0.24354444, \\\n", + " 0.148038840,0.26824970])\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_1_1_3(x, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "# And then plot it\n", + "plot_neural(x, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3, plot_all=True, x_data = x_train, y_data = y_train)\n", + "\n", + "# Run the neural network on the training data\n", + "y_predict, *_ = shallow_1_1_3(x_train, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_20, theta_21, theta_30, theta_31)\n", + "\n", + "# Compute the least squares loss and print it out\n", + "loss = least_squares_loss(y_train,y_predict)\n", + "print('Your Loss = %3.3f, True value = 9.385'%(loss))\n", + "\n", + "# TODO. Manipulate the parameters (by hand!) to make the function\n", + "# fit the data better and try to reduce the loss to as small a number\n", + "# as possible. The best that I could do was 0.181\n", + "# Tip... start by manipulating phi_0.\n", + "# It's not that easy, so don't spend too much time on this!\n" + ] + } + ], + "metadata": { + "colab": { + "authorship_tag": "ABX9TyPBNztJrxnUt1ELWfm1Awa3", + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Notebooks/Chap03/3_2_Shallow_Networks_II.ipynb b/Notebooks/Chap03/3_2_Shallow_Networks_II.ipynb new file mode 100644 index 0000000..28fb916 --- /dev/null +++ b/Notebooks/Chap03/3_2_Shallow_Networks_II.ipynb @@ -0,0 +1,293 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **Notebook 3.2 -- Shallow neural networks II**\n", + "\n", + "The purpose of this notebook is to gain some familiarity with shallow neural networks with 2D inputs. It works through an example similar to figure 3.8 and experiments with different activation functions.

\n", + "\n", + "Work through the cells below, running each cell in turn. In various places you will see the words \"TO DO\". Follow the instructions at these places and write code to complete the functions. There are also questions interspersed in the text.\n", + "\n", + "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions.\n" + ], + "metadata": { + "id": "1Z6LB4Ybn1oN" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hAM55ZjSncOk" + }, + "outputs": [], + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "source": [ + "# Code to draw 2D function -- read it so you know what is going on, but you don't have to change it\n", + "def draw_2D_function(ax, x1_mesh, x2_mesh, y):\n", + " pos = ax.contourf(x1_mesh, x2_mesh, y, levels=256 ,cmap = 'hot', vmin=-10,vmax=10.0)\n", + " ax.set_xlabel('x1');ax.set_ylabel('x2')\n", + " levels = np.arange(-10,10,1.0)\n", + " ax.contour(x1_mesh, x2_mesh, y, levels, cmap='winter')\n", + "\n", + "# Plot the shallow neural network. We'll assume input in is range [0,10],[0,10] and output [-10,10]\n", + "def plot_neural_2_inputs(x1,x2, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3):\n", + "\n", + " fig, ax = plt.subplots(3,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " draw_2D_function(ax[0,0], x1,x2,pre_1); ax[0,0].set_title('Preactivation')\n", + " draw_2D_function(ax[0,1], x1,x2,pre_2); ax[0,1].set_title('Preactivation')\n", + " draw_2D_function(ax[0,2], x1,x2,pre_3); ax[0,2].set_title('Preactivation')\n", + " draw_2D_function(ax[1,0], x1,x2,act_1); ax[1,0].set_title('Activation')\n", + " draw_2D_function(ax[1,1], x1,x2,act_2); ax[1,1].set_title('Activation')\n", + " draw_2D_function(ax[1,2], x1,x2,act_3); ax[1,2].set_title('Activation')\n", + " draw_2D_function(ax[2,0], x1,x2,w_act_1); ax[2,0].set_title('Weighted Act')\n", + " draw_2D_function(ax[2,1], x1,x2,w_act_2); ax[2,1].set_title('Weighted Act')\n", + " draw_2D_function(ax[2,2], x1,x2,w_act_3); ax[2,2].set_title('Weighted Act')\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " draw_2D_function(ax,x1,x2,y)\n", + " ax.set_title('Network output, $y$')\n", + " ax.set_aspect(1.0)\n", + " plt.show()" + ], + "metadata": { + "id": "IHtCP0t2HC4c" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define the Rectified Linear Unit (ReLU) function\n", + "def ReLU(preactivation):\n", + " activation = preactivation.clip(0.0)\n", + " return activation" + ], + "metadata": { + "id": "Lw71laEeJgKs" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Define a shallow neural network with, two input, one output, and three hidden units\n", + "def shallow_2_1_3(x1,x2, activation_fn, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11,\\\n", + " theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32):\n", + " # TODO Replace the lines below to compute the three initial linear functions\n", + " # (figure 3.8a-c) from the theta parameters. These are the preactivations\n", + " pre_1 = np.zeros_like(x1)\n", + " pre_2 = np.zeros_like(x1)\n", + " pre_3 = np.zeros_like(x1)\n", + "\n", + " # Pass these through the ReLU function to compute the activations as in\n", + " # figure 3.8 d-f\n", + " act_1 = activation_fn(pre_1)\n", + " act_2 = activation_fn(pre_2)\n", + " act_3 = activation_fn(pre_3)\n", + "\n", + " # TODO Replace the code below to weight the activations using phi1, phi2 and phi3\n", + " # To create the equivalent of figure 3.8 g-i\n", + " w_act_1 = np.zeros_like(x1)\n", + " w_act_2 = np.zeros_like(x1)\n", + " w_act_3 = np.zeros_like(x1)\n", + "\n", + " # TODO Replace the code below to combing the weighted activations and add\n", + " # phi_0 to create the output as in figure 3.8j\n", + " y = np.zeros_like(x1)\n", + "\n", + " # Return everything we have calculated\n", + " return y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3" + ], + "metadata": { + "id": "VIZA8HywIjfl" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the neural network\n", + "theta_10 = -4.0 ; theta_11 = 0.9; theta_12 = 0.0\n", + "theta_20 = 5.0 ; theta_21 = -0.9 ; theta_22 = -0.5\n", + "theta_30 = -7 ; theta_31 = 0.5; theta_32 = 0.9\n", + "phi_0 = 0.0; phi_1 = -2.0; phi_2 = 2.0; phi_3 = 1.5\n", + "\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# We run the neural network for each of these input values\n", + "y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3 = \\\n", + " shallow_2_1_3(x1,x2, ReLU, phi_0,phi_1,phi_2,phi_3, theta_10, theta_11, theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32)\n", + "# And then plot it\n", + "plot_neural_2_inputs(x1,x2, y, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_1, w_act_2, w_act_3)" + ], + "metadata": { + "id": "51lvc9bfIrs4" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "How many different linear polytopes are made by this model? Identify each in the network output." + ], + "metadata": { + "id": "j62IizIfMYZK" + } + }, + { + "cell_type": "markdown", + "source": [ + "Now we'll extend this model to have two outputs $y_1$ and $y_2$, each of which can be visualized with a separate heatmap. You will now have sets of parameters $\\phi_{10}, \\phi_{11}, \\phi_{12}, \\phi_{13}$ and $\\phi_{20}, \\phi_{21}, \\phi_{22}, \\phi_{23}$ that correspond to each of these outputs." + ], + "metadata": { + "id": "Xl6LcrUyM7Lh" + } + }, + { + "cell_type": "code", + "source": [ + "# Plot the shallow neural network. We'll assume input in is range [0,10],[0,10] and output [-10,10]\n", + "def plot_neural_2_inputs_2_outputs(x1,x2, y1, y2, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_11, w_act_12, w_act_13, w_act_21, w_act_22, w_act_23):\n", + "\n", + " # Plot intermediate plots if flag set\n", + " fig, ax = plt.subplots(4,3)\n", + " fig.set_size_inches(8.5, 8.5)\n", + " fig.tight_layout(pad=3.0)\n", + " draw_2D_function(ax[0,0], x1,x2,pre_1); ax[0,0].set_title('Preactivation')\n", + " draw_2D_function(ax[0,1], x1,x2,pre_2); ax[0,1].set_title('Preactivation')\n", + " draw_2D_function(ax[0,2], x1,x2,pre_3); ax[0,2].set_title('Preactivation')\n", + " draw_2D_function(ax[1,0], x1,x2,act_1); ax[1,0].set_title('Activation')\n", + " draw_2D_function(ax[1,1], x1,x2,act_2); ax[1,1].set_title('Activation')\n", + " draw_2D_function(ax[1,2], x1,x2,act_3); ax[1,2].set_title('Activation')\n", + " draw_2D_function(ax[2,0], x1,x2,w_act_11); ax[2,0].set_title('Weighted Act 1')\n", + " draw_2D_function(ax[2,1], x1,x2,w_act_12); ax[2,1].set_title('Weighted Act 1')\n", + " draw_2D_function(ax[2,2], x1,x2,w_act_13); ax[2,2].set_title('Weighted Act 1')\n", + " draw_2D_function(ax[3,0], x1,x2,w_act_21); ax[3,0].set_title('Weighted Act 2')\n", + " draw_2D_function(ax[3,1], x1,x2,w_act_22); ax[3,1].set_title('Weighted Act 2')\n", + " draw_2D_function(ax[3,2], x1,x2,w_act_23); ax[3,2].set_title('Weighted Act 2')\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " draw_2D_function(ax,x1,x2,y1)\n", + " ax.set_title('Network output, $y_1$')\n", + " ax.set_aspect(1.0)\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " draw_2D_function(ax,x1,x2,y2)\n", + " ax.set_title('Network output, $y_2$')\n", + " ax.set_aspect(1.0)\n", + " plt.show()" + ], + "metadata": { + "id": "DlznqZWdPtjI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "\n", + "# Define a shallow neural network with, two inputs, two outputs, and three hidden units\n", + "def shallow_2_2_3(x1,x2, activation_fn, phi_10,phi_11,phi_12,phi_13, phi_20,phi_21,phi_22,phi_23, theta_10, theta_11,\\\n", + " theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32):\n", + "\n", + " # TODO -- write this function -- replace the dummy code below\n", + " pre_1 = np.zeros_like(x1)\n", + " pre_2 = np.zeros_like(x1)\n", + " pre_3 = np.zeros_like(x1)\n", + " act_1 = np.zeros_like(x1)\n", + " act_2 = np.zeros_like(x1)\n", + " act_3 = np.zeros_like(x1)\n", + " w_act_11 = np.zeros_like(x1)\n", + " w_act_12 = np.zeros_like(x1)\n", + " w_act_13 = np.zeros_like(x1)\n", + " w_act_21 = np.zeros_like(x1)\n", + " w_act_22 = np.zeros_like(x1)\n", + " w_act_23 = np.zeros_like(x1)\n", + " y1 = np.zeros_like(x1)\n", + " y2 = np.zeros_like(x1)\n", + "\n", + "\n", + " # Return everything we have calculated\n", + " return y1,y2, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_11, w_act_12, w_act_13, w_act_21, w_act_22, w_act_23\n" + ], + "metadata": { + "id": "m8KAhwr4QWro" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Now lets define some parameters and run the neural network\n", + "theta_10 = -4.0 ; theta_11 = 0.9; theta_12 = 0.0\n", + "theta_20 = 5.0 ; theta_21 = -0.9 ; theta_22 = -0.5\n", + "theta_30 = -7 ; theta_31 = 0.5; theta_32 = 0.9\n", + "phi_10 = 0.0; phi_11 = -2.0; phi_12 = 2.0; phi_13 = 1.5\n", + "phi_20 = -2.0; phi_21 = -1.0; phi_22 = -2.0; phi_23 = 0.8\n", + "\n", + "x1 = np.arange(0.0, 10.0, 0.1)\n", + "x2 = np.arange(0.0, 10.0, 0.1)\n", + "x1,x2 = np.meshgrid(x1,x2) # https://www.geeksforgeeks.org/numpy-meshgrid-function/\n", + "\n", + "# We run the neural network for each of these input values\n", + "y1, y2, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_11, w_act_12, w_act_13, w_act_21, w_act_22, w_act_23 = \\\n", + " shallow_2_2_3(x1,x2, ReLU, phi_10,phi_11,phi_12,phi_13, phi_20,phi_21,phi_22,phi_23, theta_10, theta_11, theta_12, theta_20, theta_21, theta_22, theta_30, theta_31, theta_32)\n", + "# And then plot it\n", + "plot_neural_2_inputs_2_outputs(x1,x2, y1, y2, pre_1, pre_2, pre_3, act_1, act_2, act_3, w_act_11, w_act_12, w_act_13, w_act_21, w_act_22, w_act_23)" + ], + "metadata": { + "id": "ms4YTqbYUeRV" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/Notebooks/Chap03/3_3_Shallow_Network_Regions.ipynb b/Notebooks/Chap03/3_3_Shallow_Network_Regions.ipynb new file mode 100644 index 0000000..6f2584d --- /dev/null +++ b/Notebooks/Chap03/3_3_Shallow_Network_Regions.ipynb @@ -0,0 +1,259 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyNioITtfAcfxEfM3UOfQyb9", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# **Notebook 3.3 -- Shallow network regions**\n", + "\n", + "The purpose of this notebook is to compute the maximum possible number of linear regions as seen in figure 3.9 of the book.\n", + "\n", + "Work through the cells below, running each cell in turn. In various places you will see the words \"TO DO\". Follow the instructions at these places and write code to complete the functions. There are also questions interspersed in the text.\n", + "\n", + "Contact me at udlbookmail@gmail.com if you find any mistakes or have any suggestions." + ], + "metadata": { + "id": "DCTC8fQ6cp-n" + } + }, + { + "cell_type": "code", + "source": [ + "# Imports math library\n", + "import numpy as np\n", + "# Imports plotting library\n", + "import matplotlib.pyplot as plt\n", + "# Imports math library\n", + "import math" + ], + "metadata": { + "id": "W3C1ZA1gcpq_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The number of regions $N$ created by a shallow neural network with $D_i$ inputs and $D$ hidden units is given by Zaslavsky's formula:\n", + "\n", + "\\begin{equation}N = \\sum_{j=0}^{D_{i}}\\binom{D}{j}=\\sum_{j=0}^{D_{i}} \\frac{D!}{(D-j)!j!} \\end{equation}
\n", + "\n" + ], + "metadata": { + "id": "TbfanfXBe84L" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4UQ2n0RWcgOb" + }, + "outputs": [], + "source": [ + "def number_regions(Di, D):\n", + " # TODO -- implement Zaslavsky's formula\n", + " # You can use math.comb() https://www.w3schools.com/python/ref_math_comb.asp\n", + " # Replace this code\n", + " N = 1;\n", + "\n", + " return N" + ] + }, + { + "cell_type": "code", + "source": [ + "# Calculate the number of regions for 2D input (Di=2) and 3 hidden units (D=3) as in figure 3.8j\n", + "N = number_regions(2, 3)\n", + "print(f\"Di=2, D=3, Number of regions = {int(N)}, True value = 7\")" + ], + "metadata": { + "id": "AqSUfuJDigN9" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Calculate the number of regions for 10D input (Di=10) and 50 hidden units (D=50)\n", + "N = number_regions(10, 50)\n", + "print(f\"Di=10, D=50, Number of regions = {int(N)}, True value = 13432735556\")" + ], + "metadata": { + "id": "krNKPV9gjCu-" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "This works but there is a complication. If the number of hidden units $D$ is fewer than the number of input dimensions $D_i$ , the formula will fail. When this is the case, there are just $2^D$ regions (see figure 3.10 to understand why).\n", + "\n", + "Let's demonstrate this:" + ], + "metadata": { + "id": "rk1a2LqGkO9u" + } + }, + { + "cell_type": "code", + "source": [ + "# Depending on how you implemented it, the calculation may fail when $D_i > D$ (not to worry...)\n", + "try:\n", + " N = number_regions(10, 8)\n", + " print(f\"Di=10, D=8, Number of regions = {int(N)}, True value = 256\")\n", + "except Exception as error:\n", + " print(\"An exception occurred:\", error)\n" + ], + "metadata": { + "id": "uq5IeAZTkIMg" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Let's do the calculation properly when D