{ "cells": [ { "cell_type": "markdown", "id": "e13159d6", "metadata": {}, "source": [ "#### Инициализация Keras\n", "\n", "torch был заменен на jax, так как с torch рекуррентные сети не работали" ] }, { "cell_type": "code", "execution_count": 1, "id": "507915ea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.9.2\n" ] } ], "source": [ "import os\n", "\n", "os.environ[\"KERAS_BACKEND\"] = \"jax\"\n", "import keras\n", "\n", "print(keras.__version__)" ] }, { "cell_type": "markdown", "id": "06e989a5", "metadata": {}, "source": [ "#### Загрузка данных для классификации с помощью глубоких сетей\n", "\n", "В качестве набора данных используется набор отзывов к фильмам с сайта IMDB.\n", "\n", "Набор включает 50 000 отзывов, половина из которых находится в обучающем наборе данных (x_train), а половина - в тестовом (x_valid). \n", "\n", "Метки (y_train и y_valid) имеют бинарный характер и назначены в соответствии с этими 10-балльными оценками:\n", "- отзывы с четырьмя звездами или меньше считаются отрицательным (y = 0);\n", "- отзывы с семью звездами или больше считаются положительными (y = 1);\n", "- умеренные отзывы — с пятью или шестью звездами — не включались в набор данных, что упрощает задачу бинарной классификации.\n", "\n", "Данные уже предобработаны для простоты работы с ними.\n", "\n", "unique_words - в векторное пространство включается только слова, которые встречаются в корпусе не менее 10 000 раз.\n", "\n", "max_length - максимальная длина отзыва (если больше, то обрезается, если меньше, то дополняется \"пустыми\" словами)." ] }, { "cell_type": "code", "execution_count": 2, "id": "e0043e5c", "metadata": {}, "outputs": [], "source": [ "from keras.api.datasets import imdb\n", "import os\n", "\n", "unique_words = 10000\n", "max_length = 100\n", "\n", "output_dir = \"tmp\"\n", "if not os.path.exists(output_dir):\n", " os.makedirs(output_dir)\n", "\n", "(X_train, y_train), (X_valid, y_valid) = imdb.load_data(num_words=unique_words)" ] }, { "cell_type": "markdown", "id": "86b62f23", "metadata": {}, "source": [ "#### Приведение отзывов к длине max_length (100)\n", "\n", "padding и truncating - дополнение и обрезка отзывов начинается с начала (учитывается специфика затухания градиента в рекуррентных сетях)" ] }, { "cell_type": "code", "execution_count": 3, "id": "131e125a", "metadata": {}, "outputs": [], "source": [ "from keras.api.preprocessing.sequence import pad_sequences\n", "\n", "X_train = pad_sequences(X_train, maxlen=max_length, padding=\"pre\", truncating=\"pre\", value=0)\n", "X_valid = pad_sequences(X_valid, maxlen=max_length, padding=\"pre\", truncating=\"pre\", value=0)" ] }, { "cell_type": "markdown", "id": "a78bde02", "metadata": {}, "source": [ "#### Формирование архитектуры глубокой рекуррентной сети\n", "\n", "\n", "Первый слой (Embedding) выполняет векторизацию" ] }, { "cell_type": "code", "execution_count": 4, "id": "1e3fb0ec", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Model: \"sequential\"\n",
       "
\n" ], "text/plain": [ "\u001b[1mModel: \"sequential\"\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ embedding (Embedding)           │ (None, 100, 64)        │       640,000 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ spatial_dropout1d               │ (None, 100, 64)        │             0 │\n",
       "│ (SpatialDropout1D)              │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ simple_rnn (SimpleRNN)          │ (None, 256)            │        82,176 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense (Dense)                   │ (None, 1)              │           257 │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "
\n" ], "text/plain": [ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", "│ embedding (\u001b[38;5;33mEmbedding\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m640,000\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ spatial_dropout1d │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m100\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", "│ (\u001b[38;5;33mSpatialDropout1D\u001b[0m) │ │ │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ simple_rnn (\u001b[38;5;33mSimpleRNN\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m82,176\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m257\u001b[0m │\n", "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Total params: 722,433 (2.76 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m722,433\u001b[0m (2.76 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Trainable params: 722,433 (2.76 MB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m722,433\u001b[0m (2.76 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Non-trainable params: 0 (0.00 B)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from keras.api.models import Sequential\n", "from keras.api.layers import InputLayer, Embedding, SpatialDropout1D, SimpleRNN, Dense\n", "\n", "rnn_model = Sequential()\n", "rnn_model.add(InputLayer(shape=(max_length,), dtype=\"float32\"))\n", "rnn_model.add(Embedding(unique_words, 64))\n", "rnn_model.add(SpatialDropout1D(0.2))\n", "rnn_model.add(SimpleRNN(256, dropout=0.2))\n", "rnn_model.add(Dense(1, activation=\"sigmoid\"))\n", "\n", "rnn_model.summary()" ] }, { "cell_type": "markdown", "id": "23900b11", "metadata": {}, "source": [ "#### Обучение модели\n", "\n", "Веса модели сохраняются в каталог tmp после каждой эпохи обучения с помощью callback-параметра\n", "\n", "В дальнейшем веса можно загрузить" ] }, { "cell_type": "code", "execution_count": 5, "id": "11236198", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 68ms/step - accuracy: 0.5207 - loss: 0.6994 - val_accuracy: 0.5872 - val_loss: 0.6700\n", "Epoch 2/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 64ms/step - accuracy: 0.6188 - loss: 0.6423 - val_accuracy: 0.6368 - val_loss: 0.6183\n", "Epoch 3/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 64ms/step - accuracy: 0.7102 - loss: 0.5539 - val_accuracy: 0.6463 - val_loss: 0.6441\n", "Epoch 4/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 65ms/step - accuracy: 0.7746 - loss: 0.4737 - val_accuracy: 0.7338 - val_loss: 0.5681\n", "Epoch 5/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 65ms/step - accuracy: 0.8127 - loss: 0.4065 - val_accuracy: 0.6766 - val_loss: 0.6422\n", "Epoch 6/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 67ms/step - accuracy: 0.8613 - loss: 0.3246 - val_accuracy: 0.7152 - val_loss: 0.6385\n", "Epoch 7/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 66ms/step - accuracy: 0.8923 - loss: 0.2667 - val_accuracy: 0.7202 - val_loss: 0.6684\n", "Epoch 8/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 67ms/step - accuracy: 0.9032 - loss: 0.2335 - val_accuracy: 0.7296 - val_loss: 0.6990\n", "Epoch 9/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 70ms/step - accuracy: 0.9118 - loss: 0.2143 - val_accuracy: 0.6944 - val_loss: 0.7852\n", "Epoch 10/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 70ms/step - accuracy: 0.9205 - loss: 0.2022 - val_accuracy: 0.7359 - val_loss: 0.7074\n", "Epoch 11/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 69ms/step - accuracy: 0.9418 - loss: 0.1523 - val_accuracy: 0.7127 - val_loss: 0.8376\n", "Epoch 12/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 68ms/step - accuracy: 0.9440 - loss: 0.1462 - val_accuracy: 0.7288 - val_loss: 0.8534\n", "Epoch 13/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 69ms/step - accuracy: 0.9344 - loss: 0.1649 - val_accuracy: 0.7157 - val_loss: 0.8279\n", "Epoch 14/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 70ms/step - accuracy: 0.9201 - loss: 0.1998 - val_accuracy: 0.6386 - val_loss: 1.1343\n", "Epoch 15/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 68ms/step - accuracy: 0.9301 - loss: 0.1774 - val_accuracy: 0.7041 - val_loss: 0.9636\n", "Epoch 16/16\n", "\u001b[1m196/196\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 69ms/step - accuracy: 0.9616 - loss: 0.1055 - val_accuracy: 0.6747 - val_loss: 1.1050\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from keras.api.callbacks import ModelCheckpoint\n", "\n", "rnn_model.compile(\n", " loss=\"binary_crossentropy\",\n", " optimizer=\"adam\",\n", " metrics=[\"accuracy\"],\n", ")\n", "\n", "rnn_model.fit(\n", " X_train,\n", " y_train,\n", " batch_size=128,\n", " epochs=16,\n", " validation_data=(X_valid, y_valid),\n", " callbacks=[ModelCheckpoint(filepath=output_dir + \"/rnn_weights.{epoch:02d}.keras\")],\n", ")" ] }, { "cell_type": "markdown", "id": "ccf878d3", "metadata": {}, "source": [ "#### Загрузка лучшей модели и оценка ее качества\n", "\n", "Качество модели - 73.6 %." ] }, { "cell_type": "code", "execution_count": 6, "id": "94987771", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 10ms/step - accuracy: 0.7307 - loss: 0.7206\n" ] }, { "data": { "text/plain": [ "[0.7074107527732849, 0.7359200119972229]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rnn_model.load_weights(output_dir + \"/rnn_weights.10.keras\")\n", "rnn_model.evaluate(X_valid, y_valid)" ] }, { "cell_type": "markdown", "id": "e05b98c0", "metadata": {}, "source": [ "#### Визуализация распределения вероятностей результатов модели на валидационной выборке" ] }, { "cell_type": "code", "execution_count": 7, "id": "8965a612", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 10ms/step\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGdCAYAAAAMm0nCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAvoUlEQVR4nO3deXgUdZ7H8U8Oujm7A0i6yRAwigJRlAFG6EGdRbNEjK4OcRRlMMq1MMEdkme5VuTyCKKCoByrKGEeYRD2EVeIgDEIPEo4jEY5ow5omMEOOpg0IOSs/cNNSQsoHXPwi+/X89TzdNfvW5Vv/QT6Y3VVJcyyLEsAAAAGCW/oBgAAAEJFgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGCeyoRuoK1VVVTpy5IhatWqlsLCwhm4HAABcAMuydPz4ccXExCg8/PznWRptgDly5IhiY2Mbug0AAFADhw8fVocOHc473mgDTKtWrSR9NwEul6uBuwFQaypOSq/FfPd60BEpskXD9gOgVgUCAcXGxtqf4+cTUoCprKzU9OnT9corr8jv9ysmJkYPPPCApkyZYn9NY1mWpk2bphdffFHFxcXq16+fFi1apCuuuMLez7Fjx/TQQw9p7dq1Cg8PV3JysubNm6eWLVvaNR9//LFSU1O1a9cutWvXTg899JAmTJhwwb1W9+NyuQgwQGNSESE1///XLhcBBmikfuryj5Au4n3yySe1aNEiPf/889q/f7+efPJJzZ49W88995xdM3v2bM2fP1+LFy/Wjh071KJFCyUmJur06dN2zZAhQ7R3715lZ2dr3bp12rp1q0aNGmWPBwIBDRgwQJ06dVJeXp6eeuopTZ8+XS+88EIo7QIAgMbKCkFSUpI1bNiwoHWDBg2yhgwZYlmWZVVVVVler9d66qmn7PHi4mLL6XRaf/3rXy3Lsqx9+/ZZkqxdu3bZNevXr7fCwsKsf/zjH5ZlWdbChQut1q1bW6WlpXbNxIkTrS5dulxwryUlJZYkq6SkJJRDBHCxKz9hWcv13VJ+oqG7AVDLLvTzO6QzML/97W+Vk5OjTz75RJL00Ucf6d1339XAgQMlSYcOHZLf71dCQoK9jdvtVp8+fZSbmytJys3NVVRUlHr37m3XJCQkKDw8XDt27LBrbrzxRjkcDrsmMTFRBQUF+uabb87ZW2lpqQKBQNACAAAap5CugZk0aZICgYC6du2qiIgIVVZW6vHHH9eQIUMkSX6/X5Lk8XiCtvN4PPaY3+9XdHR0cBORkWrTpk1QTVxc3Fn7qB5r3br1Wb1lZGRoxowZoRwOAAAwVEhnYFatWqXly5drxYoV+uCDD7Rs2TI9/fTTWrZsWV31d8EmT56skpISezl8+HBDtwQAAOpISGdgxo8fr0mTJmnw4MGSpO7du+uLL75QRkaGUlJS5PV6JUlFRUVq3769vV1RUZF69OghSfJ6vTp69GjQfisqKnTs2DF7e6/Xq6KioqCa6vfVNT/kdDrldDpDORwAAGCokM7AfPvtt2c9FS8iIkJVVVWSpLi4OHm9XuXk5NjjgUBAO3bskM/nkyT5fD4VFxcrLy/Prtm0aZOqqqrUp08fu2br1q0qLy+3a7Kzs9WlS5dzfn0EAAB+WUIKMLfffrsef/xxZWVl6fPPP9eaNWs0Z84c/f73v5f03T3b48aN02OPPaY33nhDu3fv1v3336+YmBjdeeedkqRu3brplltu0ciRI7Vz50699957Gjt2rAYPHqyYmO8eTnXffffJ4XBo+PDh2rt3r1599VXNmzdP6enptXv0AADATKHc2hQIBKw///nPVseOHa2mTZtal112mfXwww8H3e5cVVVlPfLII5bH47GcTqd18803WwUFBUH7+ec//2nde++9VsuWLS2Xy2U9+OCD1vHjx4NqPvroI+v666+3nE6n9atf/cqaNWtWKK1yGzXQWHEbNdCoXejnd5hlWVZDh6i6EAgE5Ha7VVJSwpN4gcak4qS06v+f2n33CZ7ECzQyF/r5HdJXSAAAABcDAgwAADAOAQYAABiHAAMAAIwT0oPs8J1LJ2U1dAsh+3xWUkO3AABAreEMDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcUIKMJdeeqnCwsLOWlJTUyVJp0+fVmpqqtq2bauWLVsqOTlZRUVFQfsoLCxUUlKSmjdvrujoaI0fP14VFRVBNZs3b1bPnj3ldDrVuXNnZWZm/ryjBAAAjUpIAWbXrl368ssv7SU7O1uS9Ic//EGSlJaWprVr12r16tXasmWLjhw5okGDBtnbV1ZWKikpSWVlZdq2bZuWLVumzMxMTZ061a45dOiQkpKS1L9/f+Xn52vcuHEaMWKENm7cWBvHCwAAGoEwy7Ksmm48btw4rVu3Tp9++qkCgYDatWunFStW6K677pIkHThwQN26dVNubq769u2r9evX67bbbtORI0fk8XgkSYsXL9bEiRP11VdfyeFwaOLEicrKytKePXvsnzN48GAVFxdrw4YNF9xbIBCQ2+1WSUmJXC5XTQ/xnC6dlFWr+6sPn89KaugWgNpRcVJa1fK713efkCJbNGw/AGrVhX5+1/gamLKyMr3yyisaNmyYwsLClJeXp/LyciUkJNg1Xbt2VceOHZWbmytJys3NVffu3e3wIkmJiYkKBALau3evXXPmPqprqvdxPqWlpQoEAkELAABonGocYF5//XUVFxfrgQcekCT5/X45HA5FRUUF1Xk8Hvn9frvmzPBSPV499mM1gUBAp06dOm8/GRkZcrvd9hIbG1vTQwMAABe5GgeYl156SQMHDlRMTExt9lNjkydPVklJib0cPny4oVsCAAB1JLImG33xxRd6++239dprr9nrvF6vysrKVFxcHHQWpqioSF6v167ZuXNn0L6q71I6s+aHdy4VFRXJ5XKpWbNm5+3J6XTK6XTW5HAAAIBhanQGZunSpYqOjlZS0vcXhvbq1UtNmjRRTk6Ova6goECFhYXy+XySJJ/Pp927d+vo0aN2TXZ2tlwul+Lj4+2aM/dRXVO9DwAAgJADTFVVlZYuXaqUlBRFRn5/Asftdmv48OFKT0/XO++8o7y8PD344IPy+Xzq27evJGnAgAGKj4/X0KFD9dFHH2njxo2aMmWKUlNT7bMno0eP1sGDBzVhwgQdOHBACxcu1KpVq5SWllZLhwwAAEwX8ldIb7/9tgoLCzVs2LCzxubOnavw8HAlJyertLRUiYmJWrhwoT0eERGhdevWacyYMfL5fGrRooVSUlI0c+ZMuyYuLk5ZWVlKS0vTvHnz1KFDBy1ZskSJiYk1PEQAANDY/KznwFzMeA5MMJ4Dg0aD58AAjVqdPwcGAACgoRBgAACAcWp0GzUAAKg9XJoQOs7AAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACME3KA+cc//qE//vGPatu2rZo1a6bu3bvr/ffft8cty9LUqVPVvn17NWvWTAkJCfr000+D9nHs2DENGTJELpdLUVFRGj58uE6cOBFU8/HHH+uGG25Q06ZNFRsbq9mzZ9fwEAEAQGMTUoD55ptv1K9fPzVp0kTr16/Xvn379Mwzz6h169Z2zezZszV//nwtXrxYO3bsUIsWLZSYmKjTp0/bNUOGDNHevXuVnZ2tdevWaevWrRo1apQ9HggENGDAAHXq1El5eXl66qmnNH36dL3wwgu1cMgAAMB0kaEUP/nkk4qNjdXSpUvtdXFxcfZry7L07LPPasqUKbrjjjskSX/5y1/k8Xj0+uuva/Dgwdq/f782bNigXbt2qXfv3pKk5557TrfeequefvppxcTEaPny5SorK9PLL78sh8Ohq666Svn5+ZozZ05Q0AEAAL9MIZ2BeeONN9S7d2/94Q9/UHR0tH7961/rxRdftMcPHTokv9+vhIQEe53b7VafPn2Um5srScrNzVVUVJQdXiQpISFB4eHh2rFjh11z4403yuFw2DWJiYkqKCjQN998c87eSktLFQgEghYAANA4hRRgDh48qEWLFumKK67Qxo0bNWbMGP3Hf/yHli1bJkny+/2SJI/HE7Sdx+Oxx/x+v6Kjo4PGIyMj1aZNm6Cac+3jzJ/xQxkZGXK73fYSGxsbyqEBAACDhBRgqqqq1LNnTz3xxBP69a9/rVGjRmnkyJFavHhxXfV3wSZPnqySkhJ7OXz4cEO3BAAA6khIAaZ9+/aKj48PWtetWzcVFhZKkrxerySpqKgoqKaoqMge83q9Onr0aNB4RUWFjh07FlRzrn2c+TN+yOl0yuVyBS0AAKBxCinA9OvXTwUFBUHrPvnkE3Xq1EnSdxf0er1e5eTk2OOBQEA7duyQz+eTJPl8PhUXFysvL8+u2bRpk6qqqtSnTx+7ZuvWrSovL7drsrOz1aVLl6A7ngAAwC9TSAEmLS1N27dv1xNPPKHPPvtMK1as0AsvvKDU1FRJUlhYmMaNG6fHHntMb7zxhnbv3q37779fMTExuvPOOyV9d8bmlltu0ciRI7Vz50699957Gjt2rAYPHqyYmBhJ0n333SeHw6Hhw4dr7969evXVVzVv3jylp6fX7tEDAAAjhXQb9W9+8xutWbNGkydP1syZMxUXF6dnn31WQ4YMsWsmTJigkydPatSoUSouLtb111+vDRs2qGnTpnbN8uXLNXbsWN18880KDw9XcnKy5s+fb4+73W699dZbSk1NVa9evXTJJZdo6tSp3EINAAAkSWGWZVkN3URdCAQCcrvdKikpqfXrYS6dlFWr+6sPn89KaugWgNpRcVJa1fK713efkCJbNGw/QC3gc+V7F/r5ze9CAgAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjhBRgpk+frrCwsKCla9eu9vjp06eVmpqqtm3bqmXLlkpOTlZRUVHQPgoLC5WUlKTmzZsrOjpa48ePV0VFRVDN5s2b1bNnTzmdTnXu3FmZmZk1P0IAANDohHwG5qqrrtKXX35pL++++649lpaWprVr12r16tXasmWLjhw5okGDBtnjlZWVSkpKUllZmbZt26Zly5YpMzNTU6dOtWsOHTqkpKQk9e/fX/n5+Ro3bpxGjBihjRs3/sxDBQAAjUVkyBtERsrr9Z61vqSkRC+99JJWrFihm266SZK0dOlSdevWTdu3b1ffvn311ltvad++fXr77bfl8XjUo0cPPfroo5o4caKmT58uh8OhxYsXKy4uTs8884wkqVu3bnr33Xc1d+5cJSYm/szDBQAAjUHIZ2A+/fRTxcTE6LLLLtOQIUNUWFgoScrLy1N5ebkSEhLs2q5du6pjx47Kzc2VJOXm5qp79+7yeDx2TWJiogKBgPbu3WvXnLmP6prqfQAAAIR0BqZPnz7KzMxUly5d9OWXX2rGjBm64YYbtGfPHvn9fjkcDkVFRQVt4/F45Pf7JUl+vz8ovFSPV4/9WE0gENCpU6fUrFmzc/ZWWlqq0tJS+30gEAjl0AAAgEFCCjADBw60X19zzTXq06ePOnXqpFWrVp03WNSXjIwMzZgxo0F7AAAA9eNn3UYdFRWlK6+8Up999pm8Xq/KyspUXFwcVFNUVGRfM+P1es+6K6n6/U/VuFyuHw1JkydPVklJib0cPnz45xwaAAC4iP2sAHPixAn97W9/U/v27dWrVy81adJEOTk59nhBQYEKCwvl8/kkST6fT7t379bRo0ftmuzsbLlcLsXHx9s1Z+6juqZ6H+fjdDrlcrmCFgAA0DiFFGD+8z//U1u2bNHnn3+ubdu26fe//70iIiJ07733yu12a/jw4UpPT9c777yjvLw8Pfjgg/L5fOrbt68kacCAAYqPj9fQoUP10UcfaePGjZoyZYpSU1PldDolSaNHj9bBgwc1YcIEHThwQAsXLtSqVauUlpZW+0cPAACMFNI1MH//+99177336p///KfatWun66+/Xtu3b1e7du0kSXPnzlV4eLiSk5NVWlqqxMRELVy40N4+IiJC69at05gxY+Tz+dSiRQulpKRo5syZdk1cXJyysrKUlpamefPmqUOHDlqyZAm3UAMAAFuYZVlWQzdRFwKBgNxut0pKSmr966RLJ2XV6v7qw+ezkhq6BaB2VJyUVrX87vXdJ6TIFg3bD1AL+Fz53oV+fvO7kAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgnJ8VYGbNmqWwsDCNGzfOXnf69Gmlpqaqbdu2atmypZKTk1VUVBS0XWFhoZKSktS8eXNFR0dr/PjxqqioCKrZvHmzevbsKafTqc6dOyszM/PntAoAABqRGgeYXbt26b//+791zTXXBK1PS0vT2rVrtXr1am3ZskVHjhzRoEGD7PHKykolJSWprKxM27Zt07Jly5SZmampU6faNYcOHVJSUpL69++v/Px8jRs3TiNGjNDGjRtr2i4AAGhEahRgTpw4oSFDhujFF19U69at7fUlJSV66aWXNGfOHN10003q1auXli5dqm3btmn79u2SpLfeekv79u3TK6+8oh49emjgwIF69NFHtWDBApWVlUmSFi9erLi4OD3zzDPq1q2bxo4dq7vuuktz586thUMGAACmq1GASU1NVVJSkhISEoLW5+Xlqby8PGh9165d1bFjR+Xm5kqScnNz1b17d3k8HrsmMTFRgUBAe/futWt+uO/ExER7H+dSWlqqQCAQtAAAgMYpMtQNVq5cqQ8++EC7du06a8zv98vhcCgqKipovcfjkd/vt2vODC/V49VjP1YTCAR06tQpNWvW7KyfnZGRoRkzZoR6OAAAwEAhnYE5fPiw/vznP2v58uVq2rRpXfVUI5MnT1ZJSYm9HD58uKFbAgAAdSSkAJOXl6ejR4+qZ8+eioyMVGRkpLZs2aL58+crMjJSHo9HZWVlKi4uDtquqKhIXq9XkuT1es+6K6n6/U/VuFyuc559kSSn0ymXyxW0AACAximkAHPzzTdr9+7dys/Pt5fevXtryJAh9usmTZooJyfH3qagoECFhYXy+XySJJ/Pp927d+vo0aN2TXZ2tlwul+Lj4+2aM/dRXVO9DwAA8MsW0jUwrVq10tVXXx20rkWLFmrbtq29fvjw4UpPT1ebNm3kcrn00EMPyefzqW/fvpKkAQMGKD4+XkOHDtXs2bPl9/s1ZcoUpaamyul0SpJGjx6t559/XhMmTNCwYcO0adMmrVq1SllZWbVxzAAAwHAhX8T7U+bOnavw8HAlJyertLRUiYmJWrhwoT0eERGhdevWacyYMfL5fGrRooVSUlI0c+ZMuyYuLk5ZWVlKS0vTvHnz1KFDBy1ZskSJiYm13S4AADBQmGVZVkM3URcCgYDcbrdKSkpq/XqYSyeZdybo81lJDd0CUDsqTkqrWn73+u4TUmSLhu0HqAV8rnzvQj+/+V1IAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGCckALMokWLdM0118jlcsnlcsnn82n9+vX2+OnTp5Wamqq2bduqZcuWSk5OVlFRUdA+CgsLlZSUpObNmys6Olrjx49XRUVFUM3mzZvVs2dPOZ1Ode7cWZmZmTU/QgAA0OiEFGA6dOigWbNmKS8vT++//75uuukm3XHHHdq7d68kKS0tTWvXrtXq1au1ZcsWHTlyRIMGDbK3r6ysVFJSksrKyrRt2zYtW7ZMmZmZmjp1ql1z6NAhJSUlqX///srPz9e4ceM0YsQIbdy4sZYOGQAAmC7Msizr5+ygTZs2euqpp3TXXXepXbt2WrFihe666y5J0oEDB9StWzfl5uaqb9++Wr9+vW677TYdOXJEHo9HkrR48WJNnDhRX331lRwOhyZOnKisrCzt2bPH/hmDBw9WcXGxNmzYcMF9BQIBud1ulZSUyOVy/ZxDPMulk7JqdX/14fNZSQ3dAlA7Kk5Kq1p+9/ruE1Jki4btB6gFfK5870I/v2t8DUxlZaVWrlypkydPyufzKS8vT+Xl5UpISLBrunbtqo4dOyo3N1eSlJubq+7du9vhRZISExMVCATsszi5ublB+6iuqd7H+ZSWlioQCAQtAACgcQo5wOzevVstW7aU0+nU6NGjtWbNGsXHx8vv98vhcCgqKiqo3uPxyO/3S5L8fn9QeKkerx77sZpAIKBTp06dt6+MjAy53W57iY2NDfXQAACAIUIOMF26dFF+fr527NihMWPGKCUlRfv27auL3kIyefJklZSU2Mvhw4cbuiUAAFBHIkPdwOFwqHPnzpKkXr16adeuXZo3b57uuecelZWVqbi4OOgsTFFRkbxeryTJ6/Vq586dQfurvkvpzJof3rlUVFQkl8ulZs2anbcvp9Mpp9MZ6uEAAAAD/eznwFRVVam0tFS9evVSkyZNlJOTY48VFBSosLBQPp9PkuTz+bR7924dPXrUrsnOzpbL5VJ8fLxdc+Y+qmuq9wEAABDSGZjJkydr4MCB6tixo44fP64VK1Zo8+bN2rhxo9xut4YPH6709HS1adNGLpdLDz30kHw+n/r27StJGjBggOLj4zV06FDNnj1bfr9fU6ZMUWpqqn32ZPTo0Xr++ec1YcIEDRs2TJs2bdKqVauUlWXeFdoAAKBuhBRgjh49qvvvv19ffvml3G63rrnmGm3cuFH/+q//KkmaO3euwsPDlZycrNLSUiUmJmrhwoX29hEREVq3bp3GjBkjn8+nFi1aKCUlRTNnzrRr4uLilJWVpbS0NM2bN08dOnTQkiVLlJiYWEuHDAAATPeznwNzseI5MMF4DgwaDZ4Dg0aIz5Xv1flzYAAAABoKAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAME5kQzeA+nHppKyGbqFGPp+V1NAtAAAuQiGdgcnIyNBvfvMbtWrVStHR0brzzjtVUFAQVHP69Gmlpqaqbdu2atmypZKTk1VUVBRUU1hYqKSkJDVv3lzR0dEaP368Kioqgmo2b96snj17yul0qnPnzsrMzKzZEQIAgEYnpACzZcsWpaamavv27crOzlZ5ebkGDBigkydP2jVpaWlau3atVq9erS1btujIkSMaNGiQPV5ZWamkpCSVlZVp27ZtWrZsmTIzMzV16lS75tChQ0pKSlL//v2Vn5+vcePGacSIEdq4cWMtHDIAADBdmGVZVk03/uqrrxQdHa0tW7boxhtvVElJidq1a6cVK1borrvukiQdOHBA3bp1U25urvr27av169frtttu05EjR+TxeCRJixcv1sSJE/XVV1/J4XBo4sSJysrK0p49e+yfNXjwYBUXF2vDhg0X1FsgEJDb7VZJSYlcLldND/GcTP06xkR8hYSzVJyUVrX87vXdJ6TIFg3bD1ALTPxcqat/ny/08/tnXcRbUlIiSWrTpo0kKS8vT+Xl5UpISLBrunbtqo4dOyo3N1eSlJubq+7du9vhRZISExMVCAS0d+9eu+bMfVTXVO8DAAD8stX4It6qqiqNGzdO/fr109VXXy1J8vv9cjgcioqKCqr1eDzy+/12zZnhpXq8euzHagKBgE6dOqVmzZqd1U9paalKS0vt94FAoKaHBgAALnI1PgOTmpqqPXv2aOXKlbXZT41lZGTI7XbbS2xsbEO3BAAA6kiNAszYsWO1bt06vfPOO+rQoYO93uv1qqysTMXFxUH1RUVF8nq9ds0P70qqfv9TNS6X65xnXyRp8uTJKikpsZfDhw/X5NAAAIABQgowlmVp7NixWrNmjTZt2qS4uLig8V69eqlJkybKycmx1xUUFKiwsFA+n0+S5PP5tHv3bh09etSuyc7OlsvlUnx8vF1z5j6qa6r3cS5Op1MulytoAQAAjVNI18CkpqZqxYoV+t///V+1atXKvmbF7XarWbNmcrvdGj58uNLT09WmTRu5XC499NBD8vl86tu3ryRpwIABio+P19ChQzV79mz5/X5NmTJFqampcjqdkqTRo0fr+eef14QJEzRs2DBt2rRJq1atUlaWeVdpAwCA2hfSGZhFixappKRE//Iv/6L27dvby6uvvmrXzJ07V7fddpuSk5N14403yuv16rXXXrPHIyIitG7dOkVERMjn8+mPf/yj7r//fs2cOdOuiYuLU1ZWlrKzs3XttdfqmWee0ZIlS5SYmFgLhwwAAEz3s54DczHjOTCNA8+BwVl4Dgx+Av9G1w+jnwMDAADQEAgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxols6AaAH3PppKyGbiFkn89KaugWAKDR4wwMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjcBcSAOC8TLwTEL8MnIEBAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGCckAPM1q1bdfvttysmJkZhYWF6/fXXg8Yty9LUqVPVvn17NWvWTAkJCfr000+Dao4dO6YhQ4bI5XIpKipKw4cP14kTJ4JqPv74Y91www1q2rSpYmNjNXv27NCPDgAANEohB5iTJ0/q2muv1YIFC845Pnv2bM2fP1+LFy/Wjh071KJFCyUmJur06dN2zZAhQ7R3715lZ2dr3bp12rp1q0aNGmWPBwIBDRgwQJ06dVJeXp6eeuopTZ8+XS+88EINDhEAADQ2IT8HZuDAgRo4cOA5xyzL0rPPPqspU6bojjvukCT95S9/kcfj0euvv67Bgwdr//792rBhg3bt2qXevXtLkp577jndeuutevrppxUTE6Ply5errKxML7/8shwOh6666irl5+drzpw5QUEHuBiZ+NwMfoM2ANPU6jUwhw4dkt/vV0JCgr3O7XarT58+ys3NlSTl5uYqKirKDi+SlJCQoPDwcO3YscOuufHGG+VwOOyaxMREFRQU6Jtvvjnnzy4tLVUgEAhaAABA41SrAcbv90uSPB5P0HqPx2OP+f1+RUdHB41HRkaqTZs2QTXn2seZP+OHMjIy5Ha77SU2NvbnHxAAALgoNZpfJTB58mSlp6fb7wOBACEGwEXFxK8XgYtVrZ6B8Xq9kqSioqKg9UVFRfaY1+vV0aNHg8YrKip07NixoJpz7ePMn/FDTqdTLpcraAEAAI1TrZ6BiYuLk9frVU5Ojnr06CHpuzMhO3bs0JgxYyRJPp9PxcXFysvLU69evSRJmzZtUlVVlfr06WPXPPzwwyovL1eTJk0kSdnZ2erSpYtat25dmy0DkFlnBpqFndb+7g3dBYCGFnKAOXHihD777DP7/aFDh5Sfn682bdqoY8eOGjdunB577DFdccUViouL0yOPPKKYmBjdeeedkqRu3brplltu0ciRI7V48WKVl5dr7NixGjx4sGJiYiRJ9913n2bMmKHhw4dr4sSJ2rNnj+bNm6e5c+fWzlEDaBS6PbJBp6ymDd0GgAYQcoB5//331b9/f/t99XUnKSkpyszM1IQJE3Ty5EmNGjVKxcXFuv7667VhwwY1bfr9PzLLly/X2LFjdfPNNys8PFzJycmaP3++Pe52u/XWW28pNTVVvXr10iWXXKKpU6dyCzUAAJAkhVmWZTV0E3UhEAjI7XarpKSk1q+HMel0O9DYfPcV0l2SpG67/4czMEADqavnR13o5ze/CwkAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADGIcAAAADjEGAAAIBxCDAAAMA4BBgAAGAcAgwAADAOAQYAABiHAAMAAIxDgAEAAMYhwAAAAOMQYAAAgHEIMAAAwDgEGAAAYBwCDAAAMA4BBgAAGIcAAwAAjHNRB5gFCxbo0ksvVdOmTdWnTx/t3LmzoVsCAAAXgYs2wLz66qtKT0/XtGnT9MEHH+jaa69VYmKijh492tCtAQCABnbRBpg5c+Zo5MiRevDBBxUfH6/FixerefPmevnllxu6NQAA0MAiG7qBcykrK1NeXp4mT55srwsPD1dCQoJyc3PPuU1paalKS0vt9yUlJZKkQCBQ6/1VlX5b6/sEcGEqw04r8P9/BStLv1WVVdWwDQG/UHXx+Xrmfi3L+tG6izLAfP3116qsrJTH4wla7/F4dODAgXNuk5GRoRkzZpy1PjY2tk56BNBw3Par+xuwC+CXzf1s3e7/+PHjcrvd5x2/KANMTUyePFnp6en2+6qqKh07dkxt27ZVWFhYrf2cQCCg2NhYHT58WC6Xq9b2i7Mx1/WDea4fzHP9YJ7rR13Os2VZOn78uGJiYn607qIMMJdccokiIiJUVFQUtL6oqEher/ec2zidTjmdzqB1UVFRddWiXC4XfznqCXNdP5jn+sE81w/muX7U1Tz/2JmXahflRbwOh0O9evVSTk6Ova6qqko5OTny+XwN2BkAALgYXJRnYCQpPT1dKSkp6t27t6677jo9++yzOnnypB588MGGbg0AADSwizbA3HPPPfrqq680depU+f1+9ejRQxs2bDjrwt765nQ6NW3atLO+rkLtY67rB/NcP5jn+sE814+LYZ7DrJ+6TwkAAOAic1FeAwMAAPBjCDAAAMA4BBgAAGAcAgwAADAOAeYcFixYoEsvvVRNmzZVnz59tHPnzh+tX716tbp27aqmTZuqe/fuevPNN+upU7OFMs8vvviibrjhBrVu3VqtW7dWQkLCT/53wfdC/TNdbeXKlQoLC9Odd95Ztw02EqHOc3FxsVJTU9W+fXs5nU5deeWV/PtxAUKd52effVZdunRRs2bNFBsbq7S0NJ0+fbqeujXT1q1bdfvttysmJkZhYWF6/fXXf3KbzZs3q2fPnnI6nercubMyMzPrtkkLQVauXGk5HA7r5Zdftvbu3WuNHDnSioqKsoqKis5Z/95771kRERHW7NmzrX379llTpkyxmjRpYu3evbueOzdLqPN83333WQsWLLA+/PBDa//+/dYDDzxgud1u6+9//3s9d26eUOe62qFDh6xf/epX1g033GDdcccd9dOswUKd59LSUqt3797Wrbfear377rvWoUOHrM2bN1v5+fn13LlZQp3n5cuXW06n01q+fLl16NAha+PGjVb79u2ttLS0eu7cLG+++ab18MMPW6+99polyVqzZs2P1h88eNBq3ry5lZ6ebu3bt8967rnnrIiICGvDhg111iMB5geuu+46KzU11X5fWVlpxcTEWBkZGeesv/vuu62kpKSgdX369LH+/d//vU77NF2o8/xDFRUVVqtWraxly5bVVYuNRk3muqKiwvrtb39rLVmyxEpJSSHAXIBQ53nRokXWZZddZpWVldVXi41CqPOcmppq3XTTTUHr0tPTrX79+tVpn43JhQSYCRMmWFdddVXQunvuucdKTEyss774CukMZWVlysvLU0JCgr0uPDxcCQkJys3NPec2ubm5QfWSlJiYeN561Gyef+jbb79VeXm52rRpU1dtNgo1neuZM2cqOjpaw4cPr482jVeTeX7jjTfk8/mUmpoqj8ejq6++Wk888YQqKyvrq23j1GSef/vb3yovL8/+mungwYN68803deutt9ZLz78UDfFZeNE+ibchfP3116qsrDzrab8ej0cHDhw45zZ+v/+c9X6/v876NF1N5vmHJk6cqJiYmLP+wiBYTeb63Xff1UsvvaT8/Px66LBxqMk8Hzx4UJs2bdKQIUP05ptv6rPPPtOf/vQnlZeXa9q0afXRtnFqMs/33Xefvv76a11//fWyLEsVFRUaPXq0/uu//qs+Wv7FON9nYSAQ0KlTp9SsWbNa/5mcgYFxZs2apZUrV2rNmjVq2rRpQ7fTqBw/flxDhw7Viy++qEsuuaSh22nUqqqqFB0drRdeeEG9evXSPffco4cffliLFy9u6NYalc2bN+uJJ57QwoUL9cEHH+i1115TVlaWHn300YZuDT8TZ2DOcMkllygiIkJFRUVB64uKiuT1es+5jdfrDakeNZvnak8//bRmzZqlt99+W9dcc01dttkohDrXf/vb3/T555/r9ttvt9dVVVVJkiIjI1VQUKDLL7+8bps2UE3+TLdv315NmjRRRESEva5bt27y+/0qKyuTw+Go055NVJN5fuSRRzR06FCNGDFCktS9e3edPHlSo0aN0sMPP6zwcP4/vjac77PQ5XLVydkXiTMwQRwOh3r16qWcnBx7XVVVlXJycuTz+c65jc/nC6qXpOzs7PPWo2bzLEmzZ8/Wo48+qg0bNqh379710arxQp3rrl27avfu3crPz7eXf/u3f1P//v2Vn5+v2NjY+mzfGDX5M92vXz999tlndkCUpE8++UTt27cnvJxHTeb522+/PSukVIdGi18FWGsa5LOwzi4PNtTKlSstp9NpZWZmWvv27bNGjRplRUVFWX6/37Isyxo6dKg1adIku/69996zIiMjraefftrav3+/NW3aNG6jvgChzvOsWbMsh8Nh/c///I/15Zdf2svx48cb6hCMEepc/xB3IV2YUOe5sLDQatWqlTV27FiroKDAWrdunRUdHW099thjDXUIRgh1nqdNm2a1atXK+utf/2odPHjQeuutt6zLL7/cuvvuuxvqEIxw/Phx68MPP7Q+/PBDS5I1Z84c68MPP7S++OILy7Isa9KkSdbQoUPt+urbqMePH2/t37/fWrBgAbdRN4TnnnvO6tixo+VwOKzrrrvO2r59uz32u9/9zkpJSQmqX7VqlXXllVdaDofDuuqqq6ysrKx67thMocxzp06dLElnLdOmTav/xg0U6p/pMxFgLlyo87xt2zarT58+ltPptC677DLr8ccftyoqKuq5a/OEMs/l5eXW9OnTrcsvv9xq2rSpFRsba/3pT3+yvvnmm/pv3CDvvPPOOf/NrZ7blJQU63e/+91Z2/To0cNyOBzWZZddZi1durROewyzLM6hAQAAs3ANDAAAMA4BBgAAGIcAAwAAjEOAAQAAxiHAAAAA4xBgAACAcQgwAADAOAQYAABgHAIMAAAwDgEGAAAYhwADAACMQ4ABAADG+T9Q4gVg0ztxkAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "plt.hist(rnn_model.predict(X_valid))\n", "_ = plt.axvline(x=0.5, color=\"orange\")" ] } ], "metadata": { "kernelspec": { "display_name": ".venv (3.12.10)", "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.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }