{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Notebook for training and testing AI models" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import tensorflow as tf\n", "import numpy as np\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "import pandas as pd\n", "from attention import CustomAttention\n", "import json" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.8.0\n" ] } ], "source": [ "print(tf.__version__)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# CONSTANTS\n", "RAW_SLEEP_DATA_PATH = \".data/raw_bed_sleep-state.csv\"\n", "CLEANED_SLEEP_DATA_PATH = \".data/clean_bed_sleep-state.csv\"\n", "SLEEP_DATA_PATH = \".data/sleep_data_simple.csv\"\n", "UPDATED_SLEEP_DATA_PATH = \".data/updated_sleep_data.csv\"" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "## Parameters and Hyper-parameters\n", "SLEEP_STAGES = 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import Data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cleaning Raw Data" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "import csv\n", "import datetime\n", "import itertools" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "datetime.datetime(2022, 4, 21, 10, 19, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200)))" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "datetime.datetime.strptime(\"2022-04-21T10:18:00+02:00\",\"%Y-%m-%dT%H:%M:%S%z\") + datetime.timedelta(minutes=1)" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [], "source": [ "def stage_probability(stage, to_test):\n", " return 1.0 if stage == to_test else 0.0" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6.833333333333333" ] }, "execution_count": 150, "metadata": {}, "output_type": "execute_result" } ], "source": [ "((start_time - in_bed_time).seconds)/3600" ] }, { "cell_type": "code", "execution_count": 201, "metadata": {}, "outputs": [], "source": [ "cleaned_info = []\n", "date_seen = set()\n", "previous_duration = 60\n", "with open(RAW_SLEEP_DATA_PATH, mode ='r') as raw_file:\n", " csvFile = csv.reader(raw_file)\n", " # max_count = 1\n", " # stuff = set()\n", " in_bed_time = None\n", " current_sleep_id = -1\n", " for index, lines in enumerate(csvFile):\n", " if index == 0:\n", " cleaned_info.append([\n", " \"sleep_id\",\n", " \"sleep_begin\",\n", " \"stage_start\",\n", " \"time_since_begin_sec\",\n", " \"stage_duration_sec\",\n", " \"stage_end\", \n", " \"stage_value\",\n", " \"awake_probability\",\n", " \"light_probability\",\n", " \"deep_probability\",\n", " \"rem_probability\",\n", " ])\n", " continue\n", " start_time = datetime.datetime.strptime(lines[0],\"%Y-%m-%dT%H:%M:%S%z\")\n", " if start_time in date_seen:\n", " continue\n", " date_seen.add(start_time)\n", " if not in_bed_time or in_bed_time > start_time:\n", " current_sleep_id += 1\n", " in_bed_time = start_time\n", " # for duration, stage in enumerate(\n", " # for offset, (duration, stage) in enumerate(\n", " # zip(\n", " # # itertools.accumulate(lines[1].strip(\"[]\").split(\",\"), lambda x,y: int(x)+int(y)//60, initial = 0), \n", " # map(int, lines[1].strip(\"[]\").split(\",\"))\n", " # map(int, lines[2].strip(\"[]\").split(\",\"))\n", " # )\n", " # # map(int, lines[2].strip(\"[]\").split(\",\"))\n", " # ):\n", " for offset, (duration, stage) in enumerate(zip(map(int, lines[1].strip(\"[]\").split(\",\")), map(int, lines[2].strip(\"[]\").split(\",\")))):\n", " # print(f\"{(index, subindex) = }, {duration = }, {stage = }\")\n", " # print(f\"{(index, duration) = } {stage = }\")\n", " current_time = start_time + datetime.timedelta(seconds=offset*previous_duration)\n", " cleaned_info.append([\n", " current_sleep_id,\n", " in_bed_time,\n", " current_time, \n", " (current_time - in_bed_time).seconds,\n", " duration, \n", " current_time + datetime.timedelta(seconds=duration), \n", " stage,\n", " stage_probability(0, stage),\n", " stage_probability(1, stage),\n", " stage_probability(2, stage),\n", " stage_probability(3, stage),\n", " ])\n", " previous_duration = duration\n", " # print(f\"{(index, subindex) = }, {val = }\")\n", " # print(list())\n", " # if index >= max_count:\n", " # break\n" ] }, { "cell_type": "code", "execution_count": 202, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Finished Writing Cleaned Data\n" ] } ], "source": [ "with open(CLEANED_SLEEP_DATA_PATH, 'w') as clean_file:\n", " write = csv.writer(clean_file)\n", " write.writerows(cleaned_info)\n", "print(\"Finished Writing Cleaned Data\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating DataFrame from clean raw data" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [], "source": [ "# Get the cleaned data\n", "sleep_df_raw = pd.read_csv(CLEANED_SLEEP_DATA_PATH)#, parse_dates=[\"start\", \"end\"], infer_datetime_format=True)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [], "source": [ "# Preprocess data: \n", "# 1. convert to datetime\n", "sleep_df_raw[\"sleep_begin\"] = pd.to_datetime(sleep_df_raw[\"sleep_begin\"], utc=True)\n", "sleep_df_raw[\"stage_start\"] = pd.to_datetime(sleep_df_raw[\"stage_start\"], utc=True)\n", "sleep_df_raw[\"stage_end\"] = pd.to_datetime(sleep_df_raw[\"stage_end\"], utc=True)\n", "# 2. Separate time, hour and minute\n", "# MAYBE 3. smaller units: int16 or int8 " ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "def get_minute(row, index):\n", " return row[index].time().minute\n", "\n", "def get_hour(row, index):\n", " return row[index].time().hour" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [], "source": [ "sleep_df_raw[\"stage_start_hour\"] = sleep_df_raw.apply (lambda row: get_hour(row, \"stage_start\"), axis=1)\n", "sleep_df_raw[\"stage_start_minute\"] = sleep_df_raw.apply (lambda row: get_minute(row, \"stage_start\"), axis=1)" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "<class 'pandas.core.frame.DataFrame'>\n", "RangeIndex: 551042 entries, 0 to 551041\n", "Data columns (total 13 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 sleep_id 551042 non-null int64 \n", " 1 sleep_begin 551042 non-null datetime64[ns, UTC]\n", " 2 stage_start 551042 non-null datetime64[ns, UTC]\n", " 3 time_since_begin_sec 551042 non-null int64 \n", " 4 stage_duration_sec 551042 non-null int64 \n", " 5 stage_end 551042 non-null datetime64[ns, UTC]\n", " 6 stage_value 551042 non-null int64 \n", " 7 awake_probability 551042 non-null float64 \n", " 8 light_probability 551042 non-null float64 \n", " 9 deep_probability 551042 non-null float64 \n", " 10 rem_probability 551042 non-null float64 \n", " 11 stage_start_hour 551042 non-null int64 \n", " 12 stage_start_minute 551042 non-null int64 \n", "dtypes: datetime64[ns, UTC](3), float64(4), int64(6)\n", "memory usage: 54.7 MB\n" ] } ], "source": [ "sleep_df_raw.info()" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/html": [ "<div>\n", "<style scoped>\n", " .dataframe tbody tr th:only-of-type {\n", " vertical-align: middle;\n", " }\n", "\n", " .dataframe tbody tr th {\n", " vertical-align: top;\n", " }\n", "\n", " .dataframe thead th {\n", " text-align: right;\n", " }\n", "</style>\n", "<table border=\"1\" class=\"dataframe\">\n", " <thead>\n", " <tr style=\"text-align: right;\">\n", " <th></th>\n", " <th>sleep_id</th>\n", " <th>sleep_begin</th>\n", " <th>stage_start</th>\n", " <th>time_since_begin_sec</th>\n", " <th>stage_duration_sec</th>\n", " <th>stage_end</th>\n", " <th>stage_value</th>\n", " <th>awake_probability</th>\n", " <th>light_probability</th>\n", " <th>deep_probability</th>\n", " <th>rem_probability</th>\n", " <th>stage_start_hour</th>\n", " <th>stage_start_minute</th>\n", " </tr>\n", " </thead>\n", " <tbody>\n", " <tr>\n", " <th>0</th>\n", " <td>0</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>0</td>\n", " <td>60</td>\n", " <td>2022-04-21 08:19:00+00:00</td>\n", " <td>0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8</td>\n", " <td>18</td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>0</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>2022-04-21 08:19:00+00:00</td>\n", " <td>60</td>\n", " <td>60</td>\n", " <td>2022-04-21 08:20:00+00:00</td>\n", " <td>0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8</td>\n", " <td>19</td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>0</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>2022-04-21 08:20:00+00:00</td>\n", " <td>120</td>\n", " <td>60</td>\n", " <td>2022-04-21 08:21:00+00:00</td>\n", " <td>0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8</td>\n", " <td>20</td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>0</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>2022-04-21 08:21:00+00:00</td>\n", " <td>180</td>\n", " <td>60</td>\n", " <td>2022-04-21 08:22:00+00:00</td>\n", " <td>0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8</td>\n", " <td>21</td>\n", " </tr>\n", " <tr>\n", " <th>4</th>\n", " <td>0</td>\n", " <td>2022-04-21 08:18:00+00:00</td>\n", " <td>2022-04-21 08:22:00+00:00</td>\n", " <td>240</td>\n", " <td>60</td>\n", " <td>2022-04-21 08:23:00+00:00</td>\n", " <td>0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8</td>\n", " <td>22</td>\n", " </tr>\n", " <tr>\n", " <th>...</th>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " </tr>\n", " <tr>\n", " <th>551037</th>\n", " <td>1132</td>\n", " <td>2019-02-11 06:11:00+00:00</td>\n", " <td>2019-02-11 13:17:00+00:00</td>\n", " <td>25560</td>\n", " <td>60</td>\n", " <td>2019-02-11 13:18:00+00:00</td>\n", " <td>1</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>13</td>\n", " <td>17</td>\n", " </tr>\n", " <tr>\n", " <th>551038</th>\n", " <td>1132</td>\n", " <td>2019-02-11 06:11:00+00:00</td>\n", " <td>2019-02-11 13:18:00+00:00</td>\n", " <td>25620</td>\n", " <td>60</td>\n", " <td>2019-02-11 13:19:00+00:00</td>\n", " <td>1</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>13</td>\n", " <td>18</td>\n", " </tr>\n", " <tr>\n", " <th>551039</th>\n", " <td>1132</td>\n", " <td>2019-02-11 06:11:00+00:00</td>\n", " <td>2019-02-11 13:19:00+00:00</td>\n", " <td>25680</td>\n", " <td>60</td>\n", " <td>2019-02-11 13:20:00+00:00</td>\n", " <td>1</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>13</td>\n", " <td>19</td>\n", " </tr>\n", " <tr>\n", " <th>551040</th>\n", " <td>1132</td>\n", " <td>2019-02-11 06:11:00+00:00</td>\n", " <td>2019-02-11 13:20:00+00:00</td>\n", " <td>25740</td>\n", " <td>60</td>\n", " <td>2019-02-11 13:21:00+00:00</td>\n", " <td>1</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>13</td>\n", " <td>20</td>\n", " </tr>\n", " <tr>\n", " <th>551041</th>\n", " <td>1132</td>\n", " <td>2019-02-11 06:11:00+00:00</td>\n", " <td>2019-02-11 13:21:00+00:00</td>\n", " <td>25800</td>\n", " <td>60</td>\n", " <td>2019-02-11 13:22:00+00:00</td>\n", " <td>1</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>13</td>\n", " <td>21</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", "<p>551042 rows × 13 columns</p>\n", "</div>" ], "text/plain": [ " sleep_id sleep_begin stage_start \\\n", "0 0 2022-04-21 08:18:00+00:00 2022-04-21 08:18:00+00:00 \n", "1 0 2022-04-21 08:18:00+00:00 2022-04-21 08:19:00+00:00 \n", "2 0 2022-04-21 08:18:00+00:00 2022-04-21 08:20:00+00:00 \n", "3 0 2022-04-21 08:18:00+00:00 2022-04-21 08:21:00+00:00 \n", "4 0 2022-04-21 08:18:00+00:00 2022-04-21 08:22:00+00:00 \n", "... ... ... ... \n", "551037 1132 2019-02-11 06:11:00+00:00 2019-02-11 13:17:00+00:00 \n", "551038 1132 2019-02-11 06:11:00+00:00 2019-02-11 13:18:00+00:00 \n", "551039 1132 2019-02-11 06:11:00+00:00 2019-02-11 13:19:00+00:00 \n", "551040 1132 2019-02-11 06:11:00+00:00 2019-02-11 13:20:00+00:00 \n", "551041 1132 2019-02-11 06:11:00+00:00 2019-02-11 13:21:00+00:00 \n", "\n", " time_since_begin_sec stage_duration_sec stage_end \\\n", "0 0 60 2022-04-21 08:19:00+00:00 \n", "1 60 60 2022-04-21 08:20:00+00:00 \n", "2 120 60 2022-04-21 08:21:00+00:00 \n", "3 180 60 2022-04-21 08:22:00+00:00 \n", "4 240 60 2022-04-21 08:23:00+00:00 \n", "... ... ... ... \n", "551037 25560 60 2019-02-11 13:18:00+00:00 \n", "551038 25620 60 2019-02-11 13:19:00+00:00 \n", "551039 25680 60 2019-02-11 13:20:00+00:00 \n", "551040 25740 60 2019-02-11 13:21:00+00:00 \n", "551041 25800 60 2019-02-11 13:22:00+00:00 \n", "\n", " stage_value awake_probability light_probability deep_probability \\\n", "0 0 1.0 0.0 0.0 \n", "1 0 1.0 0.0 0.0 \n", "2 0 1.0 0.0 0.0 \n", "3 0 1.0 0.0 0.0 \n", "4 0 1.0 0.0 0.0 \n", "... ... ... ... ... \n", "551037 1 0.0 1.0 0.0 \n", "551038 1 0.0 1.0 0.0 \n", "551039 1 0.0 1.0 0.0 \n", "551040 1 0.0 1.0 0.0 \n", "551041 1 0.0 1.0 0.0 \n", "\n", " rem_probability stage_start_hour stage_start_minute \n", "0 0.0 8 18 \n", "1 0.0 8 19 \n", "2 0.0 8 20 \n", "3 0.0 8 21 \n", "4 0.0 8 22 \n", "... ... ... ... \n", "551037 0.0 13 17 \n", "551038 0.0 13 18 \n", "551039 0.0 13 19 \n", "551040 0.0 13 20 \n", "551041 0.0 13 21 \n", "\n", "[551042 rows x 13 columns]" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sleep_df_raw" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "sleep_data = sleep_df_raw[[\"sleep_id\", \"stage_start_hour\", \"stage_start_minute\", \"awake_probability\", \"rem_probability\",\"light_probability\", \"deep_probability\"]]\n", "sleep_data.insert(loc=1, column=\"minutes_since_begin\" , value= sleep_df_raw[\"time_since_begin_sec\"]//60)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " sleep_id minutes_since_begin stage_start_hour stage_start_minute \\\n", "0 0 0 8 18 \n", "1 0 1 8 19 \n", "2 0 2 8 20 \n", "3 0 3 8 21 \n", "4 0 4 8 22 \n", "\n", " awake_probability rem_probability light_probability deep_probability \n", "0 1.0 0.0 0.0 0.0 \n", "1 1.0 0.0 0.0 0.0 \n", "2 1.0 0.0 0.0 0.0 \n", "3 1.0 0.0 0.0 0.0 \n", "4 1.0 0.0 0.0 0.0 \n", "<class 'pandas.core.frame.DataFrame'>\n", "RangeIndex: 551042 entries, 0 to 551041\n", "Data columns (total 8 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 sleep_id 551042 non-null int64 \n", " 1 minutes_since_begin 551042 non-null int64 \n", " 2 stage_start_hour 551042 non-null int64 \n", " 3 stage_start_minute 551042 non-null int64 \n", " 4 awake_probability 551042 non-null float64\n", " 5 rem_probability 551042 non-null float64\n", " 6 light_probability 551042 non-null float64\n", " 7 deep_probability 551042 non-null float64\n", "dtypes: float64(4), int64(4)\n", "memory usage: 33.6 MB\n", "None\n" ] } ], "source": [ "print(sleep_data.head())\n", "print(sleep_data.info())" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "sleep_data.to_csv(\".data/sleep_data_simple.csv\", index=False, index_label=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Model Development" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setup" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "TEST_SIZE = 365//2\n", "VALIDATION_SIZE = 365\n", "\n", "BATCH_SIZE = 64\n", "INPUT_TIME_STEP = 5 # in minutes\n", "INPUT_FEATURES_SIZE = 7\n", "MAX_EPOCHS = 20" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "SAMPLE_COUNT = 1000\n", "# A R L D\n", "# A\n", "# R\n", "# L\n", "# D\n", "CONFUSION_MATRIX = np.array(\n", " [\n", " [66.2, 5.0, 22.5, 6.2],\n", " [1.6, 60.7, 33.0, 4.7],\n", " [3.8, 22.3, 55.4, 18.5],\n", " [0.0, 1.3, 26.7, 72.0],\n", " ]\n", ")/100" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Import Data" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "# sleep_data = pd.read_csv(SLEEP_DATA_PATH)\n", "sleep_data = pd.read_csv(UPDATED_SLEEP_DATA_PATH)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "<div>\n", "<style scoped>\n", " .dataframe tbody tr th:only-of-type {\n", " vertical-align: middle;\n", " }\n", "\n", " .dataframe tbody tr th {\n", " vertical-align: top;\n", " }\n", "\n", " .dataframe thead th {\n", " text-align: right;\n", " }\n", "</style>\n", "<table border=\"1\" class=\"dataframe\">\n", " <thead>\n", " <tr style=\"text-align: right;\">\n", " <th></th>\n", " <th>sleep_id</th>\n", " <th>minutes_since_begin</th>\n", " <th>stage_start_hour</th>\n", " <th>stage_start_minute</th>\n", " <th>awake_probability_noisy</th>\n", " <th>rem_probability_noisy</th>\n", " <th>light_probability_noisy</th>\n", " <th>deep_probability_noisy</th>\n", " <th>awake_probability_original</th>\n", " <th>rem_probability_original</th>\n", " <th>light_probability_original</th>\n", " <th>deep_probability_original</th>\n", " </tr>\n", " </thead>\n", " <tbody>\n", " <tr>\n", " <th>0</th>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>8.0</td>\n", " <td>18.0</td>\n", " <td>0.680</td>\n", " <td>0.057</td>\n", " <td>0.200</td>\n", " <td>0.063</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>8.0</td>\n", " <td>19.0</td>\n", " <td>0.652</td>\n", " <td>0.060</td>\n", " <td>0.224</td>\n", " <td>0.064</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>0.0</td>\n", " <td>2.0</td>\n", " <td>8.0</td>\n", " <td>20.0</td>\n", " <td>0.672</td>\n", " <td>0.059</td>\n", " <td>0.209</td>\n", " <td>0.060</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>0.0</td>\n", " <td>3.0</td>\n", " <td>8.0</td>\n", " <td>21.0</td>\n", " <td>0.645</td>\n", " <td>0.056</td>\n", " <td>0.235</td>\n", " <td>0.064</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>4</th>\n", " <td>0.0</td>\n", " <td>4.0</td>\n", " <td>8.0</td>\n", " <td>22.0</td>\n", " <td>0.644</td>\n", " <td>0.054</td>\n", " <td>0.244</td>\n", " <td>0.058</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>...</th>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " <td>...</td>\n", " </tr>\n", " <tr>\n", " <th>551037</th>\n", " <td>1132.0</td>\n", " <td>426.0</td>\n", " <td>13.0</td>\n", " <td>17.0</td>\n", " <td>0.041</td>\n", " <td>0.193</td>\n", " <td>0.576</td>\n", " <td>0.190</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>551038</th>\n", " <td>1132.0</td>\n", " <td>427.0</td>\n", " <td>13.0</td>\n", " <td>18.0</td>\n", " <td>0.027</td>\n", " <td>0.209</td>\n", " <td>0.563</td>\n", " <td>0.201</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>551039</th>\n", " <td>1132.0</td>\n", " <td>428.0</td>\n", " <td>13.0</td>\n", " <td>19.0</td>\n", " <td>0.032</td>\n", " <td>0.220</td>\n", " <td>0.574</td>\n", " <td>0.174</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>551040</th>\n", " <td>1132.0</td>\n", " <td>429.0</td>\n", " <td>13.0</td>\n", " <td>20.0</td>\n", " <td>0.036</td>\n", " <td>0.256</td>\n", " <td>0.530</td>\n", " <td>0.178</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " <tr>\n", " <th>551041</th>\n", " <td>1132.0</td>\n", " <td>430.0</td>\n", " <td>13.0</td>\n", " <td>21.0</td>\n", " <td>0.033</td>\n", " <td>0.205</td>\n", " <td>0.571</td>\n", " <td>0.191</td>\n", " <td>0.0</td>\n", " <td>0.0</td>\n", " <td>1.0</td>\n", " <td>0.0</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", "<p>551042 rows × 12 columns</p>\n", "</div>" ], "text/plain": [ " sleep_id minutes_since_begin stage_start_hour stage_start_minute \\\n", "0 0.0 0.0 8.0 18.0 \n", "1 0.0 1.0 8.0 19.0 \n", "2 0.0 2.0 8.0 20.0 \n", "3 0.0 3.0 8.0 21.0 \n", "4 0.0 4.0 8.0 22.0 \n", "... ... ... ... ... \n", "551037 1132.0 426.0 13.0 17.0 \n", "551038 1132.0 427.0 13.0 18.0 \n", "551039 1132.0 428.0 13.0 19.0 \n", "551040 1132.0 429.0 13.0 20.0 \n", "551041 1132.0 430.0 13.0 21.0 \n", "\n", " awake_probability_noisy rem_probability_noisy \\\n", "0 0.680 0.057 \n", "1 0.652 0.060 \n", "2 0.672 0.059 \n", "3 0.645 0.056 \n", "4 0.644 0.054 \n", "... ... ... \n", "551037 0.041 0.193 \n", "551038 0.027 0.209 \n", "551039 0.032 0.220 \n", "551040 0.036 0.256 \n", "551041 0.033 0.205 \n", "\n", " light_probability_noisy deep_probability_noisy \\\n", "0 0.200 0.063 \n", "1 0.224 0.064 \n", "2 0.209 0.060 \n", "3 0.235 0.064 \n", "4 0.244 0.058 \n", "... ... ... \n", "551037 0.576 0.190 \n", "551038 0.563 0.201 \n", "551039 0.574 0.174 \n", "551040 0.530 0.178 \n", "551041 0.571 0.191 \n", "\n", " awake_probability_original rem_probability_original \\\n", "0 1.0 0.0 \n", "1 1.0 0.0 \n", "2 1.0 0.0 \n", "3 1.0 0.0 \n", "4 1.0 0.0 \n", "... ... ... \n", "551037 0.0 0.0 \n", "551038 0.0 0.0 \n", "551039 0.0 0.0 \n", "551040 0.0 0.0 \n", "551041 0.0 0.0 \n", "\n", " light_probability_original deep_probability_original \n", "0 0.0 0.0 \n", "1 0.0 0.0 \n", "2 0.0 0.0 \n", "3 0.0 0.0 \n", "4 0.0 0.0 \n", "... ... ... \n", "551037 1.0 0.0 \n", "551038 1.0 0.0 \n", "551039 1.0 0.0 \n", "551040 1.0 0.0 \n", "551041 1.0 0.0 \n", "\n", "[551042 rows x 12 columns]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sleep_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create Randmonizations" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "def softmax(arr):\n", " val = np.exp(arr)\n", " return val / sum(val)" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [], "source": [ "def noisy_randomizer(confusion_matrix_index: int, sample_count: int = SAMPLE_COUNT, confusion_matrix = CONFUSION_MATRIX):\n", " return np.random.multinomial(sample_count, confusion_matrix[confusion_matrix_index], size=1)[0]/sample_count" ] }, { "cell_type": "code", "execution_count": 173, "metadata": {}, "outputs": [], "source": [ "def create_updated(dataframe):\n", " dataframe_array = dataframe.to_numpy()\n", " updated_probs = np.array(list(map(noisy_randomizer, np.argmax(dataframe_array[:, -4:], axis=1))))\n", " columns_tmp = dataframe.columns.to_list() \n", " noisy_column = list(map(lambda name: f\"{name}_noisy\", columns_tmp[-4:]))\n", " og_column = list(map(lambda name: f\"{name}_original\", columns_tmp[-4:]))\n", " return pd.DataFrame(np.concatenate([dataframe_array[:, :-4], updated_probs, dataframe_array[:, -4:]], axis=1), columns = columns_tmp[:-4]+noisy_column+og_column)" ] }, { "cell_type": "code", "execution_count": 174, "metadata": {}, "outputs": [], "source": [ "sleep_data_updated = create_updated(sleep_data)" ] }, { "cell_type": "code", "execution_count": 176, "metadata": {}, "outputs": [], "source": [ "sleep_data_updated.to_csv(UPDATED_SLEEP_DATA_PATH, index=False, index_label=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Helper functions and class" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def training_test_split_by_unique_index(data, index: str, test_size: int = 10):\n", " test_ids = np.random.choice(data[index].unique(), size = test_size, replace=False)\n", " return data[~data[index].isin(test_ids)], data[data[index].isin(test_ids)]" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# Adapted from https://www.tensorflow.org/tutorials/structured_data/time_series\n", "class WindowGenerator():\n", " def __init__(self, data, index: str = \"sleep_id\", input_width: int = INPUT_TIME_STEP, validation_size: int = VALIDATION_SIZE, test_size: int = TEST_SIZE, input_feature_slice: slice = slice(1,-4), label_feature_slice: slice = slice(-4,100), generate_data_now: bool = True):\n", " # Partition data\n", " self.training, self.testing = training_test_split_by_unique_index(data, index, test_size)\n", " self.training, self.validation = training_test_split_by_unique_index(self.training, index, validation_size)\n", "\n", " # Window paramters\n", " self.input_width = input_width\n", " self.label_width = 1\n", " self.shift = 1\n", "\n", " self.total_window_size = self.input_width + self.shift\n", "\n", " self.input_slice = slice(0, input_width)\n", " self.input_indices = np.arange(self.total_window_size)[self.input_slice]\n", "\n", " self.label_start = self.total_window_size - self.label_width\n", " self.labels_slice = slice(self.label_start, None)\n", " self.label_indices = np.arange(self.total_window_size)[self.labels_slice]\n", "\n", " self.input_feature_slice = input_feature_slice\n", " self.label_feature_slice = label_feature_slice\n", "\n", " self.sample_ds = self.make_dataset(data[data[index] == 0])\n", "\n", " if generate_data_now:\n", " self.training_ds = self.make_dataset(self.training, index)\n", " self.validation_ds = self.make_dataset(self.validation, index)\n", " self.testing_ds = self.make_dataset(self.testing, index)\n", "\n", "\n", " def __repr__(self):\n", " return \"WindowGenerator:\\n\\t\" +'\\n\\t'.join([\n", " f'Total window size: {self.total_window_size}',\n", " f'Input indices: {self.input_indices}',\n", " f'Label indices: {self.label_indices}',\n", " ])\n", "\n", " def split_window(self, features):\n", " inputs = features[:, self.input_slice, self.input_feature_slice]\n", " inputs.set_shape([None, self.input_width, None])\n", " \n", " labels = tf.squeeze(features[:, self.labels_slice, self.label_feature_slice])\n", " # labels.set_shape([None, self.label_width, None])\n", " return inputs, labels\n", "\n", " def make_dataset(self, data, index_group: str = \"sleep_id\", sort_by: str = \"minutes_since_begin\"):\n", " ds_all = None\n", " for i_group in data[index_group].unique():\n", " subset_data = np.array(data[data[index_group] == i_group].sort_values(by=[sort_by]), dtype=np.float32)\n", " ds = tf.keras.utils.timeseries_dataset_from_array(\n", " data=subset_data,\n", " targets=None,\n", " sequence_length=self.total_window_size,\n", " sequence_stride=1,\n", " shuffle=False,\n", " batch_size=BATCH_SIZE,)\n", " ds_all = ds if ds_all is None else ds_all.concatenate(ds)\n", " ds_all = ds_all.map(self.split_window)\n", "\n", " return ds_all" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### General Model Helper" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# Adapted from https://www.tensorflow.org/tutorials/structured_data/time_series#linear_model\n", "def compile_and_fit(model, window: WindowGenerator, loss = tf.losses.CategoricalCrossentropy(from_logits=True), optimizer = tf.optimizers.Adam(), metrics = None, early_stop: bool = True, patience:int = 2, baseline = None, epochs: int = MAX_EPOCHS):\n", " if metrics is None:\n", " metrics = [tf.keras.metrics.CategoricalCrossentropy(from_logits=True), tf.keras.metrics.CategoricalAccuracy(), tf.keras.metrics.CategoricalHinge()]\n", "\n", " callbacks = []\n", " if early_stop:\n", " early_stopping = tf.keras.callbacks.EarlyStopping(\n", " monitor='val_loss',\n", " patience=patience,\n", " baseline = baseline,\n", " mode='min'\n", " )\n", " callbacks.append(early_stopping)\n", "\n", " model.compile(\n", " loss=loss,\n", " optimizer=optimizer,\n", " metrics=metrics,\n", " )\n", "\n", " return model.fit(window.training_ds, epochs=epochs, validation_data=window.validation_ds, callbacks=callbacks)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Experimenting" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# USE SUBSET OF DATA FOR EXPERIMENTING\n", "sleep_data_sub = sleep_data[sleep_data.sleep_id < 3]" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "wg_sub = WindowGenerator(sleep_data_sub,validation_size=1, test_size=1)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ele[0][0] = array([[ 0., 7., 40., 1., 0., 0., 0.],\n", " [ 1., 7., 41., 1., 0., 0., 0.],\n", " [ 2., 7., 42., 1., 0., 0., 0.],\n", " [ 3., 7., 43., 1., 0., 0., 0.],\n", " [ 4., 7., 44., 1., 0., 0., 0.],\n", " [ 5., 7., 45., 1., 0., 0., 0.],\n", " [ 6., 7., 46., 1., 0., 0., 0.],\n", " [ 7., 7., 47., 1., 0., 0., 0.],\n", " [ 8., 7., 48., 1., 0., 0., 0.],\n", " [ 9., 7., 49., 1., 0., 0., 0.]], dtype=float32)\n", "ele[0][0] = array([[64., 8., 44., 0., 0., 1., 0.],\n", " [65., 8., 45., 0., 0., 1., 0.],\n", " [66., 8., 46., 0., 0., 1., 0.],\n", " [67., 8., 47., 0., 0., 1., 0.],\n", " [68., 8., 48., 0., 0., 1., 0.],\n", " [69., 8., 49., 0., 0., 1., 0.],\n", " [70., 8., 50., 0., 0., 1., 0.],\n", " [71., 8., 51., 0., 0., 1., 0.],\n", " [72., 8., 52., 0., 0., 1., 0.],\n", " [73., 8., 53., 0., 0., 1., 0.]], dtype=float32)\n", "ele[0][0] = array([[128., 9., 48., 0., 0., 1., 0.],\n", " [129., 9., 49., 0., 0., 1., 0.],\n", " [130., 9., 50., 0., 0., 1., 0.],\n", " [131., 9., 51., 0., 0., 1., 0.],\n", " [132., 9., 52., 0., 0., 0., 1.],\n", " [133., 9., 53., 0., 0., 0., 1.],\n", " [134., 9., 54., 0., 0., 0., 1.],\n", " [135., 9., 55., 0., 0., 0., 1.],\n", " [136., 9., 56., 0., 0., 0., 1.],\n", " [137., 9., 57., 0., 0., 0., 1.]], dtype=float32)\n", "ele[0][0] = array([[192., 10., 52., 0., 1., 0., 0.],\n", " [193., 10., 53., 0., 1., 0., 0.],\n", " [194., 10., 54., 0., 1., 0., 0.],\n", " [195., 10., 55., 0., 1., 0., 0.],\n", " [196., 10., 56., 0., 1., 0., 0.],\n", " [197., 10., 57., 0., 1., 0., 0.],\n", " [198., 10., 58., 0., 1., 0., 0.],\n", " [199., 10., 59., 0., 1., 0., 0.],\n", " [200., 11., 0., 0., 1., 0., 0.],\n", " [201., 11., 1., 0., 1., 0., 0.]], dtype=float32)\n", "ele[0][0] = array([[256., 11., 56., 0., 0., 1., 0.],\n", " [257., 11., 57., 0., 0., 1., 0.],\n", " [258., 11., 58., 0., 0., 1., 0.],\n", " [259., 11., 59., 0., 0., 1., 0.],\n", " [260., 12., 0., 0., 0., 1., 0.],\n", " [261., 12., 1., 0., 0., 1., 0.],\n", " [262., 12., 2., 0., 0., 1., 0.],\n", " [263., 12., 3., 0., 0., 1., 0.],\n", " [264., 12., 4., 0., 0., 1., 0.],\n", " [265., 12., 5., 0., 0., 1., 0.]], dtype=float32)\n", "ele[0][0] = array([[320., 13., 0., 0., 1., 0., 0.],\n", " [321., 13., 1., 0., 1., 0., 0.],\n", " [322., 13., 2., 0., 1., 0., 0.],\n", " [323., 13., 3., 0., 1., 0., 0.],\n", " [324., 13., 4., 0., 1., 0., 0.],\n", " [325., 13., 5., 0., 1., 0., 0.],\n", " [326., 13., 6., 0., 1., 0., 0.],\n", " [327., 13., 7., 0., 1., 0., 0.],\n", " [328., 13., 8., 0., 1., 0., 0.],\n", " [329., 13., 9., 0., 1., 0., 0.]], dtype=float32)\n", "ele[0][0] = array([[384., 14., 4., 0., 0., 0., 1.],\n", " [385., 14., 5., 0., 0., 0., 1.],\n", " [386., 14., 6., 0., 0., 0., 1.],\n", " [387., 14., 7., 0., 0., 0., 1.],\n", " [388., 14., 8., 0., 0., 0., 1.],\n", " [389., 14., 9., 0., 0., 0., 1.],\n", " [390., 14., 10., 0., 0., 0., 1.],\n", " [391., 14., 11., 0., 0., 0., 1.],\n", " [392., 14., 12., 0., 0., 0., 1.],\n", " [393., 14., 13., 0., 0., 0., 1.]], dtype=float32)\n", "ele[0][0] = array([[448., 15., 8., 0., 1., 0., 0.],\n", " [449., 15., 9., 0., 1., 0., 0.],\n", " [450., 15., 10., 0., 1., 0., 0.],\n", " [451., 15., 11., 0., 1., 0., 0.],\n", " [452., 15., 12., 0., 1., 0., 0.],\n", " [453., 15., 13., 0., 1., 0., 0.],\n", " [454., 15., 14., 0., 1., 0., 0.],\n", " [455., 15., 15., 0., 1., 0., 0.],\n", " [456., 15., 16., 0., 1., 0., 0.],\n", " [457., 15., 17., 0., 1., 0., 0.]], dtype=float32)\n" ] } ], "source": [ "for ele in wg_sub.training_ds.as_numpy_iterator():\n", " print(f\"{ele[0][0] = }\")" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_2\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " dense_4 (Dense) (None, 10, 16) 128 \n", " \n", " flatten_2 (Flatten) (None, 160) 0 \n", " \n", " dense_5 (Dense) (None, 4) 644 \n", " \n", "=================================================================\n", "Total params: 772\n", "Trainable params: 772\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "None\n" ] } ], "source": [ "BASELINE_UNITS = 16\n", "baseline_model = keras.Sequential(\n", " [\n", " layers.Input(shape=(INPUT_TIME_STEP, INPUT_FEATURES_SIZE)),\n", " layers.Dense(BASELINE_UNITS),\n", " # layers.Dense(BASELINE_UNITS),\n", " # layers.Dense(BASELINE_UNITS),\n", " layers.Flatten(),\n", " layers.Dense(SLEEP_STAGES),\n", " ]\n", ")\n", "baseline_model.build()\n", "print(baseline_model.summary())" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/20\n", "8955/8955 [==============================] - 60s 7ms/step - loss: 2.7762 - categorical_crossentropy: 2.7745 - categorical_accuracy: 0.7612 - categorical_hinge: 15.1798 - val_loss: 0.2711 - val_categorical_crossentropy: 0.2710 - val_categorical_accuracy: 0.9546 - val_categorical_hinge: 5.1404\n", "Epoch 2/20\n", "8955/8955 [==============================] - 60s 7ms/step - loss: 0.3110 - categorical_crossentropy: 0.3111 - categorical_accuracy: 0.9418 - categorical_hinge: 1.5468 - val_loss: 0.2106 - val_categorical_crossentropy: 0.2105 - val_categorical_accuracy: 0.9583 - val_categorical_hinge: 0.3215\n", "Epoch 3/20\n", "8955/8955 [==============================] - 60s 7ms/step - loss: 0.2253 - categorical_crossentropy: 0.2254 - categorical_accuracy: 0.9551 - categorical_hinge: 0.2726 - val_loss: 0.2068 - val_categorical_crossentropy: 0.2067 - val_categorical_accuracy: 0.9582 - val_categorical_hinge: 0.3656\n", "Epoch 4/20\n", "8955/8955 [==============================] - 63s 7ms/step - loss: 0.2059 - categorical_crossentropy: 0.2059 - categorical_accuracy: 0.9582 - categorical_hinge: 0.2735 - val_loss: 0.1957 - val_categorical_crossentropy: 0.1957 - val_categorical_accuracy: 0.9591 - val_categorical_hinge: 0.3622\n", "Epoch 5/20\n", "8955/8955 [==============================] - 82s 9ms/step - loss: 0.2016 - categorical_crossentropy: 0.2016 - categorical_accuracy: 0.9587 - categorical_hinge: 0.2638 - val_loss: 0.1970 - val_categorical_crossentropy: 0.1970 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2868\n", "Epoch 6/20\n", "8955/8955 [==============================] - 72s 8ms/step - loss: 0.1995 - categorical_crossentropy: 0.1995 - categorical_accuracy: 0.9585 - categorical_hinge: 0.2506 - val_loss: 0.1973 - val_categorical_crossentropy: 0.1973 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.3453\n", "Epoch 7/20\n", "8955/8955 [==============================] - 75s 8ms/step - loss: 0.1991 - categorical_crossentropy: 0.1992 - categorical_accuracy: 0.9591 - categorical_hinge: 0.2518 - val_loss: 0.1969 - val_categorical_crossentropy: 0.1968 - val_categorical_accuracy: 0.9591 - val_categorical_hinge: 0.2474\n", "Epoch 8/20\n", "8955/8955 [==============================] - 75s 8ms/step - loss: 0.1983 - categorical_crossentropy: 0.1983 - categorical_accuracy: 0.9587 - categorical_hinge: 0.2560 - val_loss: 0.1957 - val_categorical_crossentropy: 0.1956 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2912\n", "Epoch 9/20\n", "8955/8955 [==============================] - 76s 8ms/step - loss: 0.1965 - categorical_crossentropy: 0.1965 - categorical_accuracy: 0.9595 - categorical_hinge: 0.2328 - val_loss: 0.1957 - val_categorical_crossentropy: 0.1957 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.3268\n", "Epoch 10/20\n", "8955/8955 [==============================] - 77s 9ms/step - loss: 0.1961 - categorical_crossentropy: 0.1961 - categorical_accuracy: 0.9598 - categorical_hinge: 0.2375 - val_loss: 0.1954 - val_categorical_crossentropy: 0.1954 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2518\n", "Epoch 11/20\n", "8955/8955 [==============================] - 72s 8ms/step - loss: 0.1980 - categorical_crossentropy: 0.1981 - categorical_accuracy: 0.9584 - categorical_hinge: 0.2387 - val_loss: 0.1948 - val_categorical_crossentropy: 0.1948 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2795\n", "Epoch 12/20\n", "8955/8955 [==============================] - 69s 8ms/step - loss: 0.1959 - categorical_crossentropy: 0.1959 - categorical_accuracy: 0.9594 - categorical_hinge: 0.2465 - val_loss: 0.1950 - val_categorical_crossentropy: 0.1950 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2824\n", "Epoch 13/20\n", "8955/8955 [==============================] - 65s 7ms/step - loss: 0.1960 - categorical_crossentropy: 0.1960 - categorical_accuracy: 0.9596 - categorical_hinge: 0.2413 - val_loss: 0.1955 - val_categorical_crossentropy: 0.1954 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.3859\n", "Epoch 14/20\n", "8955/8955 [==============================] - 68s 8ms/step - loss: 0.1959 - categorical_crossentropy: 0.1959 - categorical_accuracy: 0.9591 - categorical_hinge: 0.2280 - val_loss: 0.1941 - val_categorical_crossentropy: 0.1941 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.3046\n", "Epoch 15/20\n", "8955/8955 [==============================] - 77s 9ms/step - loss: 0.2031 - categorical_crossentropy: 0.2031 - categorical_accuracy: 0.9580 - categorical_hinge: 0.2336 - val_loss: 0.1949 - val_categorical_crossentropy: 0.1948 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.1873\n", "Epoch 16/20\n", "8955/8955 [==============================] - 68s 8ms/step - loss: 0.1966 - categorical_crossentropy: 0.1966 - categorical_accuracy: 0.9589 - categorical_hinge: 0.2361 - val_loss: 0.1938 - val_categorical_crossentropy: 0.1938 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2056\n", "Epoch 17/20\n", "8955/8955 [==============================] - 67s 7ms/step - loss: 0.1924 - categorical_crossentropy: 0.1924 - categorical_accuracy: 0.9599 - categorical_hinge: 0.2510 - val_loss: 0.1934 - val_categorical_crossentropy: 0.1934 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.3111\n", "Epoch 18/20\n", "8955/8955 [==============================] - 67s 7ms/step - loss: 0.2079 - categorical_crossentropy: 0.2079 - categorical_accuracy: 0.9569 - categorical_hinge: 0.3273 - val_loss: 0.1930 - val_categorical_crossentropy: 0.1929 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.2956\n", "Epoch 19/20\n", "8955/8955 [==============================] - 67s 7ms/step - loss: 0.1923 - categorical_crossentropy: 0.1923 - categorical_accuracy: 0.9599 - categorical_hinge: 0.3248 - val_loss: 0.1924 - val_categorical_crossentropy: 0.1924 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.6417\n", "Epoch 20/20\n", "8955/8955 [==============================] - 68s 8ms/step - loss: 0.1950 - categorical_crossentropy: 0.1950 - categorical_accuracy: 0.9595 - categorical_hinge: 0.3199 - val_loss: 0.1935 - val_categorical_crossentropy: 0.1935 - val_categorical_accuracy: 0.9592 - val_categorical_hinge: 0.5098\n" ] } ], "source": [ "baseline_history = compile_and_fit(baseline_model, wg_sub)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys(['loss', 'categorical_crossentropy', 'categorical_accuracy', 'categorical_hinge', 'val_loss', 'val_categorical_crossentropy', 'val_categorical_accuracy', 'val_categorical_hinge'])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "baseline_history.history.keys()" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "save_history(baseline_history.history, \".history/baseline.csv\")" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "def save_history(history, file_name: str = \"history.csv\"):\n", " pd.DataFrame.from_dict(history).to_csv(file_name, index=False)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-05-11 15:02:03.185843: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: .model/baseline/assets\n" ] } ], "source": [ "baseline_model.save(\".model/baseline\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data Prep\n", "\n", "All inputs follow: (batch_size, timesteps, input_dim)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-05-12 14:18:02.248350: I tensorflow/core/platform/cpu_feature_guard.cc:151] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n" ] }, { "data": { "text/plain": [ "WindowGenerator:\n", "\tTotal window size: 6\n", "\tInput indices: [0 1 2 3 4]\n", "\tLabel indices: [5]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wg = WindowGenerator(sleep_data)\n", "wg" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4682" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(wg.training_ds)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ele[0].numpy()[0] = array([[ 0. , 8. , 18. , 0.68 , 0.057, 0.2 , 0.063],\n", " [ 1. , 8. , 19. , 0.652, 0.06 , 0.224, 0.064],\n", " [ 2. , 8. , 20. , 0.672, 0.059, 0.209, 0.06 ],\n", " [ 3. , 8. , 21. , 0.645, 0.056, 0.235, 0.064],\n", " [ 4. , 8. , 22. , 0.644, 0.054, 0.244, 0.058]],\n", " dtype=float32)\n", "ele[1].numpy()[0] = array([1., 0., 0., 0.], dtype=float32)\n" ] } ], "source": [ "for ele in wg.sample_ds.take(1):\n", " print(f\"{ele[0].numpy()[0] = }\")\n", " print(f\"{ele[1].numpy()[0] = }\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model 1: LSTM" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "# Hyper-parameters\n", "LSTM_UNITS = 8\n", "LSTM_LEARNING_RATE = 0.0001" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_2\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " lstm (LSTM) (None, 8) 512 \n", " \n", " dense_2 (Dense) (None, 4) 36 \n", " \n", "=================================================================\n", "Total params: 548\n", "Trainable params: 548\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "None\n" ] } ], "source": [ "# Model Definition\n", "lstm_model = keras.Sequential()\n", "lstm_model.add(layers.Input(shape=(INPUT_TIME_STEP, INPUT_FEATURES_SIZE)))\n", "# lstm_model.add(layers.LSTM(LSTM_UNITS, stateful=False, return_sequences=True))\n", "# lstm_model.add(layers.LSTM(LSTM_UNITS, stateful=False, return_sequences=True))\n", "lstm_model.add(layers.LSTM(LSTM_UNITS, stateful=False, return_sequences=False))\n", "lstm_model.add(layers.Dense(SLEEP_STAGES))\n", "lstm_model.build()\n", "print(lstm_model.summary())" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "# Model Training\n", "lstm_loss = tf.losses.CategoricalCrossentropy(from_logits=True)\n", "lstm_optm = tf.optimizers.Adam(learning_rate=LSTM_LEARNING_RATE)\n", "lstm_metrics = [tf.keras.metrics.CategoricalCrossentropy(from_logits=True), tf.keras.metrics.BinaryCrossentropy(from_logits=True),tf.keras.metrics.Accuracy()]" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9647/9647 [==============================] - 88s 9ms/step - loss: 0.6389 - categorical_crossentropy: 0.6388 - categorical_accuracy: 0.7669 - categorical_hinge: 0.5620 - val_loss: 0.2218 - val_categorical_crossentropy: 0.2217 - val_categorical_accuracy: 0.9551 - val_categorical_hinge: 0.2163\n" ] } ], "source": [ "lstm_history = compile_and_fit(model=lstm_model, window=wg, epochs=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model 2: GRU" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "# Hyper-paramters\n", "GRU_UNITS = 16" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_1\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " gru (GRU) (None, 16) 1200 \n", " \n", " dense_1 (Dense) (None, 4) 68 \n", " \n", "=================================================================\n", "Total params: 1,268\n", "Trainable params: 1,268\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "None\n" ] } ], "source": [ "gru_model = keras.Sequential()\n", "gru_model.add(layers.Input(shape=(INPUT_TIME_STEP, INPUT_FEATURES_SIZE)))\n", "gru_model.add(layers.GRU(GRU_UNITS))\n", "gru_model.add(layers.Dense(SLEEP_STAGES))\n", "gru_model.build()\n", "print(gru_model.summary())" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9647/9647 [==============================] - 97s 10ms/step - loss: 0.4700 - categorical_crossentropy: 0.4700 - categorical_accuracy: 0.8416 - categorical_hinge: 0.4278 - val_loss: 0.2088 - val_categorical_crossentropy: 0.2087 - val_categorical_accuracy: 0.9595 - val_categorical_hinge: 0.1954\n" ] } ], "source": [ "gru_history = compile_and_fit(model=gru_model, window=wg, epochs=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model 3: Attention Mechanism" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "ATTENTION_UNITS = 32" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " custom_attention (CustomAtt (None, 32) 497 \n", " ention) \n", " \n", " dense (Dense) (None, 4) 132 \n", " \n", "=================================================================\n", "Total params: 629\n", "Trainable params: 629\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "None\n" ] } ], "source": [ "am_model = keras.Sequential()\n", "am_model.add(layers.Input(shape=(INPUT_TIME_STEP, INPUT_FEATURES_SIZE)))\n", "am_model.add(CustomAttention(ATTENTION_UNITS))\n", "am_model.add(layers.Dense(SLEEP_STAGES))\n", "am_model.build()\n", "print(am_model.summary())" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x12aaebe50>" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "am_model.load_weights(\"TEST\")" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "am_history = compile_and_fit(model=am_model, window=wg, epochs=0)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1442/1442 [==============================] - 14s 4ms/step - loss: 0.1957 - categorical_crossentropy: 0.1957 - categorical_accuracy: 0.9598 - categorical_hinge: 0.1911\n" ] }, { "data": { "text/plain": [ "[0.19572481513023376,\n", " 0.19574123620986938,\n", " 0.9597873687744141,\n", " 0.1910863220691681]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "am_model.evaluate(wg.testing_ds)" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0.59796184, -0.20803624, -0.2916372 , -0.7170148 ]],\n", " dtype=float32)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "answer = am_model.predict(np.array(\n", " [[\n", " [ 150., 10., 20., 0.5, 0.1, 0., 0.4],\n", " [ 151., 10., 21., 0.5, 0.2, 0., 0.3],\n", " [ 152., 10., 22., 0.5, 0.3, 0., 0.2],\n", " [ 153., 10., 23., 0.5, 0.4, 0., 0.1],\n", " [ 154., 10., 24., 0.2, 0.1, 0., 0.],\n", " [ 155., 10., 25., 0.2, 0.2, 0., 0.],\n", " [ 156., 10., 26., 0.2, 0.2, 0.1, 0.],\n", " [ 157., 10., 27., 0.2, 0.25, 0.15, 0.],\n", " [ 158., 10., 28., 0.2, 0.3, 0.2, 0.],\n", " [ 159., 10., 29., 0.2, 0.3, 0.3, 0.]\n", " ]]\n", "))\n", "norm = np.linalg.norm(answer)\n", "normalized_answer = answer/norm\n", "normalized_answer" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "pd.DataFrame.from_dict(am_history.history).to_csv(f\"{HISTORY_DIR}/am_220512.csv\", index=False)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on method save_weights in module keras.engine.training:\n", "\n", "save_weights(filepath, overwrite=True, save_format=None, options=None) method of keras.engine.sequential.Sequential instance\n", " Saves all layer weights.\n", " \n", " Either saves in HDF5 or in TensorFlow format based on the `save_format`\n", " argument.\n", " \n", " When saving in HDF5 format, the weight file has:\n", " - `layer_names` (attribute), a list of strings\n", " (ordered names of model layers).\n", " - For every layer, a `group` named `layer.name`\n", " - For every such layer group, a group attribute `weight_names`,\n", " a list of strings\n", " (ordered names of weights tensor of the layer).\n", " - For every weight in the layer, a dataset\n", " storing the weight value, named after the weight tensor.\n", " \n", " When saving in TensorFlow format, all objects referenced by the network are\n", " saved in the same format as `tf.train.Checkpoint`, including any `Layer`\n", " instances or `Optimizer` instances assigned to object attributes. For\n", " networks constructed from inputs and outputs using `tf.keras.Model(inputs,\n", " outputs)`, `Layer` instances used by the network are tracked/saved\n", " automatically. For user-defined classes which inherit from `tf.keras.Model`,\n", " `Layer` instances must be assigned to object attributes, typically in the\n", " constructor. See the documentation of `tf.train.Checkpoint` and\n", " `tf.keras.Model` for details.\n", " \n", " While the formats are the same, do not mix `save_weights` and\n", " `tf.train.Checkpoint`. Checkpoints saved by `Model.save_weights` should be\n", " loaded using `Model.load_weights`. Checkpoints saved using\n", " `tf.train.Checkpoint.save` should be restored using the corresponding\n", " `tf.train.Checkpoint.restore`. Prefer `tf.train.Checkpoint` over\n", " `save_weights` for training checkpoints.\n", " \n", " The TensorFlow format matches objects and variables by starting at a root\n", " object, `self` for `save_weights`, and greedily matching attribute\n", " names. For `Model.save` this is the `Model`, and for `Checkpoint.save` this\n", " is the `Checkpoint` even if the `Checkpoint` has a model attached. This\n", " means saving a `tf.keras.Model` using `save_weights` and loading into a\n", " `tf.train.Checkpoint` with a `Model` attached (or vice versa) will not match\n", " the `Model`'s variables. See the\n", " [guide to training checkpoints](https://www.tensorflow.org/guide/checkpoint)\n", " for details on the TensorFlow format.\n", " \n", " Args:\n", " filepath: String or PathLike, path to the file to save the weights to.\n", " When saving in TensorFlow format, this is the prefix used for\n", " checkpoint files (multiple files are generated). Note that the '.h5'\n", " suffix causes weights to be saved in HDF5 format.\n", " overwrite: Whether to silently overwrite any existing file at the\n", " target location, or provide the user with a manual prompt.\n", " save_format: Either 'tf' or 'h5'. A `filepath` ending in '.h5' or\n", " '.keras' will default to HDF5 if `save_format` is `None`. Otherwise\n", " `None` defaults to 'tf'.\n", " options: Optional `tf.train.CheckpointOptions` object that specifies\n", " options for saving weights.\n", " \n", " Raises:\n", " ImportError: If `h5py` is not available when attempting to save in HDF5\n", " format.\n", "\n" ] } ], "source": [ "help(am_model.save_weights)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-05-12 12:12:02.267722: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.\n", "WARNING:absl:Found untraced functions such as attention_score_vec_layer_call_fn, attention_score_vec_layer_call_and_return_conditional_losses, last_hidden_state_layer_call_fn, last_hidden_state_layer_call_and_return_conditional_losses, attention_score_layer_call_fn while saving (showing 5 of 14). These functions will not be directly callable after loading.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: .model/attention/assets\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: .model/attention/assets\n" ] } ], "source": [ "am_model.save(f\"{MODEL_DIR}/attention\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model Head-to-Head testing" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "HISTORY_DIR = \".history\"\n", "MODEL_DIR = \".model\"" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "base_history = pd.read_csv(f\"{HISTORY_DIR}/baseline.csv\")\n", "lstm_history = pd.read_csv(f\"{HISTORY_DIR}/lstm.csv\")\n", "gru_history = pd.read_csv(f\"{HISTORY_DIR}/gru.csv\")\n", "attn_history = pd.read_csv(f\"{HISTORY_DIR}/attention.csv\")\n", "history_columns = [\"categorical_crossentropy\", \"val_categorical_crossentropy\"] # \"categorical_accuracy\"" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "<AxesSubplot:>" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAD4CAYAAAAJmJb0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAAsTAAALEwEAmpwYAAAwOklEQVR4nO3deXxU5fX48c+ZyUbYQyJrAqIUZQ2yCcoiVnGh4MLiCgiUUnHv9+vyxYW29tW6FK3LD0RZRFERENQWW7VCkSpoQHYQAQHZQ1jDlmXO7487iUOYkEkyyWRmzvv1GnKXZ+49ubmcufPMM+eKqmKMMSYyuUIdgDHGmIpjSd4YYyKYJXljjIlgluSNMSaCWZI3xpgIFhOqHScnJ2uzZs1CtXtjjAlLy5cvP6CqKYG2D1mSb9asGRkZGaHavTHGhCUR2V6a9tZdY4wxEcySvDHGRDBL8sYYE8FC1idvTLDl5uayc+dOTp06FepQjCm3hIQEmjRpQmxsbLm2Y0neRIydO3dSs2ZNmjVrhoiEOhxjykxVycrKYufOnZx//vnl2pZ115iIcerUKerVq2cJ3oQ9EaFevXpBeVdqSd5EFEvwJlIE61wOuyS/ce9RnvnnRo6czA11KMYYU+WFXZLfkXWCiYu2sO3A8VCHYowxVV7YJfm0eokA7Dh4IsSRGFM+ixYt4quvvqqUfV133XUcPny41M+bPn0699xzT/ADqmDbtm3jnXfeCXUYVULASV5E3CLynYj83c+6eBGZJSKbRWSZiDQLapQ+0pIsyZvIUBlJXlXxeDwsWLCAOnXqVOi+zrX/ynauJJ+Xl1fJ0YRWaYZQ3g9sAGr5WTcSOKSqF4rILcAzwJAgxHeWxLgYkmvEsyPLkrwp3u8/Xsf63UeDus1WjWrx1K9al9huxowZPP/884gI7dq1Y/DgwTz99NPk5ORQr149Zs6cycmTJ5k0aRJut5u3336bl19+mYsuuogxY8awY8cOAF588UUuu+wyMjMzue2229i9ezfdunXjs88+Y/ny5SQnJzNhwgSmTp0KwKhRo3jggQfYtm0bffv2pWvXrixfvpwFCxbQq1cvMjIySE5OPiu+t956i48//visGOvXr1/i77pv3z7GjBnD1q1bAZg4cSKNGjU6a/+vvPIKn3zyCSLC448/zpAhQ9izZw9Dhgzh6NGj5OXlMXHiRLp3787IkSPJyMhARBgxYgQPPvggW7ZsYezYsWRmZpKYmMjrr7/ORRddxPDhw6lVqxYZGRns3buXZ599loEDB/Loo4+yYcMG0tPTGTZsGHXr1uWDDz4gOzub/Px85s2bx4gRI9i6dSuJiYlMnjyZdu3aMX78eLZs2cLmzZs5cOAADz/8ML/+9a8ZOnQoN910EzfccAMAt99+O4MHD2bAgAFlPJsqT0BJXkSaANcDfwIe8tNkADDeOz0HeEVERCvoBrJpSdXsSt5USevWrePpp5/mq6++Ijk5mYMHDyIiLF26FBHhjTfe4Nlnn+Wvf/0rY8aMoUaNGvzP//wPALfddhsPPvggl19+OTt27KBv375s2LCB3//+9/Tp04fHHnuMf/7zn0yZMgWA5cuXM23aNJYtW4aq0rVrV3r16kXdunX54YcfePPNN7n00ktLjA/g8ssv9xtjSe677z569erFvHnzyM/PJzs7m0OHDp2x/7lz57Jy5UpWrVrFgQMH6Ny5Mz179uSdd96hb9++jBs3jvz8fE6cOMHKlSvZtWsXa9euBSjsYho9ejSTJk2iRYsWLFu2jLvvvpsvvvgCgD179rBkyRI2btxI//79GThwIH/5y194/vnn+fvfnY6H6dOns2LFClavXk1SUhL33nsvHTp0YP78+XzxxRcMHTqUlStXArB69WqWLl3K8ePH6dChA9dffz0jR47khRde4IYbbuDIkSN89dVXvPnmm+U7WSpJoFfyLwIPAzWLWd8Y+AlAVfNE5AhQDzjg20hERgOjAdLS0soQriMtKZFvtx0q8/NN5AvkirsifPHFFwwaNIjk5GQAkpKSWLNmTeGVa05OTrFfbvn8889Zv3594fzRo0fJzs5myZIlzJs3D4BrrrmGunXrArBkyRJuvPFGqlevDsBNN93El19+Sf/+/WnatOlZCb64+MD5IlkgMfrb3owZMwBwu93Url2bQ4cOnbH/JUuWcOutt+J2u6lfvz69evXi22+/pXPnzowYMYLc3FxuuOEG0tPTad68OVu3buXee+/l+uuv5+qrryY7O5uvvvqKQYMGFe739OnThdM33HADLpeLVq1asW/fvmJjveqqqwp/3yVLljB37lwA+vTpQ1ZWFkePOu/8BgwYQLVq1ahWrRpXXHEF33zzDTfccAN33303mZmZzJ07l5tvvpmYmPD4LmmJffIi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715NTU3V3bt368KFCzUxMVG3bt1auO2C55Q2xnOVDVBV7dKli37wwQeqqnry5Ek9fvz4Wft//vnn9a677lJV1Q0bNmhqaqqePHlS77nnHn377bdVVfX06dN64sQJnTNnjo4aNapw+4cPH9acnBzt1q2b7t+/X1VV33vvvcLt9erVSx966CFVVf3HP/6hV155paqqTps2TceOHVu4naeeekovueQSPXHihKqq9uvXT6dPn66qqlOmTNEBAwYU/k369u2r+fn5umnTJm3cuLGePHlSp0+frvfff7+qqn7//fdaXD6s9LIGVU1qUiLzV+4iJ89DXEzY9jyZilDCFXdF6dChA/v372f37t1kZmZSt25dGjRowIMPPsjixYtxuVzs2rWLffv20aBBg3Nu6/PPP+euu+4qvAIuqIW+du1aHn/8cQ4fPkx2djZ9+/Y967nnqsH+9ddfM3/+fMC5UUnBTUuKq/teq1YtunTp4rfGfHliLOrYsWPs2rWLG2+8EYCEhITCdb77X7JkCffeey8AF110EU2bNmXTpk1069aNP/3pT+zcuZObbrqJFi1a0LZtW373u9/xyCOP0K9fP3r06MHatWtZu3YtV111FeBUz2zYsGHhvm666SYAOnbsyLZt24qNt3///lSrVq3wmH7wwQcA3HnnnTz88MOF7QYPHozL5aJFixY0b96cjRs3MmjQIP74xz/y3HPPMXXqVIYPH17i8SmrsE7yaUmJqMKuwyc5P7l09bONqSiDBg1izpw57N27lyFDhjBz5kwyMzNZvnw5sbGxNGvWrFz12ocPH878+fNp374906dPZ9GiRWe18a3BHgylrU8fSIzB3v9tt91G165d+cc//sF1113Ha6+9Rp8+fVixYgULFizg8ccf58orr+TGG2+kdevWfP311363U1Cf3u12n7O/vTz16RMTE7nqqqv48MMPef/991m+vNy36yhWWF/+2jBKUxUNGTKE9957jzlz5jBo0CCOHDnCeeedR2xsLAsXLgy4BspVV13FtGnTOHHCOb8Lar8fO3aMhg0bkpubW1gTHc6soX6uGuwFt+QDeO+99wqfX1zd92DGeC41a9akSZMmhe8yTp8+XbhdX7614Ddt2sSOHTto2bIlW7dupXnz5tx3330MGDCA1atXs3v3bhITE7njjjv43//9X1asWEHLli3JzMwsTPK5ubmsW7euxNjOVZ++e/fuhcdy5syZZ9T1nz17Nh6Pp7APv2XLloBzT9777ruPzp07F97tqyJYkjcmyFq3bs2xY8do3LgxDRs25PbbbycjI4O2bdsyY8YMLrroooC2c80119C/f386depEenp64dDDP/7xj3Tt2pXLLrvsjG3dcsstPPfcc3To0IEtW7YUW4P9xRdfZMKECbRr147NmzcXVlUsru57MGMsyVtvvcVLL71Eu3bt6N69O3v37j2rzd13343H46Ft27YMGTKE6dOnEx8fz/vvv0+bNm1IT09n7dq1DB06lDVr1tClSxfS09P5/e9/z+OPP05cXBxz5szhkUceoX379qSnp5c4WuiKK65g/fr1pKenM2vWrLPWv/zyy0ybNq3wxuh/+9vfCtelpaXRpUsXrr32WiZNmlTYDdWxY0dq1apV4fXpRUNU+6VTp06akZFRrm14PMrFT/6TYd2b8X/XXRykyEy42rBhAxdfbOdBSU6cOEG1atUQEd577z3efffdEm/CYcpm+PDh9OvXj4EDB561bvfu3fTu3ZuNGzficvm/3vZ3TovIclXtFGgMYd0n73IJqUmJbM86HupQjAkby5cv55577kFVqVOnDlOnTg11SFFnxowZjBs3jgkTJhSb4IOlxCQvIgnAYiDe236Oqj5VpM1w4Dmce70CvKKqbwQ3VP+cksN2r1cTvtasWcOdd955xrL4+HiWLVtWIfvr0aNHifdIrWhjx47lv//97xnL7r///vC7tV4Jpk+f7nf50KFDGTp0aKXEEMiV/Gmgj6pmi0gssEREPlHVpUXazVLVe4If4rmlJSXyzY8HUdWzPsU20Sccz4O2bdsGbRRMuHj11VdDHUKVF6yu9EBu5K2qmu2djfU+qkwR99SkRLJP53HISg5HvYSEBLKysuweAybsqSpZWVlnfFegrALqkxcRN7AcuBB4VVX9vY+8WUR6ApuAB1X1Jz/bGQ2MBucT52DwHWGTVD0uKNs04alJkybs3LmTzMzMUIdiTLklJCTQpEmTcm8noCSvqvlAuojUAeaJSBtVXevT5GPgXVU9LSK/Ad4E+vjZzmRgMjija8obPDj1a8BJ8umpdYKxSROmYmNj/X4r05hoVqqPdVX1MLAQuKbI8ixVPe2dfQPoGJToApBa15vkbYSNMcacpcQkLyIp3it4RKQacBWwsUib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", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD4CAYAAAD8Zh1EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAAsTAAALEwEAmpwYAAAwXElEQVR4nO3deXiU9b3//+dnZpLJNiGBJOyIWg6IAkEQ3BDBDZcCLoArIqJfF9TqOUfxhwtt7VWrHqpYv1KtgigWBQRppXWFYyliDTSyi8AXIWxZgOzbzLx/f9yTYRKyDGS/5/24rrnm3uaed26G13zm3j5GRFBKKdX+OVq7AKWUUk1DA10ppWxCA10ppWxCA10ppWxCA10ppWzC1VpvnJKSIr17926tt1dKqXZp/fr1uSKSWtu8Vgv03r17k5GR0Vpvr5RS7ZIx5qe65ukuF6WUsgkNdKWUsgkNdKWUsolW24euVFOrrKwkKyuLsrKy1i5FqUaLiYmhR48eREVFhf0aDXRlG1lZWXg8Hnr37o0xprXLUeqUiQh5eXlkZWVx+umnh/063eWibKOsrIxOnTppmKt2zxhDp06dTvrXpga6shUNc2UXp/JZbneB/t2eI/zu79vR2/4qpVR17S7QN2bl8/rqXeSXVrZ2KUop1aa0u0BP9bgByCksb+VKlGqc1atXs3bt2hZ5r2uuuYZjx46d9Ovmz5/P9OnTm76gZrZnzx7ef//91i6jxbW7QE8LBHq2Brpq51oi0EUEv9/PypUrSUpKatb3qu/9W1p9ge71elu4mpbT7k5b1Ba6Cscv/7KFrQcKmnSd/bsl8uzPz25wuQULFvDSSy9hjGHgwIFMnDiR5557joqKCjp16sTChQspLS1l7ty5OJ1O3nvvPV599VX69evHfffdx969ewF4+eWXueiii8jJyeHWW2/lwIEDXHDBBXz++eesX7+elJQUZs+ezdtvvw3AtGnT+MUvfsGePXu46qqrGD58OOvXr2flypWMHDmSjIwMUlJSTqjv3Xff5S9/+csJNXbu3LnBv/Xw4cPcd9997N69G4DXX3+dbt26nfD+f/jDH/jb3/6GMYannnqKSZMmcfDgQSZNmkRBQQFer5fXX3+dCy+8kLvvvpuMjAyMMUydOpVHH32UXbt28eCDD5KTk0NcXBxvvvkm/fr1Y8qUKSQmJpKRkcGhQ4d44YUXuOmmm5gxYwbbtm0jPT2dO++8k+TkZD766COKiorw+XwsW7aMqVOnsnv3buLi4njjjTcYOHAgs2bNYteuXezcuZPc3Fwef/xx7rnnHiZPnswNN9zA+PHjAbjtttuYOHEi48aNO8VPU/Nod4F+vIWuF4+otmfLli0899xzrF27lpSUFI4cOYIxhnXr1mGM4U9/+hMvvPAC//M//8N9991HQkIC//Vf/wXArbfeyqOPPsrFF1/M3r17ueqqq9i2bRu//OUvGT16NE8++SR///vfeeuttwBYv3498+bN49tvv0VEGD58OCNHjiQ5OZkff/yRd955h/PPP7/B+gAuvvjiWmtsyMMPP8zIkSNZtmwZPp+PoqIijh49Wu39ly5dSmZmJt9//z25ubmcd955XHLJJbz//vtcddVVzJw5E5/PR0lJCZmZmezfv5/NmzcDBHcT3XvvvcydO5c+ffrw7bff8sADD/DVV18BcPDgQdasWcP27dsZO3YsN910E88//zwvvfQSf/3rXwFr19GGDRvYuHEjHTt25KGHHmLw4MEsX76cr776ismTJ5OZmQnAxo0bWbduHcXFxQwePJhrr72Wu+++m9///veMHz+e/Px81q5dyzvvvNO4D0szCCvQjTFjgFcAJ/AnEXm+xvzfA6MCo3FAmogkNWGdQQluFzFRDm2hq3qF05JuDl999RUTJkwgJSUFgI4dO7Jp06Zgi7SioqLOC0W++OILtm7dGhwvKCigqKiINWvWsGzZMgDGjBlDcnIyAGvWrOH6668nPj4egBtuuIF//OMfjB07ltNOO+2EMK+rPrAuygqnxtrWt2DBAgCcTicdOnTg6NGj1d5/zZo13HLLLTidTjp37szIkSP57rvvOO+885g6dSqVlZWMHz+e9PR0zjjjDHbv3s1DDz3Etddey5VXXklRURFr165lwoQJwfctLz/+/3/8+PE4HA769+/P4cOH66z1iiuuCP69a9asYenSpQCMHj2avLw8CgqsX3Tjxo0jNjaW2NhYRo0axb/+9S/Gjx/PAw88QE5ODkuXLuXGG2/E5Wp77eEG96EbY5zAa8DVQH/gFmNM/9BlRORREUkXkXTgVeCjZqi1qh7SPDEa6KrdeOihh5g+fTqbNm3ij3/8Y50Xi/j9ftatW0dmZmawpZqQkHBK71kV8k1dY1O+/yWXXMLXX39N9+7dmTJlCgsWLCA5OZnvv/+eSy+9lLlz5zJt2jT8fj9JSUnB7ZKZmcm2bduC63G73cHh+k5nDneb1Dz/u2p88uTJvPfee8ybN4+pU6eGta6WFs5B0WHAThHZLSIVwCKgvh1HtwB/bori6pLqcetBUdUmjR49msWLF5OXlwfAkSNHyM/Pp3v37gDVfqZ7PB4KCwuD41deeSWvvvpqcLxqF8BFF13Ehx9+CMBnn33G0aNHARgxYgTLly+npKSE4uJili1bxogRI066PqDOGhty2WWX8frrrwPg8/nIz88/YZkRI0bwwQcf4PP5yMnJ4euvv2bYsGH89NNPdO7cmXvuuYdp06axYcMGcnNz8fv93HjjjTz33HNs2LCBxMRETj/9dBYvXgxYof3999/XW1fNbVtbTQsXLgSsg9MpKSkkJiYC8PHHH1NWVkZeXh6rV6/mvPPOA2DKlCm8/PLLAPTv37/W9ba2cAK9O7AvZDwrMO0ExpjTgNOBrxpfWt1SE9zaQldt0tlnn83MmTMZOXIkgwYN4rHHHmPWrFlMmDCBIUOGBHd1APz85z9n2bJlpKen849//IM5c+aQkZHBwIED6d+/P3PnzgXg2Wef5bPPPuOcc85h8eLFdOnSBY/Hw7nnnsuUKVMYNmwYw4cPZ9q0aQwePPik6wPqrLEhr7zyCqtWrWLAgAEMGTKk2i6jKtdffz0DBw5k0KBBjB49mhdeeIEuXbqwevVqBg0axODBg/nggw945JFH2L9/P5deeinp6encfvvt/Pa3vwVg4cKFvPXWWwwaNIizzz6bjz/+uN66Bg4ciNPpZNCgQfz+978/Yf6sWbNYv349AwcOZMaMGdW+xAYOHMioUaM4//zzefrpp+nWrRsAnTt35qyzzuKuu+4Ke/u0NNPQFZfGmJuAMSIyLTB+BzBcRE44OdUY8wTQQ0QeqmNd9wL3AvTq1WvITz/V2fFGvZ75eDMfZx7g+2evPKXXK3vatm0bZ511VmuX0eTKy8txOp24XC6++eYb7r///mDrXTWtWbNmVTtQHaqkpIQBAwawYcMGOnTo0CL11PaZNsasF5GhtS0fzl79/UDPkPEegWm1uRl4sK4VicgbwBsAQ4cOPeVr91MT3OSXVlLu9eF2OU91NUq1C3v37mXixIn4/X6io6N58803W7ukiPPFF19w99138+ijj7ZYmJ+KcAL9O6CPMeZ0rCC/Gbi15kLGmH5AMvBNk1ZYi7RE6yBIblEF3ZNim/vtlGpVffr04d///ner1vCb3/wmuA+7yoQJE5g5c2YrVdQ8Zs2aVev0yy+/nFPdo9CSGgx0EfEaY6YDn2Kdtvi2iGwxxvwKyBCRFYFFbwYWSQvcNavq4qLsgjINdKVawMyZM20X3nYU1omUIrISWFlj2jM1xmc1XVn1S02IAfRqUaWUCtXu7uUCx3e56KmLSil1XLsM9E7x0RijLXSllArVLgPd5XTQKT6anCINdKWUqtIuAx0gJcFNdoEGumrfTvXS/tosX7681gt7msOFF154Sq+bNWsWL730UhNX0/wyMzNZuXJlwwu2snYb6Kket7bQlQrREoFedS/xluqYo673b2n1BXpbur9627tdWJjSPDHsys5t7TJUW/W3GXBoU9Ous8sAuPr5eheZMWMGPXv25MEHrevrZs2ahcvlYtWqVRw9epTKykqee+65sO+j/bvf/Y733nsPh8PB1VdfzfPPP8+bb77JG2+8QUVFBT/72c949913yczMZMWKFfzv//4vzz33XPBOgrXdQ3zXrl3cdtttFBcXM27cOF5++WWKiooQER5//PET7lu+evVqnn76aZKTk9m+fTs7duwgISGBoqKik6oxLi6uwb93586d3HfffeTk5OB0Olm8eDH79u2r9v4bN27k/vvvJyMjA5fLxezZsxk1ahRbtmzhrrvuoqKiAr/fz9KlS+nWrRsTJ04kKysLn8/H008/zaRJk1i/fj2PPfYYRUVFpKSkMH/+fLp27cqll17K8OHDWbVqFceOHeOtt95i+PDhPPPMM5SWlrJmzRqefPJJtm3bxq5du9i9eze9evXit7/9LVOnTiU3N5fU1FTmzZtHr169mDJlCjExMWRkZFBQUMDs2bO57rrruOSSS5gzZw7p6emAdfvi1157jUGDBoX1uaiTiLTKY8iQIdIYv125TX72/30ifr+/UetR9rF169bjIyufEHn7mqZ9rHyiwRo2bNggl1xySXD8rLPOkr1790p+fr6IiOTk5MiZZ54Z/NzGx8fXua6VK1fKBRdcIMXFxSIikpeXJyIiubm5wWVmzpwpc+bMERGRO++8UxYvXhycN3r0aNmxY4eIiKxbt05GjRolIiLXXnutvP/++yIi8vrrrwdrWLJkiVx++eXi9Xrl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", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD4CAYAAAD8Zh1EAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAAsTAAALEwEAmpwYAAA0h0lEQVR4nO3dd3hUZd7/8fc9M0kmIYVAIAkJVREECaELSFdBZQELYEVE1h8q1t21PFiw7LOuuqx1wQaI4oMCgujGLqioIElEWiCESEkgFdL7zP37YyZDCGkkmUwy831d11xz5szJub85OfnMmfs0pbVGCCFE22dwdQFCCCGahwS6EEK4CQl0IYRwExLoQgjhJiTQhRDCTZhc1XBISIju0aOHq5oXQog2KS4uLktr3amm91wW6D169CA2NtZVzQshRJuklDpS23vS5SKEEG5CAl0IIdyEBLoQQrgJl/WhC9HcysvLSUlJoaSkxNWlCNFkZrOZyMhIvLy8GvwzEujCbaSkpBAQEECPHj1QSrm6HCEaTWtNdnY2KSkp9OzZs8E/J10uwm2UlJTQsWNHCXPR5iml6Nix4zl/25RAF25Fwly4i8asy20u0HccPsk/v9iPXPZXCCHO1OYCfVdKLku3HCKnqNzVpQghRKvS5gI9PMgMQFqeHMkg2rYtW7bw888/t0hbV155JTk5Oef8cytXrmThwoXNX5CTHT58mA8++MDVZbS4NhfoYZWBniuBLtq2lgh0rTVWq5WYmBjat2/v1Lbqar+l1RXoFRUVLVxNy2lzhy2GBdoC/YQEuqjDU5/uZd/xvGadZ78ugTz5p/71Trdq1SpefPFFlFJERUUxa9Ysnn32WcrKyujYsSOrV6+muLiYZcuWYTQaef/993n11Vfp27cvCxYs4OjRowC89NJLjB49mszMTG688UaOHz/OyJEj+frrr4mLiyMkJIQlS5awfPlyAObPn8/999/P4cOHmTx5MiNGjCAuLo6YmBjGjRtHbGwsISEhZ9X33nvv8emnn55VY2hoaL2/a3p6OgsWLCA5ORmApUuX0qVLl7Paf+211/j8889RSvHYY48xe/ZsTpw4wezZs8nLy6OiooKlS5cyatQobr/9dmJjY1FKMW/ePB544AEOHTrE3XffTWZmJn5+frz11lv07duXuXPnEhgYSGxsLGlpaTz//PNcd911PPLIIyQkJBAdHc2tt95KcHAwH3/8MQUFBVgsFjZs2MC8efNITk7Gz8+PN998k6ioKBYvXsyhQ4dISkoiKyuLhx56iD//+c/MmTOHa665hhkzZgBw0003MWvWLKZPn97Itck52lygdwrwwaAgLbfY1aUIcZa9e/fy7LPP8vPPPxMSEsLJkydRSrFt2zaUUrz99ts8//zz/Otf/2LBggX4+/vz17/+FYAbb7yRBx54gEsuuYSjR48yefJkEhISeOqpp5g4cSKPPvooX3zxBe+88w4AcXFxrFixgu3bt6O1ZsSIEYwbN47g4GAOHjzIu+++y8UXX1xvfQCXXHJJjTXW595772XcuHFs2LABi8VCQUEBp06dOqP99evXs3PnTn7//XeysrIYNmwYY8eO5YMPPmDy5MksWrQIi8VCUVERO3fuJDU1lT179gA4uonuuOMOli1bRu/evdm+fTt33XUX3333HQAnTpxg69at7N+/n2nTpnHdddfx3HPP8eKLL/LZZ58Btq6j+Ph4du3aRYcOHbjnnnsYNGgQGzdu5LvvvmPOnDns3LkTgF27drFt2zYKCwsZNGgQV111Fbfffjv//ve/mTFjBrm5ufz888+8++67TVtZnKDNBbqX0UCnAB/ZQhd1asiWtDN89913zJw5k5CQEAA6dOjA7t27HVukZWVltZ4o8s0337Bv3z7H67y8PAoKCti6dSsbNmwAYMqUKQQHBwOwdetWrr76atq1awfANddcw48//si0adPo3r37WWFeW31gOymrITXWNL9Vq1YBYDQaCQoK4tSpU2e0v3XrVm644QaMRiOhoaGMGzeOHTt2MGzYMObNm0d5eTkzZswgOjqaXr16kZyczD333MNVV13F5ZdfTkFBAT///DMzZ850tFtaWuoYnjFjBgaDgX79+pGenl5rrZdddpnj9926dSvr168HYOLEiWRnZ5OXZ/tGN336dHx9ffH19WXChAn8+uuvzJgxg7vuuovMzEzWr1/Ptddei8nU+uKzzfWhA4QF+cpOUdFm3HPPPSxcuJDdu3fzxhtv1HqyiNVqZdu2bezcudOxperv79+oNitDvrlrbM72x44dyw8//EBERARz585l1apVBAcH8/vvvzN+/HiWLVvG/PnzsVqttG/f3rFcdu7cSUJCgmM+Pj4+juG6Dmdu6DKpfvx35es5c+bw/vvvs2LF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", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "base_history[history_columns].plot()\n", "lstm_history[history_columns].plot()\n", "gru_history[history_columns].plot()\n", "attn_history[history_columns].plot()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "base_model = tf.keras.models.load_model(f\"{MODEL_DIR}/baseline\")\n", "lstm_model = tf.keras.models.load_model(f\"{MODEL_DIR}/lstm\")\n", "gru_model = tf.keras.models.load_model(f\"{MODEL_DIR}/gru\")" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "ename": "RuntimeError", "evalue": "Unable to restore object of class 'Attention' likely due to name conflict with built-in Keras class '<class 'keras.layers.dense_attention.Attention'>'. To override the built-in Keras definition of the object, decorate your class with `@keras.utils.register_keras_serializable` and include that file in your program, or pass your class in a `keras.utils.CustomObjectScope` that wraps this load call.", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m/Users/nowadmin/Documents/School Folder/CS 437/Lab/Final Project/tf_model.ipynb Cell 65'\u001b[0m in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> <a href='vscode-notebook-cell:/Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/tf_model.ipynb#ch0000068?line=0'>1</a>\u001b[0m attn_model \u001b[39m=\u001b[39m tf\u001b[39m.\u001b[39;49mkeras\u001b[39m.\u001b[39;49mmodels\u001b[39m.\u001b[39;49mload_model(\u001b[39mf\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39m{\u001b[39;49;00mMODEL_DIR\u001b[39m}\u001b[39;49;00m\u001b[39m/attention\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n", "File \u001b[0;32m~/Documents/School Folder/CS 437/Lab/Final Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py:67\u001b[0m, in \u001b[0;36mfilter_traceback.<locals>.error_handler\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py?line=64'>65</a>\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mException\u001b[39;00m \u001b[39mas\u001b[39;00m e: \u001b[39m# pylint: disable=broad-except\u001b[39;00m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py?line=65'>66</a>\u001b[0m filtered_tb \u001b[39m=\u001b[39m _process_traceback_frames(e\u001b[39m.\u001b[39m__traceback__)\n\u001b[0;32m---> <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py?line=66'>67</a>\u001b[0m \u001b[39mraise\u001b[39;00m e\u001b[39m.\u001b[39mwith_traceback(filtered_tb) \u001b[39mfrom\u001b[39;00m \u001b[39mNone\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py?line=67'>68</a>\u001b[0m \u001b[39mfinally\u001b[39;00m:\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/utils/traceback_utils.py?line=68'>69</a>\u001b[0m \u001b[39mdel\u001b[39;00m filtered_tb\n", "File \u001b[0;32m~/Documents/School Folder/CS 437/Lab/Final Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py:532\u001b[0m, in \u001b[0;36mKerasObjectLoader._revive_layer_or_model_from_config\u001b[0;34m(self, metadata, node_id)\u001b[0m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=529'>530</a>\u001b[0m builtin_layer \u001b[39m=\u001b[39m layers_module\u001b[39m.\u001b[39mget_builtin_layer(class_name)\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=530'>531</a>\u001b[0m \u001b[39mif\u001b[39;00m builtin_layer:\n\u001b[0;32m--> <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=531'>532</a>\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mRuntimeError\u001b[39;00m(\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=532'>533</a>\u001b[0m \u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mUnable to restore object of class \u001b[39m\u001b[39m\\'\u001b[39;00m\u001b[39m{\u001b[39;00mclass_name\u001b[39m}\u001b[39;00m\u001b[39m\\'\u001b[39;00m\u001b[39m likely due to \u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=533'>534</a>\u001b[0m \u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mname conflict with built-in Keras class \u001b[39m\u001b[39m\\'\u001b[39;00m\u001b[39m{\u001b[39;00mbuiltin_layer\u001b[39m}\u001b[39;00m\u001b[39m\\'\u001b[39;00m\u001b[39m. To \u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=534'>535</a>\u001b[0m \u001b[39m'\u001b[39m\u001b[39moverride the built-in Keras definition of the object, decorate \u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=535'>536</a>\u001b[0m \u001b[39m'\u001b[39m\u001b[39myour class with `@keras.utils.register_keras_serializable` and \u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=536'>537</a>\u001b[0m \u001b[39m'\u001b[39m\u001b[39minclude that file in your program, or pass your class in a \u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=537'>538</a>\u001b[0m \u001b[39m'\u001b[39m\u001b[39m`keras.utils.CustomObjectScope` that wraps this load call.\u001b[39m\u001b[39m'\u001b[39m) \u001b[39mfrom\u001b[39;00m \u001b[39me\u001b[39;00m\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=538'>539</a>\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[1;32m <a href='file:///Users/nowadmin/Documents/School%20Folder/CS%20437/Lab/Final%20Project/venv/lib/python3.10/site-packages/keras/saving/saved_model/load.py?line=539'>540</a>\u001b[0m \u001b[39mraise\u001b[39;00m\n", "\u001b[0;31mRuntimeError\u001b[0m: Unable to restore object of class 'Attention' likely due to name conflict with built-in Keras class '<class 'keras.layers.dense_attention.Attention'>'. To override the built-in Keras definition of the object, decorate your class with `@keras.utils.register_keras_serializable` and include that file in your program, or pass your class in a `keras.utils.CustomObjectScope` that wraps this load call." ] } ], "source": [ "attn_model = tf.keras.models.load_model(f\"{MODEL_DIR}/attention\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def model_time():\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Scratch" ] } ], "metadata": { "kernelspec": { "display_name": "final_lab", "language": "python", "name": "final_lab" }, "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.10.4" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }