From 8fce779633f7849f758aecd13fce94dec76eb676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Tue, 5 Sep 2023 11:38:15 +1200 Subject: [PATCH] No longer need super.build() or self.built = True in build() method; also update custom optimizer section and use tf.keras.utils.set_random_seed() instead of tf.random.set_seed() --- ..._models_and_training_with_tensorflow.ipynb | 564 ++++++++++-------- 1 file changed, 321 insertions(+), 243 deletions(-) diff --git a/12_custom_models_and_training_with_tensorflow.ipynb b/12_custom_models_and_training_with_tensorflow.ipynb index 30a2bad..242570f 100644 --- a/12_custom_models_and_training_with_tensorflow.ipynb +++ b/12_custom_models_and_training_with_tensorflow.ipynb @@ -506,7 +506,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2]\n" + "cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2] name: \n" ] } ], @@ -526,7 +526,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a double tensor [Op:AddV2]\n" + "cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a double tensor [Op:AddV2] name: \n" ] } ], @@ -1020,7 +1020,8 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 42, @@ -1088,7 +1089,8 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 45, @@ -1110,7 +1112,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], @@ -1192,7 +1195,10 @@ { "data": { "text/plain": [ - "" + "SparseTensor(indices=tf.Tensor(\n", + "[[0 1]\n", + " [1 0]\n", + " [2 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([ 42. 84. 126.], shape=(3,), dtype=float32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))" ] }, "execution_count": 50, @@ -1258,17 +1264,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n", + "{{function_node __wrapped__SparseToDense_device_/job:localhost/replica:0/task:0/device:CPU:0}} indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n", " Use `tf.sparse.reorder` to create a correctly ordered copy.\n", "\n", - " [Op:SparseToDense]\n" + " [Op:SparseToDense] name: \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "2021-12-17 10:32:40.424119: W tensorflow/core/framework/op_kernel.cc:1692] OP_REQUIRES failed at sparse_to_dense_op.cc:162 : Invalid argument: indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n", + "2023-09-05 11:03:52.814492: W tensorflow/core/framework/op_kernel.cc:1828] OP_REQUIRES failed at sparse_to_dense_op.cc:161 : INVALID_ARGUMENT: indices[1] = [0,1] is out of order. Many sparse ops require sorted indices.\n", " Use `tf.sparse.reorder` to create a correctly ordered copy.\n", "\n", "\n" @@ -1428,7 +1434,12 @@ { "data": { "text/plain": [ - "" + "SparseTensor(indices=tf.Tensor(\n", + "[[0 0]\n", + " [0 1]\n", + " [0 2]\n", + " [0 3]\n", + " [0 4]], shape=(5, 2), dtype=int64), values=tf.Tensor([ 1 5 6 9 11], shape=(5,), dtype=int32), dense_shape=tf.Tensor([1 5], shape=(2,), dtype=int64))" ] }, "execution_count": 59, @@ -1692,14 +1703,12 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqQAAAFkCAYAAAD2RimAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB5/UlEQVR4nO3dd1xV5R/A8c9lg4IbRQVn7hmWYu49Mi3LmaOyX+YoMzNRK83VMHPkzJWaq9w5McW9cKSZmeZWECcoMi5wfn88XRAB5V7GuRe+79eLl5zDPfd+eTzc+z3PeZ7vY9A0TUMIIYQQQgid2OkdgBBCCCGEyNkkIRVCCCGEELqShFQIIYQQQuhKElIhhBBCCKErSUiFEEIIIYSuJCEVQgghhBC6koRUCCGEEELoShJSIYQQQgihK0lIhRBCCCGEriQhFUKIVIwaNQqDwUBgYKDeoSTTqFEjDAaD3mEIIUSGkIRUCGFTLl26hMFgoFWrVqk+5uDBgxgMBnr37p11gQkhhLCYJKRCCCGEEEJXkpAKIYQQQghdSUIqhMgxSpYsScmSJVP82bPGZP74449UrlwZFxcXfHx88Pf3JyoqKsXHnjx5ki5duuDl5YWTkxMlSpRg4MCB3LlzJ8njTMMPevfuzd9//81rr71GwYIFMRgMXLp0yaLfMTY2lu+//57q1avj6upKnjx5aNy4MRs3bkz22Pj4eObOncuLL75I/vz5cXNzo2TJknTo0IHdu3cneeyqVato2LAhnp6euLi44O3tTatWrVi7dq1FcQohxOMc9A5ACCGs3XfffUdgYCCdO3fm5ZdfZtOmTXz11VccP36czZs3J0lk169fT6dOnbC3t+eVV17B29ubv/76ix9++IGtW7dy6NAh8uXLl+T5z58/T506dahcuTK9evXi7t27ODk5mR2npml07tyZ1atXU65cOfr3709ERAQrV67k5ZdfZsqUKXzwwQcJj/f39+ebb76hTJkydOvWDXd3d65fv86ePXvYsWMHDRo0AGDmzJn069cPLy8vXn31VQoUKEBwcDCHDx9m7dq1dOjQwbKGFUKI/0hCKoSwSefPn2fUqFEp/uzatWsZ+lrbt28nKCiIypUrAzBu3DjatGnD1q1bWbJkCT169ADgzp079OjRg0KFCrFv3z58fHwSnmPZsmV069aNzz//nGnTpiV5/n379vHZZ5/x5ZdfpivOJUuWsHr1aho2bMi2bdsSktoRI0bg6+vLkCFDaNeuHaVKlQJg7ty5FCtWjJMnT+Lm5pbwPJqmce/evYTtuXPn4uTkxB9//EGhQoWSvOaTvb5CCGEJSUiFEDbp33//ZfTo0VnyWj169EhIRgEcHBwYP348AQEB/PTTTwkJ6aJFiwgPD2f69OlJklGArl27MnHiRJYvX54sIS1SpAgjR45Md5wLFy4E4JtvvknSw1q8eHE++ugj/P39+fnnn5O8lpOTEw4OST8KDAYD+fPnT7LP0dERR0fHZK9ZoECBdMcthBCSkAohbFLLli3ZsmVLij87ePAgfn5+GfZa9evXT7avVq1auLq6cuLEiSSva/r3/PnzyY6Jiori9u3b3L59m4IFCybsr169ukW36J90/PhxXF1defHFF5P9rFGjRgBJ4u3UqROzZs2iSpUqdO7cmYYNG+Ln50euXLmSHNupUyeGDRtGlSpV6NKlC40aNaJevXrkzZs33TELIQRIQiqEEM/k6emZ6v7r168nbN+9exeA6dOnP/X5IiIikiSkhQsXzoAoITw8HG9v7xR/VqRIEQDCwsIS9k2dOpXSpUuzcOFCxo4dy9ixY3FxcaFTp0589913CTEOHTqUAgUKMGvWLCZNmsR3332Hg4MDbdq0YfLkyQlDAIQQwlIyy14IkWPY2dkRGxub4s8eT9SeFBoamur+PHnyJGx7eHgAcOrUKTRNS/WrRIkSSZ4no1Zc8vDw4ObNmyn+zLTfFCOo2/CffPIJp0+f5vr16yxdupT69euzaNEiunfvniS+Pn36EBQUxK1bt1izZg2vvfYa69evp23btsTFxWVI/EKInEsSUiFEjpEvXz5CQ0OTJaURERGcO3cu1eP27NmTbF9QUBCRkZHUqFEjYV/t2rUBOHDgQMYEbKaaNWsSGRnJ4cOHk/1s165dAEnifVzRokXp2rUrW7Zs4bnnnmP79u1ERkYme1yBAgXo0KEDK1asoEmTJpw5cybF4QlCCGEOSUiFEDlGrVq1MBqN/Pzzzwn7NE3D39+fiIiIVI9bvHgxp0+fTtiOjY1l+PDhAPTq1Sth/1tvvYW7uzsjRoxI8niTR48eJYwzzQymWPz9/TEajQn7r1+/zqRJk3BwcEjo+YyOjmbHjh1ompbkOSIiInjw4AGOjo7Y29sDsHXr1mRJvNFoTBii4Orqmmm/kxAiZ5AxpEKIHGPAgAEsWLCAPn36EBAQQKFChdizZw/379+nevXq/PHHHyke16xZM+rUqUOXLl3Inz8/mzZt4s8//6Rly5a8+eabCY8rVKgQy5Yt44033qB69eq0atWKChUqEBUVxeXLl9m1axd169ZNdTJWevXo0YPVq1ezbt06qlWrxssvv5xQh/TOnTt89913lC5dGoDIyEiaNm1K6dKlqV27Nj4+Pjx8+JDffvuNkJAQPv3004SJVp07d8bNzY169epRokQJjEYjAQEB/PXXX3Tu3DlZRQEhhDCXJKRCiByjatWqbNmyheHDh/Prr7+SO3du2rRpw7fffkvnzp1TPe7jjz+mXbt2TJkyhX///ZdChQoxbNgwPv/882TjP9u2bcvx48f59ttv2b59OwEBAeTKlYvixYvz1ltvJUlgM5rBYODXX39lypQp/PTTT0ybNg0nJyeef/55Bg8ezCuvvJLw2Fy5cvH111/z+++/s2fPHkJDQ8mXLx8VKlTg66+/TtIeEyZMYMuWLRw+fJgNGzaQK1cuypYty+zZs3n77bcz7fcRQuQcBu3J+zVCCCGEEEJkIRlDKoQQQgghdCUJqRBCCCGE0JUkpEIIIYQQQlfpSkgnTJiAwWBg0KBBT33crl278PX1xcXFhdKlSzNr1qz0vKwQQgghhMhGLE5Ijxw5wpw5c6hWrdpTH3fx4kXatGlD/fr1OX78OMOHD+eDDz5g1apVlr60EEIIIYTIRixKSB8+fEj37t358ccfyZcv31MfO2vWLHx8fJg8eTIVK1akT58+vP3220ycONGigIUQQgghRPZiUR3S/v3707ZtW5o1a8bYsWOf+tgDBw7QokWLJPtatmzJvHnzMBqNODo6JjsmOjqa6OjohO34+Hju3r1LgQIFMmzNZyGEEEIIkXE0TePBgwcULVoUOzvz+jzNTkiXL1/OsWPHOHLkSJoeHxISQuHChZPsK1y4MLGxsdy+fRsvL69kx0yYMIHRo0ebG5oQQgghhNDZ1atXKV68uFnHmJWQXr16lQ8//JBt27bh4uKS5uOe7NU01eJPrbfT39+fwYMHJ2yHhYXh4+PDP//8Q/78+c0JOccyGo3s3LmTxo0bp9gLnRq7WbPQPD3RXnstE6OzXpa2W04mbWa+iIgISpQoAcC///5Lnjx5dI7INsi5Zpmc3G6Ggwexb9eO2O3boXr1NB+Xk9ssPe7evUu5cuVwd3c3+1izEtKjR48SGhqKr69vwr64uDh2797NDz/8QHR0NPb29kmOKVKkCCEhIUn2hYaG4uDgQIECBVJ8HWdnZ5ydnZPtz58/f6rHiKSMRiNubm4UKFDAvD+mESMyLygbYHG75WDSZuZ7/II+f/785M2bV79gbIica5bJ0e3WsCH89BM0agRm3ELO0W2WASwZXmlWQtq0aVNOnTqVZN9bb71FhQoV+PTTT5MlowB+fn5s2LAhyb5t27ZRq1Yt+U+2VhcvwubN0K+f3pEIIYQQlsudG3r00DsKkQZmjTh1d3enSpUqSb5y5cpFgQIFqFKlCqBut/fs2TPhmL59+3L58mUGDx7MmTNnmD9/PvPmzWPIkCEZ+5uIjHPwIHz+Ody9q3ckQgghhGVmzoRRo/SOQqRRhq/UFBwczJUrVxK2S5UqxaZNmwgMDKRGjRqMGTOGqVOn0rFjx4x+aZFRXn8drl4FGa8rhBDCVoWHw/37ekch0siisk+PCwwMTLK9cOHCZI9p2LAhx44dS+9Liazi6Ki+IiLAwQFSGM8rhBBCWLVPP9U7AmEGWctepCwsDLy94eef9Y5ECCGEMM+2bfDokd5RCDNIQipSlicPfPcdNGumdyRCCCFE2t28CW3awPLlekcizJDuW/YiG3vrLb0jEEIIIcxTuDD88w8UKaJ3JMIM0kMqnm7lSpmlKIQQwjbEx4OmQenS4OamdzTCDJKQiqe7fh3OnlV/4EIIIYQ1W74cnn9eTcoVNkVu2Yun++gjvSMQQggh0qZUKXj5ZciVS+9IhJkkIRXPpmmwZw+89BKksBqXEEIIYRX8/NSXsDlyy1482x9/qPWAt2/XOxIhhBCZafduaN8eSpQAg8G25hDMmweHDukdhbCQJKTi2WrUUMuJtmihdyRCCCEy08OHUKkSfPNNxs9SX7AAGjeGQoXA3R18fTOu1nV8PMyYAVu3ZszziSwnt+xF2tSurf7VNHXVLIQQIvtp00Z9QcavdPT77/DKKyrZzZcP1qyBHj3UioCdO6fvue3s4MgRiInJmFhFlpOEVKTdu+9C3rzw7bd6RyKEEMLWLFmSdPuTT2DnTlVeMD0JaXw8hIRA0aLg4pK+GIVu5Ja9SLvq1aFqVb2jEEIIkV3cvw8FC6bvObZsUWNez53LkJCEPqSHVKTdgAF6RyCEECK7+OknCAqCH35I3/PUq6fGp5YtmzFxCV1ID6kwz7VrMGmSFMoXQghhuXXr4L33YPZsVcg+PTw84M03ZX6DjZOEVJjnzz/hyy/h6lW9IxFCCKG3119XieDTvp4sxbR8uRozOmsWvPVW+l5/zBiYODF9zyGsgtyyF+Zp0UL1kubOrXckQgghMtrDh3D+vPo+JkZNFjpxApycVDmoJ1WqlPLnwcWLqqapszNUqZK4/8cfYeBAWLgQunRJf7zR0WqGvbB5kpAK89jZqTefyEj1ZpUnj94RCSGEyChBQapWqMns2eqrRAm4dCn547/8Mvm+f/+FRo1UErtqVeIynpMmwdChMH26+nlIiNpvb69qk1pi7FjLjhNWRy4rhPni4qByZVVLTgghRPbRqJGaI/DkV0rJaEpMyWhoKKxeDW3bJv5s6lT1+dG3L3h5JX698IL5cWqaev7oaPOPFVZJekiF+ezt1ZWulIASQghhcuGC6l0NDVU9o48no5D2pDYtTpyAjh1hx46kPbrCZklCKizToYPeEQghhLAWFy6ontGbN1Uy+vLLmft6NWuquqNlymTu64gsI7fsheW2b4fu3aUElBBC5GQXL6peyqxKRo1G9W/ZslLqKRuRhFRYTtMgPBwePNA7EiGEEOn1rPJNj3+ZXLyYOEEpK5JRgM8+UxVfpDMkW5Fb9sJyzZurLyGEELbP3ATv0iXVMxoSAr/+mjXJKECzZupWvfSOZitm9ZDOnDmTatWq4eHhgYeHB35+fmzevDnVxwcGBmIwGJJ9/f333+kOXFgJTYM9e+DGDb0jEUIIkVUuXVI9o8HBKhlt1y7rXrtZM3j33ax7PZElzOohLV68OF999RVl/1sv9qeffqJ9+/YcP36cypUrp3rc2bNn8fDwSNguZGm9MWF9Hj1Sb0TDhqkvIYQQtmvBAli0SK3KFxUF5crB4MFqvsDjevWCy5ehfHl1q37VquTP9eabKnnMKJqm6pi+/TZUrJhxzysyTHpGUZiVkLZ74gpo3LhxzJw5k4MHDz41IfX09CRv3rwWBSisXK5ccPiwGlwuhBDCtv3+O7zyiqoznS8frFkDPXqAg4Na7hMgPh6OHlXfnz2rvlLStWvGxnb9uqo92q6dJKRWKCYG+ve3t/h4i8eQxsXF8csvvxAREYGfn99TH1uzZk2ioqKoVKkSI0eOpPEzaoZFR0cT/Vix2/DwcAC+/lpj7FijDBtJA+N/sxBN/2aqUqVUseOoKHB0zPzXy0RZ2m7ZhLSZ+R5vK6PRKG2XRnKuWcasdluwIOn2oEHY79gBy5cT99prifvv3Uvri6cxyjQoXBhOn1YrBmbyOSDnmnnu34dOnewJDLR8rrxB08zrYD116hR+fn5ERUWRO3duli5dSps2bVJ87NmzZ9m9eze+vr5ER0ezePFiZs2aRWBgIA0aNEj1NUaNGsXo0aNT+EkYjRvfp1+/Ezg6yuw6a1Jm7VqK797Nru++k4HmQjxDVFQUXf5bx3v58uW4uLjoHJEQqav/6aeElyjBH/366RaD8927YDAQnS+fbjGIlN286crYsXW4etUDCAfyEBYWlmSoZlqYnZDGxMRw5coV7t+/z6pVq5g7dy67du2iUqVKaTq+Xbt2GAwG1q9fn+pjUuoh9fb2BsIADxo3jmfFijhkFEDqjEYjAQEBNG/eHMcs6LU0HDiA4fhx4v/3P3Vrx0ZldbtlB9Jm5ouIiCDffx+soaGhMqQpjeRcs0x62s2waBH2779P7N69qhi9Tuw++gi79euJPXdO9ZBmMjnX0uboUQMdOthz86bqiMqfP4y7d/NalJCanTk4OTklTGqqVasWR44cYcqUKcyePTtNx9epU4clS5Y89THOzs44OzunsF8jOhp27rSjcWM7Nm6EEiXM/Q1yFkdHx6z5Y2rQABo0wPLRI9Yly9otG5E2S7vH20nazXzSZpYxu93WrYP+/WH2bBxffDHzAkuLsWOhWzccU8gNMpOca6nbsAG6dFFzm0HNf/v551heeMGy50v3ZYamaUl6M5/l+PHjeHl5WfRaa9fGUbCg+v70aahTB44ds+ipRGZ48ABGjlTLuQkhhLBdy5erSUyzZsFbb+kdDeTNC3Xr6h2F+M/06WoFcVMyWq8e7N+vppRYyqyEdPjw4ezZs4dLly5x6tQpRowYQWBgIN3/Kwfh7+9Pz549Ex4/efJk1q5dy7lz5zh9+jT+/v6sWrWKAQMGWBTsCy9oHDgAzz2ntkNCVMfcb79Z9HQiozk6qjexkyf1jkQIIYSlfvwReveGhQvVv3qKjVW9Txs26BuHAFSBhSFDYMAA9T2oXtKAAChQIH3PbdYt+5s3b9KjRw+Cg4PJkycP1apVY8uWLTT/b7We4OBgrly5kvD4mJgYhgwZwvXr13F1daVy5cps3Lgx1UlQaVG2LBw4AO3bw759EBGhvp82DXQcby0AXFxU+Q/77HLjXgghcphJk1Stz+nTE5cEBfW+rkcN8YcPoUYN8PbO+tcWSURGqgpgj5ecHTYMxo3LmGG9ZiWk8+bNe+rPFy5cmGR76NChDB061OygnqVAAdi+XdXlXblSZen9+6sldb/+OkvGO4vU2NtDdLS6bV+lit7RCCGEMMfUqaqMX9++6sukRAm1OlNWy5tXDRsQurp1S5WnPXhQbdvbw4wZ8L//Zdxr2Gzq5uICy5bBp58m7ps4UQ15iYzULy6Burpu00a9qQkhhLAdly6p5Xae/NIjGT11Sg0Dk88SXf3zD/j5JSajuXOrERQZmYyCDSekoHpCv/pKXTyZekV//RWaNlXZvNDJRx/Btm1y614IIYTlfvsNRozQO4ocbe9elYz++6/aLloU9uyB1q0z/rVsOiE1ee89la3nyqW2DxxQk/FksrdOSpaEChUSr6yFEEIIc/n7q1I60rmhixUroFkzuHtXbVetqnpJa9TInNfLFgkpqDvEe/ao7B3g/HmV1e/bp29cOdbNm/Dii+rySgghhDBHcLD6N08efePIgTRNzcfp0kVNCQFo3lzlWJk5tyzbJKSgFpE4eDBxLs2dO+r2/cqV+saVI3l6qssoWRJRCCGEOR48gIoV4Ycf9I4kx4mNhfffV7PnTd5+GzZuzPxrg2yVkILK3vfuVdk8qOy+c2f45hu5e5ylDAZVy87SJRuEEELkTG5uMH8+vPqq3pHkKA8eqJn0jy+8OWYMzJ2ryoxntmyXkILK4jduTLq4xKefqjqlsbH6xZUjHT0KixbpHYUQQghbYW8Pr70GxYrpHUmOceOGWmho82a17egIixerxRcNhqyJIVsmpKAac948ld2bzJqlsv8HD/SLK8dZv14VWjYt6SCEEEKkZtUqtTqU0ah3JDnGqVNQuzacOKG28+ZVhXLefDNr48i2CSmorH7kSJXlm7qbN2+Ghg3V1YDIAsOGqV5SWa1ACCHEs8TEqA6MrLhHLNi+Xa1Df+2a2i5ZUq1J36hR1seSI7KEN99U2X7evGr7+HF1NXDqlK5h5Qyurur2y40b6o1GCCGESE3XrjLMK4ssWKDqiYaHq+1atdTE8IoV9YknRySkoLL9/ftV9g/qaqBePXV1IDLZzZtQurRaWksIIYRIyfLlcPu23lFke5oGn3+uZs+b5tW0bw+BgVC4sH5x5ZiEFFTWf/Bg4sTv8HB1dTB/vr5xZXuFC6txEx066B2JEEIIa3TnDrzzDqxbp3ck2VpMDPTsmXR+zQcfqKG7psWF9JKjElJQudHOnepqANTVwTvvwGefSVmoTPXGG1LgWAghRMoKFIBLl7J+Jk0Ocu8etGwJS5aobYMBvv8epkyxjsWwclxCCuoqYNUqdVVgMnasumowrUogMsHixWp8kBBCCGHy6JGaVV+oEDg76x1NtnTpErz0krotD2rNmlWrYNAgHYN6Qo5MSEFdDUyZApMnJ9bYWrIEWrVSVxEiE3h4qJllUs5DCCGEybffQrVqEBendyTZUlAQ1KkDZ86o7UKFVGJqbesO5NiE1OTDD9VVgqur2g4MVFcRly7pGVU21b49zJwp5TyEEEIkeu01GD7cOu4bZzPr16tSlzdvqu3y5dVcmtq19Y0rJTk+IQV1lbBzp7pqAHUVUbs2HDmib1zZUmysmm0vGb8QQgiAqlWhRw+9o8h2fvhB5TePHqnt+vVVtaHSpfWNKzWSkP6ndm111VC+vNoODVVXFTLhL4PFxKjBu7/9pnckQggh9BQXp+YVHD6sdyTZSnw8DB4MAwcmLpLYpYuqx54/v76xPY0kpI8pXVpdPTRooLYjI9XVxbRp+saVrbi5wd9/w4ABekcihBBCT6GhcPWq3KrPQI8eqaI233+fuM/fH37+WU1ksmaSkD4hf351FdGtm9rWNNWh99FHMt46wxQooP41DWoRQgiR83h5wd694OurdyTZQmgoNGkCq1erbXt7mDMHxo+3jdW7bSDErOfsrGbcjxiRuG/yZHXVYRqLIdLpu+/UuKHISL0jEUIIkdX++ANOntQ7imzj7Fnw84NDh9R27txqZNy77+oblzkkIU2FwaBqk/74Y+LdhDVroHFjdRUi0um119Slm5OT3pEIIYTIat9+C2+9JSvSZIA9e6BuXbhwQW0XK6Y6nlu10jcuc5mVkM6cOZNq1arh4eGBh4cHfn5+bN68+anH7Nq1C19fX1xcXChdujSzZs1KV8BZrU8f2LQJ3N3V9uHDqp7X2bP6xmXzSpVSS4nK2CEhhMh5FixQvTymQuDCIitWQLNmcPeu2q5WTU3Qrl5d37gsYVZCWrx4cb766iuCgoIICgqiSZMmtG/fntOnT6f4+IsXL9KmTRvq16/P8ePHGT58OB988AGrVq3KkOCzSosW6gqkWDG1ffGi6hrfvVvfuGye0Qi9eqlCsEIIIXKGhw9VPWofH70jsVmaBl9/rWbPx8SofaZcpXhxfWOzlFkJabt27WjTpg3lypWjXLlyjBs3jty5c3Pw4MEUHz9r1ix8fHyYPHkyFStWpE+fPrz99ttMnDgxQ4LPStWrq7EZpquOe/egeXNYulTfuGyao6O6OpaVm4QQImc4fx6KFFGZk7BIbCz07QvDhiXue+cdNWbUw0O/uNLL4jGkcXFxLF++nIiICPz8/FJ8zIEDB2jRokWSfS1btiQoKAijDSYhxYqpvyHTuIyYGOjeXc1gk2EwFlq4UF3iCSGEyP4KFIDPPoNatfSOxCY9eADt2qkpGCbjxqn5Lra+CKKDuQecOnUKPz8/oqKiyJ07N2vWrKFSpUopPjYkJITChQsn2Ve4cGFiY2O5ffs2Xl5eKR4XHR1NdHR0wnZ4eDgARqNR90TWxUXdYf7gA3vmzVP5/IgR8O+/8UybFmc1J4SpnfRurzS5cwfD2rVo77yjdyS21W5WQtrMfI+3lTW8r9kKOdcsY1Xtlju3qtoOVn13zKra7D/Xr0OHDg788Ycad+vkpPHjj3F07aoRG6tzcP9JT3uZnZCWL1+eEydOcP/+fVatWkWvXr3YtWtXqkmp4YkBy9p/XYlP7n/chAkTGD16dLL9O3fuxM3NzdyQM8XLL0NMzHMsXqx+7/nz7Th27DZDhx7Bzc1KzgwgICBA7xCeqcjBg/hOmsROe3siPT31DgewjXazNtJmaRcVFZXw/Y4dO3Cx9orVVkbONcvo3W5l1q4lzsmJS23a6BqHOfRuM5NLlzwYM6YOd+6oXq/cuWMYNuwwefLcYdMmnYN7zKN01MY0aFr6bjY3a9aMMmXKMHv27GQ/a9CgATVr1mTKlCkJ+9asWUOnTp149OgRjql0J6bUQ+rt7U1wcDAFTEXVrcSKFQbeeceemBiVYFetqrFuXazug4qNRiMBAQE0b9481Xa2GvHxaopgwYJ6R2Jb7WYlpM3MFxERQb58+QAIDQ0lb968+gZkI+Rcs4y1tJvdkCHg4kL82LG6xZBW1tJmAAEBBrp0sefBA5VnlCypsX59LBUq6BpWiu7cuYOXlxdhYWF4mDmg1ewe0idpmpYkeXycn58fGzZsSLJv27Zt1KpV66n/wc7Ozjg7Oyfb7+joqPuJ8aQ334QSJVQFo7t34dQpA/XqObJxI9SooXd01tlmKfLyUoNyHzxIXMlJRzbTblZE2iztHm8naTfzSZtZRvd2+69zypaK/endZvPnw3vvkXBL/sUXYf16A4ULW+f5n562MmtS0/Dhw9mzZw+XLl3i1KlTjBgxgsDAQLp37w6Av78/PXv2THh83759uXz5MoMHD+bMmTPMnz+fefPmMWTIEIsDtkb168P+/VC6tNq+cUPt27pV37hsTrNmap1WIYQQ2UdkpFrPMj5e70hshqbByJFq9rwpGW3fHnbuhCem5mQbZiWkN2/epEePHpQvX56mTZty6NAhtmzZQvPmzQEIDg7mypUrCY8vVaoUmzZtIjAwkBo1ajBmzBimTp1Kx44dM/a3sALly8OBA1C7ttp++BDatlUz30Qaff45DB+udxRCCCEy0ubN0KkTXLqkdyQ2IToaevRQs+dNPvhATai2kmk0mcKsW/bz5s176s8XLlyYbF/Dhg05duyYWUHZKk9PdfXy5pvqYjAuDv73P1VIf+xYsJOFWp+uWTO9IxBCCJHRXntNLW9ouo0oUnXvHrz6KuzapbYNBvj+e/jwQ33jygqSImUwV1f45ZfEqhYAEyaoeqWpDLUVj/vnH2jUCIKD9Y5ECCFEeoWFqX/LlNE3Dhtw8aJak96UjLq6qs6tnJCMgiSkmcLODr77DqZNS+wVXb5crex0546+sVm9woXVX6FpYV4hhBC2KS4OXngBxozROxKrd+QI1KkDf/+ttgsVUndcO3TQNawsJQlpJhowANauTRzzsWePuvq5cEHXsKxbnjxqvFHlynpHIoQQIj0MBjVerX17vSOxauvWQcOGEBqqtsuXh4MHE+ek5BSSkGaydu1U97tpVtw//6iroIMH9Y3L6p08qUZwCyGEsE12dmoyU7VqekditaZOVWNGIyPVdoMGSav25CSSkGaBWrVUAlqxotq+dQsaN1ZjQ0Qq5s+H8eNV7QshhBC2ZeNGNas3JkbvSKxSXBx89JEaH2r6mOvWDbZtg/z59Y1NL5KQZpGSJdVVT+PGajsqCl5/Xc2ek5wrBWPGqCz+KUvMCiGEsFLh4XD/Pjg56R2J1Xn0CN54AyZPTtw3YgQsXgwprAmUY0hCmoXy5oUtW1R9MVCJ6ODB6gopLk7X0KyPuzs4OkJICERE6B2NEEIIc3TtCitX6h2F1QkNhSZNYM0atW1vr+qVS2lISUiznJMT/PQTfPFF4r5p09QYEsm7nvDggRrdPWuW3pEIIYRIq59+Ur2jIomzZ9UckkOH1La7uxrZ0KePvnFZC0lIdWAwwKhRsGABOPy3NMGGDar8ZkiInpFZGXd3WLIE3n5b70iEEEKkxaVLavH1nTv1jsSq7NkDfn6q1ihAsWJqX8uW+sZlTSQh1VHv3uoWvoeH2g4KUldPf/2la1jWpV07yJdPBtoKIYQtKFlSJaVS6inBsmVqIcJ799R2tWpqikT16vrGZW0kIdVZ06awbx94e6vty5dVrVK5uHzMli2quHJUlN6RCCGESE1oKMTGQpEiMiAS1Y8yYYKaPW8qNtCypeoZLV5c39iskZwxVqBKFXW19PzzajssTJ20ixfrG5fVKFVKXUrKIFshhLBevXurCRECo1GNXBg+PHFfnz5qeJ7prqhIykHvAIRStKgqoN+lixrkbDRCz55qvMlnn+Xw6kfly8O8eXpHIYQQ4mnGj1eTUXO4Bw9UWaetWxP3jR8Pw4bl8M/yZ5AeUiuSO7daavT99xP3ffGFmtMjtYVRKzetW6d3FEIIIVJSowbUr693FLq6dk01gSkZdXKCn38Gf39JRp9FElIr4+AA06fDt98m7lu4ENq2Vbfyc7Rly9T9DiGEENbjyBG1GPvNm3pHoquTJ9XE5D/+UNv58kFAgBpDKp5NElIrZDDAkCGqprBp1Ybt2+Gll+DKFX1j09WSJTB3rt5RCCGEeFxcHHh5QcGCekeim61boV49uH5dbZcqpVZnbNBA37hsiSSkVuyNN2DHDihQQG2fPq2uvo4d0zcu3bi4qH+DgtRMTiGEEPqrUweWL1fLDuVA8+apu5im4bMvvqgmKleooG9ctkYSUitXt646scuWVdvBweqKa+NGfePSzYUL6q991Sq9IxFCCDFpEvzzj95R6ELTYORINXvetPx3hw6qbKOnp66h2SRJSG1A2bJw4IBKTkFVP3rlFZg5U9+4dFG6tCpH8PrrekcihBA52/37MHmyGkOaw0RHw5tvwrhxifsGDYJffwU3N93CsmmSkNqIggXh99/VbXyA+Hjo1w+GDlXf5yj166tbQ1J6QAgh9JM3L5w7p+oV5iB370KLFrB0qdo2GGDKFPj++xw7aiFDSEJqQ1xc1DCdoUMT9337rXoviIzULy5dzJ8PlStLUiqEEHq4fBlu31Yzb3NQFnbhgrpbuXu32nZ1hTVr4IMP9I0rO5CE1MbY2cHXX6vb9aaV2X75Ra2Te/u2vrFlKT8/+N//cmD3sBBCWIGhQ1U3oabpHUmWOXxYffScPau2PT0hMBDat9c1rGxDVmqyUX37go8PdOqkxpTu36/+UDZtguee0zu6LFCxovoSQgiR9aZPV72kOaTa+9q1qp6o6W5khQrq87ZUKV3DylbM6iGdMGECL7zwAu7u7nh6etKhQwfOmi4VUhEYGIjBYEj29ffff6crcAFt2qjbBl5eavv8eZWU7t+vb1xZ6uuv1coBQgghsobRqCY2+PrqHUmWmDIFXnstMRlt2FB9zkoymrHMSkh37dpF//79OXjwIAEBAcTGxtKiRQsiIiKeeezZs2cJDg5O+HouR3TjZb7nn1dloapUUdt37kCTJvDrrznjqpXz5+HqVb2jEEKInGHPHlXt5NIlvSPJdHFx8PHHdgwalDgyoXt3VQQ/Xz5dQ8uWzLplv2XLliTbCxYswNPTk6NHj9LgGcsReHp6kjdvXrMDFM/m4wN796pKSNu3q3IU3bo50KtXWVq31ju6TDZnTo65ZSSEELorWlRlZT4+ekeSqR49gm++eZFDhxInbI0cCV9+KR85mSVdY0jD/ltcPX/+/M98bM2aNYmKiqJSpUqMHDmSxo0bp/rY6OhooqOjE7bDw8MBMBqNGI3G9IScbbm5wbp18P779ixapDq+f/qpMo6ORqZONeKQnUcLx8ZiWLkSrUOHdBeAM51fcp6lnbSZ+R5vK3lfSzs51yyToe3m4wNjxqjuQ1M1+Gzm5k149VU7goLUeDh7e40ZM+J46y1NFgl8hvScYwZNs2yKnKZptG/fnnv37rFnz55UH3f27Fl2796Nr68v0dHRLF68mFmzZhEYGJhqr+qoUaMYPXp0sv1Lly7FTSrOPpWmwcqV5Vi2LHHCj69vCEOGBOHqmj3fPNxu3qRp//4cGTKEkDp19A5HiGeKioqiy3+1G5cvX46LaVlcIayVplFj+nSuNGnC3UqV9I4m01y7lpsxY+pw82YuAFxdjQwdeoSaNW/pHJltePToEd26dSMsLAwPDw+zjrU4Ie3fvz8bN25k7969FC9e3Kxj27Vrh8FgYP369Sn+PKUeUm9vb4KDgylgWthdPNWiRfH07etIbKzqLa1RQ2Pt2liKFtU5sMxy7RqYeR6mxGg0EhAQQPPmzXF0dMyAwLI/aTPzRUREkO+/QWihoaEynCmN5FyzTIa027172HfsSPzw4WjNmmVsgFZizx4Dr79uz7176p58gQKRbNwIzz+fPW4x7tlj4Pvv7Th50sCVKwZGjozj888ztnTinTt38PLysightaiVBw4cyPr169m9e7fZyShAnTp1WLJkSao/d3Z2xtnZOdl+R0dHeRNKo549jQQH7+e7717i/n0DJ04YqF/fkU2bEidAZSum6Y5XrmTI2CY518wnbZZ2j7eTtJv5pM0sk6528/SE3bvVTOhsOIhy6VJ4663EtVaqVdP48MPdPP98k2xzrkVFqc//N99Uy5za29vj6Jixixqkp63MmmWvaRoDBgxg9erV7Nixg1IW1jw4fvw4XqZaRSLTVK16h8DAWEqUUNtXr8JLL6mJT9nS9OlQtapa100IIUTG2LsXTpxQiWg2S0Y1DcaPV/O0TMloq1awc2csBQpE6RtcBmvTBiZMgM6d1QJb1sashLR///4sWbKEpUuX4u7uTkhICCEhIUQ+tm6lv78/PXv2TNiePHkya9eu5dy5c5w+fRp/f39WrVrFgAEDMu63EKmqVEmVhapVS22Hh0Pr1tm0dGenTrBokdTjEEKIjPTNN/Dpp3pHkeGMRrXg34gRifvefRfWrwd396SPXbhQ5eLp+ezMiOfIzsy6ZT9z5kwAGjVqlGT/ggUL6N27NwDBwcFcuXIl4WcxMTEMGTKE69ev4+rqSuXKldm4cSNt2rRJX+QizYoUUcubdeum/tBiY9WtiYsXYdSobHTBW6hQ4hpumpaNfjEhhNDR6tWqyHU2Eh4Ob7wB27Yl7pswQeXdBoNKVkXWMishTcv8p4VPpP5Dhw5l6NChZgUlMl6uXOo95aOPYNo0te/LL1VSOncuODnpG1+GGjRIZd0//KB3JEIIYbuMRggNhWLFoHBhvaPJMNeuQdu2cPKk2nZygp9+gv8KXwidmHXLXtg2e3uYOhW+/z6x83DxYmjZEu7d0ze2DFWlClSrpncUQghh2xYuhOeeU0lpNnHiBNSunZiM5sun5lVIMqo/SUhzoEGD4NdfwVT6MDBQTXbKNivB9emjBgYJIYSwXOfOqtfC01PvSDLE1q1Qvz7cuKG2S5eGAwfUvvR4/fXE+V6pfR06lP74s7vsUVxLmO2111Qi2q4d3LoFZ85AnTrw22+JE6Bs2qNHajWRbt3UzHshhBBpFx8PHh7QsaPekWSIH3+E999PXFyqdm01pyIjcu1KlSB37uT7L16E3bvVjPYqVdTnrJ4ePoTz59X3MTEQEqJ6jJ2c1O+gN0lIc7DatdUM/DZt4OxZtVxaw4awfLlKVG2aoyNs2qSSUUlIhRAi7e7cUT0UP/4IT0xitjXx8WoN+gkTEve9+iosWZLulaYTfPll8n3//quazskJVq1S8zj0FhQEj6/aPnu2+ipRwjrukMot+xyudGnYvz/xlsWjR9ChQzaYD+ToCMeOqR5SIYQQaRcfD82bW0e3WTpER6si8I8nox99BL/8knHJaEpMyWhoqJpM3LZt5r2WORo1UgVonvyyhmQUpIdUAPnzQ0CAKgW1bJl6Lxo4EC5cgIkTwc5WL1vs7dV9ifXr1W0nKQMlhBDPVqgQzJihdxTpcveu6lzZs0dt29nB5Mnqsy0zXbigeiFDQ1XPaHqS0ddfhz//NO+YRYvgxRctf009SUIqADXGZckStQLn+PFq3/ffw+XLakx7Zl5NZqodO9TA/BMn5Na9EEI8y+jR4OsLL7+sdyQWu3AhcSgagKurGor2yiuZ/7qNGqnhb6tWpb8JL11K/B3S6tGj9L2mniQhFQns7GDcOJWU9u2rBn+vXg3Xr2fc4O8s17Kl+osuW1bvSIQQwrrFxamBhvnz6x2JxQ4dSpysC6p86oYN8MILmfu6Fy+qntGMSkZB/VfkJLZ6M1Zkoj59YOPGxFmDhw6Bn5/5V2pWwWBQyaimwWMriAkhhHiCvb3K3mx0ae81a1RSaEpGK1ZUE3ezIhlt1EjNWs+oZDSjPass1eNfepGEVKSoZUvYu1ct0AHqVoSfX+J4HJvz2Weq2Gp0tN6RCCGE9fnjD9i3T31vg+PtJ09WUwUiI9V2w4bq1ylZMnNf99IllQSHhKj63taYjELKk5lS+9KLJKQiVdWrq6tL06JH9+5Bs2ZqLI7NefttteqIs7PekQghhPWZMQP69dM3I7FAXBx8+KGaPW8K/c03VRH8fPky97UvXVI9o8HBKhm1+XKJOpMxpOKpihdXvaKdOqk/8JgY6NpV/SF++qkNXUiXLq2+QJURsNnSAUIIkQlmzlTdfDbzpg4REdC9O6xbl7hv5EhVFzQrfo1evdTE3/Ll1a36VauSP+bNN1VHjjVYsEDNwv/zT4iKgnLlYPBg1YbWQBJS8UweHmpYUb9+MHeu2ufvr27jT5+uSn7ajN691YD9SZP0jkQIIfQXG6t6GMqWhaJF9Y4mzW7eVD2SR46obQcHVeT97bez5vXj4+HoUfX92bOpz7Ho2jVr4kmL339XlQa++Ub1Hq9ZAz16qLbr3Fnv6CQhFWnk6Ahz5qhOxuHD1b4ff1TzhH75Bdzd9Y0vzerUgTx59I5CCCGsw+LFqqzKxYs2k5CeOaPKOpkKuru7q97J5s2zLgY7O7UUpy1ZsiTp9iefwM6dsHKlJKTCxhgMqme0ZEnV0RgTo27j168Pv/2mbu9bvb599Y5ACCGsR5cuULCgzSSju3apgvf376vt4sUTV4kW5rt/H7y99Y5CkYF0wmxdu8L27YkDxv/4Q3U8njypb1xp9vChKmtiut8ihBA5UUyMqhpvI7Nxfv5Z9YKaktEaNVRZQklGLfPTT6rW6Xvv6R2JIgmpsEj9+nDggCqiD6p4fr16qsfU6rm4wPHjahCsEELkRNeugY+P6nK0cpoGY8eqCUJGo9rXujXs3m0zHbtWZ906lYjOng3PP693NIokpMJi5curslC1a6vtBw/Uur2miU9Wy8FBFVl94w29IxFCCH3kygVvvQU1a+odyVMZjWqxls8+S9z33ntq9UCbmbtgZZYvV2NGZ81Sp4C1kIRUpIunp1ou/tVX1XZcHLz7LowYYeXl7AwGVUF52rTES24hhMgp8uWDCRNUGRUrFR6uOjnmz0/c9/XXqkKVQxbPgKlRA774Qv2r53Ok148/qjkgCxeqf62JTGoS6ebmpmbaf/IJfP+92jd+vJoBOX++Fdei/+cfGDpU9RDUq6d3NEIIkfk0TRXQ7NgR2rfXO5pUXb2qktFTp9S2k5OqoanXbPAaNdKfSGbEc6THpEnqI2/69MSlTkGtGFuokH5xmUgPqcgQ9vbqZJ86NbHm/NKlagD63bv6xpaq6tXVu54ko0KInCIqSi2hbMWLg5w4oSbKmpLR/PlVDU1rKE1ky6ZOVXcx+/YFL6/Erxde0DsyxXrPSGGTBg5UxXZdXdX2nj1Qt64Vzx8qWFD9hR46pHckQgiR+VxdYcUKq51Zv3mzmjR744baLl1aTaCVfoP0u3Qp5bXrTfVc9SYJqchwr7yiJm4WLqy2z55VV7tWm/PNnaveAU33L4QQIhsyrF4N27bpHUaq5sxRebKp4HydOmribLly+sYlsoZZCemECRN44YUXcHd3x9PTkw4dOnA2tfWyHrNr1y58fX1xcXGhdOnSzJo1y+KAhW144QX1RlKxotq+dQsaN1a9p1anZ0/VlVukiN6RCCFEprFbvlwV87Qy8fFq0ZX33lM3rEANcd2xwzrGNoqsYVZCumvXLvr378/BgwcJCAggNjaWFi1aEBERkeoxFy9epE2bNtSvX5/jx48zfPhwPvjgA1atWpXu4IV1K1kS9u1Tg6dBTWrv2BEmT9YxqJS4uqraVZoG9+7pHY0QQmSKuBUr1BR1KxIVBd27w1dfJe4bPFgtZ2ka+iVyBrNm2W/ZsiXJ9oIFC/D09OTo0aM0aNAgxWNmzZqFj48Pk//LQipWrEhQUBATJ06kY8eOlkUtbEa+fLBli6ojt2SJyvk++kgtmzxpkpoMZTU+/RSHLVtg1Ci9IxFCiIxz/jweFy+qcndubnpHk+DOHbUM6N69atvODqZMUQvpiZwnXWWfwsLCAMifP3+qjzlw4AAtWrRIsq9ly5bMmzcPo9GIo6NjsmOio6OJjo5O2A4PDwfAaDRilJqRaWJqJ2toLzs7mDcPfHzsGD9eZaBTp8KFC/EsXhxHrlw6B2jy+uvE+/qCnZ1VtJutsKZzzVY83lbyvpZ2cq5Z6LvveGHzZozvvKN3JAn+/RdeecWBc+cMALi5aSxZEsfLL2tWURpazjXLpKe9DJpmWflyTdNo37499+7dY8+ePak+rly5cvTu3Zvhw4cn7Nu/fz8vvfQSN27cwMvLK9kxo0aNYvTo0cn2L126FDcruroT5vv9dx9mzKhOXJwaLfLcc/cYMeIQefNGP+PILKZpqjdBiEwQFRVFly5dAFi+fDkuLi46RySyM0NsLG63bhGRwuetHs6ezcf48bUJC1NFqvPmjWLkyEOULXtf38BEuj169Ihu3boRFhaGh5mLLljcQzpgwABOnjzJXlNf+1MYnvhgN+XAT+438ff3Z/DgwQnb4eHheHt707hxYwoUKGBpyDmK0WgkICCA5s2bp9gLrZc2baBNm3g6dzYQHm7g3Ll8jBrVknXrYhMmQOnJaDRys2NHileurFYxEc9kreeaNXt83H2TJk3ImzevfsHYEDnXzBQTAyEhGL28rKbd1qwx8MUX9kRFqc//ChU01q+3p2TJurrG9SQ51yxz584di4+1KCEdOHAg69evZ/fu3RQvXvypjy1SpAghT5TTCQ0NxcHBIdXk0tnZGecUlvdxdHSUE8NM1thmrVqpMUNt26q69JcuGWjY0JE1axInQOnpYbFiGMqVw8HK2s3aWeO5Zq0ebydpN/NJm6XRrFkwfDicPw/o226apia0fvxx4rLSjRrB6tUG8uWz3v9LOdfMk562MmuWvaZpDBgwgNWrV7Njxw5KlSr1zGP8/PwICAhIsm/btm3UqlVL/pNzsKpVVVmomjXV9v370KKFmviktwvt2qG99ZbeYQghRPr07q3KPD1lnkdWiIuDDz9Us+dNyWiPHrB1q5r4KgSYmZD279+fJUuWsHTpUtzd3QkJCSEkJITIyMiEx/j7+9OzZ8+E7b59+3L58mUGDx7MmTNnmD9/PvPmzWPIkCEZ91sIm1S0KOzerW7jAxiN6k1qzJjENy3dxMaqwni//aZzIEIIYYGoKHB3VyuV6CgiAl57DaZNS9z3+efw009qfXohTMxKSGfOnElYWBiNGjXCy8sr4WvFihUJjwkODubKlSsJ26VKlWLTpk0EBgZSo0YNxowZw9SpU6XkkwAgd25Yt06trWvy+eeqTJSukxvt7eHvv9WYAiGEsCXHjkGJEvDnn7qGERKibsuvX6+2HRxg/nwYPVrmjIrkzBpDmpYJ+QsXLky2r2HDhhw7dsyclxI5iIMDzJih1iweOlTtmz8frlyBX3+FPHl0CMpggNWr5V1TCGF7ihaFd96BChV0C+HMGWjdGi5fVtseHrBqFTRrpltIwsrJWvbCKhgM8MknsGIFmOazbd8O9erp2ElpMKhu2ilTEt9VhRDC2hUpAuPHq6t9HezcCXXrJr5tenuriaySjIqnkYRUWJVOneD338FUgOHPP9WqnseP6xRQVBRMnKiyYyGEsGb374OfHxw5olsIS5ZAy5YqFFATVw8eVBNZhXgaSUiF1XnpJThwAMqWVdvBwVC/PmzapEMw7u7q3pMVrXAihBApevhQ9Y4WLZrlL61pakJqjx6J4//btFETV3UIR9ggSUiFVXruOZWU+vmp7YgINVl09mwdgsmdW73brl+v80wrIYR4iuLFYc0aKFYsS1/WaFTX7J9/nrjvvffUhNXcubM0FGHDJCEVVqtgQXX7/o031HZcnJqN/+mnEB+fxcGcPQuvvgqbN2fxCwshxDPEx6s3Rx0mD4eFqZ7QBQsS9339NcycqdsQVmGjJCEVVs3VFZYvVxOeTL75Brp2VcM7s0yFCnDqlO41/YQQIpnbt+HwYQgPz9KXvXpVTTw1DbF3dlYTU4cOlQIlwnySkAqrZ2enktDp09X3ACtXqhmbt29nYSCVKql/T53KwhcVQohn8PSEoKAsXXv5+HE14dRU6jR/fpWYduqUZSGIbEYSUmEz+vVTwzhz5VLb+/ap0iL/LdOcNfbuhWrV1IsLIYTeZs2Cc+cSr9azwObN0KCBmnAKUKaMmklfr16WhSCyIUlIhU1p21bN2ixSRG2fOwd16sD+/VkUwEsvqeVE69bNohcUQohUPHoE334LGzdm2UvOng3t2qkJ/aAmnh44oCaiCpEekpAKm/P883DoEFSurLbv3IEmTdSqTpnOYFBZscGQxeMFhBDiCW5uagjRgAGZ/lLx8TBsmJo7FRen9nXsqCaeFiqU6S8vcgBJSIVN8vFRd82bNlXb0dFqNv7EiapCU6bbulUF8c8/WfBiQgjxhIAACA1VSWkmT2ePioJu3dTseZMhQ9RYflfXTH1pkYNIQipsVp48qlh+796J+z75RHUWxMZm8os3bKhmWpUsmckvJIQQT4iNVYU+x43L9Je6c0dNIF2xQm3b2akJpt9+m6XDVkUOIFXChE1zcoL586F06cSizDNmqDWUly/PxKLMLi6Jt8mMRnB0zKQXEkKIJzg4qHFLmfy+8++/0Lq1GqsPqjN2xQp4+eVMfVmRQ8n1jbB5BgN89hksWpT4/rxxo+rENM0CzTQbNkD58nDvXia/kBBCACdPqhlFhQpB3ryZ9jIHDqgJo6ZktEgRNaFUklGRWSQhFdlGjx6wZYu6lQ9q0ZI6deD06Ux8UV9feP116SEVQmS++HhV6HPgwEx9mVWr1ERR07zNSpVUWSdf30x9WZHDSUIqspUmTVQJqBIl1PaVK6pC0++/Z9ILFi2qxpKa1rsXQojMYmenBs6PHp0pT69pMGmSmiBqWgmvcWM1gdT0nipEZpGEVGQ7T17Nh4dDq1bw00+Z+KJbt6pK0Vm6nqkQIse4fl2NVy9dWlX4yGBxcarj9eOPE6+te/ZUd50ycWSAEAkkIRXZUpEisGuXKuAMalJq794walQmdWR6e6suBElIhRAZTdPg1Vfhrbcy5ekjItTTT5+euO+LL2DhQjVxVIisILPsRbaVKxesWQODBsEPP6h9o0fDxYvw448Z/EZbqRIsWZKBTyiEEP8xGNQSoZlQZykkRE1UOnpUbTs4qPfHx8vpCZEVpIdUZGv29jB1qhoXZTCofYsWqVv49+9nwgvu2aMmHZiWMhFCiPQID1c9pM8/DzVqZOhTnz6tJn6aklEPD3WLXpJRoQdJSEW2ZzDARx+ppUVdXNS+nTvVsvSXLmXwizk4qBJQmZLtCiFyFE1TVTzefjvDn9r0Hnj5str29k66+p0QWU0SUpFjvPaaehMuWFBt//WX6h0ICsrAF/HzU0v6FSiQgU8qhMiRDAa1/FzPnhn6tIsWQcuWEBamtp9/Xk0ErVIlQ19GCLOYnZDu3r2bdu3aUbRoUQwGA2vXrn3q4wMDAzEYDMm+/v77b0tjFsJideqoN95y5dT2zZuqgP6GDRn8QidOqMGrUgpKCGGJ6Gj1b/PmqvZSBtA0+PJL6NVLTdgHaNNGTQAtWjRDXkIIi5mdkEZERFC9enV+MM0SSaOzZ88SHByc8PXcc8+Z+9JCZIgyZVSt0nr11PajR9ChQ9IZpukWHKy6Y+/cycAnFULkCJoGHTuqsUYZxGg08O679nzxReK+vn1h3bpMXGJZCDOYPcu+devWtG7d2uwX8vT0JK8UMxNWokABdWf9rbfUmvfx8Wpp+n//taN+/Qx4gdatoUULNatKCCHM1bUr5MuXIU8VFgZjx9bhjz8S+6C++QaGDEmc7CmE3rJsDGnNmjXx8vKiadOm7Ny5M6teVohUubjAzz+Dv3/ivu+/t+fbb18gMjIDXsDeXtWYyrTip0KIbCc+XmWJ3bur++npdOUKNGzowB9/eALg7AwrV6qhqZKMCmuS6XVIvby8mDNnDr6+vkRHR7N48WKaNm1KYGAgDRo0SPGY6Ohook3jZ4Dw8HAAjEYjRtPAF/FUpnaS9nq20aPB29vAwIH2xMUZOHCgKM2bx7FmjZFChdL33IZjx7BfsIDYd95R1fqzITnXzPd4W8n7Wtpl+3NN07Dv0gWtalXiR45M99MdPw4dOjgQHKwyzwIFNFatiqNuXY3s2oQZJdufa5kkPe1l0DTLu24MBgNr1qyhQ4cOZh3Xrl07DAYD69evT/Hno0aNYnQKa/UuXboUNzc3S0IV4pmOHfPkm29eICpKXacVLhzB558foFixiHQ9r11MDPGy3Il4TFRUFF26dAFg+fLluJjqkYmcTdMos349jwoXJrhOnXQ9VVCQJxMnJr6feXk95LPPDlK0aPrez4R4mkePHtGtWzfCwsLw8PAw61hdEtJx48axZMkSzpw5k+LPU+oh9fb2Jjg4mAJSTidNjEYjAQEBNG/eHEdHR73DsRlHj8by8stw544rAPnzqx6Fl15K5y3327exW7CA+Gw4aEvONfNFRESQ77/xgaGhoTK+Po2y9bmmaRn23jBnjh0ffGBHfLx6vtq14+jffxsdOzbMfu2WSbL1uZaJ7ty5g5eXl0UJqS5Lhx4/fhwvL69Uf+7s7Iyzs3Oy/Y6OjnJimEnazDy+vvD11zuYMqUFp04ZuHvXQMuWDixaBJ07p+OJjx+H777DvksXKF06w+K1JnKupd3j7STtZr5s12aapmqN1q6tZldaKD4ehg2Db79N3PfGGzB3bjw7d8Zkv3bLAtJm5klPW5mdkD58+JDz588nbF+8eJETJ06QP39+fHx88Pf35/r16yxatAiAyZMnU7JkSSpXrkxMTAxLlixh1apVrFq1yuKghchMBQtGsXNnLN26ObJtG8TEQJcualWnoUMt7MRo00ZNcDLzilEIkQPEx4OXFxQubPFTREWpnPaXXxL3ffIJfPWVrGQsbIPZCWlQUBCNHyvSO3jwYAB69erFwoULCQ4O5sqVKwk/j4mJYciQIVy/fh1XV1cqV67Mxo0baZMBsweFyCweHvDbb9CvH8ydq/YNGwYXLqh6pQ6W3Fvw8FBFTxcsUE+czW7dCyEsZG+v6jBZ6PZtaN9e1VcGsLODadPU2wxIQipsg9kfq40aNeJpw04XLlyYZHvo0KEMHTrU7MCE0JujI8yZA6VKwYgRat+cOaqMysqV4O5uwZMePKi6LRo0gKpVMzReIYSNiY+HTp3ULZjXX7foKc6fVzdgzp1T27lywYoV0LZtBsYpRBaQteyFeAqDAYYPV/VKTRPlt2yB+vXh+nULnrBJE7h8WZJRIYRaHjRXLsiTx6LD9+9XyyGbktEiRdQyoJKMClskCakQadCtm1rZybRwyh9/qA+CkycteLJChSA2Vo0FiI3N0DiFEDbE1RV++kmtV2+mX39V17em1YkrV1Y3YHx9MzhGIbKIJKRCpFGDBqpHolQptX3tGtSrB9u2WfBkp05B//6wd2+GxiiEsAGxsdChA1iwaqGmwcSJava8qTpikybqraREiYwNU4isJAmpEGaoUEH1Qrz4otp+8ECN35o/38wnqllTzZBq1CijQxRCWLsHD1RSmiuXWYfFxqqqUJ98krivVy/YvBmklK2wdZKQCmEmT0/VsWFaDyIuDt55B0aONHPJ+mLF1AFLlsDDh5kRqhDCGuXLp8p4mK5s0+DhQ/WeM2NG4r5Ro1TRDlkITmQHkpAKYQE3NzWGa9CgxH3jxsGbbybeRkuTGzegb19YsyajQxRCWJuHD6FdO7MHnwcHQ8OGsHGj2nZwgIUL4YsvpHqcyD50WalJiOzA3h6+/16NKR00SHV2Ll2qxpauWQP586fhSYoVg7//huLFMztcIYTe7t2D8HBIYSXC1Jw+rYYFmcp758kDq1ercaNCZCfSQypEOn3wgUpAXV3V9u7d8NJLamGmNDEloxs2qB5TIUT25O2t6jKVL5+mh+/Yod5LTMmojw/s2yfJqMieJCEVIgO0b68+Zzw91fbff6uyUIcPp/EJHj2C996DefMyLUYhhE4uXYKWLdXtkzRatAhatYKwMLX9/PNqQmXlypkTohB6k4RUiAzywgvqA6NCBbUdGqom0a9dm4aD3dzg0CE1M0oIkb3cv6+myOfO/cyHahqMHq1mzxuNal/btuqC18src8MUQk+SkAqRgUqVUrVKGzZU25GR8NprMGVKGg729lYzFPbvh6CgTI1TCJGFatSA339/Zm2mmBh46y01e96kXz91UZuGXFYImyYJqRAZLF8+2LpVzbgH1eMxaBB8+KEqEfVUmgZDh8LkyZkcpRAi0wUGqvE8Dx4886H370Pr1mrhJpOJE+GHH9SseiGyOznNhcgEzs5qDFjJkjB2rNo3daqanPDzz+oOfYoMBjVDyrRGqRDCdsXEqCKhqf7BK5cvq9vyp0+rbWdnVZ749dezIEYhrIT0kAqRSQwGGDNGzVMy9XCsXavGld68+ZQDCxVSB/z9N6xcmQWRCiEylGmFjBYt4JdfVI24VBw9qiZAmpLRggXV7HpJRkVOIwmpEJns7bdh0yZwd1fbR46oD6AzZ55x4Jw5MGGCmgwhhLAdkyfD//73zKXbfvsNGjSAkBC1XbYsHDgAdetmfohCWBtJSIXIAs2bq/qBppKjly6pD51du55y0IQJsHevDCATwtbky6dqwD1lGaUZM9Tw0keP1PZLL6lktGzZLIpRCCsjCakQWaRqVVXZqUYNtX3/vkpUf/45lQOcnSFXLlUs/5tvntnbIoTQmWnWYu/eiYPHnxAfD598Av37q+8B3ngDtm9Xt+uFyKkkIRUiCxUtqlZyat1abRuNajb+uHFPyTf37lW3AE339YQQ1icuDl5+GSZNSvUhkZHQubOaPW8ydCgsXw4uLlkQoxBWTBJSIbKYuzusX68WZjIZORL69EkshJ1Ep05w9qxUxRbCmhkM6r57tWop/vjWLWjaFH79VW3b2cHMmfD11+p7IXI6+TMQQgcODokfRibz56vSL+HhKRzg7q5qGQ4cCHfuZFmcQog0iIpSWeXIkdCsWbIfnzunxowfOKC2c+WCDRugb98sjlMIKyYJqRA6MRjU7boVK9RwUYCAAKhXD65eTeGAe/dg48bE+jBCCP3duAHlyqlSGinYtw/8/OD8ebXt5aWG7bRpk4UxCmEDJCEVQmedOqkJDfnzq+1Tp1RZqBMnnnigj4+6dd+gQVaHKIRITf780L07vPhish+tXKlu05tualSpAgcPwvPPZ3GMQtgASUiFsAL16qkPqjJl1PaNG1C/Pmze/MQDHR1VXdKPPlIDUYUQ+rl1S81GmjAhyRR5TVOFMTp3huhota9ZMzU/0cdHp1iFsHJmJ6S7d++mXbt2FC1aFIPBwNq1a595zK5du/D19cXFxYXSpUsza9YsS2IVIlt77jk1xszPT20/fAjt2qn6+EnY26uM9anLPQkhMtWyZVC+PFy7lmR3bCz06weffpq4r3dvdUc/T56sDVEIW2J2QhoREUH16tX54Ycf0vT4ixcv0qZNG+rXr8/x48cZPnw4H3zwAatWrTI7WCGyu0KF4PffE5cNjItTs/GHDUusWYjBoOrEvPuu2pb6pEJkvdatVb0202oXqIvI9u3h8T6XL79UExYdHXWIUQgbYvYSMK1bt6a1qYhiGsyaNQsfHx8mT54MQMWKFQkKCmLixIl07NjR3JcXIttzdVUTnT79NLFe4ddfq9WdFi78r16haQWYadPUWqQ//fTUVWGEEBkkJETdpShUCN5/P2H3jRuqDOnx42rb0VElom++qVOcQtiYTF+T8MCBA7Ro0SLJvpYtWzJv3jyMRiOOKVw2RkdHE20aeAOE/1cHx2g0YkyxUKN4kqmdpL3MY03tNn48+PjYMWiQHfHxBlasgKtX41m1Ko4CBdRjDAULYvD0JD4mRrdihtbUZrbi8baS97W0s4Zzzf7dd+HuXeJ27ky4CPzzT2jf3oGrV9V2njwav/wSR6NGWsq1hbOYNbSbrZE2s0x62sugaZbf7zMYDKxZs4YOHTqk+phy5crRu3dvhg8fnrBv//79vPTSS9y4cQOvFIp9jxo1itGjRyfbv3TpUtzc3CwNVwibdORIYSZOrEV0tLp+LFr0IZ99dgAvr0dJHmcfHU2cqX6UsGpRUVF06dIFgOXLl+Miy/TYDJdbt3B+8ICw0qUB+OOPQnz99Qs8eqQ6VwoVesTnnx/E2/uBnmEKoYtHjx7RrVs3wsLC8PDwMOvYTO8hBZW4Ps6UAz+538Tf35/BgwcnbIeHh+Pt7U3jxo0pYOoaEk9lNBoJCAigefPmKfZCi5RZY7u1aQPt2ml06KAREmLgxo3cfPZZM1avjqNOnf/+lvbvx75TJ2K3bYNKlbI0PmtsM2sXERGR8H2TJk3ImzevfsHYED3PNcP27Wh168JjnSKLFhkYM8ae2Fj1WebrG8+aNY4UKVI/S2N7FvkbNZ+0mWXupGPhlkxPSIsUKULIE2twh4aG4uDgkGpy6ezsjHMKPT2Ojo5yYphJ2swy1tZutWurslBt26q6+LdvG2jRwoElS6BjR6BWLejTB8fnntNt9oS1tZk1e7ydpN3Ml+VtFhYGXbvCiBHwySdoGowapSYsmbRrB8uW2ZErl/VWU5RzzXzSZuZJT1tl+l+On58fAQEBSfZt27aNWrVqyX+yEGYoUULVMWzSRG1HRcEbb8CkSaC55VIzft3cVBmax8ZgCyHSKU8eVZNt0CBiYqBXr6TJ6IABsGaNWhJUCGEZsxPShw8fcuLECU78t4zMxYsXOXHiBFeuXAHU7faePXsmPL5v375cvnyZwYMHc+bMGebPn8+8efMYMmRIxvwGQuQgefOqYvm9eqltTYOPP1ZL3MfGohLRl16CL77QM0whsofbt1XR+7g4qFiRew8dadkSFi9WPzYY1AXh1Klq4r0QwnJmJ6RBQUHUrFmTmjVrAjB48GBq1qzJ559/DkBwcHBCcgpQqlQpNm3aRGBgIDVq1GDMmDFMnTpVSj4JYSEnJ1iwAB6f9zd9Orz6KkTEOqsiiB9/rF+AQmQXgYEq2wwJ4dIlda0XGKh+5OICv/6qFk2TimtCpJ/ZY0gbNWrE0ybmL1y4MNm+hg0bcuzYMXNfSgiRCoMBPv8cSpaEd95RvaO//QYNG8KGDa3xKgTcvw8nT0KDBjpHK4SNev11aNmSoLPuvPxy4uJoBQvChg1Qp46+4QmRnVjv6GshxDP17AlbtyYuSXj0qPqQPH0aNaa0e3c12FQIkXbjxsGMGQBsCHSnYcPEZLRcOTXBUJJRITKWJKRC2LgmTWDfPvDxUdtXrvx3a7HJl7Bz539LOwkh0kTT4M4duHuXH36ADh3g0X8lf+vVg/37oUwZXSMUIluShFSIbKByZdVr8/zzajssDFq0d2XR/rIQEwP+/mqChhAiddHRYDAQP3ESH98dwcCBEB+vftSlCwQEgJTCFiJzSEIqRDbh5QW7dqn1tAGMRjUb//thN9F+/hmCgvQNUAhrdvYsPPcc0Tv3q3Jq3yfOVBo2DH7+WW42CJGZJCEVIhvJnRvWroX+/RP3Df7em/81/IeYJq3UDstXCxYi+/L25lGb13l5aCVWr1a77O1h9mxV+clOPi2FyFRZsnSoECLr2NvDtGlQujQMGaLyz7lLXLhwA36rOx7XsBCYMkVq1QgBarxoRAT/RPnQOmASFy6o3blzw8qV0Lq1vuEJkVPINZ8Q2ZDBAIMHwy+/JN5m3LEDvplXgPuOhfQNTghrMmAAD5t1wK+OlpCMFi0Ke/ZIMipEVpKEVIhsrGNHlYgWLKi2RwW/R8Wln3H0mAGuX9c3OCGswLqGk2h8cT5376k7BlWrqgmCNWroG5cQOY0kpEJkc35+6gP2uefUdkgIDKx3nLhSZeD33/UNTgg9xMejfTuR70eH0+F9L4JiawDQvDns3Qve3vqGJ0ROJAmpEDlAmTJw4ICqTwpwMKo6/WKnMesvWcVJ5Dyx/1zg0Wfj2T5qT8K+d96BjRvBw0PHwITIwSQhFSKHKFAAtm+Hzp1Bw4452ru8/4Ej3771F/E7d+kdnhBZ4kG4RruPylI8+l820RaAsWPhxx/B0VHn4ITIwSQhFSIHcXGBpUtVXUWTYgvH8s8bw4l8JOWgRPYWNmw8AaX+x5YtGvfJh5MTLFkCI0ZI0Qkh9CZln4TIYezsVF3FUqWgXz94N+5HnO9EU6GZgXXroJBMwhfZ0MmTMH9OcXLfiwcM5M2ravY2bKhzYEIIIBsnpHFxcRiNRr3D0I3RaMTBwYGoqCji4uL0DsdmpNRu9vb2OGbDe3n/+5+avNGpUy7uPczF3wfu8leJ7pT4ZSIl21bWOzwhMsy+H/+i9ceVePCgJwAlS8KmTVCxor5xCSESZbuEVNM0QkJCCAsLQ8vBK9JomkaRIkW4evUqBrkXlWaptZuzszMFCxbEI5vNeGjdWtVbbNsWom/EExMZS49ucXy1KXEClBC27Df/fbT5qj7V2cVe6vPCC7BhAxQurHdkQojHZbuENCwsjPv371OoUCFy5cqVY5Ox+Ph4Hj58SO7cubGTNe/S7Ml20zQNo9FIWFgY1/+r25ndktIaNVRZqLZtC9LiVACEQ4smsayYeJWXB5bSOzwhLKJp8NlnMO6rurRnNXupR/v2agy1m5ve0QkhnpStElJN0wgNDcXDw4OCpkrgOVR8fDwxMTG4uLhIQmqGlNrN1dUVd3d3rl27xu3bt7NdQgrq1v3evfD66xAQAMNiRvP8B/P47v55Bo90kwkfwqZER8PCxj+x90AJoBHr6MAHH8CkSWppXSGE9clWmUpcXBxxcXHZMmEQ+jIYDOTJk4fo6OhsOzbZw0PVYXz7bfiej+jNQoZ87ka/fhAbq3d0QqTNvXvQqkU8JQ8spT3rMBhg8mSYMkWSUSGsWbbqIY3971PTwSFb/VrCSpgmNsXFxWXLSU6g6jDOnQulS+dn5MgWat+sqXx4qiFfba6Ou7vOAQrxFBcvQqeWYQSdy8MB1mHn4szqZdChg96RCSGeJVv1kJrk1HGjInPllPPKYFB1GZcsgdyO0fRkEbn2baVBA7hxQ+/ohEjZ4cMwq9oMfjlXnTzcx6OQCzsDDZKMCmEjpCtRCJGi7t2heHFnXmm/m+AwVzgBLWvdYenWAlStqnd0QiRatw66doX8ka/wiDiKlM/Lpk1QurTekQkh0ipb9pAKITJGw4bw+wE3SpY0UIsj7A8uyUd1DhAQoHdkQihTp2j83mEahsgIrlOckw0Gsn+/JKNC2BpJSIUQT1WxoioL5ehbnVGMYvcjX9q0gfnz9Y5M5GRxcTBoEEwedJGxjKAZ2+nWDbZtg/z59Y5OCGEuixLSGTNmUKpUKVxcXPD19WXPnj2pPjYwMBCDwZDs6++//7Y4aCFE1ipcGLbvduLf9h9jxImysWf4450pfPaZqvcoRFZ69Aje7PCQaVPiuEhpynKeqiPas3gxODvrHZ0QwhJmJ6QrVqxg0KBBjBgxguPHj1O/fn1at27NlStXnnrc2bNnCQ4OTvh67rnnLA5apM50ATB69OhMff5Ro0ZlyvOnVXx8PNWrV6dNmzYWHX/+/HkcHByYMWNGBkeWfbm5wapV8OGH0JrN9GEu3419RO/e9hiNcrNFZI37951o1Uzjo9+aMJ7h2NvD+B89GTsWpOSyELbL7D/fSZMm8c4779CnTx8qVqzI5MmT8fb2ZubMmU89ztPTkyJFiiR82UtBOJEOCxcu5OTJkxYnxmXLlqV79+6MGjWK8PDwjA0uG7O3VzUdS0wejB8HicSN28sCcOqzmHs3IvUOT2RzF7aeo8B7s/kzKJofGMA6t25s3Ah9+ugdmRAivcyaZR8TE8PRo0cZNmxYkv0tWrRg//79Tz22Zs2aREVFUalSJUaOHEnjxo1TfWx0dDTR0dEJ26aEwWg0PrUoudFoRNM04uPjiY+PT8uvlO2Yfm/tv/uopvbIjOfXq43j4uIYPXo0DRs2pFatWhbH8fHHH7No0SKmTJnCiBEjgKe3W3x8fMJSojn9gqpfPyhWzJnhb15iQ3Q7nMOMnKhwhQfbf8HnxSJ6h2f1Hn8fe9b7mlBOTdtN2Y9fpTwPWEZX+hVdy+p1GtWrG5HmezrT+SXnWdpJm1kmPe1lVkJ6+/Zt4uLiKFy4cJL9hQsXJiQkJMVjvLy8mDNnDr6+vkRHR7N48WKaNm1KYGAgDRo0SPGYCRMmpHjLeefOnbg9ZRFiBwcHihQpwsOHD4mJiTHjN8s+Hj16BJDw+z948CBTnj86Olq3nsXNmzdz5coVhgwZkq4YfHx8qFKlCnPmzKF///5JllhNqd1iYmKIjIxk9+7dCYsw5GSOjvBZt78otyAWA/BX1CHu1K/L0kGjyNswZy/d+yxRUVEJ3+/YsQMXFxcdo7F+D6ce4+Ud46hGHADrHM4xYcgqrl934fp1nYOzIQFSHsNs0mbmMeUIlrCoDumTBcI1TUu1aHj58uUpX758wrafnx9Xr15l4sSJqSak/v7+DB48OGE7PDwcb29vGjduTIECBVKNKyoqiqtXr5I7d+4c+wZvStidnJz4448/GDduHAcOHMDOzo7GjRszadIkSpYsmfD4hQsX8s477zBv3jx69+6d5LkCAwNp2rQpn3/+OV988UWS53d2dubEiRN88cUXHD16FCcnJ1q2bMnXX39N8eLFk8W1e/duJk6cyMGDB3nw4AE+Pj506tQJf3//JBcZj79mixYtGD16NIcPHyYsLIy4OPVh9Msvv2AwGOjevXuKy8RWrVqVv/76K9U2mjBhAkOHDgWgS5cujBw5kiNHjtC8eXM0TePBgwe4u7snO6ejoqJwdXWlQYMGOfb8SqZNG+q2bYxL5zdwi7uGm3aNTt8P4LjTUl4Y87Le0VmtiIiIhO+bNGlC3rx59QvGisVGx7G/wQjaH58EwCVgv3sjihxdRqWSqX8WiKSMRiMBAQE0b948264yl9GkzSxz584di481KyEtWLAg9vb2yXpDQ0NDk/WaPk2dOnVYsmRJqj93dnbGOYWpko6Ojk89MeLi4jAYDNjZ2SXp7cpJTL/30aNH+e6772jYsCHvvfcex48fZ926dfz555/8+eefCQmV6fEptZlp29Smj+87dOgQX331FW3btuWDDz7g2LFjLF++nH379nHkyJEk58OsWbPo168f+fLlo127dhQqVIgjR44wfvx4AgMD2blzJ05OTkme/8CBA0yYMIHGjRvzv//9jytXrmBnZ4emaezatYsKFSqQP5XaLl27dk3WgxkdHc3kyZOJjo6mQYMGCa9Tt25dQCXCLVu2TLhN//jv/Hh7GAyGZ56HOY3PK76smzyBKv6TqfDwKK5EUefrjuz762vqrR2CwS5nrHBljsfPHzmfUnbv6kPO+Han6a31Cft2Vh3IvZGNeaFkAWkzC8i5Zj5pM/Okp63MSkidnJzw9fUlICCAV199NWF/QEAA7du3T/PzHD9+HC8vL3NeWphp06ZNCb2epsSqZ8+eLF68mLVr19KlS5d0Pf/WrVuZO3cu77zzTsK+L7/8ki+++ILhw4czb948AP766y8GDhxIjRo12L59e5Ik8quvvsLf359p06bx8ccfJ3n+gIAA5s2bx9tvv51k/5kzZ7h79y6tW7dONbaRI0cm2Y6KiqJDhw7ExMQwb968hCQUoFatWgDPHAMtns7R253iF3awv9Z71L2yHDs06m8Yyu6yf1IraDZu+aVHWaTdv1vOEdv+NerG/AlAHHbs7/YD9Rb2YdOmTTpHJ4TIDGbfsh88eDA9evSgVq1a+Pn5MWfOHK5cuULfvn0Bdbv9+vXrLFq0CIDJkydTsmRJKleuTExMDEuWLGHVqlWsWrUqY3+TZ6hVC1IZ5mo1ihSBoKCMea4GDRrw2muvJdn39ttvs3jxYo4cOZLuhLR8+fLJksVPPvmEH374gWXLljFz5kycnJyYPXs2sbGxTJ06NVmP5tChQ5k0aRLLli1LlpDWrFkz2fMDXLt2DSDNPfKPHj3ilVdeITAwkIULF9KjR48kP3d3d8fFxSXheYV5IiMjqV+/PmFhYRw9ehS/i0v5vXFFmu5WQzwaXFzE6eKnyb1lFSUalNA5WmELgkb9RvnRXXHnIQBhhjxc/vYXavWrh5+fH2FhYTRu3Fh6rYTIZsxOSDt37sydO3f48ssvCQ4OpkqVKmzatIkSJdSHTXBwcJKapDExMQwZMoTr16/j6upK5cqV2bhxo8X1Iy0VEkKOGvxes2bNZPtMYzvv37+f7ud/6aWXko2xdHV1xdfXly1btvDPP/9QpUoVDh48CMCWLVvYvn17sudxdHRMcZGEF198McXXNY1PyZcv3zNjjIiI4OWXX2bPnj0sXryYrl27pvi4/Pnzc/v27Wc+n0guPj6eo0ePJnxvsDPQdNfnHPy4AtUn9cKVKCpHHuVeo5oc/nI5L45soXPEwlrFGePZ2+JLGgYmTmi95Fweh43rqNa0PBEREUnONSFE9mLRpKZ+/frRr1+/FH+2cOHCJNtDhw5NmECipyI2UIkmI2PMkydPsn0ODuq/2zQ5KD08PT1T3G/quQwLCwPg7t27AIwbN86s50+tB9TV1RVQPXNP8+DBA9q0acPBgwdZvnw5r7/+eqqPjYyMfGr1BmG+Ot914kL9Cth3eo0Sxn/Jp92j1met2LFzDI22+mPnkDPHeIuUhf59l0svdafh3S0J+/YXfZ1qQfPJ7eWuY2RCiKxiUUJqizLqVnh2YxpfmlIZI1NSmZLQ0NAU99+8eRNITIhNs+DDw8Nxd0/7B0tqVRsKFSoEJCa6KQkPD6dVq1YEBQXxyy+/0KFDh1QfGx8fT1hYGJUrV05zbCJtSneoRvj5IIJqv0mtkI3YodFkx0iOFN1PqV0LKVixkN4hCitwbNo+Cg/qyovxVwE1XjSw5QQab/wEO3uZECdETiHdFDmc6db39RTGMxw/fjzV4/bt25dQRN4kMjKSo0eP4urqSrly5QCoXbs2QMKt+/SqXLkydnZ2nDt3LsWf379/n+bNm3Ps2DFWr1791GQU4Ny5c8THx1O1atUMiU8k5eGTF99r69ndYizxqOTihVub0KpUIeibHTpHJ/QUZ4xnR7PxVP+gAcX+S0bvGgpweuIWmm4ZKsmoEDmMJKQ53PPPP4/BYGD58uVJinWfO3eOKVOmpHrc2bNnmT9/fpJ93377Lbdu3aJr164JZZz69euHg4MDAwcO5OrVq8me5/79+09NfJ+UN29eqlWrRlBQULKE+O7duzRt2pSTJ0+yZs0aXn752XUwDx06BEDDhg3THIMwj8HejgZbR3BiwhbuGtTEtkLxoTz/aTN+rz2c6IeyEkpOE3oyhBNFWtLk9xHYo8aDnszbgPhjJ6j2cXOdoxNC6CHH3LIXKStWrBidO3dm+fLl+Pr60qpVK0JDQ1mzZg2tWrVKtRpCixYt6NevHxs3bqRChQocO3aMrVu34u3tzfjx4xMeV6VKFWbMmMH7779P+fLladOmDWXKlCE8PJwLFy6wa9cuevfuzaxZs9Icc4cOHRg1ahRHjhxJMvmpa9euHDt2jMaNG3Po0KGEZNOkaNGi/O9//0uyLyAgAHt7+zQlryJ9nh/WgtA2pznapCe+dwKwQ6Pp4Qn86bkd17XLKNOijN4hiiywb8gaKk3qg6+mht3EY2Bvo894actn2DvLR5IQOZX89QvmzZtHoUKFWLlyJdOnT6d8+fLMmTOHokWLppqQ+vn5MWLECEaOHMmUKVNwcnKiS5cufPPNN8kmJL377rvUqFGDSZMmsXv3btavX0+ePHnw8fHho48+olevXmbF26dPH8aMGcOSJUsSEtL4+Hj27t0LqCVmd+7cmey4N954I0lC+ujRI9auXUu7du0oWrSoWTGIRAULFkzzUr2e1YpQMGQLe16diN9vw3EgjiqRR4hoWY09Xb6l3pK+GOzlxk12dO9SGKcaf0CDS4sS9oXYeRH87c80GNw4Tc9hzrkmhLAxmg0ICwvTAO327dtPfVxkZKT2119/aZGRkVkUmfWKi4vT7t27p8XFxekdSqbo2rWrVqBAAe3hw4cWP8e8efM0QNu1a1fCvqe1m5xfKYuJidHWrl2rxcTEmHXc2UUHtcuOpTUNEr6O5WusXdl7OZMitR4PHz7UAA3Q7t27p3c4me7guO1asF3RJP/Xh73aabf/umnW81h6ruV00m7mkzazzO3btzVACwsLM/tY6YoQNmncuHE8fPiQ6dOnW3R8bGws48eP55VXXqFBgwYZHJ1Ii3I9alPw2h/srtQ3YV/NezvxqFeV7V3nERerPeVoYQvCr4axs1I/ao9oRpH4G2ofHhx4byG1rq2jQMWUy8cJIXIeSUiFTSpVqhQ//fQTuXLlsuj4a9eu8eabbzJp0qQMjkyYw80zNw1Oz+TwmK0E2xcDIA/hNFvehz/z1efchuSLJgjrp8VrHBiyiuiS5Wl8ZmbC/j/yNyby8Cn8ZvXCYCez6IUQiWQMqbBZnTt3tvjYkiVLMmrUqIwLJoeKjIykVatW3LlzJ13LOb44sgXhPf/kQMuP8Pt7IQDVH+4j5pVq7GroT511/jjnccnAyEVmubTnKsEdB+B3a33Cvofk4mSXCfgt6W/xGOGMOteEENZJekiFEBaLj49n9+7dnD59Ot3LOXr45MXvzAJOTdzCNYeSADhhpOGuLwktWImDX25Dk7v4VisqLJrtzb+mUIMKSZLRIwVbc3fPX9RdNjBdE9Yy8lwTQlgfSUiFEFal6sctKXjzNIF+/hj/u4njHXuROl+05JBnO85t/EfnCMXjtHiNo6PWc7NQZZptH0YuHgEQaleYQx+vpNbNjfjU89E5SiGEtZOEVAhhdVzyu9Fo/3gu/HqcP939EvbXuf0bpV6uxM6ag7l38b5+AQoATv/yF8cLNsd3dHtKGP8F1NKf+6v3xe3SGWpPfEPGigoh0kQSUiGE1SrfsQqV7+3l8MDFhNirWrEOxNH4xPfElynLrvaTiLwbqXOUOc/lvVcILP02FTpV5fl7vyfsP+7RkAu/HKPuiZnk9s6nY4RCCFuTLRNSTQaaiUwg55U+DPZ2vDj1TfKE/MPuRp8TiZrcVEC7Q8P1H3Ov0HPs6DKbqAeyBGlmu/1XKIE1B1G0fhkaXVyQsOxniH1R9n6wkup3d/Lc69V1jlIIYYuyVULq4KDGm8XGxuociciOjEaV8Njb2+scSc7kWjAXDXaOJuzQWfaV7E486lZw0fjrNFnRlzt5y7Cj50KiH0pimtFC/rjJ7y8Ow7lyGRqdmIIj6j32viEv+16eQL5b56g35Q3s7OX2vBDCMtkqIbW3t8fe3p7w8HC9QxHZjKZphIWF4ezsLOVmnuDm5oazs3OWvV6RF3146eISzv/6B4e92ifsLxZ/lSaL3+JW3rLseWMqEaERWRZTdnUx8DI7Kg8gT42SND3yNe48BOARruyuOwy7ixd4acMwnPO5ZUk8WX2uCSGyTraqQ2owGPD09CQ4OBhnZ2dy5cqFwZAzr9jj4+OJiYkhKioKO7tsdd2RqZ5sN03TMBqNhIWF8fDhQ4oVK6Z3iFYlV65c3L9/n02bNlm8SIGlynWsCh3XcnbxYSIHD6fGbTWWsXjcFYr/+iH3V40ioO6HVPqhH8VqFMrS2Gzd30uPETr8e+peXkYp4hL2x+DIwcp9KL/kMxrU8MrSmPQ814QQmS9bJaQAefLkITIyktu3b3Pr1i29w9GNpmlERkbi6uqaY5NyS6TWbs7OzhQrVgwPDw8doxMpKd/jReixnb/n7iVsxNfUDv0NgLzaPZrvG0V0zfHs9XmdvCMHUKVPHZC/hxRFhsVwZNgq8v08jaoPDlDhsZ89JBfHXuhLhTmDaVCjqG4xCiGyr2yXkBoMBry8vPD09EwY85cTGY1Gdu/eTYMGDeQWsxlSajd7e3tpQxtQoU896FOPv1ac4p7/N9S+uAwH4nAmhnpXlsL/lnL2wxoEd3ifauM6k79UHr1DtgrnN5/jwhc/US1oHg20kCQ/Czd48Efjj6j240AalC6gU4RCiJwg2yWkJqbxpDmVvb09sbGxuLi4SDJlBmk380RFRfHaa68RGhpKkyZNrKLNKnWuCp0Xc+vIGP75cDpVDv5IHi0MgPKRJyi/7D0il33IvmKvYOjVk1rDW+CUS/+4s9Lt8/c5M2oF+dcvoPKDQ5R94uf/OFfhxmsDqT21O/ULWsftcWs814QQGSfbJqRCiMwXFxfH5s2bE763JoVeKEmh/d8Sde9L9nyykrzLZlD10WEAXInipesrYfxK7k3Ix/7K3cjdvQNVBzTEOXf2THRu/3OXUxM24PrbL9S8HUB9YpL8PBZ7jvl0wPWTgVTp14ByVlbQ3prPNSFE+klCKoTI1lzyuVJ/bi+Y24t/lh0l9JuFVPxjOQW02wDk0+7R6M/p4D+dh/65OFK8HbEvd6DSh83xrJBf5+gtp8VrnNv4DzcWbiPvjtVUub+HxiRP5M45VSK49dtUndCdFysW0SFSIYSwsOzTjBkzKFWqFC4uLvj6+rJnz56nPn7Xrl34+vri4uJC6dKlmTVrlkXBCiFEepTr6ku949PIE3GDY6PWc8j7daJILCOUmwjqXVtOo1ldKFixIP+4VWfXi59w4PPN3Lr4UMfI00DTuLr/KoHv/syu0r256Viccq9UoNHqD6hxPxCHx5LRO3aF2Ov7AaeXHKNs5J80WPsx+SQZFULoyOwe0hUrVjBo0CBmzJjBSy+9xOzZs2ndujV//fUXPj4+yR5/8eJF2rRpw7vvvsuSJUvYt28f/fr1o1ChQnTs2DFDfgkhhDCHg6sjz3/RDr5oR/j1Bxz/bgva2rVUvbQBd+0BAHZolIs8SbkjJ+HIROLHGPjHqRIhPi9iePEFCrSoRfHWVfHwdMny+DUNbvxxi8u/neJR4GFy/3mQsrf24x1/C+9Ujrnu4MP55ztRuO9rlO9Zm3r2Ug5OCGE9zE5IJ02axDvvvEOfPn0AmDx5Mlu3bmXmzJlMmDAh2eNnzZqFj48PkydPBqBixYoEBQUxceJESUiFELrzKOaO36Q3YNIbxEUZOf3jbu4t2UiRP7ZSNvqvhMfZoVEu5jTlzp+G8wtgKcRj4LJ9SW55lOWBdyUMFcqTq4I3bmWLkqeCFwUreeKSy7LJlcZHRkKO3eDW8Ws8OHON6PNXcbp8jvw3/6JY+BmKaXd4WlXcaJw4XbARD+s0o0jPFjzXsRrFrGxcqBBCmJiVkMbExHD06FGGDRuWZH+LFi3Yv39/isccOHCAFi1aJNnXsmVL5s2bh9FoNGumZEREBC4uWd8bYYuMRiNRUVFERETIbFQzSLuZJyIiIsn32aHNSr5dh5Jv1wHGcPHMba4s2UPs77vw/PcAPpFncPhv/XZFo2DcRQreuwj3AuBk0ueKwUAo+Yiyz02EUx6i7N0xOrjwwJDYO3mobEec4+1wjnlI7ui7uMU9wEWLwINw8gOpjWJ9ch2qCNw4n8eXh1XqkLdDQ8q9WYfy7onvl48iH6WjVfSXHc+1rCLva+aTNrPM43+n5jIrIb19+zZxcXEULlw4yf7ChQsTEhKS4jEhISEpPj42Npbbt2/j5ZV8tY/o6Giio6MTtsPCVMmWEiVKmBOuECILFS9eXO8QrJAG3IW4uxCZ8iNa3dmRQa/1CML2wL49sO9b+CSDntYKybkmhHXTNM3sYywaRPTkyj+apj11NaCUHp/SfpMJEyaQJ0+ehK+UxqYKIYQQQgjrc+fOHbOPMauHtGDBgtjb2yfrDQ0NDU3WC2pSpEiRFB/v4OBAgQIpr/zh7+/P4MGDE7bv379PiRIluHLlCnnyyOoqaREeHo63tzdXr16V5S7NIO1mPmkzy0i7mU/azDLSbuaTNrNMWFgYPj4+5M9vfsk8sxJSJycnfH19CQgI4NVXX03YHxAQQPv27VM8xs/Pjw0bNiTZt23bNmrVqpXquAxnZ2ecnZ2T7c+TJ4+cGGby8PCQNrOAtJv5pM0sI+1mPmkzy0i7mU/azDJ2dubfgDf7iMGDBzN37lzmz5/PmTNn+Oijj7hy5Qp9+/YFVO9mz549Ex7ft29fLl++zODBgzlz5gzz589n3rx5DBkyxOxghRBCCCFE9mN22afOnTtz584dvvzyS4KDg6lSpQqbNm1KmHAUHBzMlStXEh5fqlQpNm3axEcffcT06dMpWrQoU6dOlZJPQgghhBACsHDp0H79+tGvX78Uf7Zw4cJk+xo2bMixY8cseSlA3cL/4osvUryNL1ImbWYZaTfzSZtZRtrNfNJmlpF2M5+0mWXS024GzZK5+UIIIYQQQmQQWTtOCCGEEELoShJSIYQQQgihK0lIhRBCCCGEriQhFUIIIYQQurLZhDQ6OpoaNWpgMBg4ceKE3uFYvVdeeQUfHx9cXFzw8vKiR48e3LhxQ++wrNalS5d45513KFWqFK6urpQpU4YvvviCmJgYvUOzeuPGjaNu3bq4ubmRN29evcOxSjNmzKBUqVK4uLjg6+vLnj179A7Jqu3evZt27dpRtGhRDAYDa9eu1TskqzdhwgReeOEF3N3d8fT0pEOHDpw9e1bvsKzezJkzqVatWkJBfD8/PzZv3qx3WDZlwoQJGAwGBg0aZNZxNpuQDh06lKJFi+odhs1o3LgxK1eu5OzZs6xatYp///2X119/Xe+wrNbff/9NfHw8s2fP5vTp03z//ffMmjWL4cOH6x2a1YuJieGNN97g/fff1zsUq7RixQoGDRrEiBEjOH78OPXr16d169ZJ6jeLpCIiIqhevTo//PCD3qHYjF27dtG/f38OHjxIQEAAsbGxtGjRgoiICL1Ds2rFixfnq6++IigoiKCgIJo0aUL79u05ffq03qHZhCNHjjBnzhyqVatm/sGaDdq0aZNWoUIF7fTp0xqgHT9+XO+QbM66des0g8GgxcTE6B2Kzfjmm2+0UqVK6R2GzViwYIGWJ08evcOwOi+++KLWt2/fJPsqVKigDRs2TKeIbAugrVmzRu8wbE5oaKgGaLt27dI7FJuTL18+be7cuXqHYfUePHigPffcc1pAQIDWsGFD7cMPPzTreJvrIb158ybvvvsuixcvxs3NTe9wbNLdu3f5+eefqVu3Lo6OjnqHYzPCwsLInz+/3mEIGxYTE8PRo0dp0aJFkv0tWrRg//79OkUlcoKwsDAAeQ8zQ1xcHMuXLyciIgI/Pz+9w7F6/fv3p23btjRr1syi420qIdU0jd69e9O3b19q1aqldzg259NPPyVXrlwUKFCAK1eusG7dOr1Dshn//vsv06ZNo2/fvnqHImzY7du3iYuLo3Dhwkn2Fy5cmJCQEJ2iEtmdpmkMHjyYevXqUaVKFb3DsXqnTp0id+7cODs707dvX9asWUOlSpX0DsuqLV++nGPHjjFhwgSLn8MqEtJRo0ZhMBie+hUUFMS0adMIDw/H399f75CtQlrbzeSTTz7h+PHjbNu2DXt7e3r27ImWwxbqMrfNAG7cuEGrVq1444036NOnj06R68uSdhOpMxgMSbY1TUu2T4iMMmDAAE6ePMmyZcv0DsUmlC9fnhMnTnDw4EHef/99evXqxV9//aV3WFbr6tWrfPjhhyxZsgQXFxeLn8cqlg69ffs2t2/ffupjSpYsSZcuXdiwYUOSN+64uDjs7e3p3r07P/30U2aHalXS2m4pnSDXrl3D29ub/fv356hbEea22Y0bN2jcuDG1a9dm4cKF2NlZxTVclrPkXFu4cCGDBg3i/v37mRyd7YiJicHNzY1ffvmFV199NWH/hx9+yIkTJ9i1a5eO0dkGg8HAmjVr6NChg96h2ISBAweydu1adu/eTalSpfQOxyY1a9aMMmXKMHv2bL1DsUpr167l1Vdfxd7ePmFfXFwcBoMBOzs7oqOjk/wsNQ6ZGWRaFSxYkIIFCz7zcVOnTmXs2LEJ2zdu3KBly5asWLGC2rVrZ2aIVimt7ZYS03VIdHR0RoZk9cxps+vXr9O4cWN8fX1ZsGBBjk1GIX3nmkjk5OSEr68vAQEBSRLSgIAA2rdvr2NkIrvRNI2BAweyZs0aAgMDJRlNB03TctxnpTmaNm3KqVOnkux76623qFChAp9++mmaklGwkoQ0rXx8fJJs586dG4AyZcpQvHhxPUKyCYcPH+bw4cPUq1ePfPnyceHCBT7//HPKlCmTo3pHzXHjxg0aNWqEj48PEydO5NatWwk/K1KkiI6RWb8rV65w9+5drly5QlxcXEKd4LJlyyb8zeZkgwcPpkePHtSqVQs/Pz/mzJnDlStXZHzyUzx8+JDz588nbF+8eJETJ06QP3/+ZJ8LQunfvz9Lly5l3bp1uLu7J4xRzpMnD66urjpHZ72GDx9O69at8fb25sGDByxfvpzAwEC2bNmid2hWy93dPdnYZNN8FbPGLGfonP8sdvHiRSn7lAYnT57UGjdurOXPn19zdnbWSpYsqfXt21e7du2a3qFZrQULFmhAil/i6Xr16pViu+3cuVPv0KzG9OnTtRIlSmhOTk7a888/L6V4nmHnzp0pnlO9evXSOzSrldr714IFC/QOzaq9/fbbCX+bhQoV0po2bapt27ZN77BsjiVln6xiDKkQQgghhMi5cu6gOCGEEEIIYRUkIRVCCCGEELqShFQIIYQQQuhKElIhhBBCCKErSUiFEEIIIYSuJCEVQgghhBC6koRUCCGEEELoShJSIYQQQgihK0lIhRBCCCGEriQhFUIIIYQQupKEVAghstD48eMxGAzJviZNmqR3aEIIoRtZy14IIbLQgwcPiIiISNj+8ssv2bRpE3v37qV48eI6RiaEEPpx0DsAIYTISdzd3XF3dwdg9OjRbNq0iV27dkkyKoTI0eSWvRBC6GD06NEsWLCAXbt2UaJECb3DEUIIXUlCKoQQWUySUSGESEoSUiGEyEKSjAohRHIyhlQIIbLI2LFj+eGHH/jtt99wdnYmJCQEgHz58uHs7KxzdEIIoR+ZZS+EEFlA0zTy5s1LeHh4sp8dPHiQ2rVr6xCVEEJYB0lIhRBCCCGErmQMqRBCCCGE0JUkpEIIIYQQQleSkAohhBBCCF1JQiqEEEIIIXQlCakQQgghhNCVJKRCCCGEEEJXkpAKIYQQQghdSUIqhBBCCCF0JQmpEEIIIYTQlSSkQgghhBBCV5KQCiGEEEIIXUlCKoQQQgghdPV/5WIvF6V5bCwAAAAASUVORK5CYII=\n", "text/plain": [ - "
" + "
" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -1763,7 +1772,7 @@ "\n", "input_shape = X_train.shape[1:]\n", "\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -1792,15 +1801,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 969us/step - loss: 0.3970 - mae: 0.7423 - val_loss: 0.3721 - val_mae: 0.6864\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.4858 - mae: 0.8357 - val_loss: 0.3479 - val_mae: 0.6527\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 702us/step - loss: 0.2330 - mae: 0.5302 - val_loss: 0.2730 - val_mae: 0.5552\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.2415 - mae: 0.5419 - val_loss: 0.2630 - val_mae: 0.5473\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 74, @@ -1831,6 +1840,13 @@ "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss/assets\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss/assets\n" + ] } ], "source": [ @@ -1857,15 +1873,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 981us/step - loss: 0.1904 - mae: 0.4699 - val_loss: 0.2363 - val_mae: 0.5045\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.2052 - mae: 0.4910 - val_loss: 0.2210 - val_mae: 0.4946\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 743us/step - loss: 0.1773 - mae: 0.4514 - val_loss: 0.2182 - val_mae: 0.4884\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.1888 - mae: 0.4683 - val_loss: 0.2021 - val_mae: 0.4773\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 77, @@ -1915,15 +1931,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 996us/step - loss: 0.1950 - mae: 0.4469 - val_loss: 0.2734 - val_mae: 0.4741\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.2051 - mae: 0.4598 - val_loss: 0.2249 - val_mae: 0.4582\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 744us/step - loss: 0.1909 - mae: 0.4434 - val_loss: 0.2507 - val_mae: 0.4685\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.1982 - mae: 0.4531 - val_loss: 0.2035 - val_mae: 0.4527\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 80, @@ -1947,6 +1963,13 @@ "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss_threshold_2/assets\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss_threshold_2/assets\n" + ] } ], "source": [ @@ -1973,15 +1996,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 996us/step - loss: 0.1880 - mae: 0.4395 - val_loss: 0.2452 - val_mae: 0.4571\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.1935 - mae: 0.4465 - val_loss: 0.2020 - val_mae: 0.4410\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 755us/step - loss: 0.1858 - mae: 0.4374 - val_loss: 0.2243 - val_mae: 0.4526\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.1899 - mae: 0.4422 - val_loss: 0.1867 - val_mae: 0.4399\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 83, @@ -2024,7 +2047,7 @@ "outputs": [], "source": [ "# extra code – creates another basic Keras model\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2051,15 +2074,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 985us/step - loss: 0.4997 - mae: 0.7514 - val_loss: 0.5202 - val_mae: 0.6936\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.6492 - mae: 0.8468 - val_loss: 0.5093 - val_mae: 0.6723\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 753us/step - loss: 0.2781 - mae: 0.5435 - val_loss: 0.3794 - val_mae: 0.5651\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.2912 - mae: 0.5552 - val_loss: 0.3715 - val_mae: 0.5683\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 87, @@ -2083,6 +2106,13 @@ "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss_class/assets\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_a_custom_loss_class/assets\n" + ] } ], "source": [ @@ -2109,15 +2139,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 981us/step - loss: 0.2206 - mae: 0.4783 - val_loss: 0.3241 - val_mae: 0.5093\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.2416 - mae: 0.5034 - val_loss: 0.2922 - val_mae: 0.5057\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 760us/step - loss: 0.2018 - mae: 0.4574 - val_loss: 0.2909 - val_mae: 0.4934\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.2173 - mae: 0.4774 - val_loss: 0.2503 - val_mae: 0.4843\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 90, @@ -2200,9 +2230,9 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 1ms/step - loss: 1.1668 - mae: 0.7430 - val_loss: inf - val_mae: inf\n", + "363/363 [==============================] - 1s 1ms/step - loss: 1.4714 - mae: 0.8316 - val_loss: inf - val_mae: inf\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 750us/step - loss: 0.7359 - mae: 0.5977 - val_loss: 2.6252 - val_mae: 0.5870\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.8094 - mae: 0.6172 - val_loss: 2.6153 - val_mae: 0.6058\n", "INFO:tensorflow:Assets written to: my_model_with_many_custom_parts/assets\n" ] }, @@ -2218,15 +2248,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 1ms/step - loss: 0.5646 - mae: 0.5293 - val_loss: 0.9063 - val_mae: 0.5070\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.6333 - mae: 0.5617 - val_loss: 1.1687 - val_mae: 0.5468\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 759us/step - loss: 0.4981 - mae: 0.4975 - val_loss: 0.7695 - val_mae: 0.4918\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.5570 - mae: 0.5303 - val_loss: 1.0440 - val_mae: 0.5250\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 94, @@ -2238,7 +2268,7 @@ "# extra code – show that building, training, saving, loading, and training again\n", "# works fine with a model containing many custom parts\n", "\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2291,20 +2321,33 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 992us/step - loss: 1.1668 - mae: 0.7430 - val_loss: inf - val_mae: inf\n", + "363/363 [==============================] - 1s 1ms/step - loss: 1.4714 - mae: 0.8316 - val_loss: inf - val_mae: inf\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 752us/step - loss: 0.7359 - mae: 0.5977 - val_loss: 2.6252 - val_mae: 0.5870\n", - "INFO:tensorflow:Assets written to: my_model_with_many_custom_parts/assets\n", + "363/363 [==============================] - 0s 998us/step - loss: 0.8094 - mae: 0.6172 - val_loss: 2.6153 - val_mae: 0.6058\n", + "INFO:tensorflow:Assets written to: my_model_with_many_custom_parts/assets\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_many_custom_parts/assets\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 980us/step - loss: 0.5646 - mae: 0.5293 - val_loss: 0.9063 - val_mae: 0.5070\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.6333 - mae: 0.5617 - val_loss: 1.1687 - val_mae: 0.5468\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 783us/step - loss: 0.4981 - mae: 0.4975 - val_loss: 0.7695 - val_mae: 0.4918\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.5570 - mae: 0.5303 - val_loss: 1.0440 - val_mae: 0.5250\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 96, @@ -2316,7 +2359,7 @@ "# extra code – again, show that everything works fine, this time using our\n", "# custom regularizer class\n", "\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2356,7 +2399,7 @@ "outputs": [], "source": [ "# extra code – once again, lets' create a basic Keras model\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2383,15 +2426,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 596us/step - loss: 1.3734 - huber_fn: 0.5275\n", + "363/363 [==============================] - 1s 844us/step - loss: 1.7474 - huber_fn: 0.6846\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 556us/step - loss: 0.7705 - huber_fn: 0.3166\n" + "363/363 [==============================] - 0s 796us/step - loss: 0.7843 - huber_fn: 0.3136\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 99, @@ -2676,7 +2719,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2704,15 +2747,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 587us/step - loss: 0.4997 - huber_metric_10: 0.4997\n", + "363/363 [==============================] - 1s 886us/step - loss: 0.6492 - huber_metric_1: 0.6492\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 574us/step - loss: 0.2781 - huber_metric_10: 0.2781\n" + "363/363 [==============================] - 0s 838us/step - loss: 0.2912 - huber_metric_1: 0.2912\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 113, @@ -2735,6 +2778,13 @@ "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_metric/assets\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_a_custom_metric/assets\n" + ] } ], "source": [ @@ -2766,15 +2816,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 625us/step - loss: 0.2206 - huber_metric_10: 0.2206\n", + "363/363 [==============================] - 1s 916us/step - loss: 0.2416 - huber_metric_1: 0.2416\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 609us/step - loss: 0.2018 - huber_metric_10: 0.2018\n" + "363/363 [==============================] - 0s 859us/step - loss: 0.2173 - huber_metric_1: 0.2173\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 116, @@ -2854,7 +2904,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", " input_shape=input_shape),\n", @@ -2884,9 +2934,9 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 645us/step - loss: 0.2505 - HuberMetric: 0.5049\n", + "363/363 [==============================] - 1s 898us/step - loss: 0.3272 - HuberMetric: 0.6594\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 635us/step - loss: 0.1416 - HuberMetric: 0.2854\n" + "363/363 [==============================] - 0s 892us/step - loss: 0.1449 - HuberMetric: 0.2919\n" ] } ], @@ -2905,7 +2955,7 @@ { "data": { "text/plain": [ - "(0.2505398094654083, 0.2505398573110885)" + "(0.3272010087966919, 0.3272010869771911)" ] }, "execution_count": 122, @@ -2929,6 +2979,13 @@ "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_metric_v2/assets\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: my_model_with_a_custom_metric_v2/assets\n" + ] } ], "source": [ @@ -2955,15 +3012,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 665us/step - loss: 0.2257 - HuberMetric: 0.2257\n", + "363/363 [==============================] - 1s 970us/step - loss: 0.2442 - HuberMetric: 0.2442\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 628us/step - loss: 0.2034 - HuberMetric: 0.2034\n" + "363/363 [==============================] - 0s 857us/step - loss: 0.2184 - HuberMetric: 0.2184\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 125, @@ -3051,22 +3108,22 @@ "output_type": "stream", "text": [ "Epoch 1/5\n", - "363/363 [==============================] - 0s 845us/step - loss: 1.0631 - val_loss: 0.4457\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.7784 - val_loss: 0.4393\n", "Epoch 2/5\n", - "363/363 [==============================] - 0s 591us/step - loss: 0.4562 - val_loss: 0.3798\n", + "363/363 [==============================] - 0s 891us/step - loss: 0.5702 - val_loss: 0.4094\n", "Epoch 3/5\n", - "363/363 [==============================] - 0s 585us/step - loss: 0.4029 - val_loss: 0.3548\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.4431 - val_loss: 0.3760\n", "Epoch 4/5\n", - "363/363 [==============================] - 0s 597us/step - loss: 0.3851 - val_loss: 0.3464\n", + "363/363 [==============================] - 0s 921us/step - loss: 0.4984 - val_loss: 0.3785\n", "Epoch 5/5\n", - "363/363 [==============================] - 0s 582us/step - loss: 0.3708 - val_loss: 0.3449\n", - "162/162 [==============================] - 0s 427us/step - loss: 0.3586\n" + "363/363 [==============================] - 0s 943us/step - loss: 0.3966 - val_loss: 0.3633\n", + "162/162 [==============================] - 0s 631us/step - loss: 0.3781\n" ] }, { "data": { "text/plain": [ - "0.3586341440677643" + "0.3781099021434784" ] }, "execution_count": 129, @@ -3075,7 +3132,7 @@ } ], "source": [ - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", input_shape=input_shape),\n", " tf.keras.layers.Dense(1),\n", @@ -3112,14 +3169,10 @@ " initializer=\"he_normal\")\n", " self.bias = self.add_weight(\n", " name=\"bias\", shape=[self.units], initializer=\"zeros\")\n", - " super().build(batch_input_shape) # must be at the end\n", "\n", " def call(self, X):\n", " return self.activation(X @ self.kernel + self.bias)\n", "\n", - " def compute_output_shape(self, batch_input_shape):\n", - " return tf.TensorShape(batch_input_shape.as_list()[:-1] + [self.units])\n", - "\n", " def get_config(self):\n", " base_config = super().get_config()\n", " return {**base_config, \"units\": self.units,\n", @@ -3136,17 +3189,24 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 836us/step - loss: 2.8036 - val_loss: 2.9430\n", + "363/363 [==============================] - 1s 1ms/step - loss: 3.1183 - val_loss: 6.9549\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 671us/step - loss: 0.7903 - val_loss: 1.3091\n", - "162/162 [==============================] - 0s 426us/step - loss: 0.6557\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.8702 - val_loss: 3.2627\n", + "162/162 [==============================] - 0s 718us/step - loss: 0.7039\n", + "INFO:tensorflow:Assets written to: my_model_with_a_custom_layer/assets\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ "INFO:tensorflow:Assets written to: my_model_with_a_custom_layer/assets\n" ] } ], "source": [ "# extra code – shows that a custom layer can be used normally\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " MyDense(30, activation=\"relu\", input_shape=input_shape),\n", " MyDense(1)\n", @@ -3168,15 +3228,15 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 892us/step - loss: 0.5665 - val_loss: 0.4506\n", + "363/363 [==============================] - 1s 1ms/step - loss: 0.5945 - val_loss: 0.5318\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 692us/step - loss: 0.4502 - val_loss: 0.5153\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.4712 - val_loss: 0.5751\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 132, @@ -3202,11 +3262,7 @@ " def call(self, X):\n", " X1, X2 = X\n", " print(\"X1.shape: \", X1.shape ,\" X2.shape: \", X2.shape) # extra code\n", - " return X1 + X2, X1 * X2, X1 / X2\n", - "\n", - " def compute_output_shape(self, batch_input_shape):\n", - " batch_input_shape1, batch_input_shape2 = batch_input_shape\n", - " return [batch_input_shape1, batch_input_shape1, batch_input_shape1]" + " return X1 + X2, X1 * X2, X1 / X2" ] }, { @@ -3231,9 +3287,9 @@ { "data": { "text/plain": [ - "(,\n", - " ,\n", - " )" + "(,\n", + " ,\n", + " )" ] }, "execution_count": 134, @@ -3317,10 +3373,7 @@ " noise = tf.random.normal(tf.shape(X), stddev=self.stddev)\n", " return X + noise\n", " else:\n", - " return X\n", - "\n", - " def compute_output_shape(self, batch_input_shape):\n", - " return batch_input_shape" + " return X" ] }, { @@ -3340,16 +3393,16 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 867us/step - loss: 2.1976 - val_loss: 26.5902\n", + "363/363 [==============================] - 1s 1ms/step - loss: 2.2220 - val_loss: 25.1506\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 671us/step - loss: 1.4224 - val_loss: 19.3606\n", - "162/162 [==============================] - 0s 423us/step - loss: 1.0180\n" + "363/363 [==============================] - 0s 1ms/step - loss: 1.4104 - val_loss: 17.0415\n", + "162/162 [==============================] - 0s 655us/step - loss: 1.1059\n" ] }, { "data": { "text/plain": [ - "1.0180009603500366" + "1.1058681011199951" ] }, "execution_count": 137, @@ -3359,7 +3412,7 @@ ], "source": [ "# extra code – tests MyGaussianNoise\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([\n", " MyGaussianNoise(stddev=1.0, input_shape=input_shape),\n", " tf.keras.layers.Dense(30, activation=\"relu\",\n", @@ -3432,23 +3485,10 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 810us/step - loss: 5.2455\n", + "363/363 [==============================] - 2s 1ms/step - loss: 32.7847\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 807us/step - loss: 0.8515\n", - "162/162 [==============================] - 0s 512us/step - loss: 0.6072\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:absl:Found untraced functions such as dense_19_layer_call_and_return_conditional_losses, dense_19_layer_call_fn, dense_20_layer_call_and_return_conditional_losses, dense_20_layer_call_fn, dense_21_layer_call_and_return_conditional_losses while saving (showing 5 of 20). These functions will not be directly callable after loading.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "363/363 [==============================] - 0s 1ms/step - loss: 1.3612\n", + "162/162 [==============================] - 0s 713us/step - loss: 1.1603\n", "INFO:tensorflow:Assets written to: my_custom_model/assets\n" ] }, @@ -3462,7 +3502,7 @@ ], "source": [ "# extra code – shows that the model can be used normally\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = ResidualRegressor(1)\n", "model.compile(loss=\"mse\", optimizer=\"nadam\")\n", "history = model.fit(X_train_scaled, y_train, epochs=2)\n", @@ -3480,17 +3520,18 @@ "output_type": "stream", "text": [ "Epoch 1/2\n", - "363/363 [==============================] - 1s 879us/step - loss: 0.7176\n", + "363/363 [==============================] - 2s 1ms/step - loss: 1.3451\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 816us/step - loss: 0.5186\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.7928\n", + "1/1 [==============================] - 0s 76ms/step\n" ] }, { "data": { "text/plain": [ - "array([[0.62953055],\n", - " [1.2767944 ],\n", - " [4.634055 ]], dtype=float32)" + "array([[1.1431919],\n", + " [1.0584592],\n", + " [4.71127 ]], dtype=float32)" ] }, "execution_count": 141, @@ -3519,7 +3560,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "block1 = ResidualBlock(2, 30)\n", "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\",\n", @@ -3537,13 +3578,6 @@ "## Losses and Metrics Based on Model Internals" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Warning**: due to an issue introduced in TF 2.2 ([#46858](https://github.com/tensorflow/tensorflow/issues/46858)), `super().build()` fails. We can work around this issue by setting `self.built = True` instead." - ] - }, { "cell_type": "code", "execution_count": 143, @@ -3563,7 +3597,6 @@ " def build(self, batch_input_shape):\n", " n_inputs = batch_input_shape[-1]\n", " self.reconstruct = tf.keras.layers.Dense(n_inputs)\n", - " self.built = True # WORKAROUND for super().build(batch_input_shape)\n", "\n", " def call(self, inputs, training=None):\n", " Z = inputs\n", @@ -3588,21 +3621,22 @@ "output_type": "stream", "text": [ "Epoch 1/5\n", - "363/363 [==============================] - 1s 820us/step - loss: 0.7640 - reconstruction_error: 1.2728\n", + "363/363 [==============================] - 2s 1ms/step - loss: 0.8198 - reconstruction_error: 1.0892\n", "Epoch 2/5\n", - "363/363 [==============================] - 0s 809us/step - loss: 0.4584 - reconstruction_error: 0.6340\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.4778 - reconstruction_error: 0.5583\n", "Epoch 3/5\n", - "363/363 [==============================] - 0s 786us/step - loss: 0.4211 - reconstruction_error: 0.4342\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.4419 - reconstruction_error: 0.4227\n", "Epoch 4/5\n", - "363/363 [==============================] - 0s 745us/step - loss: 0.3753 - reconstruction_error: 0.3597\n", + "363/363 [==============================] - 0s 1ms/step - loss: 0.3852 - reconstruction_error: 0.3587\n", "Epoch 5/5\n", - "363/363 [==============================] - 0s 772us/step - loss: 0.3618 - reconstruction_error: 0.2908\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.3714 - reconstruction_error: 0.3245\n", + "162/162 [==============================] - 0s 658us/step\n" ] } ], "source": [ "# extra code\n", - "tf.random.set_seed(42)\n", + "tf.keras.utils.set_random_seed(42)\n", "model = ReconstructingRegressor(1)\n", "model.compile(loss=\"mse\", optimizer=\"nadam\")\n", "history = model.fit(X_train_scaled, y_train, epochs=5)\n", @@ -4031,7 +4065,7 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, "execution_count": 166, @@ -4126,7 +4160,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42) # extra code – to ensure reproducibility\n", + "tf.keras.utils.set_random_seed(42) # extra code – to ensure reproducibility\n", "l2_reg = tf.keras.regularizers.l2(0.05)\n", "model = tf.keras.models.Sequential([\n", " tf.keras.layers.Dense(30, activation=\"relu\", kernel_initializer=\"he_normal\",\n", @@ -4165,8 +4199,7 @@ "metadata": {}, "outputs": [], "source": [ - "np.random.seed(42)\n", - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -4196,15 +4229,15 @@ "output_type": "stream", "text": [ "Epoch 1/5\n", - "362/362 - mean: 0.6219 - mean_absolute_error: 0.4975\n", + "362/362 - mean: 3.5419 - mean_absolute_error: 0.6640\n", "Epoch 2/5\n", - "362/362 - mean: 0.6272 - mean_absolute_error: 0.5049\n", + "362/362 - mean: 1.8693 - mean_absolute_error: 0.5431\n", "Epoch 3/5\n", - "362/362 - mean: 0.6019 - mean_absolute_error: 0.4951\n", + "362/362 - mean: 1.1428 - mean_absolute_error: 0.5030\n", "Epoch 4/5\n", - "362/362 - mean: 0.6088 - mean_absolute_error: 0.4971\n", + "362/362 - mean: 0.8501 - mean_absolute_error: 0.4977\n", "Epoch 5/5\n", - "362/362 - mean: 0.6159 - mean_absolute_error: 0.5032\n" + "362/362 - mean: 0.7280 - mean_absolute_error: 0.5014\n" ] } ], @@ -4244,7 +4277,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "0425ac6b66024c7d83d98459be6f1811", + "model_id": "28534c4a7baf4b78a8a9f1db10024cfd", "version_major": 2, "version_minor": 0 }, @@ -4258,7 +4291,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "fac07a118bd649158e28c73591809f95", + "model_id": "cd7c0a89c62f476db08f755e6e4f1178", "version_major": 2, "version_minor": 0 }, @@ -4272,7 +4305,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "162f6cd2e9b4491d9a3b1bc378990eef", + "model_id": "5866293693b1455584e6a2e28811692a", "version_major": 2, "version_minor": 0 }, @@ -4286,7 +4319,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "116af880df174758bf744dc1fe5fa81e", + "model_id": "84cf94014b644e07b649063016221d3f", "version_major": 2, "version_minor": 0 }, @@ -4300,7 +4333,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "20afe56af0b54d12be3dd84e29e9f0d1", + "model_id": "21e3803f4d4249049efc0b725c9bd23f", "version_major": 2, "version_minor": 0 }, @@ -4314,7 +4347,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "662afff06af24ded83a719eabc1a8a83", + "model_id": "c8c0aa7115374ed8891175bafc6f7d0d", "version_major": 2, "version_minor": 0 }, @@ -4426,7 +4459,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 180, @@ -4512,7 +4545,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 184, @@ -4580,7 +4613,7 @@ { "data": { "text/plain": [ - "" + "PyGraph<6956689888>" ] }, "execution_count": 187, @@ -4706,7 +4739,7 @@ { "data": { "text/plain": [ - "name: \"__inference_tf_cube_3515915\"\n", + "name: \"__inference_tf_cube_592407\"\n", "input_arg {\n", " name: \"x\"\n", " type: DT_FLOAT\n", @@ -4843,14 +4876,14 @@ "output_type": "stream", "text": [ "x = Tensor(\"x:0\", shape=(2, 2), dtype=float32)\n", - "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" + "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" + "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] } ], @@ -4892,7 +4925,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -4924,24 +4957,20 @@ "name": "stdout", "output_type": "stream", "text": [ - "Python inputs incompatible with input_signature:\n", - " inputs: (\n", - " tf.Tensor(\n", - "[[[0.7413678 0.62854624]\n", - " [0.01738465 0.3431449 ]]\n", + "Binding inputs to tf.function `shrink` failed due to `Can not cast TensorSpec(shape=(2, 2, 2), dtype=tf.float32, name=None) to TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name=None)`. Received args: (,) and kwargs: {} for signature: (images: TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name=None)).\n" ] } ], "source": [ "img_batch_3 = tf.random.uniform(shape=[2, 2, 2])\n", "try:\n", - " preprocessed_images = shrink(img_batch_3) # ValueError! Incompatible inputs\n", - "except ValueError as ex:\n", + " preprocessed_images = shrink(img_batch_3) # TypeError! Incompatible inputs\n", + "except TypeError as ex:\n", " print(ex)" ] }, @@ -5483,7 +5512,6 @@ " shape=(self.units,),\n", " initializer='zeros',\n", " trainable=True)\n", - " super().build(input_shape)\n", "\n", " def call(self, X):\n", " print(\"Tracing MyDense.call()\")\n", @@ -5496,7 +5524,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -5555,22 +5583,22 @@ "Tracing MyDense.call()\n", "Tracing loss my_mse()\n", "Tracing metric my_mae()\n", - "296/363 [=======================>......] - ETA: 0s - loss: 1.5172 - my_mae: 0.8562Tracing MyModel.call()\n", + "315/363 [=========================>....] - ETA: 0s - loss: 1.5746 - my_mae: 0.8719Tracing MyModel.call()\n", "Tracing MyDense.call()\n", "Tracing MyDense.call()\n", "Tracing MyDense.call()\n", "Tracing loss my_mse()\n", "Tracing metric my_mae()\n", - "363/363 [==============================] - 1s 1ms/step - loss: 1.3255 - my_mae: 0.7900 - val_loss: 0.5569 - val_my_mae: 0.4819\n", + "363/363 [==============================] - 1s 1ms/step - loss: 1.4303 - my_mae: 0.8219 - val_loss: 0.4932 - val_my_mae: 0.4764\n", "Epoch 2/2\n", - "363/363 [==============================] - 0s 792us/step - loss: 0.4419 - my_mae: 0.4767 - val_loss: 0.4664 - val_my_mae: 0.4576\n", - "162/162 [==============================] - 0s 460us/step - loss: 0.4164 - my_mae: 0.4639\n" + "363/363 [==============================] - 0s 1ms/step - loss: 0.4386 - my_mae: 0.4760 - val_loss: 1.0322 - val_my_mae: 0.4793\n", + "162/162 [==============================] - 0s 704us/step - loss: 0.4204 - my_mae: 0.4711\n" ] }, { "data": { "text/plain": [ - "[0.4163525104522705, 0.4639028012752533]" + "[0.4203692376613617, 0.4711270332336426]" ] }, "execution_count": 230, @@ -5597,7 +5625,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -5675,7 +5703,7 @@ { "data": { "text/plain": [ - "[5.507260322570801, 2.0566811561584473]" + "[5.545090198516846, 2.0603599548339844]" ] }, "execution_count": 234, @@ -5702,7 +5730,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -5773,7 +5801,7 @@ { "data": { "text/plain": [ - "[5.507260322570801, 2.0566811561584473]" + "[5.545090198516846, 2.0603599548339844]" ] }, "execution_count": 238, @@ -5809,41 +5837,49 @@ "source": [ "class MyMomentumOptimizer(tf.keras.optimizers.Optimizer):\n", " def __init__(self, learning_rate=0.001, momentum=0.9, name=\"MyMomentumOptimizer\", **kwargs):\n", - " \"\"\"Call super().__init__() and use _set_hyper() to store hyperparameters\"\"\"\n", + " \"\"\"Gradient descent with momentum optimizer.\"\"\"\n", " super().__init__(name, **kwargs)\n", - " self._set_hyper(\"learning_rate\", kwargs.get(\"lr\", learning_rate)) # handle lr=learning_rate\n", - " self._set_hyper(\"decay\", self._initial_decay) # \n", - " self._set_hyper(\"momentum\", momentum)\n", - " \n", - " def _create_slots(self, var_list):\n", - " \"\"\"For each model variable, create the optimizer variable associated with it.\n", - " TensorFlow calls these optimizer variables \"slots\".\n", - " For momentum optimization, we need one momentum slot per model variable.\n", + " self._learning_rate = self._build_learning_rate(learning_rate)\n", + " self.momentum = momentum\n", + "\n", + " def build(self, var_list):\n", + " \"\"\"Initialize optimizer variables.\n", + "\n", + " Args:\n", + " var_list: list of model variables to build SGD variables on.\n", " \"\"\"\n", + " super().build(var_list)\n", + " if getattr(self, \"_built\", False):\n", + " return\n", + " self.momentums = []\n", " for var in var_list:\n", - " self.add_slot(var, \"momentum\")\n", - "\n", - " @tf.function\n", - " def _resource_apply_dense(self, grad, var):\n", - " \"\"\"Update the slots and perform one optimization step for one model variable\n", - " \"\"\"\n", - " var_dtype = var.dtype.base_dtype\n", - " lr_t = self._decayed_lr(var_dtype) # handle learning rate decay\n", - " momentum_var = self.get_slot(var, \"momentum\")\n", - " momentum_hyper = self._get_hyper(\"momentum\", var_dtype)\n", - " momentum_var.assign(momentum_var * momentum_hyper - (1. - momentum_hyper)* grad)\n", - " var.assign_add(momentum_var * lr_t)\n", - "\n", - " def _resource_apply_sparse(self, grad, var):\n", - " raise NotImplementedError\n", + " self.momentums.append(\n", + " self.add_variable_from_reference(\n", + " model_variable=var, variable_name=\"m\"\n", + " )\n", + " )\n", + " self._built = True\n", "\n", + " def update_step(self, gradient, variable):\n", + " \"\"\"Update step given gradient and the associated model variable.\"\"\"\n", + " lr = tf.cast(self.learning_rate, variable.dtype)\n", + " m = None\n", + " var_key = self._var_key(variable)\n", + " momentum = tf.cast(self.momentum, variable.dtype)\n", + " m = self.momentums[self._index_dict[var_key]]\n", + " if m is None:\n", + " variable.assign_add(-gradient * lr)\n", + " else:\n", + " m.assign(-gradient * lr + m * momentum)\n", + " variable.assign_add(m)\n", + " \n", " def get_config(self):\n", " base_config = super().get_config()\n", + " print(\"Config!\")\n", " return {\n", " **base_config,\n", - " \"learning_rate\": self._serialize_hyperparameter(\"learning_rate\"),\n", - " \"decay\": self._serialize_hyperparameter(\"decay\"),\n", - " \"momentum\": self._serialize_hyperparameter(\"momentum\"),\n", + " \"learning_rate\": self._serialize_hyperparameter(self._learning_rate),\n", + " \"momentum\": self.momentum,\n", " }" ] }, @@ -5851,9 +5887,48 @@ "cell_type": "code", "execution_count": 240, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/5\n", + "363/363 [==============================] - 0s 660us/step - loss: 1.1844\n", + "Epoch 2/5\n", + "363/363 [==============================] - 0s 625us/step - loss: 0.5635\n", + "Epoch 3/5\n", + "363/363 [==============================] - 0s 609us/step - loss: 0.9703\n", + "Epoch 4/5\n", + "363/363 [==============================] - 0s 627us/step - loss: 0.5678\n", + "Epoch 5/5\n", + "363/363 [==============================] - 0s 640us/step - loss: 0.6350\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 240, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "tf.random.set_seed(42)" + "optimizer = MyMomentumOptimizer()\n", + "\n", + "tf.keras.utils.set_random_seed(42)\n", + "model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=[8])])\n", + "model.compile(loss=\"mse\", optimizer=optimizer)\n", + "model.fit(X_train_scaled, y_train, epochs=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's compare that to Keras's built-in momentum optimizer:" ] }, { @@ -5866,21 +5941,21 @@ "output_type": "stream", "text": [ "Epoch 1/5\n", - "363/363 [==============================] - 0s 444us/step - loss: 4.9648\n", + "363/363 [==============================] - 0s 645us/step - loss: 1.1844\n", "Epoch 2/5\n", - "363/363 [==============================] - 0s 444us/step - loss: 1.7888\n", + "363/363 [==============================] - 0s 721us/step - loss: 0.5635\n", "Epoch 3/5\n", - "363/363 [==============================] - 0s 437us/step - loss: 1.0021\n", + "363/363 [==============================] - 0s 612us/step - loss: 0.9703\n", "Epoch 4/5\n", - "363/363 [==============================] - 0s 451us/step - loss: 0.7869\n", + "363/363 [==============================] - 0s 625us/step - loss: 0.5678\n", "Epoch 5/5\n", - "363/363 [==============================] - 0s 446us/step - loss: 0.7122\n" + "363/363 [==============================] - 0s 626us/step - loss: 0.6350\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 241, @@ -5889,11 +5964,21 @@ } ], "source": [ + "optimizer = tf.keras.optimizers.SGD(learning_rate=0.001, momentum=0.9)\n", + "\n", + "tf.keras.utils.set_random_seed(42)\n", "model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=[8])])\n", - "model.compile(loss=\"mse\", optimizer=MyMomentumOptimizer())\n", + "model.compile(loss=\"mse\", optimizer=optimizer)\n", "model.fit(X_train_scaled, y_train, epochs=5)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Yep, we get the exact same model! 👍" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -5974,15 +6059,11 @@ " self.beta = self.add_weight(\n", " name=\"beta\", shape=batch_input_shape[-1:],\n", " initializer=\"zeros\")\n", - " super().build(batch_input_shape) # must be at the end\n", "\n", " def call(self, X):\n", " mean, variance = tf.nn.moments(X, axes=-1, keepdims=True)\n", " return self.alpha * (X - mean) / (tf.sqrt(variance + self.eps)) + self.beta\n", "\n", - " def compute_output_shape(self, batch_input_shape):\n", - " return batch_input_shape\n", - "\n", " def get_config(self):\n", " base_config = super().get_config()\n", " return {**base_config, \"eps\": self.eps}" @@ -6018,7 +6099,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 243, @@ -6051,7 +6132,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 244, @@ -6060,6 +6141,7 @@ } ], "source": [ + "tf.keras.utils.set_random_seed(42)\n", "random_alpha = np.random.rand(X.shape[-1])\n", "random_beta = np.random.rand(X.shape[-1])\n", "\n", @@ -6112,9 +6194,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.keras.backend.clear_session()\n", - "np.random.seed(42)\n", - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -6153,7 +6233,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "901e5649b50840538874aed5bab0d4ed", + "model_id": "a0c8a6efecb44efdbaf6f6f2107a37e6", "version_major": 2, "version_minor": 0 }, @@ -6167,7 +6247,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "2f29690a5ade4bd8a6d164d106ba2d31", + "model_id": "ba37766cb41848b4ae0f544c8ddf238f", "version_major": 2, "version_minor": 0 }, @@ -6181,7 +6261,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c2ea6579132c48c087c7f59e6309387a", + "model_id": "dc1d7d5c3f2148b1bb06e974bba09f52", "version_major": 2, "version_minor": 0 }, @@ -6195,7 +6275,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "94fa1527062c4cf7a277a548bbddc855", + "model_id": "a9fccf049df546079656b4fa4d53cf8a", "version_major": 2, "version_minor": 0 }, @@ -6209,7 +6289,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "dbcfc9a0c4b64151a18cf27080872dd3", + "model_id": "e63ee530efcf46af907e7ee80bea8be0", "version_major": 2, "version_minor": 0 }, @@ -6223,7 +6303,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "fc3831d9b98e488c837ba9644bf4b94a", + "model_id": "a9bbff8ceb73461398293a4f5f1cade8", "version_major": 2, "version_minor": 0 }, @@ -6280,9 +6360,7 @@ "metadata": {}, "outputs": [], "source": [ - "tf.keras.backend.clear_session()\n", - "np.random.seed(42)\n", - "tf.random.set_seed(42)" + "tf.keras.utils.set_random_seed(42)" ] }, { @@ -6335,7 +6413,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "7e81cf85cf7548748ec760afcbd71aa2", + "model_id": "5bdc4d309e3e4f03a27150634a0b89c3", "version_major": 2, "version_minor": 0 }, @@ -6349,7 +6427,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "475109b927d044a7bba030f234c67838", + "model_id": "b816337dd6ba4177a8bcdd41639a8930", "version_major": 2, "version_minor": 0 }, @@ -6363,7 +6441,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "af0a22afae4f47359f8fdfbac96e38bb", + "model_id": "b4cba66f77474d2b9f9de9a207eadf6c", "version_major": 2, "version_minor": 0 }, @@ -6377,7 +6455,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "5519ec96e42f4281987a84a5434a0734", + "model_id": "5649fae110bf4f90bce00b39838e05bf", "version_major": 2, "version_minor": 0 }, @@ -6391,7 +6469,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ed04f31b3a7d4b3b9a0cd63b644e2ed5", + "model_id": "7cd99923c6cc43e78faf87b13be2df7b", "version_major": 2, "version_minor": 0 }, @@ -6405,7 +6483,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "bfc4b1b4d40f4003ab8a3140a68ec883", + "model_id": "39ad913b024f4a2bb31477cfb2d61fbf", "version_major": 2, "version_minor": 0 },